CAMP 1.0.0
Chemistry Across Multiple Phases
rxn_emission.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_emission module.
7
8!> \page camp_rxn_emission CAMP: Emission
9!!
10!! Emission reactions take the form:
11!!
12!! \f[
13!! \rightarrow \mbox{X}
14!! \f]
15!!
16!! where \f$\ce{X}\f$ is the species being emitted.
17!!
18!! Emission rates can be constant or set from an external module using the
19!! \c camp_rxn_emission::rxn_update_data_emission_t object.
20!! External modules can use the
21!! \c camp_rxn_emission::rxn_emission_t::get_property_set()
22!! function during initilialization to access any needed reaction parameters
23!! to identify certain emission reactions.
24!! An \c camp_rxn_emission::update_data_emission_t object should be
25!! initialized for each emissions reaction. These objects can then be used
26!! during solving to update the emission rate from an external module.
27!!
28!! Input data for emission reactions have the following format :
29!! \code{.json}
30!! {
31!! "type" : "EMISSION",
32!! "species" : "species_name",
33!! "scaling factor" : 1.2,
34!! ...
35!! }
36!! \endcode
37!! The key-value pair \b species is required and its value must be the name
38!! of the species being emitted. The \b scaling
39!! \b factor is optional, and can be used to set a constant scaling
40!! factor for the rate. When a \b scaling \b factor is not provided, it is
41!! assumed to be 1.0. All other data is optional and will be available to
42!! external modules during initialization. Rates are in units of
43!! \f$\mbox{concentration units} \quad s^{-1}\f$, and must be set using a
44!! \c rxn_update_data_emission_t object.
45
46!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
47
48!> The rxn_emission_t type and associated functions.
50
53 use camp_constants, only: const
55 use camp_mpi
58 use camp_util, only: i_kind, dp, to_string, &
60
61 use iso_c_binding
62
63 implicit none
64 private
65
66#define RXN_ID_ this%condensed_data_int(1)
67#define SPECIES_ this%condensed_data_int(2)
68#define DERIV_ID_ this%condensed_data_int(3)
69#define SCALING_ this%condensed_data_real(1)
70#define NUM_INT_PROP_ 3
71#define NUM_REAL_PROP_ 1
72#define NUM_ENV_PARAM_ 2
73
75
76 !> Generic test reaction data type
77 type, extends(rxn_data_t) :: rxn_emission_t
78 contains
79 !> Reaction initialization
80 procedure :: initialize
81 !> Get the reaction property set
82 procedure :: get_property_set
83 !> Initialize update data
85 !> Finalize the reaction
87 end type rxn_emission_t
88
89 !> Constructor for rxn_emission_t
91 procedure :: constructor
92 end interface rxn_emission_t
93
94 !> Emission rate update object
96 private
97 !> Flag indicating whether the update data as been allocated
98 logical :: is_malloced = .false.
99 !> Unique id for finding reactions during model initialization
100 integer(kind=i_kind) :: rxn_unique_id = 0
101 contains
102 !> Update the rate data
103 procedure :: set_rate => update_data_rate_set
104 !> Determine the pack size of the local update data
106 !> Pack the local update data to a binary
107 procedure :: internal_bin_pack
108 !> Unpack the local update data from a binary
110 !> Finalize the rate update data
113
114 !> Interface to c reaction functions
115 interface
116
117 !> Allocate space for a rate update
119 result(update_data) bind (c)
120 use iso_c_binding
121 !> Allocated update_data object
122 type(c_ptr) :: update_data
124
125 !> Set a new emission rate
126 subroutine rxn_emission_set_rate_update_data(update_data, &
127 rxn_unique_id, base_rate) bind (c)
128 use iso_c_binding
129 !> Update data
130 type(c_ptr), value :: update_data
131 !> Reaction unique id
132 integer(kind=c_int), value :: rxn_unique_id
133 !> New pre-scaling base emission rate
134 real(kind=c_double), value :: base_rate
136
137 !> Free an update rate data object
138 pure subroutine rxn_free_update_data(update_data) bind (c)
139 use iso_c_binding
140 !> Update data
141 type(c_ptr), value, intent(in) :: update_data
142 end subroutine rxn_free_update_data
143
144 end interface
145
146contains
147
148!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
149
150 !> Constructor for Emission reaction
151 function constructor() result(new_obj)
152
153 !> A new reaction instance
154 type(rxn_emission_t), pointer :: new_obj
155
156 allocate(new_obj)
157 new_obj%rxn_phase = gas_rxn
158
159 end function constructor
160
161!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
162
163 !> Initialize the reaction data, validating component data and loading
164 !! any required information into the condensed data arrays for use during
165 !! solving
166 subroutine initialize(this, chem_spec_data, aero_rep, n_cells)
167
168 !> Reaction data
169 class(rxn_emission_t), intent(inout) :: this
170 !> Chemical species data
171 type(chem_spec_data_t), intent(in) :: chem_spec_data
172 !> Aerosol representations
173 type(aero_rep_data_ptr), pointer, intent(in) :: aero_rep(:)
174 !> Number of grid cells to solve simultaneously
175 integer(kind=i_kind), intent(in) :: n_cells
176
177 type(property_t), pointer :: spec_props
178 character(len=:), allocatable :: key_name, spec_name
179 integer(kind=i_kind) :: i_spec, i_qty
180
181 integer(kind=i_kind) :: temp_int
182 real(kind=dp) :: temp_real
183
184 ! Get the species involved
185 call assert_msg(135066145, associated(this%property_set), &
186 "Missing property set needed to initialize reaction")
187 key_name = "species"
188 call assert_msg(247384490, &
189 this%property_set%get_string(key_name, spec_name), &
190 "Emission reaction is missing species name")
191
192 ! Allocate space in the condensed data arrays
193 allocate(this%condensed_data_int(num_int_prop_))
194 allocate(this%condensed_data_real(num_real_prop_))
195 this%condensed_data_int(:) = int(0, kind=i_kind)
196 this%condensed_data_real(:) = real(0.0, kind=dp)
197
198 ! Save space for the environment-dependent parameters
199 this%num_env_params = num_env_param_
200
201 ! Get reaction parameters
202 key_name = "scaling factor"
203 if (.not. this%property_set%get_real(key_name, scaling_)) then
204 scaling_ = real(1.0, kind=dp)
205 end if
206
207 ! Save the index of this species in the state variable array
208 species_ = chem_spec_data%gas_state_id(spec_name)
209
210 ! Make sure the species exists
211 call assert_msg(814240522, species_.gt.0, &
212 "Missing emission species: "//spec_name)
213
214 ! Initialize the rxn id
215 rxn_id_ = -1
216
217 end subroutine initialize
218
219!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
220
221 !> Get the reaction properties. (For use by external modules.)
222 function get_property_set(this) result(prop_set)
223
224 !> Reaction properties
225 type(property_t), pointer :: prop_set
226 !> Reaction data
227 class(rxn_emission_t), intent(in) :: this
228
229 prop_set => this%property_set
230
231 end function get_property_set
232
233!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
234
235 !> Finalize the reaction
236 subroutine finalize(this)
237
238 !> Reaction data
239 type(rxn_emission_t), intent(inout) :: this
240
241 if (associated(this%property_set)) &
242 deallocate(this%property_set)
243 if (allocated(this%condensed_data_real)) &
244 deallocate(this%condensed_data_real)
245 if (allocated(this%condensed_data_int)) &
246 deallocate(this%condensed_data_int)
247
248 end subroutine finalize
249
250!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
251
252 !> Finalize an array of reactions
253 subroutine finalize_array(this)
254
255 !> Array of reactions
256 type(rxn_emission_t), intent(inout) :: this(:)
257
258 integer(kind=i_kind) :: i
259
260 do i = 1, size(this)
261 call finalize(this(i))
262 end do
263
264 end subroutine finalize_array
265
266!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
267
268 !> Set packed update data for emission rate constants
269 subroutine update_data_rate_set(this, base_rate)
270
271 !> Update data
272 class(rxn_update_data_emission_t), intent(inout) :: this
273 !> Updated pre-scaling emission rate
274 real(kind=dp), intent(in) :: base_rate
275
276 call rxn_emission_set_rate_update_data(this%get_data(), &
277 this%rxn_unique_id, base_rate)
278
279 end subroutine update_data_rate_set
280
281!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
282
283 !> Initialize update data
284 subroutine update_data_initialize(this, update_data, rxn_type)
285
286 use camp_rand, only : generate_int_id
287
288 !> The reaction to be udpated
289 class(rxn_emission_t), intent(inout) :: this
290 !> Update data object
291 class(rxn_update_data_emission_t), intent(out) :: update_data
292 !> Reaction type id
293 integer(kind=i_kind), intent(in) :: rxn_type
294
295 ! If a reaction id has not yet been generated, do it now
296 if (rxn_id_.eq.-1) then
297 rxn_id_ = generate_int_id()
298 endif
299
300 update_data%rxn_unique_id = rxn_id_
301 update_data%rxn_type = int(rxn_type, kind=c_int)
302 update_data%update_data = rxn_emission_create_rate_update_data()
303 update_data%is_malloced = .true.
304
305 end subroutine update_data_initialize
306
307!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
308
309 !> Determine the size of a binary required to pack the reaction data
310 integer(kind=i_kind) function internal_pack_size(this, comm) &
311 result(pack_size)
312
313 !> Reaction update data
314 class(rxn_update_data_emission_t), intent(in) :: this
315 !> MPI communicator
316 integer, intent(in) :: comm
317
318 pack_size = &
319 camp_mpi_pack_size_logical(this%is_malloced, comm) + &
320 camp_mpi_pack_size_integer(this%rxn_unique_id, comm)
321
322 end function internal_pack_size
323
324!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
325
326 !> Pack the given value to the buffer, advancing position
327 subroutine internal_bin_pack(this, buffer, pos, comm)
328
329 !> Reaction update data
330 class(rxn_update_data_emission_t), intent(in) :: this
331 !> Memory buffer
332 character, intent(inout) :: buffer(:)
333 !> Current buffer position
334 integer, intent(inout) :: pos
335 !> MPI communicator
336 integer, intent(in) :: comm
337
338#ifdef CAMP_USE_MPI
339 integer :: prev_position
340
341 prev_position = pos
342 call camp_mpi_pack_logical(buffer, pos, this%is_malloced, comm)
343 call camp_mpi_pack_integer(buffer, pos, this%rxn_unique_id, comm)
344 call assert(945453741, &
345 pos - prev_position <= this%pack_size(comm))
346#endif
347
348 end subroutine internal_bin_pack
349
350!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
351
352 !> Unpack the given value from the buffer, advancing position
353 subroutine internal_bin_unpack(this, buffer, pos, comm)
354
355 !> Reaction update data
356 class(rxn_update_data_emission_t), intent(inout) :: this
357 !> Memory buffer
358 character, intent(inout) :: buffer(:)
359 !> Current buffer position
360 integer, intent(inout) :: pos
361 !> MPI communicator
362 integer, intent(in) :: comm
363
364#ifdef CAMP_USE_MPI
365 integer :: prev_position
366
367 prev_position = pos
368 call camp_mpi_unpack_logical(buffer, pos, this%is_malloced, comm)
369 call camp_mpi_unpack_integer(buffer, pos, this%rxn_unique_id, comm)
370 call assert(775296837, &
371 pos - prev_position <= this%pack_size(comm))
372 this%update_data = rxn_emission_create_rate_update_data()
373#endif
374
375 end subroutine internal_bin_unpack
376
377!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
378
379 !> Finalize an update data object
380 subroutine update_data_finalize(this)
381
382 !> Update data object to free
383 type(rxn_update_data_emission_t), intent(inout) :: this
384
385 if (this%is_malloced) call rxn_free_update_data(this%update_data)
386
387 end subroutine update_data_finalize
388
389!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
390
391 !> Finalize an array of update data objects
393
394 !> Array of update data objects to free
395 type(rxn_update_data_emission_t), intent(inout) :: this(:)
396
397 integer(kind=i_kind) :: i
398
399 do i = 1, size(this)
400 call update_data_finalize(this(i))
401 end do
402
403 end subroutine update_data_finalize_array
404
405!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
406
407end module camp_rxn_emission
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.
subroutine finalize_array(this_array)
Finalize the chemical species data.
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_emission_t type and associated functions.
subroutine update_data_rate_set(this, base_rate)
Set packed update data for emission rate constants.
subroutine update_data_finalize(this)
Finalize an update data object.
subroutine update_data_finalize_array(this)
Finalize an array of update data objects.
subroutine update_data_initialize(this, update_data, rxn_type)
Initialize update data.
Common utility subroutines.
Definition util.F90:9
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
Definition util.F90:165
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.