CAMP 1.0.0
Chemistry Across Multiple Phases
rxn_surface.F90
Go to the documentation of this file.
1! Copyright (C) 2023 Barcelona Supercomputing Center, University of
2! Illinois at Urbana-Champaign, and National Center for Atmospheric Research
3! SPDX-License-Identifier: MIT
4
5!> \file
6!> The camp_rxn_surface module.
7
8!> \page camp_rxn_surface CAMP: Surface (Hetergeneous) Reaction
9!!
10!! Surface reactions transform gas-phase species into gas-phase products
11!! according to a rate that is calculated based on the total exposed surface
12!! area of a condensed phase.
13!!
14!! For surface reactions of the gas phase species X, the reaction rate is
15!! calculated assuming large particles (continuum regime) as:
16!!
17!! \f[
18!! r_{surface} = k_{surface}\mbox{[X]}
19!! \f]
20!!
21!! where \f$[\mbox{X}]\f$ is the gas-phase concentration of species X [ppm]
22!! and the rate constant \f$k_{surface}\f$ [1/s] is calculated as:
23!!
24!! \f[
25!! k_{surface} = \frac{4N_a \pi r^2_e}{\left(\frac{r_e}{D_g} + \frac{4}{v(T)\gamma}\right)}
26!! \f]
27!!
28!! where \f$N_a\f$ is the number concentration of particles
29!! [particles\f$\mbox{m}^{-3}\f$], \f$r_e\f$ is the effective particle radius [m],
30!! \f$D_g\f$ is the gas-phase diffusion coefficient of the reactant
31!! [\f$\mbox{m}^2\mbox{s}^{-1}\f$], \f$\gamma\f$ is the reaction probability [unitless],
32!! and v is the mean free speed of the gas-phase reactant:
33!!
34!! \f[
35!! v = \sqrt{\frac{8RT}{\pi MW}}
36!! \f]
37!!
38!! where R is the ideal gas constant [\f$\mbox{J}\, \mbox{K}^{-1}\,
39!! \mbox{mol}^{-1}\f$], T is temperature [K], and MW is the molecular weight of
40!! the gas-phase reactant [\f$\mbox{kg}\, \mbox{mol}^{-1}\f$]
41!!
42!! Input data for surface reactions have the following format :
43!! \code{.json}
44!! {
45!! "type" : "SURFACE",
46!! "gas-phase reactant" : "my gas species",
47!! "reaction probability" : 0.2,
48!! "gas-phase products" : {
49!! "my other gas species" : { },
50!! "another gas species" : { "yield" : 0.3 }
51!! },
52!! "areosol phase" : "my aqueous phase"
53!! }
54!! \endcode
55!! The key-value pairs \b gas-phase \b reactant, \b reaction \b probability,
56!! and \b aerosol-phase are required.
57!! Only one gas-phase reactant is allowed, but multiple products can be present.
58!! The key-value pair \b yield for product species is optional and defaults to 1.0.
59!!
60!! The gas-phase reactant species must include properties
61!! \b diffusion \b coeff \b [\b m2 \b s-1],
62!! which specifies the diffusion coefficient in
63!! \f$\mbox{m}^2\,\mbox{s}^{-1}\f$, and \b molecular \b weight
64!! \b [\b kg \b mol-1], which specifies the molecular weight of the species in
65!! \f$\mbox{kg}\,\mbox{mol}^{-1}\f$.
66
67!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
68
69!> The rxn_surface_t type and associated functions.
71
75 use camp_constants, only: const
79 use camp_util, only: i_kind, dp, to_string, &
82
83 implicit none
84 private
85
86#define DIFF_COEFF_ this%condensed_data_real(1)
87#define GAMMA_ this%condensed_data_real(2)
88#define MW_ this%condensed_data_real(3)
89#define NUM_AERO_PHASE_ this%condensed_data_int(1)
90#define REACT_ID_ this%condensed_data_int(2)
91#define NUM_PROD_ this%condensed_data_int(3)
92#define NUM_INT_PROP_ 3
93#define NUM_REAL_PROP_ 3
94#define NUM_ENV_PARAM_ 1
95#define PROD_ID_(x) this%condensed_data_int(NUM_INT_PROP_+x)
96#define DERIV_ID_(x) this%condensed_data_int(NUM_INT_PROP_+NUM_PROD_+x)
97#define JAC_ID_(x) this%condensed_data_int(NUM_INT_PROP_+1+2*NUM_PROD_+x)
98#define PHASE_INT_LOC_(x) this%condensed_data_int(NUM_INT_PROP_+2+3*NUM_PROD_+x)
99#define PHASE_REAL_LOC_(x) this%condensed_data_int(NUM_INT_PROP_+2+3*NUM_PROD_+NUM_AERO_PHASE_+x)
100#define AERO_PHASE_ID_(x) this%condensed_data_int(PHASE_INT_LOC_(x))
101#define AERO_REP_ID_(x) this%condensed_data_int(PHASE_INT_LOC_(x)+1)
102#define NUM_AERO_PHASE_JAC_ELEM_(x) this%condensed_data_int(PHASE_INT_LOC_(x)+2)
103#define PHASE_JAC_ID_(x,s,e) this%condensed_data_int(PHASE_INT_LOC_(x)+3+(s-1)*NUM_AERO_PHASE_JAC_ELEM_(x)+e)
104#define YIELD_(x) this%condensed_data_real(NUM_REAL_PROP_+x)
105#define EFF_RAD_JAC_ELEM_(x,e) this%condensed_data_real(PHASE_REAL_LOC_(x)+(e-1))
106#define NUM_CONC_JAC_ELEM_(x,e) this%condensed_data_real(PHASE_REAL_LOC_(x)+NUM_AERO_PHASE_JAC_ELEM_(x)+(e-1))
107
108 public :: rxn_surface_t
109
110 !> Generic test reaction data type
111 type, extends(rxn_data_t) :: rxn_surface_t
112 contains
113 !> Reaction initialization
114 procedure :: initialize
115 !> Finalize the reaction
116 final :: finalize
117 end type rxn_surface_t
118
119 !> Constructor for rxn_surface_t
120 interface rxn_surface_t
121 procedure :: constructor
122 end interface rxn_surface_t
123
124contains
125
126!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
127
128 !> Constructor for surface reaction
129 function constructor() result(new_obj)
130
131 !> A new reaction instance
132 type(rxn_surface_t), pointer :: new_obj
133
134 allocate(new_obj)
135 new_obj%rxn_phase = aero_rxn
136
137 end function constructor
138
139!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
140
141 !> Initialize the reaction data, validating component data and loading
142 !! any required information into the condensed data arrays for use during
143 !! solving
144 subroutine initialize(this, chem_spec_data, aero_rep, n_cells)
145
146 !> Reaction data
147 class(rxn_surface_t), intent(inout) :: this
148 !> Chemical species data
149 type(chem_spec_data_t), intent(in) :: chem_spec_data
150 !> Aerosol representations
151 type(aero_rep_data_ptr), pointer, intent(in) :: aero_rep(:)
152 !> Number of grid cells to solve simultaneously
153 integer(kind=i_kind), intent(in) :: n_cells
154
155 type(property_t), pointer :: products, spec_props
156 character(len=:), allocatable :: key_name, reactant_name, product_name, &
157 phase_name, error_msg
158 integer :: i_spec, n_aero_jac_elem, n_aero_phase, i_phase, i_aero_rep, &
159 i_aero_id
160 integer, allocatable :: phase_ids(:)
161 real(kind=dp) :: temp_real
162
163 if (.not. associated(this%property_set)) call die_msg(244070915, &
164 "Missing property set needed to initialize surface reaction.")
165
166 key_name = "gas-phase reactant"
167 call assert_msg(807568174, &
168 this%property_set%get_string(key_name, reactant_name), &
169 "Missing gas-phase reactant name in surface reaction.")
170
171 key_name = "gas-phase products"
172 call assert_msg(285567904, &
173 this%property_set%get_property_t(key_name, products), &
174 "Missing gas-phase products for surface reaction.")
175
176 key_name = "aerosol phase"
177 call assert_msg(939211358, &
178 this%property_set%get_string(key_name, phase_name), &
179 "Missing aerosol phase in surface reaction.")
180
181 error_msg = " for surface reaction of gas-phase species '"// &
182 reactant_name//"' on aerosol phase '"//phase_name//"'"
183
184 call assert(362731302, associated(aero_rep))
185 call assert_msg(187310091, size(aero_rep) .gt. 0, &
186 "Missing aerosol representation"//error_msg)
187
188 ! Count the number of Jacobian elements needed in calculations of mass,
189 ! volume, etc. and the number of instances of the aerosol phase
190 n_aero_jac_elem = 0
191 n_aero_phase = 0
192 do i_aero_rep = 1, size(aero_rep)
193 phase_ids = aero_rep(i_aero_rep)%val%phase_ids(phase_name, is_at_surface=.true.)
194 n_aero_phase = n_aero_phase + size(phase_ids)
195 do i_phase = 1, size(phase_ids)
196 n_aero_jac_elem = n_aero_jac_elem + &
197 aero_rep(i_aero_rep)%val%num_jac_elem(phase_ids(i_phase))
198 end do
199 end do
200
201 allocate(this%condensed_data_int(num_int_prop_ & ! NUM_AERO_PHASE, REACT_ID, NUM_PROD
202 + 2 + 3 * products%size() & ! PROD_ID, DERIV_ID, JAC_ID
203 + 2 * n_aero_phase & ! PHASE_INT_LOC, PHASE_REAL_LOC
204 + n_aero_phase * 3 & ! AERO_PHASE_ID, AERO_REP_ID, NUM_AERO_PHASE_JAC_ELEM
205 + (1 + products%size()) * n_aero_jac_elem)) ! PHASE_JAC_ID
206 allocate(this%condensed_data_real(num_real_prop_ & ! DIFF_COEFF, GAMMA, MW
207 + products%size() & ! YIELD
208 + 2 * n_aero_jac_elem)) ! EFF_RAD_JAC_ELEM, NUM_CONC_JAC_ELEM
209 this%condensed_data_int(:) = 0_i_kind
210 this%condensed_data_real(:) = 0.0_dp
211
212 ! Save space for the environment-dependent parameters
213 this%num_env_params = num_env_param_
214
215 num_aero_phase_ = n_aero_phase
216
217 key_name = "reaction probability"
218 call assert_msg(388486564, &
219 this%property_set%get_real(key_name, gamma_), &
220 "Missing reaction probability for"//error_msg)
221
222 ! Save the reactant information
223 react_id_ = chem_spec_data%gas_state_id(reactant_name)
224 call assert_msg(908581300, react_id_ .gt. 0, &
225 "Missing gas-phase species"//error_msg)
226 call assert_msg(792904182, &
227 chem_spec_data%get_property_set(reactant_name, spec_props), &
228 "Missing gas-phase species properties"//error_msg)
229 key_name = "molecular weight [kg mol-1]"
230 call assert_msg(110823327, spec_props%get_real(key_name, mw_), &
231 "Missing molecular weight for gas-phase reactant"//error_msg)
232 key_name = "diffusion coeff [m2 s-1]"
233 call assert_msg(860403969, spec_props%get_real(key_name, diff_coeff_), &
234 "Missing diffusion coefficient for gas-phase reactant"// &
235 error_msg)
236
237 ! Save the product information
238 num_prod_ = products%size()
239 call products%iter_reset()
240 i_spec = 1
241 do while (products%get_key(product_name))
242 prod_id_(i_spec) = chem_spec_data%gas_state_id(product_name)
243 call assert_msg(863839516, prod_id_(i_spec) .gt. 0, &
244 "Missing surface reaction product: "//product_name)
245 call assert(237691686, products%get_property_t(val=spec_props))
246 yield_(i_spec) = 1.0_dp
247 key_name = "yield"
248 if (spec_props%get_real(key_name, temp_real)) yield_(i_spec) = temp_real
249 call products%iter_next()
250 i_spec = i_spec + 1
251 end do
252
253 ! Set aerosol phase specific indices
254 i_aero_id = 1
255 phase_int_loc_(i_aero_id) = num_int_prop_ + 2 + 3 * num_prod_ + &
256 2 * num_aero_phase_ + 1
257 phase_real_loc_(i_aero_id) = num_real_prop_ + num_prod_ + 1
258 do i_aero_rep = 1, size(aero_rep)
259 phase_ids = aero_rep(i_aero_rep)%val%phase_ids(phase_name, is_at_surface=.true.)
260 do i_phase = 1, size(phase_ids)
261 num_aero_phase_jac_elem_(i_aero_id) = &
262 aero_rep(i_aero_rep)%val%num_jac_elem(phase_ids(i_phase))
263 aero_phase_id_(i_aero_id) = phase_ids(i_phase)
264 aero_rep_id_(i_aero_id) = i_aero_rep
265 i_aero_id = i_aero_id + 1
266 if (i_aero_id .le. num_aero_phase_) then
267 phase_int_loc_(i_aero_id) = phase_int_loc_(i_aero_id - 1) + 3 + &
268 (1 + num_prod_) * &
269 num_aero_phase_jac_elem_(i_aero_id - 1)
270 phase_real_loc_(i_aero_id) = phase_real_loc_(i_aero_id - 1) + &
271 2 * num_aero_phase_jac_elem_(i_aero_id - 1)
272 end if
273 end do
274 end do
275
276 end subroutine initialize
277
278!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
279
280 !> Finalize the reaction
281 elemental subroutine finalize(this)
282
283 !> Reaction data
284 type(rxn_surface_t), intent(inout) :: this
285
286 if (associated(this%property_set)) &
287 deallocate(this%property_set)
288 if (allocated(this%condensed_data_real)) &
289 deallocate(this%condensed_data_real)
290 if (allocated(this%condensed_data_int)) &
291 deallocate(this%condensed_data_int)
292
293 end subroutine finalize
294
295!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
296
297end module camp_rxn_surface
Initialize the aerosol representation data, validating component data and loading any required inform...
Interface for to_string functions.
Definition util.F90:32
The abstract aero_phase_data_t structure and associated subroutines.
elemental subroutine finalize(this)
Finalize the aerosol phase data.
type(aero_phase_data_t) function, pointer constructor(phase_name, init_size)
Constructor for aero_phase_data_t.
The abstract aero_rep_data_t structure and associated subroutines.
The camp_state_t structure and associated subroutines.
Definition camp_state.F90:9
The chem_spec_data_t structure and associated subroutines.
Physical constants.
Definition constants.F90:9
integer, parameter dp
Kind of a double precision real number.
Definition constants.F90:16
type(const_t), save const
Fixed variable for accessing the constant's values.
Definition constants.F90:77
integer, parameter i_kind
Kind of an integer.
Definition constants.F90:21
The property_t structure and associated subroutines.
Definition property.F90:9
The rxn_data_t structure and associated subroutines.
Definition rxn_data.F90:60
integer(kind=i_kind), parameter, public aero_rxn
Aerosol-phase reaction.
Definition rxn_data.F90:88
The rxn_surface_t type and associated functions.
Common utility subroutines.
Definition util.F90:9
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
Definition util.F90:165
subroutine die_msg(code, error_msg)
Error immediately.
Definition util.F90:196
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Definition util.F90:130
Pointer to aero_rep_data_t extending types.
Abstract reaction data type.
Definition rxn_data.F90:98
Generic test reaction data type.
String type for building arrays of string of various size.
Definition util.F90:38