CAMP 1.0.0
Chemistry Across Multiple Phases
mechanism_data.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_mechanism_data module.
7
8!> \page camp_mechanism CAMP: Chemical Mechanism
9!!
10!! A mechanism in the \ref index "camp-chem" module is a set of
11!! \ref camp_rxn "reactions" that occur in the gas-phase or within one of
12!! several \ref camp_aero_phase "aerosol phases" or across an interface
13!! between two phases (gas or aerosol). One or several mechanisms may be
14!! included in a \ref index "camp-chem" model run.
15!!
16!! Every mechanism in a \ref index "camp-chem" run will have access to
17!! the same set of \ref camp_species "chemical species" and \ref
18!! camp_aero_phase "aerosol phases", so phase and species names must be
19!! consistent across all concurrently loaded mechanisms. The division of \ref
20!! camp_rxn "reactions" into distinct mechanisms permits a host model to
21!! specificy which mechanisms should be solved during a call to
22!! \c camp_camp_core::camp_core_t::solve().
23!!
24!! The input format for mechanism data can be found \ref
25!! input_format_mechanism "here".
26
27!> The mechanism_data_t structure and associated subroutines.
29
30#ifdef CAMP_USE_JSON
31 use json_module
32#endif
33#ifdef CAMP_USE_MPI
34 use mpi
35#endif
38 use camp_constants, only : i_kind, dp
39 use camp_mpi
43 use camp_util, only : die_msg, string_t
44
45 implicit none
46 private
47
49
50 !> Reallocation increment
51 integer(kind=i_kind), parameter :: realloc_inc = 50
52 !> Fixed module file unit
53 integer(kind=i_kind), parameter :: mech_file_unit = 16
54
55 !> A chemical mechanism
56 !!
57 !! Instances of mechanism_data_t represent complete \ref camp_mechanism
58 !! chemical mechanism. Multiple mechanisms may be used during one model run
59 !! and will be solved simultaneously.
61 private
62 !> Number of reactions
63 integer(kind=i_kind) :: num_rxn = 0
64 !> Mechanism name
65 character(len=:), allocatable :: mech_name
66 !> Path and prefix for fixed module output
67 character(len=:), allocatable :: fixed_file_prefix
68 !> Reactions
69 type(rxn_data_ptr), pointer :: rxn_ptr(:) => null()
70 contains
71 !> Load reactions from an input file
72 procedure :: load
73 !> Initialize the mechanism
74 procedure :: initialize
75 !> Get the mechanism name
76 procedure :: name => get_name
77 !> Get the size of the reaction database
78 procedure :: size => get_size
79 !> Get a reaction by its index
80 procedure :: get_rxn
81 !> Determine the number of bytes required to pack the given value
82 procedure :: pack_size
83 !> Packs the given value into the buffer, advancing position
84 procedure :: bin_pack
85 !> Unpacks the given value from the buffer, advancing position
86 procedure :: bin_unpack
87 !> Print the mechanism data
88 procedure :: print => do_print
89 !> Finalize the mechanism
90 final :: finalize
91
92 ! Private functions
93 !> Ensure there is enough room in the reaction dataset to add a
94 !! specified number of reactions
95 procedure, private :: ensure_size
96 end type mechanism_data_t
97
98 ! Constructor for mechanism_data_t
99 interface mechanism_data_t
100 procedure :: constructor
101 end interface mechanism_data_t
102
103 !> Pointer type for building arrays
105 type(mechanism_data_t), pointer :: val => null()
106 contains
107 !> Dereference the pointer
108 procedure :: dereference
109 !> Finalize the pointer
111 end type mechanism_data_ptr
112
113contains
114
115!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
116
117 !> Constructor for mechanism_data_t
118 function constructor(mech_name, init_size) result(new_obj)
119
120 !> Chemical mechanism
121 type(mechanism_data_t), pointer :: new_obj
122 !> Name of the mechanism
123 character(len=*), intent(in), optional :: mech_name
124 !> Number of reactions to allocate space for initially
125 integer(i_kind), intent(in), optional :: init_size
126
127 integer(i_kind) :: alloc_size
128
129 alloc_size = realloc_inc
130
131 allocate(new_obj)
132 if (present(init_size)) alloc_size = init_size
133 if (present(mech_name)) then
134 new_obj%mech_name = mech_name
135 else
136 new_obj%mech_name = ""
137 endif
138 allocate(new_obj%rxn_ptr(alloc_size))
139
140 end function constructor
141
142!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
143
144 !> Ensure there is enough room in the reaction dataset to add a specified
145 !! number of reactions
146 subroutine ensure_size(this, num_rxn)
147
148 !> Chemical mechanism
149 class(mechanism_data_t), intent(inout) :: this
150 !> Number of new reactions to ensure space for
151 integer(i_kind), intent(in) :: num_rxn
152
153 integer(kind=i_kind) :: new_size
154 type(rxn_data_ptr), pointer :: new_rxn_ptr(:)
155
156 if (size(this%rxn_ptr) .ge. this%num_rxn + num_rxn) return
157 new_size = this%num_rxn + num_rxn + realloc_inc
158 allocate(new_rxn_ptr(new_size))
159 new_rxn_ptr(1:this%num_rxn) = this%rxn_ptr(1:this%num_rxn)
160 call this%rxn_ptr(:)%dereference()
161 deallocate(this%rxn_ptr)
162 this%rxn_ptr => new_rxn_ptr
163
164 end subroutine ensure_size
165
166!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
167
168 !> \page input_format_mechanism Input JSON Object Format: Mechanism
169 !!
170 !! A \c json object containing information about a \ref camp_mechanism
171 !! "chemical mechanism" has the following format :
172 !! \code{.json}
173 !! { "camp-data" : [
174 !! {
175 !! "name" : "my mechanism",
176 !! "type" : "MECHANISM",
177 !! "reactions" : [
178 !! ...
179 !! ]
180 !! }
181 !! ]}
182 !! \endcode
183 !! A \ref camp_mechanism "mechanism" object must have a unique \b name,
184 !! a \b type of \b MECHANISM and an array of \ref input_format_rxn
185 !! "reaction objects" labelled \b reactions. Mechanism data may be split
186 !! into multiple mechanism objects across input files - they will be
187 !! combined based on the mechanism name.
188
189!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
190
191 !> Load a chemical mechanism from an input file
192#ifdef CAMP_USE_JSON
193 subroutine load(this, json, j_obj)
194
195 !> Chemical mechanism
196 class(mechanism_data_t), intent(inout) :: this
197 !> JSON core
198 type(json_core), pointer, intent(in) :: json
199 !> JSON object
200 type(json_value), pointer, intent(in) :: j_obj
201
202 type(json_value), pointer :: child, next
203 character(kind=json_ck, len=:), allocatable :: unicode_str_val
204 type(rxn_factory_t) :: rxn_factory
205 logical :: found
206
207 ! Cycle through the set of reactions in the json file
208 next => null()
209
210 ! Get the reaction set
211 call json%get(j_obj, 'reactions(1)', child, found)
212 do while (associated(child) .and. found)
213
214 ! Increase the size of the mechanism
215 call this%ensure_size(1)
216 this%num_rxn = this%num_rxn + 1
217
218 ! Load the reaction into the mechanism
219 this%rxn_ptr(this%num_rxn)%val => rxn_factory%load(json, child)
220
221 ! Get the next reaction in the json file
222 call json%get_next(child, next)
223 child => next
224 end do
225
226 ! Determine whether and where to build fixed module code
227 call json%get(j_obj, 'build fixed module', unicode_str_val, found)
228 if (found) then
229 call assert_msg(410823202, .not.allocated(this%fixed_file_prefix), &
230 "Received multiple file prefixes for fixed mechanism module.")
231 this%fixed_file_prefix = trim(unicode_str_val)
232 end if
233
234#else
235 subroutine load(this)
236
237 !> Chemical mechanism
238 class(mechanism_data_t), intent(inout) :: this
239
240 call warn_msg(384838139, "No support for input files")
241#endif
242
243 end subroutine load
244
245!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
246
247 !> Initialize the mechanism
248 subroutine initialize(this, chem_spec_data, aero_rep_data, n_cells)
249
250 !> Chemical mechanism
251 class(mechanism_data_t), intent(inout) :: this
252 !> Chemical species data
253 type(chem_spec_data_t), intent(in) :: chem_spec_data
254 !> Aerosol representation data
255 type(aero_rep_data_ptr), pointer, intent(in) :: aero_rep_data(:)
256 !> Number of grid cells to solve simultaneously
257 integer(kind=i_kind), intent(in) :: n_cells
258
259 integer(kind=i_kind) :: i_rxn
260
261 do i_rxn = 1, this%num_rxn
262 call assert(340397127, associated(this%rxn_ptr(i_rxn)%val))
263 call this%rxn_ptr(i_rxn)%val%initialize(chem_spec_data, aero_rep_data, &
264 n_cells)
265 end do
266
267 end subroutine initialize
268
269!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
270
271 !> Get the current size of the chemical mechanism
272 integer(kind=i_kind) function get_size(this)
273
274 !> Chemical mechanism
275 class(mechanism_data_t), intent(in) :: this
276
277 get_size = this%num_rxn
278
279 end function get_size
280
281!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
282
283 !> Get a reaction by its index
284 function get_rxn(this, rxn_id) result (rxn_ptr)
285
286 !> Pointer to the reaction
287 class(rxn_data_t), pointer :: rxn_ptr
288 !> Mechanism data
289 class(mechanism_data_t), intent(in) :: this
290 !> Reaction index
291 integer(kind=i_kind), intent(in) :: rxn_id
292
293 call assert_msg(129484547, rxn_id.gt.0 .and. rxn_id .le. this%num_rxn, &
294 "Invalid reaction id: "//trim(to_string(rxn_id))//&
295 "exptected a value between 1 and "//trim(to_string(this%num_rxn)))
296
297 rxn_ptr => this%rxn_ptr(rxn_id)%val
298
299 end function get_rxn
300
301!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
302
303 !> Get the name of the mechanism
304 function get_name(this) result(mech_name)
305
306 !> Name of the mechanism
307 character(len=:), allocatable :: mech_name
308 !> Chemical mechanism
309 class(mechanism_data_t), intent(in) :: this
310
311 mech_name = this%mech_name
312
313 end function get_name
314
315!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
316
317 !> Determine the size of a binary required to pack the mechanism
318 integer(kind=i_kind) function pack_size(this, comm)
319
320 !> Chemical mechanism
321 class(mechanism_data_t), intent(in) :: this
322 !> MPI communicator
323 integer, intent(in) :: comm
324
325 type(rxn_factory_t) :: rxn_factory
326 integer(kind=i_kind) :: i_rxn
327
328 pack_size = camp_mpi_pack_size_integer(this%num_rxn, comm)
329 do i_rxn = 1, this%num_rxn
330 pack_size = pack_size + rxn_factory%pack_size(this%rxn_ptr(i_rxn)%val, &
331 comm)
332 end do
333
334 end function pack_size
335
336!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
337
338 !> Pack the given value to the buffer, advancing position
339 subroutine bin_pack(this, buffer, pos, comm)
340
341 !> Chemical mechanism
342 class(mechanism_data_t), intent(in) :: this
343 !> Memory buffer
344 character, intent(inout) :: buffer(:)
345 !> Current buffer position
346 integer, intent(inout) :: pos
347 !> MPI communicator
348 integer, intent(in) :: comm
349
350#ifdef CAMP_USE_MPI
351 type(rxn_factory_t) :: rxn_factory
352 integer :: i_rxn, prev_position
353
354 prev_position = pos
355 call camp_mpi_pack_integer(buffer, pos, this%num_rxn, comm)
356 do i_rxn = 1, this%num_rxn
357 associate(rxn => this%rxn_ptr(i_rxn)%val)
358 call rxn_factory%bin_pack(rxn, buffer, pos, comm)
359 end associate
360 end do
361 call assert(669506045, &
362 pos - prev_position <= this%pack_size(comm))
363#endif
364
365 end subroutine bin_pack
366
367!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
368
369 !> Unpack the given value to the buffer, advancing position
370 subroutine bin_unpack(this, buffer, pos, comm)
371
372 !> Chemical mechanism
373 class(mechanism_data_t), intent(inout) :: this
374 !> Memory buffer
375 character, intent(inout) :: buffer(:)
376 !> Current buffer position
377 integer, intent(inout) :: pos
378 !> MPI communicator
379 integer, intent(in) :: comm
380
381#ifdef CAMP_USE_MPI
382 type(rxn_factory_t) :: rxn_factory
383 integer :: i_rxn, prev_position, num_rxn
384
385 prev_position = pos
386 call camp_mpi_unpack_integer(buffer, pos, num_rxn, comm)
387 call this%ensure_size(num_rxn)
388 this%num_rxn = num_rxn
389 do i_rxn = 1, this%num_rxn
390 this%rxn_ptr(i_rxn)%val => rxn_factory%bin_unpack(buffer, pos, comm)
391 end do
392 call assert(360900030, &
393 pos - prev_position <= this%pack_size(comm))
394#endif
395
396 end subroutine bin_unpack
397
398!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
399
400 !> Print the mechanism data
401 subroutine do_print(this, file_unit)
402
403 !> Chemical mechanism
404 class(mechanism_data_t), intent(in) :: this
405 !> File unit for output
406 integer(kind=i_kind), optional :: file_unit
407
408 integer :: i_rxn
409 integer(kind=i_kind) :: f_unit
410
411 f_unit = 6
412
413 if (present(file_unit)) f_unit = file_unit
414
415 write(f_unit,*) "Mechanism: "//trim(this%name())
416 do i_rxn = 1, this%num_rxn
417 call this%rxn_ptr(i_rxn)%val%print(f_unit)
418 end do
419 write(f_unit,*) "End mechanism: "//trim(this%name())
420
421 end subroutine do_print
422
423!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
424
425 !> Finalize the mechanism
426 elemental subroutine finalize(this)
427
428 !> Mechanism data
429 type(mechanism_data_t), intent(inout) :: this
430
431 if (allocated(this%mech_name)) deallocate(this%mech_name)
432 if (allocated(this%fixed_file_prefix)) deallocate(this%fixed_file_prefix)
433 if (associated(this%rxn_ptr)) deallocate(this%rxn_ptr)
434
435 end subroutine finalize
436
437!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
438
439 !> Dereference a pointer to a mechanism
440 elemental subroutine dereference(this)
441
442 !> Pointer to the mechanism
443 class(mechanism_data_ptr), intent(inout) :: this
444
445 this%val => null()
446
447 end subroutine dereference
448
449!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
450
451 !> Finalize a pointer to mechanism data
452 elemental subroutine ptr_finalize(this)
453
454 !> Pointer to mechanism data
455 type(mechanism_data_ptr), intent(inout) :: this
456
457 if (associated(this%val)) deallocate(this%val)
458
459 end subroutine ptr_finalize
460
461!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
462
463end module camp_mechanism_data
Get the size of the section of the camp_camp_state::camp_state_t::state_var array required for this a...
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_rep_data_t structure and associated subroutines.
subroutine do_print(this, file_unit)
Print the aerosol representation data.
integer(kind=i_kind) function pack_size(this, comm)
Determine the size of a binary required to pack the aerosol representation data.
subroutine load(this, json, j_obj)
Load an aerosol representation from an input file.
subroutine bin_unpack(this, buffer, pos, comm)
Unpack the given value from the buffer, advancing position.
elemental subroutine dereference(this)
Deference a pointer to an aerosol representation.
subroutine bin_pack(this, buffer, pos, comm)
Pack the given value to the buffer, advancing position.
elemental subroutine ptr_finalize(this)
Finalize a pointer to an aerosol representation.
character(len=:) function, allocatable get_name(this)
Get the name of the aerosol representation.
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.
integer(kind=i_kind), parameter realloc_inc
Reallocation increment.
subroutine ensure_size(this, num_spec)
Ensure there is enough room in the species dataset to add a specified number of species.
type(chem_spec_data_t) function, pointer constructor(init_size)
Constructor for chem_spec_data_t.
Physical constants.
Definition constants.F90:9
integer, parameter dp
Kind of a double precision real number.
Definition constants.F90:16
integer, parameter i_kind
Kind of an integer.
Definition constants.F90:21
The mechanism_data_t structure and associated subroutines.
integer(kind=i_kind), parameter mech_file_unit
Fixed module file unit.
class(rxn_data_t) function, pointer get_rxn(this, rxn_id)
Get a reaction by its index.
Wrapper functions for MPI.
Definition mpi.F90:13
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_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 rxn_data_t structure and associated subroutines.
Definition rxn_data.F90:60
The abstract rxn_factory_t structure and associated subroutines.
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
subroutine warn_msg(code, warning_msg, already_warned)
Prints a warning message.
Definition util.F90:90
Pointer to aero_rep_data_t extending types.
Pointer type for building arrays.
Pointer type for building arrays of mixed reactions.
Definition rxn_data.F90:149
Abstract reaction data type.
Definition rxn_data.F90:98
Factory type for chemical reactions.
String type for building arrays of string of various size.
Definition util.F90:38