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
117 end type rxn_surface_t
118
119 !> Constructor for 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_phase, 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 phase data
151 type(aero_phase_data_ptr), intent(in) :: aero_phase(:)
152 !> Aerosol representations
153 type(aero_rep_data_ptr), pointer, intent(in) :: aero_rep(:)
154 !> Number of grid cells to solve simultaneously
155 integer(kind=i_kind), intent(in) :: n_cells
156
157 type(property_t), pointer :: products, spec_props
158 character(len=:), allocatable :: key_name, reactant_name, product_name, &
159 phase_name, error_msg
160 integer :: i_spec, n_aero_jac_elem, n_aero_phase, i_phase, i_aero_rep, &
161 i_aero_id
162 integer, allocatable :: phase_ids(:)
163 real(kind=dp) :: temp_real
164
165 if (.not. associated(this%property_set)) call die_msg(244070915, &
166 "Missing property set needed to initialize surface reaction.")
167
168 key_name = "gas-phase reactant"
169 call assert_msg(807568174, &
170 this%property_set%get_string(key_name, reactant_name), &
171 "Missing gas-phase reactant name in surface reaction.")
172
173 key_name = "gas-phase products"
174 call assert_msg(285567904, &
175 this%property_set%get_property_t(key_name, products), &
176 "Missing gas-phase products for surface reaction.")
177
178 key_name = "aerosol phase"
179 call assert_msg(939211358, &
180 this%property_set%get_string(key_name, phase_name), &
181 "Missing aerosol phase in surface reaction.")
182
183 error_msg = " for surface reaction of gas-phase species '"// &
184 reactant_name//"' on aerosol phase '"//phase_name//"'"
185
186 call assert(362731302, associated(aero_rep))
187 call assert_msg(187310091, size(aero_rep) .gt. 0, &
188 "Missing aerosol representation"//error_msg)
189
190 ! Count the number of Jacobian elements needed in calculations of mass,
191 ! volume, etc. and the number of instances of the aerosol phase
192 n_aero_jac_elem = 0
193 n_aero_phase = 0
194 do i_aero_rep = 1, size(aero_rep)
195 phase_ids = aero_rep(i_aero_rep)%val%phase_ids(phase_name, is_at_surface=.true.)
196 n_aero_phase = n_aero_phase + size(phase_ids)
197 do i_phase = 1, size(phase_ids)
198 n_aero_jac_elem = n_aero_jac_elem + &
199 aero_rep(i_aero_rep)%val%num_jac_elem(phase_ids(i_phase))
200 end do
201 end do
202
203 allocate(this%condensed_data_int(num_int_prop_ & ! NUM_AERO_PHASE, REACT_ID, NUM_PROD
204 + 2 + 3 * products%size() & ! PROD_ID, DERIV_ID, JAC_ID
205 + 2 * n_aero_phase & ! PHASE_INT_LOC, PHASE_REAL_LOC
206 + n_aero_phase * 3 & ! AERO_PHASE_ID, AERO_REP_ID, NUM_AERO_PHASE_JAC_ELEM
207 + (1 + products%size()) * n_aero_jac_elem)) ! PHASE_JAC_ID
208 allocate(this%condensed_data_real(num_real_prop_ & ! DIFF_COEFF, GAMMA, MW
209 + products%size() & ! YIELD
210 + 2 * n_aero_jac_elem)) ! EFF_RAD_JAC_ELEM, NUM_CONC_JAC_ELEM
211 this%condensed_data_int(:) = 0_i_kind
212 this%condensed_data_real(:) = 0.0_dp
213
214 ! Save space for the environment-dependent parameters
215 this%num_env_params = num_env_param_
216
217 num_aero_phase_ = n_aero_phase
218
219 key_name = "reaction probability"
220 call assert_msg(388486564, &
221 this%property_set%get_real(key_name, gamma_), &
222 "Missing reaction probability for"//error_msg)
223
224 ! Save the reactant information
225 react_id_ = chem_spec_data%gas_state_id(reactant_name)
226 call assert_msg(908581300, react_id_ .gt. 0, &
227 "Missing gas-phase species"//error_msg)
228 call assert_msg(792904182, &
229 chem_spec_data%get_property_set(reactant_name, spec_props), &
230 "Missing gas-phase species properties"//error_msg)
231 key_name = "molecular weight [kg mol-1]"
232 call assert_msg(110823327, spec_props%get_real(key_name, mw_), &
233 "Missing molecular weight for gas-phase reactant"//error_msg)
234 key_name = "diffusion coeff [m2 s-1]"
235 call assert_msg(860403969, spec_props%get_real(key_name, diff_coeff_), &
236 "Missing diffusion coefficient for gas-phase reactant"// &
237 error_msg)
238
239 ! Save the product information
240 num_prod_ = products%size()
241 call products%iter_reset()
242 i_spec = 1
243 do while (products%get_key(product_name))
244 prod_id_(i_spec) = chem_spec_data%gas_state_id(product_name)
245 call assert_msg(863839516, prod_id_(i_spec) .gt. 0, &
246 "Missing surface reaction product: "//product_name)
247 call assert(237691686, products%get_property_t(val=spec_props))
248 yield_(i_spec) = 1.0_dp
249 key_name = "yield"
250 if (spec_props%get_real(key_name, temp_real)) yield_(i_spec) = temp_real
251 call products%iter_next()
252 i_spec = i_spec + 1
253 end do
254
255 ! Set aerosol phase specific indices
256 i_aero_id = 1
257 phase_int_loc_(i_aero_id) = num_int_prop_ + 2 + 3 * num_prod_ + &
258 2 * num_aero_phase_ + 1
259 phase_real_loc_(i_aero_id) = num_real_prop_ + num_prod_ + 1
260 do i_aero_rep = 1, size(aero_rep)
261 phase_ids = aero_rep(i_aero_rep)%val%phase_ids(phase_name, is_at_surface=.true.)
262 do i_phase = 1, size(phase_ids)
263 num_aero_phase_jac_elem_(i_aero_id) = &
264 aero_rep(i_aero_rep)%val%num_jac_elem(phase_ids(i_phase))
265 aero_phase_id_(i_aero_id) = phase_ids(i_phase)
266 aero_rep_id_(i_aero_id) = i_aero_rep
267 i_aero_id = i_aero_id + 1
268 if (i_aero_id .le. num_aero_phase_) then
269 phase_int_loc_(i_aero_id) = phase_int_loc_(i_aero_id - 1) + 3 + &
270 (1 + num_prod_) * &
271 num_aero_phase_jac_elem_(i_aero_id - 1)
272 phase_real_loc_(i_aero_id) = phase_real_loc_(i_aero_id - 1) + &
273 2 * num_aero_phase_jac_elem_(i_aero_id - 1)
274 end if
275 end do
276 end do
277
278 end subroutine initialize
279
280!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
281
282 !> Finalize the reaction
283 subroutine finalize(this)
284
285 !> Reaction data
286 type(rxn_surface_t), intent(inout) :: this
287
288 if (associated(this%property_set)) &
289 deallocate(this%property_set)
290 if (allocated(this%condensed_data_real)) &
291 deallocate(this%condensed_data_real)
292 if (allocated(this%condensed_data_int)) &
293 deallocate(this%condensed_data_int)
294
295 end subroutine finalize
296
297!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
298
299 !> Finalize an array of reactions
300 subroutine finalize_array(this)
301
302 !> Array of reaction data
303 type(rxn_surface_t), intent(inout) :: this(:)
304
305 integer :: i_rxn
306
307 do i_rxn = 1, size(this)
308 call finalize(this(i_rxn))
309 end do
310
311 end subroutine finalize_array
312
313!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
314
315end 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.
subroutine finalize_array(this)
Finalize the aerosol phase data.
type(aero_phase_data_t) function, pointer constructor(phase_name, init_size)
Constructor for aero_phase_data_t.
subroutine finalize(this)
Finalize the aerosol phase data.
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:89
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 type for building arrays.
Pointer to aero_rep_data_t extending types.
Abstract reaction data type.
Definition rxn_data.F90:99
Generic test reaction data type.
String type for building arrays of string of various size.
Definition util.F90:53