CAMP 1.0.0
Chemistry Across Multiple Phases
rxn_condensed_phase_diffusion.F90
Go to the documentation of this file.
1! Copyright (C) 2021 Barcelona Supercomputing Center and University of
2! Illinois at Urbana-Champaign
3! SPDX-License-Identifier: MIT
4
5!> \file
6!> The camp_rxn_condensed_phase_diffusion module.
7
8!> \page camp_rxn_condensed_phase_diffusion CAMP: Condensed Phase Diffusion Reactions
9!!
10!! Condensed phase diffusion reactions are based on Fick's Law of
11!! diffusion and align with kinetic modeling approaches
12!! (e.g., \cite Shiraiwa2012 ).
13!!
14!!
15!!
16!! Input data for condensed phase diffusion reactions have the following format :
17!! \code{.json}
18!! {
19!! "name" : "condensed phase diffusion",
20!! "type" : "MECHANISM",
21!! "reactions" : [
22!! {
23!! "type" : "CONDENSED_PHASE_DIFFUSION",
24!! "species": [{
25!! "phase": "aqueous",
26!! "name": "H2O_aq"
27!! },
28!! {
29!! "phase": "organic",
30!! "name": "H2O_org"
31!! }]
32!! }
33!! \endcode
34!! The key-value pairs \b condensed phase and associated \b species
35!! of the diffusing species are required. One phase/species pair is
36!! required, with a maximum of two phase/species pairs. The species
37!! indicated must have an associated diffusion coefficient [m2 s-1]
38!! listed as a property associated with the phase it exists in.
39!!
40!!
41
42!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
43
44!> The rxn_condensed_phase_diffusion_t type and associated functions.
46
50 use camp_constants, only: const
54 use camp_util, only: i_kind, dp, to_string, &
57
58 implicit none
59 private
60
61#define NUM_ADJACENT_PAIRS_ this%condensed_data_int(1)
62
63#define NUM_INT_PROP_ 1
64#define NUM_REAL_PROP_ 0
65#define NUM_ENV_PARAM_ 0
66#define BLOCK_SIZE_ 1000
67
68#define DIFF_COEFF_INNER_(x) this%condensed_data_real(NUM_REAL_PROP_ + (x))
69#define DIFF_COEFF_OUTER_(x) this%condensed_data_real(NUM_REAL_PROP_ + NUM_ADJACENT_PAIRS_ + (x))
70! PHASE_ID_INNER_ and PHASE_ID_OUTER_ are arrays of
71! length NUM_ADJACENT_PAIRS_
72#define PHASE_ID_INNER_(x) this%condensed_data_int(NUM_INT_PROP_ + (x))
73#define PHASE_ID_OUTER_(x) this%condensed_data_int(NUM_INT_PROP_ + NUM_ADJACENT_PAIRS_ + (x))
74#define AERO_SPEC_INNER_(x) this%condensed_data_int(NUM_INT_PROP_ + 2*NUM_ADJACENT_PAIRS_ + (x))
75#define AERO_SPEC_OUTER_(x) this%condensed_data_int(NUM_INT_PROP_ + 3*NUM_ADJACENT_PAIRS_ + (x))
76#define AERO_REP_ID_(x) this%condensed_data_int(NUM_INT_PROP_ + 4*NUM_ADJACENT_PAIRS_ + (x))
77#define DERIV_ID_INNER_(x) this%condensed_data_int(NUM_INT_PROP_ + 5*NUM_ADJACENT_PAIRS_ + (x))
78#define DERIV_ID_OUTER_(x) this%condensed_data_int(NUM_INT_PROP_ + 6*NUM_ADJACENT_PAIRS_ + (x))
79!#define JAC_ID_(x) this%condensed_data_int(4*BLOCK_SIZE_ + x)
80!#define PHASE_INT_LOC_(x) this%condensed_data_int(5*BLOCK_SIZE_ + x)
81!#define PHASE_REAL_LOC_(x) this%condensed_data_int(6*BLOCK_SIZE_ + x)
82!#define NUM_AERO_PHASE_JAC_ELEM_INNER_(x) this%condensed_data_int(10*BLOCK_SIZE_ + x)
83!#define NUM_AERO_PHASE_JAC_ELEM_OUTER_(x) this%condensed_data_int(11*BLOCK_SIZE_ + x)
84!#define PHASE_JAC_ID_(x) this%condensed_data_int(12*BLOCK_SIZE_ + x)
85!#define NUM_CONC_JAC_ELEM_(x) this%condensed_data_int(13*BLOCK_SIZE_ + x)
86!#define MASS_JAC_ELEM_(x) this%condensed_data_int(14*BLOCK_SIZE_ + x)
87
89
90 !> Generic test reaction data type
92 contains
93 !> Reaction initialization
94 procedure :: initialize
95 !> Finalize the reaction
98
99 !> Constructor for rxn_condensed_phase_diffusion_t
101 procedure :: constructor
103
104contains
105
106!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
107
108 !> Constructor for condensed phase diffusion reaction
109 function constructor() result(new_obj)
110
111 !> A new reaction instance
112 type(rxn_condensed_phase_diffusion_t), pointer :: new_obj
113
114 allocate(new_obj)
115 new_obj%rxn_phase = aero_rxn
116
117 end function constructor
118
119!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
120
121 !> Initialize the reaction data, validating component data and loading
122 !! any required information into the condensed data arrays for use during
123 !! solving
124 subroutine initialize(this, chem_spec_data, aero_phase, aero_rep, n_cells)
125
126 !> Reaction data
127 class(rxn_condensed_phase_diffusion_t), intent(inout) :: this
128 !> Chemical species data
129 type(chem_spec_data_t), intent(in) :: chem_spec_data
130 !> Aerosol phase data
131 type(aero_phase_data_ptr), intent(in) :: aero_phase(:)
132 !> Aerosol representations
133 type(aero_rep_data_ptr), pointer, intent(in) :: aero_rep(:)
134 !> Number of grid cells to solve simultaneously
135 integer(kind=i_kind), intent(in) :: n_cells
136
137 type(aero_phase_data_t), pointer :: aero_phase_data
138
139 type(string_t), allocatable :: diffusion_phase_names(:)
140 type(string_t), allocatable :: diffusion_species_names(:)
141 type(string_t), allocatable :: diffusion_species_names_inner(:), diffusion_species_names_outer(:)
142 type(string_t), allocatable :: diffusion_phase_names_inner(:), diffusion_phase_names_outer(:)
143 type(property_t), pointer :: species, spec_props, spec_property_set, aero_phase_property_set
144 character(len=:), allocatable :: key_name, error_msg
145 character(len=:), allocatable :: phase_name, species_name
146 character(len=:), allocatable :: inner_phase_name, outer_phase_name
147 integer(kind=i_kind) :: num_adjacent_pairs
148 integer(kind=i_kind) :: i_aero_rep, i_aero_id, i, i_adj_rep_id
149 integer(kind=i_kind) :: i_phase, i_species, i_adj_pairs
150 logical :: found_inner_coeff, found_outer_coeff
151 integer(kind=i_kind), allocatable :: adj_phase_size(:)
152 type(index_pair_t), allocatable :: adjacent_phases(:)
153 integer(kind=i_kind), allocatable :: phase_ids(:)
154 real(kind=dp) :: temp_real
155
156 ! Get the property set
157 if (.not. associated(this%property_set)) call die_msg(300992470, &
158 "Missing property set needed to initialize reaction")
159
160 ! Get the species involved in diffusion
161 key_name = "species"
162 call assert_msg(712818751, &
163 this%property_set%get_property_t(key_name, species), &
164 "Missing species for condensed phase diffusion "// &
165 "reaction")
166 call assert_msg(340551815, species%size() .gt. 0, &
167 "No species specified for the condensed phase "// &
168 "diffusion reaction.")
169 call assert_msg(023007260, species%size() .lt. 3, &
170 "Too many species specified for condensed phase "// &
171 "diffusion reaction (two species maximum).")
172
173
174 ! Allocate space for phases and species involved in reaction
175 allocate(diffusion_phase_names(species%size()))
176 allocate(diffusion_species_names(species%size()))
177
178 call species%iter_reset()
179 do i_species = 1, species%size()
180
181 ! Get the species properties
182 call assert_msg(815257799, species%get_property_t(val=spec_props), &
183 "Invalid structure for species '"// &
184 to_string(i_species)// &
185 "' in condensed phase diffusion reaction.")
186
187 ! Get the phase names
188 key_name = "phase"
189 call assert_msg(354574496, spec_props%get_string(key_name, phase_name), &
190 "Missing phase name in condensed phase diffusion reaction for species entry "// &
191 trim(to_string(i_species)))
192 diffusion_phase_names(i_species)%string = phase_name
193
194 ! Get the associated species names
195 key_name = "name"
196 call assert_msg(629919883, spec_props%get_string(key_name, species_name), &
197 "Missing species name in condensed phase diffusion reaction for species entry "// &
198 trim(to_string(i_species)))
199 diffusion_species_names(i_species)%string = species_name
200
201 call species%iter_next()
202 end do
203
204 ! If only one phase/species pair is found then add that phase/species pair
205 ! to the second element of the diffusion_phase_names and diffusion_species_names
206 ! arrays for indexing purposes
207 if (allocated(diffusion_species_names)) then
208 if (size(diffusion_species_names) == 1) then
209 diffusion_phase_names = [diffusion_phase_names, diffusion_phase_names(1)]
210 diffusion_species_names = [diffusion_species_names, diffusion_species_names(1)]
211 end if
212 end if
213
214 ! Make sure the phase and species names array are the correct length.
215 call assert_msg(593348903, size(diffusion_phase_names) .le. 2, &
216 "Too many diffusing species in diffusion_phase_names array.")
217 call assert_msg(379981970, size(diffusion_species_names) .le. 2, &
218 "Too many diffusing species in diffusion_species_names array.")
219
220 ! Allocate space in the condensed data arrays early so macros can be used
221 ! TODO: allocate int data and real data once length is known
222 allocate(this%condensed_data_int(block_size_ * 20 ))
223 allocate(this%condensed_data_real(block_size_ * 2 ))
224 this%condensed_data_int(:) = int(0, kind=i_kind)
225 this%condensed_data_real(:) = real(0.0, kind=dp)
226
227 ! Check that the species exist in adjacent layers.
228 ! For the modal/binned aerosol representation (no layers) the adjacent_phases array
229 ! is always 0.
230 ! Accumulate adjacent phase pairs from all aerosol representations
231 allocate(adj_phase_size(size(aero_rep)))
232 num_adjacent_pairs = 0
233 do i_aero_rep = 1, size(aero_rep)
234 adjacent_phases = aero_rep(i_aero_rep)%val%adjacent_phases(diffusion_phase_names(1)%string, &
235 diffusion_phase_names(SIZE(diffusion_phase_names))%string)
236 adj_phase_size(i_aero_rep) = size(adjacent_phases)
237 num_adjacent_pairs = num_adjacent_pairs + size(adjacent_phases)
238 end do
239 num_adjacent_pairs_ = num_adjacent_pairs
240
241 i_adj_pairs = 0
242 do i_aero_rep = 1, size(aero_rep)
243 adjacent_phases = aero_rep(i_aero_rep)%val%adjacent_phases(diffusion_phase_names(1)%string, &
244 diffusion_phase_names(SIZE(diffusion_phase_names))%string)
245 do i = 1, size(adjacent_phases)
246 i_adj_pairs = i_adj_pairs + 1
247 phase_id_inner_(i_adj_pairs) = adjacent_phases(i)%first_
248 phase_id_outer_(i_adj_pairs) = adjacent_phases(i)%second_
249 end do
250 end do
251
252 ! Map the diffusing phases and species to the inner and outer phases for each adjacent phase pair.
253 i_adj_pairs = 0
254 allocate(diffusion_phase_names_inner(num_adjacent_pairs))
255 allocate(diffusion_phase_names_outer(num_adjacent_pairs))
256 allocate(diffusion_species_names_inner(num_adjacent_pairs))
257 allocate(diffusion_species_names_outer(num_adjacent_pairs))
258 do i_aero_rep = 1, size(aero_rep)
259 adjacent_phases = aero_rep(i_aero_rep)%val%adjacent_phases(diffusion_phase_names(1)%string, &
260 diffusion_phase_names(SIZE(diffusion_phase_names))%string)
261 do i = 1, size(adjacent_phases)
262 i_adj_pairs = i_adj_pairs + 1
263 inner_phase_name = aero_rep(i_aero_rep)%val%aero_phase(adjacent_phases(i)%first_)%val%name()
264 outer_phase_name = aero_rep(i_aero_rep)%val%aero_phase(adjacent_phases(i)%second_)%val%name()
265
266 if (inner_phase_name .eq. diffusion_phase_names(1)%string) then
267 diffusion_species_names_inner(i_adj_pairs) = diffusion_species_names(1)
268 diffusion_phase_names_inner(i_adj_pairs) = diffusion_phase_names(1)
269 else if (inner_phase_name .eq. diffusion_phase_names(SIZE(diffusion_phase_names))%string) then
270 diffusion_species_names_inner(i_adj_pairs) = diffusion_species_names(SIZE(diffusion_species_names))
271 diffusion_phase_names_inner(i_adj_pairs) = diffusion_phase_names(SIZE(diffusion_phase_names))
272 else
273 call die_msg(918766455, "Could not map inner phase name to diffusing species.")
274 end if
275 if (outer_phase_name .eq. diffusion_phase_names(1)%string) then
276 diffusion_species_names_outer(i_adj_pairs) = diffusion_species_names(1)
277 diffusion_phase_names_outer(i_adj_pairs) = diffusion_phase_names(1)
278 else if (outer_phase_name .eq. diffusion_phase_names(SIZE(diffusion_phase_names))%string) then
279 diffusion_species_names_outer(i_adj_pairs) = diffusion_species_names(SIZE(diffusion_species_names))
280 diffusion_phase_names_outer(i_adj_pairs) = diffusion_phase_names(SIZE(diffusion_phase_names))
281 else
282 call die_msg(286189763, "Could not map outer phase name to diffusing species.")
283 end if
284 end do
285 end do
286 if (i_adj_pairs .ne. num_adjacent_pairs_ .or. &
287 size(diffusion_phase_names_inner) .ne. num_adjacent_pairs_ .or. &
288 size(diffusion_phase_names_outer) .ne. num_adjacent_pairs_ .or. &
289 size(diffusion_species_names_inner) .ne. num_adjacent_pairs_ .or. &
290 size(diffusion_species_names_outer) .ne. num_adjacent_pairs_) then
291 call die_msg(286189821, "Mismatch between number of adjacent phase pairs and number of diffusion species.")
292 end if
293
294 i_adj_pairs = 0
295 do i_aero_rep = 1, size(aero_rep)
296 adjacent_phases = aero_rep(i_aero_rep)%val%adjacent_phases(diffusion_phase_names(1)%string, &
297 diffusion_phase_names(SIZE(diffusion_phase_names))%string)
298 do i = 1, size(adjacent_phases)
299 i_adj_pairs = i_adj_pairs + 1
300 aero_spec_inner_(i_adj_pairs) = aero_rep(i_aero_rep)%val%spec_state_id_by_phase( &
301 adjacent_phases(i)%first_, diffusion_species_names_inner(i_adj_pairs)%string)
302 aero_spec_outer_(i_adj_pairs) = aero_rep(i_aero_rep)%val%spec_state_id_by_phase( &
303 adjacent_phases(i)%second_, diffusion_species_names_outer(i_adj_pairs)%string)
304 end do
305 end do
306
307 call assert_msg(051987857, num_adjacent_pairs .gt. 0, &
308 "No adjacent phases found condensed phase diffusion reaction.")
309
310 ! Create the arrays of diffusion coefficients for each adjacent phase pair
311 found_inner_coeff = .false.
312 found_outer_coeff = .false.
313 do i_phase = 1, size(aero_phase)
314 do i_adj_pairs = 1, num_adjacent_pairs
315 if (aero_phase(i_phase)%val%name() .eq. diffusion_phase_names_inner(i_adj_pairs)%string) then
316 spec_property_set => aero_phase(i_phase)%val%get_spec_property_set( &
317 diffusion_species_names_inner(i_adj_pairs)%string)
318 key_name = "diffusion coefficient [m2 s-1]"
319 if (spec_property_set%get_real(key_name, temp_real)) then
320 diff_coeff_inner_(i_adj_pairs) = temp_real
321 found_inner_coeff = .true.
322 end if
323 end if
324 if (aero_phase(i_phase)%val%name() .eq. diffusion_phase_names_outer(i_adj_pairs)%string) then
325 spec_property_set => aero_phase(i_phase)%val%get_spec_property_set( &
326 diffusion_species_names_outer(i_adj_pairs)%string)
327 key_name = "diffusion coefficient [m2 s-1]"
328 if (spec_property_set%get_real(key_name, temp_real)) then
329 diff_coeff_outer_(i_adj_pairs) = temp_real
330 found_outer_coeff = .true.
331 end if
332 end if
333 end do
334 end do
335
336 call assert_msg(857293144, found_inner_coeff, "Missing diffusion coefficient [m2 s-1] for species '"// &
337 diffusion_species_names(1)%string//"' in phase '"// &
338 diffusion_phase_names(1)%string//"'.")
339 call assert_msg(857293145, found_outer_coeff, "Missing diffusion coefficient [m2 s-1] for species '"// &
340 diffusion_species_names(SIZE(diffusion_species_names))%string//"' in phase '"// &
341 diffusion_phase_names(SIZE(diffusion_phase_names))%string//"'.")
342
343 ! Set up a general error message
344 error_msg = " for condensed phase diffusion of aerosol species '"// &
345 diffusion_species_names(1)%string//"' to aerosol species '"// &
346 diffusion_species_names(SIZE(diffusion_species_names))%string
347
348 ! Check for aerosol representations
349 call assert_msg(161043212, associated(aero_rep), &
350 "Missing aerosol representation"//error_msg)
351 call assert_msg(411220610, size(aero_rep).gt.0, &
352 "Missing aerosol representation"//error_msg)
353
354 ! Save space for the environment-dependent parameters
355 this%num_env_params = num_env_param_
356
357 ! Set aerosol phase specific indices
358 i_adj_rep_id = 1
359 i_aero_id = 1
360 do i_aero_rep = 1, size(aero_rep)
361 do i_adj_pairs = 1, adj_phase_size(i_aero_rep)
362 aero_rep_id_(i_adj_rep_id) = i_aero_id
363 i_adj_rep_id = i_adj_rep_id + 1
364 end do
365 i_aero_id = i_aero_id + 1
366 end do
367
368 deallocate(adj_phase_size)
369
370 end subroutine initialize
371
372!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
373
374 !> Finalize the reaction
375 subroutine finalize(this)
376
377 !> Reaction data
378 type(rxn_condensed_phase_diffusion_t), intent(inout) :: this
379
380 if (associated(this%property_set)) &
381 deallocate(this%property_set)
382 if (allocated(this%condensed_data_real)) &
383 deallocate(this%condensed_data_real)
384 if (allocated(this%condensed_data_int)) &
385 deallocate(this%condensed_data_int)
386
387 end subroutine finalize
388
389!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
390
391 !> Finalize an array of reactions
392 subroutine finalize_array(this)
393
394 !> Array of reaction data
395 type(rxn_condensed_phase_diffusion_t), intent(inout) :: this(:)
396
397 integer(kind=i_kind) :: i
398
399 do i = 1, size(this)
400 call finalize(this(i))
401 end do
402
403 end subroutine finalize_array
404
405!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
406
Determine if specified phase(s) exist in adjacent layers. Returns array of phase_ids for adjacent pha...
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_condensed_phase_diffusion_t type and associated functions.
The rxn_data_t structure and associated subroutines.
Definition: rxn_data.F90:61
integer(kind=i_kind), parameter, public aero_rxn
Aerosol-phase reaction.
Definition: rxn_data.F90:90
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.
Define index_pair array for adjacent_phases functions.
Abstract reaction data type.
Definition: rxn_data.F90:100
String type for building arrays of string of various size.
Definition: util.F90:38