CAMP 1.0.0
Chemistry Across Multiple Phases
rxn_photolysis.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_photolysis module.
7
8!> \page camp_rxn_photolysis CAMP: Photolysis
9!!
10!! Photolysis reactions take the form:
11!!
12!! \f[\ce{
13!! X + h $\nu$ -> Y_1 ( + Y_2 \dots )
14!! }\f]
15!!
16!! where \f$\ce{X}\f$ is the species being photolyzed, and
17!! \f$\ce{Y_n}\f$ are the photolysis products.
18!!
19!! Photolysis rate constants (including the \f$\ce{h $\nu$}\f$ term)
20!! can be constant or set from an external photolysis module using the
21!! \c camp_rxn_photolysis::rxn_update_data_photolysis_t object.
22!! External modules can use the
23!! \c camp_rxn_photolysis::rxn_photolysis_t::get_property_set() function during
24!! initilialization to access any needed reaction parameters to identify
25!! certain photolysis reactions.
26!! An \c camp_rxn_photolysis::update_data_photolysis_t object should be
27!! initialized for each photolysis reaction. These objects can then be used
28!! during solving to update the photolysis rate from an external module.
29!!
30!! Input data for photolysis reactions have the following format :
31!! \code{.json}
32!! {
33!! "type" : "PHOTOLYSIS",
34!! "reactants" : {
35!! "spec1" : {}
36!! },
37!! "products" : {
38!! "spec2" : {},
39!! "spec3" : { "yield" : 0.65 },
40!! ...
41!! },
42!! "scaling factor" : 1.2,
43!! ...
44!! }
45!! \endcode
46!! The key-value pairs \b reactants, and \b products are required. There must
47!! be exactly one key-value pair in the \b reactants object whose name is the
48!! species being photolyzed and whose value is an empty \c json object. Any
49!! number of products may be present. Products without a specified \b yield
50!! are assumed to have a \b yield of 1.0. The \b scaling \b factor is
51!! optional, and can be used to set a constant scaling factor for the rate
52!! constant. When the \b scaling \b factor is not provided, it is assumed to
53!! be 1.0. All other data is optional and will be available to external
54!! photolysis modules during initialization. Rate constants are in units of
55!! \f$s^{-1}\f$, and must be set using a \c rxn_photolysis_update_data_t
56!! object.
57
58!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
59
60!> The rxn_photolysis_t type and associated functions.
62
65 use camp_constants, only: const
67 use camp_mpi
70 use camp_util, only: i_kind, dp, to_string, &
72
73 use iso_c_binding
74
75 implicit none
76 private
77
78#define NUM_REACT_ this%condensed_data_int(1)
79#define NUM_PROD_ this%condensed_data_int(2)
80#define RXN_ID_ this%condensed_data_int(3)
81#define SCALING_ this%condensed_data_real(1)
82#define NUM_INT_PROP_ 3
83#define NUM_REAL_PROP_ 1
84#define NUM_ENV_PARAM_ 2
85#define REACT_(x) this%condensed_data_int(NUM_INT_PROP_ + x)
86#define PROD_(x) this%condensed_data_int(NUM_INT_PROP_ + NUM_REACT_ + x)
87#define DERIV_ID_(x) this%condensed_data_int(NUM_INT_PROP_ + NUM_REACT_ + NUM_PROD_ + x)
88#define JAC_ID_(x) this%condensed_data_int(NUM_INT_PROP_ + 2*(NUM_REACT_+NUM_PROD_) + x)
89#define YIELD_(x) this%condensed_data_real(NUM_REAL_PROP_ + x)
90
92
93 !> Generic test reaction data type
94 type, extends(rxn_data_t) :: rxn_photolysis_t
95 contains
96 !> Reaction initialization
97 procedure :: initialize
98 !> Get the reaction property set
99 procedure :: get_property_set
100 !> Initialize update data
102 !> Finalize the reaction
103 final :: finalize
104 end type rxn_photolysis_t
105
106 !> Constructor for rxn_photolysis_t
107 interface rxn_photolysis_t
108 procedure :: constructor
109 end interface rxn_photolysis_t
110
111 !> Photolysis rate update object
113 private
114 !> Flag indicating whether the update data as been allocated
115 logical :: is_malloced = .false.
116 !> Unique id for finding reactions during model initialization
117 integer(kind=i_kind) :: rxn_unique_id = 0
118 contains
119 !> Update the rate data
120 procedure :: set_rate => update_data_rate_set
121 !> Determine the pack size of the local update data
123 !> Pack the local update data to a binary
124 procedure :: internal_bin_pack
125 !> Unpack the local update data from a binary
127 !> Finalize the rate update data
130
131 !> Interface to c reaction functions
132 interface
133
134 !> Allocate space for a rate update
135 function rxn_photolysis_create_rate_update_data() result (update_data) &
136 bind (c)
137 use iso_c_binding
138 !> Allocated update_data object
139 type(c_ptr) :: update_data
141
142 !> Set a new photolysis rate
143 subroutine rxn_photolysis_set_rate_update_data(update_data, photo_id, &
144 base_rate) bind (c)
145 use iso_c_binding
146 !> Update data
147 type(c_ptr), value :: update_data
148 !> Photo id
149 integer(kind=c_int), value :: photo_id
150 !> New pre-scaling base photolysis rate
151 real(kind=c_double), value :: base_rate
153
154 !> Free an update rate data object
155 pure subroutine rxn_free_update_data(update_data) bind (c)
156 use iso_c_binding
157 !> Update data
158 type(c_ptr), value, intent(in) :: update_data
159 end subroutine rxn_free_update_data
160
161 end interface
162
163contains
164
165!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
166
167 !> Constructor for Photolysis reaction
168 function constructor() result(new_obj)
169
170 !> A new reaction instance
171 type(rxn_photolysis_t), pointer :: new_obj
172
173 allocate(new_obj)
174 new_obj%rxn_phase = gas_rxn
175
176 end function constructor
177
178!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
179
180 !> Initialize the reaction data, validating component data and loading
181 !! any required information into the condensed data arrays for use during
182 !! solving
183 subroutine initialize(this, chem_spec_data, aero_rep, n_cells)
184
185 !> Reaction data
186 class(rxn_photolysis_t), intent(inout) :: this
187 !> Chemical species data
188 type(chem_spec_data_t), intent(in) :: chem_spec_data
189 !> Aerosol representations
190 type(aero_rep_data_ptr), pointer, intent(in) :: aero_rep(:)
191 !> Number of grid cells to solve simultaneously
192 integer(kind=i_kind), intent(in) :: n_cells
193
194 type(property_t), pointer :: spec_props, reactants, products
195 character(len=:), allocatable :: key_name, spec_name
196 integer(kind=i_kind) :: i_spec, i_qty
197
198 integer(kind=i_kind) :: temp_int
199 real(kind=dp) :: temp_real
200
201 ! Get the species involved
202 if (.not. associated(this%property_set)) call die_msg(408416753, &
203 "Missing property set needed to initialize reaction")
204 key_name = "reactants"
205 call assert_msg(415586594, &
206 this%property_set%get_property_t(key_name, reactants), &
207 "Photolysis reaction is missing reactants")
208 key_name = "products"
209 call assert_msg(180421290, &
210 this%property_set%get_property_t(key_name, products), &
211 "Photolysis reaction is missing products")
212
213 ! Count the number of reactants (including those with a qty specified)
214 call reactants%iter_reset()
215 i_spec = 0
216 do while (reactants%get_key(spec_name))
217 ! Get properties included with this reactant in the reaction data
218 call assert(240165383, reactants%get_property_t(val=spec_props))
219 key_name = "qty"
220 if (spec_props%get_int(key_name, temp_int)) i_spec = i_spec+temp_int-1
221 call reactants%iter_next()
222 i_spec = i_spec + 1
223 end do
224
225 ! Allocate space in the condensed data arrays
226 ! Space in this example is allocated for two sets of inidices for the
227 ! reactants and products, one molecular property for each reactant,
228 ! yields for the products and three reaction parameters.
229 allocate(this%condensed_data_int(num_int_prop_ + &
230 (i_spec + 2) * (i_spec + products%size())))
231 allocate(this%condensed_data_real(num_real_prop_ + products%size()))
232 this%condensed_data_int(:) = int(0, kind=i_kind)
233 this%condensed_data_real(:) = real(0.0, kind=dp)
234
235 ! Save space for the environment-dependent parameters
236 this%num_env_params = num_env_param_
237
238 ! Save the size of the reactant and product arrays (for reactions where
239 ! these can vary)
240 num_react_ = i_spec
241 num_prod_ = products%size()
242
243 ! Get reaction parameters (it might be easiest to keep these at the
244 ! beginning of the condensed data array, so they can be accessed using
245 ! compliler flags)
246 key_name = "scaling factor"
247 if (.not. this%property_set%get_real(key_name, scaling_)) then
248 scaling_ = real(1.0, kind=dp)
249 end if
250
251 ! Get the indices and chemical properties for the reactants
252 call reactants%iter_reset()
253 i_spec = 1
254 do while (reactants%get_key(spec_name))
255
256 ! Save the index of this species in the state variable array
257 react_(i_spec) = chem_spec_data%gas_state_id(spec_name)
258
259 ! Make sure the species exists
260 call assert_msg(747277322, react_(i_spec).gt.0, &
261 "Missing photolysis reactant: "//spec_name)
262
263 ! Get properties included with this reactant in the reaction data
264 call assert(231542303, reactants%get_property_t(val=spec_props))
265 key_name = "qty"
266 if (spec_props%get_int(key_name, temp_int)) then
267 do i_qty = 1, temp_int - 1
268 react_(i_spec + i_qty) = react_(i_spec)
269 end do
270 i_spec = i_spec + temp_int - 1
271 end if
272
273 call reactants%iter_next()
274 i_spec = i_spec + 1
275 end do
276
277 ! Make sure exactly one reactant is present
278 call assert_msg(908486656, i_spec.eq.2, "Incorrect number of reactants"//&
279 " for Photolysis reaction: "//to_string(i_spec-1))
280
281 ! Get the indices and chemical properties for the products
282 call products%iter_reset()
283 i_spec = 1
284 do while (products%get_key(spec_name))
285
286 ! Save the index of this species in the state variable array
287 prod_(i_spec) = chem_spec_data%gas_state_id(spec_name)
288
289 ! Make sure the species exists
290 call assert_msg(360988742, prod_(i_spec).gt.0, &
291 "Missing photolysis product: "//spec_name)
292
293 ! Get properties included with this product in the reaction data
294 call assert(173703744, products%get_property_t(val=spec_props))
295 key_name = "yield"
296 if (spec_props%get_real(key_name, temp_real)) then
297 yield_(i_spec) = temp_real
298 else
299 yield_(i_spec) = 1.0
300 end if
301
302 call products%iter_next()
303 i_spec = i_spec + 1
304 end do
305
306 ! Initialize the reaction id
307 rxn_id_ = -1
308
309 end subroutine initialize
310
311!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
312
313 !> Get the reaction properties. (For use by external photolysis modules.)
314 function get_property_set(this) result(prop_set)
315
316 !> Reaction properties
317 type(property_t), pointer :: prop_set
318 !> Reaction data
319 class(rxn_photolysis_t), intent(in) :: this
320
321 prop_set => this%property_set
322
323 end function get_property_set
324
325!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
326
327 !> Finalize the reaction
328 elemental subroutine finalize(this)
329
330 !> Reaction data
331 type(rxn_photolysis_t), intent(inout) :: this
332
333 if (associated(this%property_set)) &
334 deallocate(this%property_set)
335 if (allocated(this%condensed_data_real)) &
336 deallocate(this%condensed_data_real)
337 if (allocated(this%condensed_data_int)) &
338 deallocate(this%condensed_data_int)
339
340 end subroutine finalize
341
342!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
343
344 !> Set packed update data for photolysis rate constants
345 subroutine update_data_rate_set(this, base_rate)
346
347 !> Update data
348 class(rxn_update_data_photolysis_t), intent(inout) :: this
349 !> Updated pre-scaling photolysis rate
350 real(kind=dp), intent(in) :: base_rate
351
352 call rxn_photolysis_set_rate_update_data(this%get_data(), &
353 this%rxn_unique_id, base_rate)
354
355 end subroutine update_data_rate_set
356
357!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
358
359 !> Initialize update data
360 subroutine update_data_initialize(this, update_data, rxn_type)
361
362 use camp_rand, only : generate_int_id
363
364 !> The reaction to update
365 class(rxn_photolysis_t), intent(inout) :: this
366 !> Update data object
367 class(rxn_update_data_photolysis_t), intent(out) :: update_data
368 !> Reaction type id
369 integer(kind=i_kind), intent(in) :: rxn_type
370
371 ! If a reaction id has not yet been generated, do it now
372 if (rxn_id_.eq.-1) then
373 rxn_id_ = generate_int_id()
374 endif
375
376 update_data%rxn_unique_id = rxn_id_
377 update_data%rxn_type = int(rxn_type, kind=c_int)
378 update_data%update_data = rxn_photolysis_create_rate_update_data()
379 update_data%is_malloced = .true.
380
381 end subroutine update_data_initialize
382
383!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
384
385 !> Determine the size of a binary required to pack the reaction data
386 integer(kind=i_kind) function internal_pack_size(this, comm) &
387 result(pack_size)
388
389 !> Reaction update data
390 class(rxn_update_data_photolysis_t), intent(in) :: this
391 !> MPI communicator
392 integer, intent(in) :: comm
393
394 pack_size = &
395 camp_mpi_pack_size_logical(this%is_malloced, comm) + &
396 camp_mpi_pack_size_integer(this%rxn_unique_id, comm)
397
398 end function internal_pack_size
399
400!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
401
402 !> Pack the given value to the buffer, advancing position
403 subroutine internal_bin_pack(this, buffer, pos, comm)
404
405 !> Reaction update data
406 class(rxn_update_data_photolysis_t), intent(in) :: this
407 !> Memory buffer
408 character, intent(inout) :: buffer(:)
409 !> Current buffer position
410 integer, intent(inout) :: pos
411 !> MPI communicator
412 integer, intent(in) :: comm
413
414#ifdef CAMP_USE_MPI
415 integer :: prev_position
416
417 prev_position = pos
418 call camp_mpi_pack_logical(buffer, pos, this%is_malloced, comm)
419 call camp_mpi_pack_integer(buffer, pos, this%rxn_unique_id, comm)
420 call assert(649543400, &
421 pos - prev_position <= this%pack_size(comm))
422#endif
423
424 end subroutine internal_bin_pack
425
426!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
427
428 !> Unpack the given value from the buffer, advancing position
429 subroutine internal_bin_unpack(this, buffer, pos, comm)
430
431 !> Reaction update data
432 class(rxn_update_data_photolysis_t), intent(inout) :: this
433 !> Memory buffer
434 character, intent(inout) :: buffer(:)
435 !> Current buffer position
436 integer, intent(inout) :: pos
437 !> MPI communicator
438 integer, intent(in) :: comm
439
440#ifdef CAMP_USE_MPI
441 integer :: prev_position
442
443 prev_position = pos
444 call camp_mpi_unpack_logical(buffer, pos, this%is_malloced, comm)
445 call camp_mpi_unpack_integer(buffer, pos, this%rxn_unique_id, comm)
446 call assert(254749806, &
447 pos - prev_position <= this%pack_size(comm))
448 this%update_data = rxn_photolysis_create_rate_update_data()
449#endif
450
451 end subroutine internal_bin_unpack
452
453!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
454
455 !> Finalize an update data object
456 elemental subroutine update_data_finalize(this)
457
458 !> Update data object to free
459 type(rxn_update_data_photolysis_t), intent(inout) :: this
460
461 if (this%is_malloced) call rxn_free_update_data(this%update_data)
462
463 end subroutine update_data_finalize
464
465!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
466
467end module camp_rxn_photolysis
Initialize the aerosol representation data, validating component data and loading any required inform...
Extending-type binary pack function (Internal use only)
Extending-type binary unpack function (Internal use only)
Extending-type binary pack size (internal use only)
Get the non-unique name of a chemical species by its unique name.
Free an update rate data object.
Interface for to_string functions.
Definition util.F90:32
The abstract aero_rep_data_t structure and associated subroutines.
integer(kind=i_kind) function pack_size(this, comm)
Determine the size of a binary required to pack the aerosol representation data.
The camp_state_t structure and associated subroutines.
Definition camp_state.F90:9
elemental subroutine finalize(this)
Finalize the state.
The chem_spec_data_t structure and associated subroutines.
type(chem_spec_data_t) function, pointer constructor(init_size)
Constructor for chem_spec_data_t.
logical function get_property_set(this, spec_name, property_set)
Get a species property set. Returns true if the species is found, or false otherwise.
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
Wrapper functions for MPI.
Definition mpi.F90:13
subroutine camp_mpi_pack_logical(buffer, position, val, comm)
Packs the given value into the buffer, advancing position.
Definition mpi.F90:792
subroutine camp_mpi_unpack_integer(buffer, position, val, comm)
Unpacks the given value from the buffer, advancing position.
Definition mpi.F90:1023
subroutine camp_mpi_unpack_logical(buffer, position, val, comm)
Unpacks the given value from the buffer, advancing position.
Definition mpi.F90:1131
integer function camp_mpi_pack_size_logical(val, comm)
Determines the number of bytes required to pack the given value.
Definition mpi.F90:484
subroutine camp_mpi_pack_integer(buffer, position, val, comm)
Packs the given value into the buffer, advancing position.
Definition mpi.F90:691
integer function camp_mpi_pack_size_integer(val, comm)
Determines the number of bytes required to pack the given value.
Definition mpi.F90:398
The property_t structure and associated subroutines.
Definition property.F90:9
Random number generators.
Definition rand.F90:9
integer(kind=i_kind) function generate_int_id()
Generate an integer id Ids will be sequential, and can only be generated by the primary process.
Definition rand.F90:435
The rxn_data_t structure and associated subroutines.
Definition rxn_data.F90:60
integer(kind=i_kind), parameter, public gas_rxn
Gas-phase reaction.
Definition rxn_data.F90:84
The rxn_photolysis_t type and associated functions.
subroutine update_data_initialize(this, update_data, rxn_type)
Initialize update data.
subroutine update_data_rate_set(this, base_rate)
Set packed update data for photolysis rate constants.
elemental subroutine update_data_finalize(this)
Finalize an update data object.
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.