A Simple Forward Chemical Reaction
This verification problem is taken from Longhurst et al. (1992) and Ambrosek and Longhurst (2008), and it has been updated and extended in Simon et al. (2025). A simple time-dependent chemical reaction given by
is modeled in a functional enclosure. The reaction rate, , is positive if the species AB is being produced in the reaction and negative if it is being consumed. The forward rate coefficient, , for the reaction has no spatial or time dependence. The reaction rate is:
where and are the concentrations of A and B, respectively. The reaction rate in terms of the concentrations of the reactants and product is given as:
where is the concentration of species AB. The analytical solution for the concentration of species AB as a function of time () is given as:
(1)
where and are the initial concentrations of A and B, respectively. For the special case when and are equal, Eq. (1) becomes:
For this verification exercise, three cases were considered: (a) the initial concentrations of A and B are equal, (b) the initial concentrations of A and B are different and use the TMAP4 verification case values, and (c) the initial concentrations of A and B are different and use the TMAP7 verification case values. The equal concentration case is the same in TMAP4 and TMAP7, and is used for verification of TMAP8 here. While both TMAP4 and TMAP7 verification cases ((b) and (c) respectively) have the same analytical solution, the different initial conditions produce different values over time, and we replicate both results here.
For case (a), the initial pressures of A and B were 1 Pa, and the reaction rate is 4.14 10 m / atoms. For case (b) the initial pressure of A was same as in case (a) while the initial pressure of B is 0.1 Pa as per TMAP4. For case (c) the initial pressure of A was same as in case (a) while the initial pressure of B is 0.5 Pa. In all cases, the initial pressures of A and B are first converted to their initial concentrations and using the ideal gas law to be used in the TMAP8 simulations and analytical solutions. The initial concentration of component is
where is the initial pressure, is Avogardro's constant, is the gas constant (from PhysicalConstants), and = 298.15 K (25C) is the temperature. The factor converts the concentration from atoms/m to atoms/m.
A comparison of the concentration of AB as a function of time is plotted in Figure 1 for case (a), and Figure 2 for the cases (b) and (c), respectively. The TMAP8 calculations are found to be in good agreement with the analytical solution with the root mean square percentage errors of (a) RMSPE = 0.27 %, (b) RMSPE = 0.22 %, and (c) RMSPE = 0.24 %.

Figure 1: Comparison of concentration of AB as a function of time calculated through TMAP8 and analytically for the case when A and B have equal concentrations.

Figure 2: Comparison of concentration of AB as a function of time calculated through TMAP8 and analytically for the case when A and B have different concentrations. The plot shows comparisons for the initial conditions specified in both TMAP4 (case (b)) and TMAP7 (case (c)).
(test/tests/ver-1g/ver-1g.i)
## Run this file with one of three input files to simulate various verification cases
## a. equal_conc.i -> TMAP4 and TMAP7 equal concentration case
## b. diff_conc_TMAP4.i -> TMAP4 different concentration case
## c. diff_conc_TMAP7.i -> TMAP7 different concentration case
## Example: ~/projects/TMAP8/tmap8-opt -i ver-1g.i equal_conc.i
R = 8.31446261815324 # Gas constant (from PhysicalConstants.h - https://physics.nist.gov/cgi-bin/cuu/Value?r)
T = '${units 25 degC -> K}' # Temperature
Na = 6.02214076E23 # Avogadro's constant (from PhysicalConstants.h - https://physics.nist.gov/cgi-bin/cuu/Value?na)
[Mesh]
type = GeneratedMesh
dim = 2
[]
[Variables]
[c_a]
[]
[c_b]
[]
[c_ab]
initial_condition = 0
[]
[]
[Kernels]
[timeDerivative_c_a]
type = ADTimeDerivative
variable = c_a
[]
[timeDerivative_c_b]
type = TimeDerivative
variable = c_b
[]
[timeDerivative_c_ab]
type = TimeDerivative
variable = c_ab
[]
[MatReaction_b]
type = ADMatReactionFlexible
variable = c_b
vs = 'c_a c_b'
coeff = -1
reaction_rate_name = K
[]
[MatReaction_a]
type = ADMatReactionFlexible
variable = c_a
vs = 'c_b c_a'
coeff = -1
reaction_rate_name = K
[]
[MatReaction_ab]
type = ADMatReactionFlexible
variable = c_ab
vs = 'c_b c_a'
coeff = 1
reaction_rate_name = K
[]
[]
[Materials]
[K]
type = ADParsedMaterial
property_name = 'K'
expression = '4.14e3' # units: molecule.micrometer^3/atom/second
[]
[]
[BCs]
[c_a_neumann] # No flux on the sides
type = NeumannBC
variable = c_a
boundary = 'left right bottom top'
value = 0
[]
[c_b_neumann] # No flux on the sides
type = NeumannBC
variable = c_b
boundary = 'left right bottom top'
value = 0
[]
[c_ab_neumann] # No flux on the sides
type = NeumannBC
variable = c_ab
boundary = 'left right bottom top'
value = 0
[]
[]
[Postprocessors]
[conc_a]
type = ElementAverageValue
variable = c_a
[]
[conc_b]
type = ElementAverageValue
variable = c_b
[]
[conc_ab]
type = ElementAverageValue
variable = c_ab
[]
[]
[Executioner]
type = Transient
scheme = bdf2
nl_rel_tol = 1e-10
nl_abs_tol = 1e-15
solve_type = 'NEWTON'
petsc_options = '-snes_ksp_ew'
petsc_options_iname = '-pc_type'
petsc_options_value = 'lu'
start_time = 0.0
end_time = 40
num_steps = 60000
dt = .2
n_startup_steps = 0
[]
[Outputs]
exodus = true
csv = true
[]
(test/tests/ver-1g/tests)
[Tests]
design = 'ADMatReactionFlexible.md'
issues = '#12'
verification = 'ver-1g.md'
[binary_reaction_equal_concentrations]
type = Exodiff
input = 'ver-1g.i equal_conc.i'
exodiff = equal_conc_out.e
requirement = 'The system shall be able to model a chemical reaction between two species with the same concentrations and calculate the concentrations of reactants and product as a function of time'
[]
[binary_reaction_diff_concentrations_TMAP4]
type = Exodiff
input = 'ver-1g.i diff_conc_TMAP4.i'
exodiff = diff_conc_TMAP4_out.e
requirement = 'The system shall be able to model a chemical reaction between two species with different concentrations and calculate the concentrations of reactants and product as a function of time using the initial conditions from the TMAP4 case'
[]
[binary_reaction_diff_concentrations_TMAP7]
type = Exodiff
input = 'ver-1g.i diff_conc_TMAP7.i'
exodiff = diff_conc_TMAP7_out.e
requirement = 'The system shall be able to model a chemical reaction between two species with different concentrations and calculate the concentrations of reactants and product as a function of time using the initial conditions from the TMAP7 case'
[]
[binary_reaction_equal_concentrations_csv_diff]
type = CSVDiff
input = 'ver-1g.i equal_conc.i'
should_execute = False # this test relies on the output files from binary_reaction_equal_concentrations, so it shouldn't be run twice
csvdiff = equal_conc_out.csv
requirement = 'The system shall be able to model a chemical reaction between two species with the same concentrations and calculate the concentrations of reactants and product as a function of time, to match the analytical solution to generate CSV data for use in comparisons with the analytic solution over time.'
prereq = binary_reaction_equal_concentrations
[]
[binary_reaction_diff_concentrations_csv_diff_TMAP4]
type = CSVDiff
input = 'ver-1g.i diff_conc_TMAP4.i'
should_execute = False # this test relies on the output files from binary_reaction_equal_concentrations, so it shouldn't be run twice
csvdiff = diff_conc_TMAP4_out.csv
requirement = 'The system shall be able to model a chemical reaction between two species with different concentrations using the initial conditions from the TMAP4 case and calculate the concentrations of reactants and product as a function of time to generate CSV data for use in comparisons with the analytic solution over time.'
prereq = binary_reaction_diff_concentrations_TMAP4
[]
[binary_reaction_diff_concentrations_csv_diff_TMAP7]
type = CSVDiff
input = 'ver-1g.i diff_conc_TMAP7.i'
should_execute = False # this test relies on the output files from binary_reaction_equal_concentrations, so it shouldn't be run twice
csvdiff = diff_conc_TMAP7_out.csv
requirement = 'The system shall be able to model a chemical reaction between two species with different concentrations using the initial conditions from the TMAP7 case and calculate the concentrations of reactants and product as a function of time to generate CSV data for use in comparisons with the analytic solution over time.'
prereq = binary_reaction_diff_concentrations_TMAP7
[]
[ver-1g_comparison]
type = RunCommand
command = 'python3 comparison_ver-1g.py'
requirement = 'The system shall be able to generate comparison plots between the analytical solution and simulated solution of a chemical reaction between two species with same or different concentrations, using the initial conditions from both TMAP4 and TMAP7 cases.'
required_python_packages = 'matplotlib numpy pandas os'
[]
[]
(test/tests/ver-1g/equal_conc.i)
[ICs]
ca_IC = '${fparse ${units 1 muPa -> Pa} * ${Na} / ( ${R} * ${T} ) }'
cb_IC = '${fparse ${units 1 muPa -> Pa} * ${Na} / ( ${R} * ${T} ) }'
[ca_same_conc_IC]
type = ConstantIC
variable = c_a
value = '${units ${ca_IC} at/m^3 -> at/mum^3 }'
[]
[cb_same_conc_IC]
type = ConstantIC
variable = c_b
value = '${units ${cb_IC} at/m^3 -> at/mum^3 }'
[]
[]
(test/tests/ver-1g/diff_conc_TMAP4.i)
[ICs]
ca_IC = '${fparse ${units 1 muPa -> Pa} * ${Na} / ( ${R} * ${T} ) }'
cb_IC = '${fparse ${units 0.1 muPa -> Pa} * ${Na} / ( ${R} * ${T} ) }'
[ca_same_conc_IC]
type = ConstantIC
variable = c_a
value = '${units ${ca_IC} at/m^3 -> at/mum^3 }'
[]
[cb_same_conc_IC]
type = ConstantIC
variable = c_b
value = '${units ${cb_IC} at/m^3 -> at/mum^3 }'
[]
[]
(test/tests/ver-1g/diff_conc_TMAP7.i)
[ICs]
ca_IC = '${fparse ${units 1 muPa -> Pa} * ${Na} / ( ${R} * ${T} ) }'
cb_IC = '${fparse ${units 0.5 muPa -> Pa} * ${Na} / ( ${R} * ${T} ) }'
[ca_same_conc_IC]
type = ConstantIC
variable = c_a
value = '${units ${ca_IC} at/m^3 -> at/mum^3 }'
[]
[cb_same_conc_IC]
type = ConstantIC
variable = c_b
value = '${units ${cb_IC} at/m^3 -> at/mum^3 }'
[]
[]