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