CAMP 1.0.0
Chemistry Across Multiple Phases
aero_rep_modal_binned_mass.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_aero_rep_modal_binned_mass module.
7
8!> \page camp_aero_rep_modal_binned_mass CAMP: Modal/Binned Mass Aerosol Representation
9!!
10!! The modal/binned mass aerosol representation includes a set of sections/bins
11!! that are made up of one or more \ref camp_aero_phase "aerosol phases." The
12!! \c json object for this \ref camp_aero_rep "aerosol representation" has the
13!! following format:
14!! \code{.json}
15!! { "camp-data" : [
16!! {
17!! "name" : "my modal/binned aero rep",
18!! "type" : "AERO_REP_MODAL_BINNED_MASS",
19!! "modes/bins" :
20!! {
21!! "dust" :
22!! {
23!! "type" : "BINNED",
24!! "phases" : [ "insoluble", "organic", "aqueous" ],
25!! "bins" : 8,
26!! "minimum diameter [m]" : 0.8e-9,
27!! "maximum diameter [m]" : 1.0e-6,
28!! "scale" : "LOG"
29!! },
30!! "depeche" :
31!! {
32!! "type" : "MODAL",
33!! "phases" : [ "moody", "listless" ],
34!! "shape" : "LOG_NORMAL",
35!! }
36!! }
37!! },
38!! ...
39!! ]}
40!! \endcode
41!! The key-value pair \b type is required and must be
42!! \b AERO_REP_MODAL_BINNED_MASS. The key-value pair \b modes/bins is also
43!! required and must contain a set of at least one uniquely named mode or
44!! bin-set key-value pair whose value(s) specify a \b type that must be either
45!! \b MODAL or \b BINNED and an array of \b phases that correspond to existing
46!! \ref camp_aero_phase "aerosol phase" objects. Each phase will be present
47!! once within a mode or once within each bin in a bin-set.
48!!
49!! Modes must also specify a distribution \b shape which must be \b LOG_NORMAL
50!! (the available shapes may be expanded in the future). Log-normal sections
51!! have \b geometric \b mean \b diameter (m) and a \b geometric
52!! \b standard \b deviation (unitless) properties that must be set using an
53!! \c aero_rep_update_data_modal_binned_mass_GMD_t or and
54!! \c aero_rep_update_data_modal_binned_mass_GSD_t object and will be used along
55!! with the mass
56!! concentration of species in each phase and their densities to calculate a
57!! lognormal distribution for each mode at runtime.
58!!
59!! Bin sets must specify the number of \b bins, a \b minimum \b diameter (m),
60!! a \b maximum \b diameter (m) and a \b scale, which must be \b LOG or
61!! \b LINEAR. The number concentration will be calculated at run-time based on
62!! the total mass of each bin, the species densities and the diameter of
63!! particles in that bin.
64!!
65!! The GMD and GSD for each mode must be set from an external model using
66!! \c camp_aero_rep_modal_binned_mass::aero_rep_update_data_modal_binned_mass_GMD_t
67!! and
68!! \c camp_aero_rep_modal_binned_mass::aero_rep_update_data_modal_binned_mass_GSD_t
69!! objects.
70
71!> The abstract aero_rep_modal_binned_mass_t structure and associated subroutines.
73
78 use camp_mpi
80 use camp_util, only: dp, i_kind, &
83
84 use iso_c_binding
85
86 implicit none
87 private
88
89#define BINNED 1
90#define MODAL 2
91
92#define NUM_SECTION_ this%condensed_data_int(1)
93#define INT_DATA_SIZE_ this%condensed_data_int(2)
94#define REAL_DATA_SIZE_ this%condensed_data_int(3)
95#define AERO_REP_ID_ this%condensed_data_int(4)
96#define NUM_INT_PROP_ 4
97#define NUM_REAL_PROP_ 0
98#define NUM_ENV_PARAM_ 0
99#define MODE_INT_PROP_LOC_(x) this%condensed_data_int(NUM_INT_PROP_+x)
100#define MODE_REAL_PROP_LOC_(x) this%condensed_data_int(NUM_INT_PROP_+NUM_SECTION_+x)
101#define SECTION_TYPE_(x) this%condensed_data_int(MODE_INT_PROP_LOC_(x))
102
103! For modes, NUM_BINS_ = 1
104#define NUM_BINS_(x) this%condensed_data_int(MODE_INT_PROP_LOC_(x)+1)
105
106! Number of aerosol phases in this mode/bin set
107#define NUM_PHASE_(x) this%condensed_data_int(MODE_INT_PROP_LOC_(x)+2)
108
109! Phase state and model data ids
110#define PHASE_STATE_ID_(x,y,b) this%condensed_data_int(MODE_INT_PROP_LOC_(x)+2+(b-1)*NUM_PHASE_(x)+y)
111#define PHASE_MODEL_DATA_ID_(x,y,b) this%condensed_data_int(MODE_INT_PROP_LOC_(x)+2+NUM_BINS_(x)*NUM_PHASE_(x)+(b-1)*NUM_PHASE_(x)+y)
112
113! Number of Jacobian elements in a phase
114#define PHASE_NUM_JAC_ELEM_(x,y,b) this%condensed_data_int(MODE_INT_PROP_LOC_(x)+2+2*NUM_BINS_(x)*NUM_PHASE_(x)+(b-1)*NUM_PHASE_(x)+y)
115
116! Bin diameter (bins only)
117#define BIN_DP_(x,b) this%condensed_data_real(MODE_REAL_PROP_LOC_(x)+(b-1)*3)
118
119! Real-time number concetration - used for modes and bins - for modes, b=1
120#define NUMBER_CONC_(x,b) this%condensed_data_real(MODE_REAL_PROP_LOC_(x)+(b-1)*3+1)
121
122! Real-time effective radius - for modes, b=1
123#define EFFECTIVE_RADIUS_(x,b) this%condensed_data_real(MODE_REAL_PROP_LOC_(x)+(b-1)*3+2)
124
125! Real-time aerosol phase mass - used for modes and bins - for modes, b=1
126#define PHASE_MASS_(x,y,b) this%condensed_data_real(MODE_REAL_PROP_LOC_(x)+3*NUM_BINS_(x)+(b-1)*NUM_PHASE_(x)+y-1)
127
128! Real-time aerosol phase average MW - used for modes and bins - for modes, b=0
129#define PHASE_AVG_MW_(x,y,b) this%condensed_data_real(MODE_REAL_PROP_LOC_(x)+(3+NUM_PHASE_(x))*NUM_BINS_(x)+(b-1)*NUM_PHASE_(x)+y-1)
130
131 ! Update types (These must match values in aero_rep_modal_binned_mass.c)
132 integer(kind=i_kind), parameter, public :: update_gmd = 0
133 integer(kind=i_kind), parameter, public :: update_gsd = 1
134
138
139 !> Modal mass aerosol representation
140 !!
141 !! Time-invariant data related to a modal/binned mass aerosol representation.
143 !> Mode names (only used during initialization)
144 type(string_t), allocatable :: section_name(:)
145 !> Phase state id (only used during initialization)
146 integer(kind=i_kind), allocatable :: phase_state_id(:)
147 contains
148 !> Initialize the aerosol representation data, validating component data and
149 !! loading any required information from the \c
150 !! aero_rep_data_t::property_set. This routine should be called once for
151 !! each aerosol representation at the beginning of a model run after all
152 !! the input files have been read in. It ensures all data required during
153 !! the model run are included in the condensed data arrays.
154 procedure :: initialize
155 !> Initialize an update data GSD object
156 procedure :: update_data_initialize_gsd => update_data_init_gsd
157 !> Initialize an update data GMD object
158 procedure :: update_data_initialize_gmd => update_data_init_gmd
159 !> Get an id for a mode or bin in the aerosol representation by name for
160 !! use with updates from external modules
161 procedure :: get_section_id
162 !> Get the size of the section of the
163 !! \c camp_camp_state::camp_state_t::state_var array required for this
164 !! aerosol representation.
165 !!
166 !! For a modal/binned mass representation, the size will correspond to the
167 !! the sum of the sizes of a single instance of each aerosol phase
168 !! provided to \c aero_rep_modal_binned_mass::initialize()
169 procedure :: size => get_size
170 !> Get a list of unique names for each element on the
171 !! \c camp_camp_state::camp_state_t::state_var array for this aerosol
172 !! representation. The list may be restricted to a particular phase and/or
173 !! aerosol species by including the phase_name and spec_name arguments.
174 !!
175 !! For a modal/binned mass representation, the unique names for bins are:
176 !! - "bin name.bin #.phase name.species name"
177 !!
178 !! ... and for modes are:
179 !! - "mode name.phase name.species name"
180 procedure :: unique_names
181 !> Get a species id on the \c camp_camp_state::camp_state_t::state_var
182 !! array by its unique name. These are unique ids for each element on the
183 !! state array for this \ref camp_aero_rep "aerosol representation" and
184 !! are numbered:
185 !!
186 !! \f[x_u \in x_f ... (x_f+n-1)\f]
187 !!
188 !! where \f$x_u\f$ is the id of the element corresponding to the species
189 !! with unique name \f$u\f$ on the \c
190 !! camp_camp_state::camp_state_t::state_var array, \f$x_f\f$ is the index
191 !! of the first element for this aerosol representation on the state array
192 !! and \f$n\f$ is the total number of variables on the state array from
193 !! this aerosol representation.
194 procedure :: spec_state_id
195 !> Get the non-unique name of a species by its unique name
196 procedure :: spec_name
197 !> Get the number of instances of an aerosol phase in this representation
199 !> Get the number of Jacobian elements used in calculations of aerosol mass,
200 !! volume, number, etc. for a particular phase
201 procedure :: num_jac_elem
202 !> Returns index_pair_t type with phase_ids of adjacent phases
203 !! for modal/binned representation there are no adjacent phases
204 procedure :: adjacent_phases
205 !> Get the species id for a phase and species name
207 !> Finalize the aerosol representation
209
211
212 ! Constructor for aero_rep_modal_binned_mass_t
214 procedure :: constructor
215 end interface aero_rep_modal_binned_mass_t
216
217 !> Update GMD object
218 type, extends(aero_rep_update_data_t) :: &
220 private
221 !> Flag indicating whether the update data has been allocated
222 logical :: is_malloced = .false.
223 !> Unique id for finding aerosol representations during initialization
224 integer(kind=i_kind) :: aero_rep_unique_id = 0
225 contains
226 !> Update the GMD
227 procedure :: set_gmd => update_data_set_gmd
228 !> Determine the pack size of the local update data
230 !> Pack the local update data to a binary
232 !> Unpack the local update data from a binary
234 !> Finalize the GMD update data
237
238 !> Update GSD object
239 type, extends(aero_rep_update_data_t) :: &
241 private
242 !> Flag indicating whether the update data has been allocated
243 logical :: is_malloced = .false.
244 !> Unique id for finding aerosol representations during initialization
245 integer(kind=i_kind) :: aero_rep_unique_id = 0
246 contains
247 !> Update the GSD
248 procedure :: set_gsd => update_data_set_gsd
249 !> Determine the pack size of the local update data
251 !> Pack the local update data to a binary
253 !> Unpack the local update data from a binary
255 !> Finalize the GSD update data
258
259 !> Interface to c aerosol representation functions
260 interface
261
262 !> Allocate space for a GMD update object
263 !! @return Allocated update data object
265 result(update_data) bind (c)
266 use iso_c_binding
267 type(c_ptr) :: update_data
269
270 !> Set a new mode GMD
272 aero_rep_unique_id, section_id, gmd) bind (c)
273 use iso_c_binding
274 !> Update data
275 type(c_ptr), value :: update_data
276 !> Aerosol representation unique id
277 integer(kind=c_int), value :: aero_rep_unique_id
278 !> Section id from
279 !! camp_aero_rep_modal_binned_mass::aero_rep_modal_binned_mass_t::get_section_id
280 integer(kind=c_int), value :: section_id
281 !> New GMD (m)
282 real(kind=c_double), value :: gmd
284
285 !> Allocate space for a GSD update object
286 !! @return Allocated update data object
288 result(update_data) bind (c)
289 use iso_c_binding
290 type(c_ptr) :: update_data
292
293 !> Set a new mode GSD
295 aero_rep_unique_id, section_id, gsd) bind (c)
296 use iso_c_binding
297 !> Update data
298 type(c_ptr), value :: update_data
299 !> Aerosol representation unique id
300 integer(kind=c_int), value :: aero_rep_unique_id
301 !> Section id from
302 !! camp_aero_rep_modal_binned_mass::aero_rep_modal_binned_mass_t::get_section_id
303 integer(kind=c_int), value :: section_id
304 !> New GSD (m)
305 real(kind=c_double), value :: gsd
307
308 !> Free an update data object
309 pure subroutine aero_rep_free_update_data(update_data) bind (c)
310 use iso_c_binding
311 !> Update data
312 type(c_ptr), value, intent(in) :: update_data
313 end subroutine aero_rep_free_update_data
314
315 end interface
316
317contains
318
319!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
320
321 !> Constructor for aero_rep_modal_binned_mass_t
322 function constructor() result (new_obj)
323
324 !> New aerosol representation
325 type(aero_rep_modal_binned_mass_t), pointer :: new_obj
326
327 allocate(new_obj)
328
329 end function constructor
330
331!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
332
333 !> Initialize the aerosol representation data, validating component data and
334 !! loading any required information from the \c
335 !! aero_rep_data_t::property_set. This routine should be called once for
336 !! each aerosol representation at the beginning of a model run after all
337 !! the input files have been read in. It ensures all data required during
338 !! the model run are included in the condensed data arrays.
339 subroutine initialize(this, aero_phase_set, spec_state_id)
340
341 !> Aerosol representation data
342 class(aero_rep_modal_binned_mass_t), intent(inout) :: this
343 !> The set of aerosol phases
344 type(aero_phase_data_ptr), pointer, intent(in) :: aero_phase_set(:)
345 !> Beginning state id for this aerosol representationin the model species
346 !! state array
347 integer(kind=i_kind), intent(in) :: spec_state_id
348
349 type(property_t), pointer :: sections, section, phases
350 integer(kind=i_kind) :: i_section, i_phase, j_phase, k_phase, &
351 i_bin
352 integer(kind=i_kind) :: curr_spec_state_id
353 integer(kind=i_kind) :: num_phase, num_bin
354 integer(kind=i_kind) :: n_int_param, n_float_param
355 character(len=:), allocatable :: key_name, phase_name, sect_type, str_val
356 real(kind=dp) :: min_dp, max_dp, d_log_dp
357
358 ! Determine the size of the condensed data arrays
359 n_int_param = num_int_prop_
360 n_float_param = num_real_prop_
361
362 ! Get the set of sections/bin-sets
363 key_name = "modes/bins"
364 call assert_msg(877855909, &
365 this%property_set%get_property_t(key_name, sections), &
366 "Missing sections/bins for modal/binned mass aerosol "// &
367 "representation '"//this%rep_name//"'")
368 call assert_msg(894962494, sections%size().gt.0, "No sections or bins "// &
369 "specified for modal/binned mass aerosol representation '"// &
370 this%rep_name//"'")
371
372 ! Allocate space for the mode/bin names
373 allocate(this%section_name(sections%size()))
374
375 ! Loop through the sections, adding names and counting the spaces needed
376 ! on the condensed data arrays, and counting the total phases instances
377 num_phase = 0
378 call sections%iter_reset()
379 do i_section = 1, sections%size()
380
381 ! Get the mode/bin name
382 call assert(867378489, sections%get_key(key_name))
383 call assert_msg(234513113, len(key_name).gt.0, "Missing mode/bin "// &
384 "name in modal/binned mass aerosol representation '"// &
385 this%rep_name//"'")
386 this%section_name(i_section)%string = key_name
387
388 ! Get the mode/bin properties
389 call assert_msg(517138327, sections%get_property_t(val=section), &
390 "Invalid structure for mode/bin '"// &
391 this%section_name(i_section)%string// &
392 "' in modal/binned mass aerosol representation '"// &
393 this%rep_name//"'")
394
395 ! Get the section type
396 key_name = "type"
397 call assert_msg(742404898, section%get_string(key_name, sect_type), &
398 "Missing mode/bin type in mode/bin '"// &
399 this%section_name(i_section)%string// &
400 "' in modal/binned mass aerosol representation '"// &
401 this%rep_name//"'")
402 call assert_msg(618556995, &
403 sect_type.eq."MODAL".or.sect_type.eq."BINNED", &
404 "Invalid mode/bin type '"//sect_type//"' in mode/bin '"// &
405 this%section_name(i_section)%string// &
406 "' in modal/binned mass aerosol representation '"// &
407 this%rep_name//"'")
408
409 ! Get the number of bins (or set to 1 for a mode)
410 num_bin = 1
411 if (sect_type.eq."BINNED") then
412
413 key_name = "bins"
414 call assert_msg(824494286, section%get_int(key_name, num_bin), &
415 "Missing number of bins in bin '"// &
416 this%section_name(i_section)%string// &
417 "' in modal/binned mass aerosol representation '"// &
418 this%rep_name//"'")
419 end if
420
421 ! Add space for the mode/bin type, number of bins, and phase count
422 ! and parameter locations
423 n_int_param = n_int_param + 5
424
425 ! Add space for the bin diameter, number concentration, and
426 ! effective radius
427 n_float_param = n_float_param + 3*num_bin
428
429 ! Get the set of phases
430 key_name = "phases"
431 call assert_msg(815518058, section%get_property_t(key_name, phases), &
432 "Missing phases for mode '"// &
433 this%section_name(i_section)%string// &
434 "' in modal/binned mass aerosol representation '"// &
435 this%rep_name//"'")
436
437 ! Add the phases to the counter
438 call assert_msg(772593427, phases%size().gt.0, &
439 "No phases specified for mode '"// &
440 this%section_name(i_section)%string// &
441 "' in modal/binned mass aerosol representation '"// &
442 this%rep_name//"'")
443 num_phase = num_phase + phases%size() * num_bin
444
445 ! Loop through the phases and make sure they exist
446 call phases%iter_reset()
447 do i_phase = 1, phases%size()
448
449 ! Get the phase name
450 call assert_msg(393427582, phases%get_string(val=phase_name), &
451 "Non-string phase name for mode '"// &
452 this%section_name(i_section)%string// &
453 "' in modal/binned mass aerosol representation '"// &
454 this%rep_name//"'")
455
456 ! Find the aerosol phase and add space for its variables
457 do j_phase = 1, size(aero_phase_set)
458 if (phase_name.eq.aero_phase_set(j_phase)%val%name()) then
459
460 ! Add space for the phase state, model data ids, and number
461 ! of Jacobian elements
462 n_int_param = n_int_param + 3 * num_bin
463
464 ! Add space for total aerosol phase mass and average MW,
465 n_float_param = n_float_param + 2 * num_bin
466
467 exit
468 else if (j_phase.eq.size(aero_phase_set)) then
469 call die_msg(652391420, "Non-existant aerosol phase '"// &
470 phase_name//"' specified for mode '"// &
471 this%section_name(i_section)%string// &
472 "' in modal/binned mass aerosol representation '"// &
473 this%rep_name//"'")
474 end if
475 end do
476
477 call phases%iter_next()
478 end do
479
480 call sections%iter_next()
481 end do
482
483 ! Allocate space for the aerosol phases and species state ids
484 allocate(this%aero_phase(num_phase))
485 allocate(this%aero_phase_is_at_surface(num_phase))
486 allocate(this%phase_state_id(size(this%aero_phase)))
487
488 ! Allocate condensed data arrays
489 allocate(this%condensed_data_int(n_int_param))
490 allocate(this%condensed_data_real(n_float_param))
491 this%condensed_data_int(:) = int(0, kind=i_kind)
492 this%condensed_data_real(:) = real(0.0, kind=dp)
493 int_data_size_ = n_int_param
494 real_data_size_ = n_float_param
495
496 ! Set the number of sections
497 num_section_ = sections%size()
498
499 ! Save space for the environment-dependent parameters (GMD and GSD)
500 this%num_env_params = 2 * num_section_
501
502 ! Loop through the sections, adding names and distribution parameters and
503 ! counting the phases in each section
504 i_phase = 1
505 curr_spec_state_id = spec_state_id
506 n_int_param = num_int_prop_+2*num_section_+1
507 n_float_param = num_real_prop_+1
508 call sections%iter_reset()
509 do i_section = 1, num_section_
510
511 ! Set the data locations for this mode
512 mode_int_prop_loc_(i_section) = n_int_param
513 mode_real_prop_loc_(i_section) = n_float_param
514
515 ! Get the mode/bin properties
516 call assert(394743663, sections%get_property_t(val=section))
517
518 ! Get the mode/bin type
519 key_name = "type"
520 call assert(667058653, section%get_string(key_name, sect_type))
521 if (sect_type.eq."MODAL") then
522 section_type_(i_section) = modal
523 else if (sect_type.eq."BINNED") then
524 section_type_(i_section) = binned
525 else
526 call die_msg(256924433, "Internal error")
527 end if
528
529 ! Get the number of bins (or set to 1 for a mode)
530 num_bins_(i_section) = 1
531 if (section_type_(i_section).eq.binned) then
532 key_name = "bins"
533 call assert(315215287, section%get_int(key_name, num_bins_(i_section)))
534 end if
535
536 ! Get mode parameters
537 if (section_type_(i_section).eq.modal) then
538
539 ! Currently no mode parameters
540
541 effective_radius_(i_section,1) = -9999.9
542 number_conc_(i_section,1) = -9999.9
543
544 ! Get bin parameters
545 else if (section_type_(i_section).eq.binned) then
546
547 ! Get the minimum diameter (m)
548 key_name = "minimum diameter [m]"
549 call assert_msg(548762180, section%get_real(key_name, min_dp), &
550 "Missing minimum diameter for bin '"// &
551 this%section_name(i_section)%string// &
552 "' in modal/binned mass aerosol representation '"// &
553 this%rep_name//"'")
554
555 ! Get the maximum diameter (m)
556 key_name = "maximum diameter [m]"
557 call assert_msg(288632226, section%get_real(key_name, max_dp), &
558 "Missing maximum diameter for bin '"// &
559 this%section_name(i_section)%string// &
560 "' in modal/binned mass aerosol representation '"// &
561 this%rep_name//"'")
562
563 ! Get the scale
564 key_name = "scale"
565 call assert_msg(404761639, section%get_string(key_name, str_val), &
566 "Missing bin scale for bin '"// &
567 this%section_name(i_section)%string// &
568 "' in modal/binned mass aerosol representation '"// &
569 this%rep_name//"'")
570
571 ! Assign the bin diameters
572 if (str_val.eq."LINEAR") then
573 do i_bin = 1, num_bins_(i_section)
574 bin_dp_(i_section,i_bin) = min_dp + &
575 (i_bin-1) * (max_dp-min_dp)/(num_bins_(i_section)-1)
576 end do
577 else if (str_val.eq."LOG") then
578 d_log_dp = (log10(max_dp)-log10(min_dp))/(num_bins_(i_section)-1)
579 do i_bin = 1, num_bins_(i_section)
580 bin_dp_(i_section,i_bin) = 10.0d0**( log10(min_dp) + &
581 (i_bin-1) * d_log_dp )
582 end do
583 else
584 call die_msg(236797392, "Invalid scale specified for bin '"// &
585 this%section_name(i_section)%string// &
586 "' in modal/binned mass aerosol representation '"// &
587 this%rep_name//"'")
588 end if
589 do i_bin = 1, num_bins_(i_section)
590 ! Set the effective radius
591 effective_radius_(i_section,i_bin) = bin_dp_(i_section,i_bin) / 2.0
592 number_conc_(i_section,i_bin) = -9999.9
593 end do
594 end if
595
596 ! Get the set of phases
597 key_name = "phases"
598 call assert(712411046, section%get_property_t(key_name, phases))
599
600 ! Save the number of phases
601 num_phase_(i_section) = phases%size()
602
603 ! Add space for the mode/bin type, number of bins, and number of phases
604 n_int_param = n_int_param + 3
605
606 ! Add space for bin diameter, number concentration and effective radius
607 n_float_param = n_float_param + 3 * num_bins_(i_section)
608
609 ! Loop through the phase names, look them up, and add them to the list
610 call phases%iter_reset()
611 do j_phase = 1, phases%size()
612
613 ! Get the phase name
614 call assert(775801035, phases%get_string(val=phase_name))
615
616 ! Find the aerosol phase and add it to the list
617 do k_phase = 1, size(aero_phase_set)
618 if (phase_name.eq.aero_phase_set(k_phase)%val%name()) then
619
620 ! Loop through the bins
621 do i_bin = 1, num_bins_(i_section)
622
623 ! Add the aerosol phase to the list
624 this%aero_phase(i_phase) = aero_phase_set(k_phase)
625
626 ! No species exist at surface
627 this%aero_phase_is_at_surface(i_phase) = .true.
628
629 ! Save the starting id for this phase on the state array
630 this%phase_state_id(i_phase) = curr_spec_state_id
631 phase_state_id_(i_section, j_phase, i_bin) = curr_spec_state_id
632
633 ! Increment the state id by the size of the phase
634 curr_spec_state_id = curr_spec_state_id + &
635 aero_phase_set(k_phase)%val%size()
636
637 ! Save the phase model data id
638 phase_model_data_id_(i_section, j_phase, i_bin) = k_phase
639
640 i_phase = i_phase + 1
641 end do
642
643 ! Add space for aerosol phase state, model data ids, and
644 ! number of Jacobian elements
645 n_int_param = n_int_param + 3*num_bins_(i_section)
646
647 ! Add space for aerosol phase mass and average MW
648 n_float_param = n_float_param + 2*num_bins_(i_section)
649
650 exit
651 else if (k_phase.eq.size(aero_phase_set)) then
652 call die_msg(652391420, "Internal error.")
653 end if
654 end do
655
656 call phases%iter_next()
657 end do
658
659 call sections%iter_next()
660 end do
661
662 ! Initialize the aerosol representation id
663 aero_rep_id_ = -1
664
665 ! Check the data sizes
666 call assert(951534966, i_phase-1.eq.num_phase)
667 call assert(951534966, n_int_param.eq.int_data_size_+1)
668 call assert(325387136, n_float_param.eq.real_data_size_+1)
669
670 end subroutine initialize
671
672!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
673
674 !> Get an id for a mode or bin by name for use with updates from external
675 !! modules
676 function get_section_id(this, section_name, section_id) result (found)
677
678 !> Flag indicating whether the mode/bin was found
679 logical :: found
680 !> Aerosol representation
681 class(aero_rep_modal_binned_mass_t), intent(in) :: this
682 !> Section name
683 character(len=*), intent(in) :: section_name
684 !> Section id
685 integer(kind=i_kind), intent(out) :: section_id
686
687 integer(kind=i_kind) :: i_section
688
689 call assert_msg(194186171, len(trim(section_name)).gt.0, &
690 "Trying to get section id of unnamed aerosol "// &
691 "representation.")
692
693 found = .false.
694 do i_section = 1, size(this%section_name)
695 if (this%section_name(i_section)%string.eq.trim(section_name)) then
696 found = .true.
697 section_id = i_section
698 return
699 end if
700 end do
701
702 end function get_section_id
703
704!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
705
706 !> Get the size of the section of the
707 !! \c camp_camp_state::camp_state_t::state_var array required for this
708 !! aerosol representation.
709 !!
710 !! For a modal/binned mass representation, the size will correspond to the
711 !! the sum of the sizes of a single instance of each aerosol phase
712 !! provided to \c aero_rep_modal_binned_mass::initialize()
713 function get_size(this) result (state_size)
714
715 !> Size on the state array
716 integer(kind=i_kind) :: state_size
717 !> Aerosol representation data
718 class(aero_rep_modal_binned_mass_t), intent(in) :: this
719
720 integer(kind=i_kind) :: i_phase
721
722 ! Get the total number of species across all phases
723 state_size = 0
724 do i_phase = 1, size(this%aero_phase)
725 state_size = state_size + this%aero_phase(i_phase)%val%size()
726 end do
727
728 end function get_size
729
730!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
731
732 !> Get a list of unique names for each element on the
733 !! \c camp_camp_state::camp_state_t::state_var array for this aerosol
734 !! representation. The list may be restricted to a particular phase and/or
735 !! aerosol species by including the phase_name and spec_name arguments.
736 !!
737 !! For a modal/binned mass representation, the unique names for bins are:
738 !! - "bin name.bin #.phase name.species name"
739 !!
740 !! ... and for modes are:
741 !! - "mode name.phase name.species name"
742 function unique_names(this, phase_name, tracer_type, spec_name, &
743 phase_is_at_surface)
744
745 !> List of unique names
746 type(string_t), allocatable :: unique_names(:)
747 !> Aerosol representation data
748 class(aero_rep_modal_binned_mass_t), intent(in) :: this
749 !> Aerosol phase name
750 character(len=*), optional, intent(in) :: phase_name
751 !> Aerosol-phase species tracer type
752 integer(kind=i_kind), optional, intent(in) :: tracer_type
753 !> Aerosol-phase species name
754 character(len=*), optional, intent(in) :: spec_name
755 !> Aerosol-phase species is at surface
756 logical, optional, intent(in) :: phase_is_at_surface
757
758 integer(kind=i_kind) :: num_spec, i_spec, j_spec, i_phase, j_phase, &
759 i_section, i_bin
760 integer(kind=i_kind) :: curr_tracer_type
761 character(len=:), allocatable :: curr_section_name, curr_phase_name, &
762 curr_bin_str
763 type(string_t), allocatable :: spec_names(:)
764
765 ! Count the number of unique names
766 num_spec = 0
767 do i_phase = 1, size(this%aero_phase)
768
769 ! Filter by phase name
770 if (present(phase_name)) then
771 curr_phase_name = this%aero_phase(i_phase)%val%name()
772 if (phase_name.ne.curr_phase_name) cycle
773 end if
774
775 ! Filter by phase is at surface
776 if (present(phase_is_at_surface)) then
777 if (phase_is_at_surface .neqv. &
778 this%aero_phase_is_at_surface(i_phase)) cycle
779 end if
780
781 ! Filter by spec name and/or tracer type
782 if (present(spec_name).or.present(tracer_type)) then
783 spec_names = this%aero_phase(i_phase)%val%get_species_names()
784 do j_spec = 1, size(spec_names)
785 curr_tracer_type = &
786 this%aero_phase(i_phase)%val%get_species_type( &
787 spec_names(j_spec)%string)
788 if (present(spec_name)) then
789 if (spec_name.ne.spec_names(j_spec)%string) cycle
790 end if
791 if (present(tracer_type)) then
792 if (tracer_type.ne.curr_tracer_type) cycle
793 end if
794 num_spec = num_spec + 1
795 end do
796 else
797 num_spec = num_spec + this%aero_phase(i_phase)%val%size()
798 end if
799
800 end do
801
802 ! Allocate space for the unique names
803 allocate(unique_names(num_spec))
804
805 ! Loop through the modes/bin sets
806 i_phase = 1
807 i_spec = 1
808 do i_section = 1, num_section_
809
810 ! Get the current section name
811 curr_section_name = this%section_name(i_section)%string
812
813 ! Loop through the phases for this mode/bin set
814 do j_phase = 1, num_phase_(i_section)
815
816 ! Set the current phase name
817 curr_phase_name = this%aero_phase(i_phase)%val%name()
818
819 ! Filter by phase name
820 if (present(phase_name)) then
821 if (phase_name.ne.curr_phase_name) then
822 i_phase = i_phase + num_bins_(i_section)
823 cycle
824 end if
825 end if
826
827 ! Filter by phase is at surface
828 if (present(phase_is_at_surface)) then
829 if (phase_is_at_surface .neqv. &
830 this%aero_phase_is_at_surface(i_phase)) then
831 i_phase = i_phase + num_bins_(i_section)
832 cycle
833 end if
834 end if
835
836 ! Get the species names in this phase
837 spec_names = this%aero_phase(i_phase)%val%get_species_names()
838
839 ! Loop through the bins (one iteration for modes)
840 do i_bin = 1, num_bins_(i_section)
841
842 ! Set the current bin label (except for single bins or mode)
843 if (num_bins_(i_section).gt.1) then
844 curr_bin_str = trim(to_string(i_bin))//"."
845 else
846 curr_bin_str = ""
847 end if
848
849 ! Add species from this phase/bin
850 num_spec = this%aero_phase(i_phase)%val%size()
851 do j_spec = 1, num_spec
852
853 ! Filter by species name
854 if (present(spec_name)) then
855 if (spec_name.ne.spec_names(j_spec)%string) cycle
856 end if
857
858 ! Filter by species tracer type
859 if (present(tracer_type)) then
860 curr_tracer_type = &
861 this%aero_phase(i_phase)%val%get_species_type( &
862 spec_names(j_spec)%string)
863 if (tracer_type.ne.curr_tracer_type) cycle
864 end if
865
866 ! Add the unique name for this species
867 unique_names(i_spec)%string = curr_section_name//"."// &
868 curr_bin_str//curr_phase_name//'.'// &
869 spec_names(j_spec)%string
870
871 i_spec = i_spec + 1
872 end do
873
874 ! Move to the next phase instance
875 i_phase = i_phase + 1
876
877 end do
878
879 deallocate(spec_names)
880
881 end do
882 end do
883
884 end function unique_names
885
886!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
887
888 !> Get a species id on the \c camp_camp_state::camp_state_t::state_var
889 !! array by its unique name. These are unique ids for each element on the
890 !! state array for this \ref camp_aero_rep "aerosol representation" and
891 !! are numbered:
892 !!
893 !! \f[x_u \in x_f ... (x_f+n-1)\f]
894 !!
895 !! where \f$x_u\f$ is the id of the element corresponding to the species
896 !! with unique name \f$u\f$ on the \c
897 !! camp_camp_state::camp_state_t::state_var array, \f$x_f\f$ is the index
898 !! of the first element for this aerosol representation on the state array
899 !! and \f$n\f$ is the total number of variables on the state array from
900 !! this aerosol representation.
901 function spec_state_id(this, unique_name) result (spec_id)
902
903 !> Species state id
904 integer(kind=i_kind) :: spec_id
905 !> Aerosol representation data
906 class(aero_rep_modal_binned_mass_t), intent(in) :: this
907 !> Unique name
908 character(len=*), intent(in) :: unique_name
909
910 type(string_t), allocatable :: unique_names(:)
911 integer(kind=i_kind) :: i_spec
912
913 spec_id = 0
914 unique_names = this%unique_names()
915 do i_spec = 1, size(unique_names)
916 if (unique_names(i_spec)%string .eq. unique_name) then
917 spec_id = this%phase_state_id(1) + i_spec - 1
918 return
919 end if
920 end do
921 call die_msg( 105414960, "Cannot find species '"//unique_name//"'" )
922
923 end function spec_state_id
924
925!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
926
927 !> Get the non-unique name of a species by its unique name
928 function spec_name(this, unique_name)
929
930 !> Chemical species name
931 character(len=:), allocatable :: spec_name
932 !> Aerosol representation data
933 class(aero_rep_modal_binned_mass_t), intent(in) :: this
934 !> Unique name of the species in this aerosol representation
935 character(len=*), intent(in) :: unique_name
936
937 ! Indices for iterators
938 integer(kind=i_kind) :: i_spec, j_spec, i_phase
939
940 ! species names in the aerosol phase
941 type(string_t), allocatable :: spec_names(:)
942
943 ! unique name list
944 type(string_t), allocatable :: unique_names(:)
945
946 unique_names = this%unique_names()
947
948 i_spec = 1
949 do i_phase = 1, size(this%aero_phase)
950 spec_names = this%aero_phase(i_phase)%val%get_species_names()
951 do j_spec = 1, this%aero_phase(i_phase)%val%size()
952 if (unique_name.eq.unique_names(i_spec)%string) then
953 spec_name = spec_names(j_spec)%string
954 end if
955 i_spec = i_spec + 1
956 end do
957 deallocate(spec_names)
958 end do
959
960 deallocate(unique_names)
961
962 end function spec_name
963
964!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
965
966 !> Get the number of instances of a specified aerosol phase.
967 function num_phase_instances(this, phase_name, is_at_surface)
968
969 !> Number of instances of the aerosol phase
970 integer(kind=i_kind) :: num_phase_instances
971 !> Aerosol representation data
972 class(aero_rep_modal_binned_mass_t), intent(in) :: this
973 !> Aerosol phase name
974 character(len=*), intent(in) :: phase_name
975 !> Indicates if aerosol phase is at the surface of particle
976 logical, intent(in), optional :: is_at_surface
977
978 integer(kind=i_kind) :: i_phase
979
981 if (present(is_at_surface)) then
982 if (is_at_surface) then
983 do i_phase = 1, size(this%aero_phase)
984 if (this%aero_phase(i_phase)%val%name().eq.phase_name .and. &
985 this%aero_phase_is_at_surface(i_phase)) then
987 end if
988 end do
989 else
990 do i_phase = 1, size(this%aero_phase)
991 if (this%aero_phase(i_phase)%val%name().eq.phase_name .and. &
992 .not. this%aero_phase_is_at_surface(i_phase)) then
993 call die_msg(507144607, "Species must exist at surface "// &
994 "in modal/binned mass aerosol representation '"// &
995 this%rep_name//"'")
996 end if
997 end do
998 end if
999 else
1000 do i_phase = 1, size(this%aero_phase)
1001 if (this%aero_phase(i_phase)%val%name().eq.phase_name) then
1003 end if
1004 end do
1005 end if
1006
1007 end function num_phase_instances
1008
1009!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1010
1011 !> Get the number of Jacobian elements used in calculations of aerosol mass,
1012 !! volume, number, etc. for a particular phase
1013 function num_jac_elem(this, phase_id)
1014
1015 !> Number of Jacobian elements used
1016 integer(kind=i_kind) :: num_jac_elem
1017 !> Aerosol respresentation data
1018 class(aero_rep_modal_binned_mass_t), intent(in) :: this
1019 !> Aerosol phase id
1020 integer(kind=i_kind), intent(in) :: phase_id
1021
1022 integer(kind=i_kind) :: i_section, i_phase, i_bin, j_phase, &
1023 phase_id_to_find, section_size, &
1024 section_start
1025
1026 phase_id_to_find = phase_id
1027 section_start = 1
1028 do i_section = 1, num_section_
1029 section_size = num_phase_(i_section) * num_bins_(i_section)
1030 if( phase_id_to_find .le. section_size ) then
1031 i_phase = ( phase_id_to_find - 1 ) / num_bins_(i_section) + 1
1032 i_bin = mod( phase_id_to_find - 1, num_bins_(i_section) ) + 1
1033 num_jac_elem = 0
1034 do j_phase = section_start + i_bin - 1, &
1035 section_start + i_bin - 1 + &
1036 ( num_phase_(i_section) - 1 ) * num_bins_(i_section), &
1037 num_bins_(i_section)
1039 this%aero_phase( j_phase )%val%num_jac_elem( )
1040 end do
1041 return
1042 end if
1043 phase_id_to_find = phase_id_to_find - section_size
1044 section_start = section_start + section_size
1045 end do
1046
1047 end function num_jac_elem
1048
1049!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1050
1051 !> Determine is specified phase(s) exist in adjacent layers. Returns array
1052 !! of phase_ids for adjacent phases first and second.
1053
1054 function adjacent_phases(this, phase_name_first, &
1055 phase_name_second) result(index_pairs)
1056 !> Aerosol representation data
1057 class(aero_rep_modal_binned_mass_t), intent(in) :: this
1058 !> Name of first phase
1059 character(len=*), intent(in) :: phase_name_first
1060 !> Name of second phase
1061 character(len=*), intent(in) :: phase_name_second
1062 type(index_pair_t), allocatable :: index_pairs(:)
1063
1064 allocate(index_pairs(0))
1065
1066 end function adjacent_phases
1067
1068!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1069
1070 !> Get the species id on the state array by phase_id and species name
1071 function spec_state_id_by_phase(this, phase_id, spec_name) result(spec_id)
1072
1073 !> Species state id
1074 integer(kind=i_kind) :: spec_id
1075 !> Aerosol representation data
1076 class(aero_rep_modal_binned_mass_t), intent(in) :: this
1077 !> Phase id
1078 integer(kind=i_kind), intent(in) :: phase_id
1079 !> Species name
1080 character(len=*), intent(in) :: spec_name
1081
1082 type(string_t), allocatable :: spec_names(:)
1083 integer(kind=i_kind) :: i_spec
1084
1085 call assert_msg(237861905, phase_id .ge. 1 .and. phase_id .le. size(this%phase_state_id), &
1086 "Phase id out of range")
1087
1088 spec_names = this%aero_phase(phase_id)%val%get_species_names()
1089 spec_id = 0
1090 do i_spec = 1, size(spec_names)
1091 if (spec_name .eq. spec_names(i_spec)%string) then
1092 spec_id = this%phase_state_id(phase_id) + i_spec - 1
1093 exit
1094 end if
1095 end do
1096 deallocate(spec_names)
1097
1098 if (spec_id .eq. 0) then
1099 call die_msg(509274806, "Cannot find species '"//trim(spec_name)//"' for phase id "// &
1100 trim(to_string(phase_id)))
1101 end if
1102
1103 end function spec_state_id_by_phase
1104
1105!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1106
1107 !> Finalize the aerosol representation
1108 subroutine finalize(this)
1109
1110 !> Aerosol representation data
1111 type(aero_rep_modal_binned_mass_t), intent(inout) :: this
1112
1113 if (allocated(this%rep_name)) deallocate(this%rep_name)
1114 if (allocated(this%aero_phase)) then
1115 ! The core will deallocate the aerosol phases
1116 call this%aero_phase(:)%dereference()
1117 deallocate(this%aero_phase)
1118 end if
1119 if (associated(this%property_set)) &
1120 deallocate(this%property_set)
1121 if (allocated(this%condensed_data_real)) &
1122 deallocate(this%condensed_data_real)
1123 if (allocated(this%condensed_data_int)) &
1124 deallocate(this%condensed_data_int)
1125
1126 end subroutine finalize
1127
1128!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1129
1130 !> Finalize the aerosol representation array
1131 subroutine finalize_array(aero_reps)
1132
1133 !> Aerosol representation array
1134 type(aero_rep_modal_binned_mass_t), intent(inout) :: aero_reps(:)
1135
1136 integer(kind=i_kind) :: i_rep
1137
1138 do i_rep = 1, size(aero_reps)
1139 call finalize(aero_reps(i_rep))
1140 end do
1141
1142 end subroutine finalize_array
1143
1144!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1145
1146 !> Initialize a GMD update object
1147 subroutine update_data_init_gmd(this, update_data, aero_rep_type)
1148
1149 use camp_rand, only : generate_int_id
1150
1151 !> Aerosol representation to update
1152 class(aero_rep_modal_binned_mass_t), intent(inout) :: this
1153 !> Update data object
1154 class(aero_rep_update_data_modal_binned_mass_gmd_t), intent(out) :: &
1155 update_data
1156 !> Aerosol representation id
1157 integer(kind=i_kind), intent(in) :: aero_rep_type
1158
1159 ! If an aerosol representation id has not been generated, do it now
1160 if (aero_rep_id_.eq.-1) then
1161 aero_rep_id_ = generate_int_id()
1162 end if
1163
1164 update_data%aero_rep_unique_id = aero_rep_id_
1165 update_data%aero_rep_type = int(aero_rep_type, kind=c_int)
1166 update_data%update_data = aero_rep_modal_binned_mass_create_gmd_update_data()
1167 update_data%is_malloced = .true.
1168
1169 end subroutine update_data_init_gmd
1170
1171!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1172
1173 !> Set packed update data for mode GMD
1174 subroutine update_data_set_gmd(this, section_id, GMD)
1175
1176 !> Update data
1177 class(aero_rep_update_data_modal_binned_mass_gmd_t), intent(inout) :: this
1178 !> Aerosol section id from
1179 !! camp_aero_rep_modal_binned_mass::aero_rep_modal_binned_mass_t::get_section_id
1180 integer(kind=i_kind), intent(in) :: section_id
1181 !> Updated GMD (m)
1182 real(kind=dp), intent(in) :: gmd
1183
1185 this%aero_rep_unique_id, section_id-1, gmd)
1186
1187 end subroutine update_data_set_gmd
1188
1189!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1190
1191 !> Determine the size of a binary required to pack the reaction data
1192 integer(kind=i_kind) function internal_pack_size_gmd(this, comm) &
1193 result(pack_size)
1194
1195 !> Aerosol representation update data
1196 class(aero_rep_update_data_modal_binned_mass_gmd_t), intent(in) :: this
1197 !> MPI communicator
1198 integer, intent(in) :: comm
1199
1200 pack_size = &
1201 camp_mpi_pack_size_logical(this%is_malloced, comm) + &
1202 camp_mpi_pack_size_integer(this%aero_rep_unique_id, comm)
1203
1204 end function internal_pack_size_gmd
1205
1206!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1207
1208 !> Pack the given value to the buffer, advancing position
1209 subroutine internal_bin_pack_gmd(this, buffer, pos, comm)
1210
1211 !> Aerosol representation update data
1212 class(aero_rep_update_data_modal_binned_mass_gmd_t), intent(in) :: this
1213 !> Memory buffer
1214 character, intent(inout) :: buffer(:)
1215 !> Current buffer position
1216 integer, intent(inout) :: pos
1217 !> MPI communicator
1218 integer, intent(in) :: comm
1219
1220#ifdef CAMP_USE_MPI
1221 integer :: prev_position
1222
1223 prev_position = pos
1224 call camp_mpi_pack_logical(buffer, pos, this%is_malloced, comm)
1225 call camp_mpi_pack_integer(buffer, pos, this%aero_rep_unique_id, comm)
1226 call assert(685522546, &
1227 pos - prev_position <= this%pack_size(comm))
1228#endif
1229
1230 end subroutine internal_bin_pack_gmd
1231
1232!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1233
1234 !> Unpack the given value from the buffer, advancing position
1235 subroutine internal_bin_unpack_gmd(this, buffer, pos, comm)
1236
1237 !> Aerosol representation update data
1238 class(aero_rep_update_data_modal_binned_mass_gmd_t), intent(inout) :: this
1239 !> Memory buffer
1240 character, intent(inout) :: buffer(:)
1241 !> Current buffer position
1242 integer, intent(inout) :: pos
1243 !> MPI communicator
1244 integer, intent(in) :: comm
1245
1246#ifdef CAMP_USE_MPI
1247 integer :: prev_position
1248
1249 prev_position = pos
1250 call camp_mpi_unpack_logical(buffer, pos, this%is_malloced, comm)
1251 call camp_mpi_unpack_integer(buffer, pos, this%aero_rep_unique_id, comm)
1252 call assert(855679450, &
1253 pos - prev_position <= this%pack_size(comm))
1255#endif
1256
1257 end subroutine internal_bin_unpack_gmd
1258
1259!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1260
1261 !> Finalize a GMD update data object
1263
1264 !> Update data object to free
1265 type(aero_rep_update_data_modal_binned_mass_gmd_t), intent(inout) :: this
1266
1267 if (this%is_malloced) call aero_rep_free_update_data(this%update_data)
1268
1269 end subroutine update_data_gmd_finalize
1270
1271!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1272
1273 !> Finalize a GMD update data array
1274 subroutine update_data_gmd_finalize_array(update_data)
1275
1276 !> Update data array to free
1277 type(aero_rep_update_data_modal_binned_mass_gmd_t), intent(inout) :: &
1278 update_data(:)
1279
1280 integer(kind=i_kind) :: i_data
1281
1282 do i_data = 1, size(update_data)
1283 call update_data_gmd_finalize(update_data(i_data))
1284 end do
1285
1286 end subroutine update_data_gmd_finalize_array
1287
1288!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1289
1290 !> Initialize a GSD update data object
1291 subroutine update_data_init_gsd(this, update_data, aero_rep_type)
1292
1293 use camp_rand, only : generate_int_id
1294
1295 !> Aerosol representation to update
1296 class(aero_rep_modal_binned_mass_t), intent(inout) :: this
1297 !> Update data object
1298 class(aero_rep_update_data_modal_binned_mass_gsd_t), intent(out) :: &
1299 update_data
1300 !> Aerosol representation id
1301 integer(kind=i_kind), intent(in) :: aero_rep_type
1302
1303 ! If an aerosol representation id has not been generated, do it now
1304 if (aero_rep_id_.eq.-1) then
1305 aero_rep_id_ = generate_int_id()
1306 end if
1307
1308 update_data%aero_rep_unique_id = aero_rep_id_
1309 update_data%aero_rep_type = int(aero_rep_type, kind=c_int)
1310 update_data%update_data = aero_rep_modal_binned_mass_create_gsd_update_data()
1311 update_data%is_malloced = .true.
1312
1313 end subroutine update_data_init_gsd
1314
1315!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1316
1317 !> Set packed update data for mode GSD
1318 subroutine update_data_set_gsd(this, section_id, GSD)
1319
1320 !> Update data
1321 class(aero_rep_update_data_modal_binned_mass_gsd_t), intent(inout) :: this
1322 !> Aerosol section id from
1323 !! camp_aero_rep_modal_binned_mass::aero_rep_modal_binned_mass_t::get_section_id
1324 integer(kind=i_kind), intent(in) :: section_id
1325 !> Updated GSD (m)
1326 real(kind=dp), intent(in) :: gsd
1327
1329 this%aero_rep_unique_id, section_id-1, gsd)
1330
1331 end subroutine update_data_set_gsd
1332
1333!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1334
1335 !> Determine the size of a binary required to pack the reaction data
1336 integer(kind=i_kind) function internal_pack_size_gsd(this, comm) &
1337 result(pack_size)
1338
1339 !> Aerosol representation update data
1340 class(aero_rep_update_data_modal_binned_mass_gsd_t), intent(in) :: this
1341 !> MPI communicator
1342 integer, intent(in) :: comm
1343
1344 pack_size = &
1345 camp_mpi_pack_size_logical(this%is_malloced, comm) + &
1346 camp_mpi_pack_size_integer(this%aero_rep_unique_id, comm)
1347
1348 end function internal_pack_size_gsd
1349
1350!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1351
1352 !> Pack the given value to the buffer, advancing position
1353 subroutine internal_bin_pack_gsd(this, buffer, pos, comm)
1354
1355 !> Aerosol representation update data
1356 class(aero_rep_update_data_modal_binned_mass_gsd_t), intent(in) :: this
1357 !> Memory buffer
1358 character, intent(inout) :: buffer(:)
1359 !> Current buffer position
1360 integer, intent(inout) :: pos
1361 !> MPI communicator
1362 integer, intent(in) :: comm
1363
1364#ifdef CAMP_USE_MPI
1365 integer :: prev_position
1366
1367 prev_position = pos
1368 call camp_mpi_pack_logical(buffer, pos, this%is_malloced, comm)
1369 call camp_mpi_pack_integer(buffer, pos, this%aero_rep_unique_id, comm)
1370 call assert(295993259, &
1371 pos - prev_position <= this%pack_size(comm))
1372#endif
1373
1374 end subroutine internal_bin_pack_gsd
1375
1376!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1377
1378 !> Unpack the given value from the buffer, advancing position
1379 subroutine internal_bin_unpack_gsd(this, buffer, pos, comm)
1380
1381 !> Aerosol representation update data
1382 class(aero_rep_update_data_modal_binned_mass_gsd_t), intent(inout) :: this
1383 !> Memory buffer
1384 character, intent(inout) :: buffer(:)
1385 !> Current buffer position
1386 integer, intent(inout) :: pos
1387 !> MPI communicator
1388 integer, intent(in) :: comm
1389
1390#ifdef CAMP_USE_MPI
1391 integer :: prev_position
1392
1393 prev_position = pos
1394 call camp_mpi_unpack_logical(buffer, pos, this%is_malloced, comm)
1395 call camp_mpi_unpack_integer(buffer, pos, this%aero_rep_unique_id, comm)
1396 call assert(518724415, &
1397 pos - prev_position <= this%pack_size(comm))
1399#endif
1400
1401 end subroutine internal_bin_unpack_gsd
1402
1403!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1404
1405 !> Finalize a GSD update data object
1407
1408 !> Update data object to free
1409 type(aero_rep_update_data_modal_binned_mass_gsd_t), intent(inout) :: this
1410
1411 if (this%is_malloced) call aero_rep_free_update_data(this%update_data)
1412
1413 end subroutine update_data_gsd_finalize
1414
1415!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1416
1417 !> Finalize a GSD update data array
1418 subroutine update_data_gsd_finalize_array(update_data)
1419
1420 !> Update data array to free
1421 type(aero_rep_update_data_modal_binned_mass_gsd_t), intent(inout) :: &
1422 update_data(:)
1423
1424 integer(kind=i_kind) :: i_data
1425
1426 do i_data = 1, size(update_data)
1427 call update_data_gsd_finalize(update_data(i_data))
1428 end do
1429
1430 end subroutine update_data_gsd_finalize_array
1431
1432!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1433
Determine if specified phase(s) exist in adjacent layers. Returns array of phase_ids for adjacent pha...
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...
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 number of Jacobian elements used in calculations of aerosol mass, volume, number,...
Get the number of instances of a specified aerosol phase.
Get the non-unique name of a chemical species by its unique name.
Get the species id on the state array by phase_id and species name.
Get a species id on the camp_camp_state::camp_state_t::state_var array by unique name....
Get a list of unique names for each element on the camp_camp_state::camp_state_t::state_var array for...
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.
integer(kind=i_kind) function pack_size(this, comm)
Determine the size of a binary required to pack the aerosol representation data.
The abstract aero_rep_data_t structure and associated subroutines.
The abstract aero_rep_modal_binned_mass_t structure and associated subroutines.
subroutine update_data_init_gsd(this, update_data, aero_rep_type)
Initialize a GSD update data object.
subroutine internal_bin_unpack_gsd(this, buffer, pos, comm)
Unpack the given value from the buffer, advancing position.
logical function get_section_id(this, section_name, section_id)
Get an id for a mode or bin by name for use with updates from external modules.
subroutine internal_bin_pack_gmd(this, buffer, pos, comm)
Pack the given value to the buffer, advancing position.
subroutine update_data_gmd_finalize_array(update_data)
Finalize a GMD update data array.
subroutine internal_bin_unpack_gmd(this, buffer, pos, comm)
Unpack the given value from the buffer, advancing position.
subroutine internal_bin_pack_gsd(this, buffer, pos, comm)
Pack the given value to the buffer, advancing position.
subroutine update_data_set_gsd(this, section_id, GSD)
Set packed update data for mode GSD.
integer(kind=i_kind) function internal_pack_size_gmd(this, comm)
Determine the size of a binary required to pack the reaction data.
subroutine update_data_set_gmd(this, section_id, GMD)
Set packed update data for mode GMD.
integer(kind=i_kind) function internal_pack_size_gsd(this, comm)
Determine the size of a binary required to pack the reaction data.
integer(kind=i_kind), parameter, public update_gsd
subroutine update_data_gsd_finalize(this)
Finalize a GSD update data object.
subroutine update_data_gsd_finalize_array(update_data)
Finalize a GSD update data array.
subroutine update_data_gmd_finalize(this)
Finalize a GMD update data object.
integer(kind=i_kind), parameter, public update_gmd
subroutine update_data_init_gmd(this, update_data, aero_rep_type)
Initialize a GMD update object.
The camp_state_t structure and associated subroutines.
Definition: camp_state.F90:9
The chem_spec_data_t structure and associated subroutines.
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
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.
Abstract aerosol representation data type.
Define index_pair array for adjacent_phases functions.
String type for building arrays of string of various size.
Definition: util.F90:38