CAMP 1.0.0
Chemistry Across Multiple Phases
aero_rep_single_particle.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_single_particle module.
7
8!> \page camp_aero_rep_single_particle CAMP: Single Particle Aerosol Representation
9!!
10!! The single particle aerosol representation is for use with a PartMC
11!! particle-resolved run. The \c json object for this \ref camp_aero_rep
12!! "aerosol representation" has the following format:
13!! \code{.json}
14!! { "camp-data" : [
15!! {
16!! "name" : "my single particle aero rep",
17!! "type" : "AERO_REP_SINGLE_PARTICLE"
18!! },
19!! ...
20!! ]}
21!! \endcode
22!! The key-value pair \b type is required and must be \b
23!! AERO_REP_SINGLE_PARTICLE. In this representation, particles are divided
24!! into layers. Phases in each layer are specified by the user.
25!!
26!! Phase configuration within particles follows "fractional volume overlap".
27!! The shared surface area between phases in adjacent layers is scaled by phase
28!! volume fraction within respective layers.
29!! In this configuration, the surface area of the layer interface between two phases
30!! is calculated as f_first * f_second * total_interface_surface_area where
31!! the first and second subscripts refer to the two phases in adjacent layers and
32!!
33!! f_first = volume_phase_first / volume_total_layer_first
34!! f_second = volume_phase_second / volume_total_layer_second
35!!
36!!
37!! The number concentration for each particle must be
38!! set from an external model using
39!! \c camp_aero_rep_single_particle::aero_rep_update_data_single_particle_number_t
40!! objects.
41
42!> The aero_rep_single_particle_t type and associated subroutines.
44
49 use camp_mpi
51 use camp_util, only: dp, i_kind, &
54 assert
55
56 use iso_c_binding
57
58 implicit none
59 private
60
61#define NUM_LAYERS_ this%condensed_data_int(1)
62#define AERO_REP_ID_ this%condensed_data_int(2)
63#define MAX_PARTICLES_ this%condensed_data_int(3)
64#define PARTICLE_STATE_SIZE_ this%condensed_data_int(4)
65#define NUM_INT_PROP_ 4
66#define NUM_REAL_PROP_ 0
67#define NUM_ENV_PARAM_PER_PARTICLE_ 1
68#define LAYER_PHASE_START_(l) this%condensed_data_int(NUM_INT_PROP_+l)
69#define LAYER_PHASE_END_(l) this%condensed_data_int(NUM_INT_PROP_+NUM_LAYERS_+l)
70#define TOTAL_NUM_PHASES_ (LAYER_PHASE_END_(NUM_LAYERS_))
71#define NUM_PHASES_(l) (LAYER_PHASE_END_(l)-LAYER_PHASE_START_(l)+1)
72#define PHASE_STATE_ID_(l,p) this%condensed_data_int(NUM_INT_PROP_+2*NUM_LAYERS_+LAYER_PHASE_START_(l)+p-1)
73#define PHASE_MODEL_DATA_ID_(l,p) this%condensed_data_int(NUM_INT_PROP_+2*NUM_LAYERS_+TOTAL_NUM_PHASES_+LAYER_PHASE_START_(l)+p-1)
74#define PHASE_NUM_JAC_ELEM_(l,p) this%condensed_data_int(NUM_INT_PROP_+2*NUM_LAYERS_+2*TOTAL_NUM_PHASES_+LAYER_PHASE_START_(l)+p-1)
75
76 ! Update types (These must match values in aero_rep_single_particle.c)
77 integer(kind=i_kind), parameter, public :: update_number_conc = 0
78
82
83 !> Single particle aerosol representation
84 !!
85 !! Time-invariant data related to a single particle aerosol representation.
87 !> Unique names for each instance of every chemical species in the
88 !! aerosol representaiton
89 type(string_t), allocatable, private :: unique_names_(:)
90 !> Layer names, ordered inner-most to outer-most
91 type(string_t), allocatable, private :: layer_names_(:)
92 !> First state id for the representation (only used during initialization)
93 integer(kind=i_kind) :: state_id_start = -99999
94 contains
95 !> Initialize the aerosol representation data, validating component data and
96 !! loading any required information from the \c
97 !! aero_rep_data_t::property_set. This routine should be called once for
98 !! each aerosol representation at the beginning of a model run after all
99 !! the input files have been read in. It ensures all data required during
100 !! the model run are included in the condensed data arrays.
101 procedure :: initialize
102 !> Returns the maximum number of computational particles
104 !> Initialize an update data number object
105 procedure :: update_data_initialize_number => update_data_init_number
106 !> Get the size of the section of the
107 !! \c camp_camp_state::camp_state_t::state_var array required for this
108 !! aerosol representation.
109 !!
110 !! For a single particle representation, the size will correspond to the
111 !! the sum of the sizes of a single instance of each aerosol phase
112 !! provided to \c aero_rep_single_particle::initialize()
113 procedure :: size => get_size
114 !> Get the number of state variables per-particle
115 !!
116 !! Calling functions can assume each particle has the same size on the
117 !! state array, and that individual particle states are contiguous and
118 !! arranged sequentially
119 procedure :: per_particle_size
120 !> Get a list of unique names for each element on the
121 !! \c camp_camp_state::camp_state_t::state_var array for this aerosol
122 !! representation. The list may be restricted to a particular phase and/or
123 !! aerosol species by including the phase_name and spec_name arguments.
124 !!
125 !! For a single particle representation, the unique names will be the
126 !! phase name with the species name separated by a '.'
127 procedure :: unique_names
128 !> Get a species id on the \c camp_camp_state::camp_state_t::state_var
129 !! array by its unique name. These are unique ids for each element on the
130 !! state array for this \ref camp_aero_rep "aerosol representation" and
131 !! are numbered:
132 !!
133 !! \f[x_u \in x_f ... (x_f+n-1)\f]
134 !!
135 !! where \f$x_u\f$ is the id of the element corresponding to the species
136 !! with unique name \f$u\f$ on the \c
137 !! camp_camp_state::camp_state_t::state_var array, \f$x_f\f$ is the index
138 !! of the first element for this aerosol representation on the state array
139 !! and \f$n\f$ is the total number of variables on the state array from
140 !! this aerosol representation.
141 procedure :: spec_state_id
142 !> Get the non-unique name of a species by its unique name
143 procedure :: spec_name
144 !> Get the number of instances of an aerosol phase in this representation
146 !> Get the number of Jacobian elements used in calculations of aerosol
147 !! mass, volume, number, etc. for a particular phase
148 procedure :: num_jac_elem
149 !> Returns the number of layers
150 procedure :: num_layers
151 !> Returns the number of phases in a layer or overall
152 procedure :: num_phases
153 !> Returns the number of state variables for a layer and phase
154 procedure :: phase_state_size
155 !> Returns index_pair_t type with phase_ids of adjacent phases
156 procedure :: adjacent_phases
157 !> Get spec_state_id for a phase_id and species name
159 !> Finalize the aerosol representation
162
163 ! Constructor for aero_rep_single_particle_t
165 procedure :: constructor
166 end interface aero_rep_single_particle_t
167
168 !> Single particle update number concentration object
169 type, extends(aero_rep_update_data_t) :: &
171 private
172 !> Flag indicating whether the update data is allocated
173 logical :: is_malloced = .false.
174 !> Unique id for finding aerosol representations during initialization
175 integer(kind=i_kind) :: aero_rep_unique_id = 0
176 !> Maximum number of computational particles
177 integer(kind=i_kind) :: maximum_computational_particles = 0
178 contains
179 !> Update the number
180 procedure :: set_number__n_m3 => update_data_set_number__n_m3
181 !> Determine the pack size of the local update data
183 !> Pack the local update data to a binary
185 !> Unpack the local update data from a binary
187 !> Finalize the number update data
190
191 !> Interface to c aerosol representation functions
192 interface
193
194 !> Allocate space for a number update
195 !! @return Allocated update_data object
197 result(update_data) bind (c)
198 use iso_c_binding
199 type(c_ptr) :: update_data
201
202 !> Set a new particle number concentration
204 update_data, aero_rep_unique_id, particle_id, number_conc) &
205 bind (c)
206 use iso_c_binding
207 !> Update data
208 type(c_ptr), value :: update_data
209 !> Aerosol representation unique id
210 integer(kind=c_int), value :: aero_rep_unique_id
211 !> Computational particle index
212 integer(kind=c_int), value :: particle_id
213 !> New number (m)
214 real(kind=c_double), value :: number_conc
216
217 !> Free an update data object
218 pure subroutine aero_rep_free_update_data(update_data) bind (c)
219 use iso_c_binding
220 !> Update data
221 type(c_ptr), value, intent(in) :: update_data
222 end subroutine aero_rep_free_update_data
223
224 end interface
225
226contains
227
228!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
229
230 !> Constructor for aero_rep_single_particle_t
231 function constructor() result (new_obj)
232
233 !> New aerosol representation
234 type(aero_rep_single_particle_t), pointer :: new_obj
235
236 allocate(new_obj)
237
238 end function constructor
239
240!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
241
242 !> Initialize the aerosol representation data, validating component data and
243 !! loading any required information from the \c
244 !! aero_rep_data_t::property_set. This routine should be called once for
245 !! each aerosol representation at the beginning of a model run after all
246 !! the input files have been read in. It ensures all data required during
247 !! the model run are included in the condensed data arrays.
248 subroutine initialize(this, aero_phase_set, spec_state_id)
249
250 !> Aerosol representation data
251 class(aero_rep_single_particle_t), intent(inout) :: this
252 !> The set of aerosol phases
253 type(aero_phase_data_ptr), pointer, intent(in) :: aero_phase_set(:)
254 !> Beginning state id for this aerosol representation in the model species
255 !! state array
256 integer(kind=i_kind), intent(in) :: spec_state_id
257
258 ! Unordered layer names (only used during initialization)
259 type(string_t), allocatable :: layer_names_unordered(:)
260 ! Cover names (only used during initialization)
261 type(string_t), allocatable :: cover_names_unordered(:)
262 ! Index in layer_names_unordered for each layer from inner- to outer-most
263 ! layer
264 integer(kind=i_kind), allocatable :: ordered_layer_id(:)
265
266 character(len=:), allocatable :: key_name, layer_name, layer_covers, &
267 phase_name
268 type(property_t), pointer :: layers, layer
269 type(property_ptr), allocatable :: phases(:)
270 integer(kind=i_kind) :: i_particle, i_phase, i_layer, i_aero, curr_id
271 integer(kind=i_kind) :: i_cover, j_phase, j_layer, i_map, curr_phase
272 integer(kind=i_kind) :: num_phases, num_int_param, num_float_param, &
273 num_particles
274 logical :: found
275
276 ! Get the maximum number of computational particles
277 key_name = "maximum computational particles"
278 call assert_msg(331697425, &
279 this%property_set%get_int(key_name, num_particles), &
280 "Missing maximum number of computational particles")
281
282 ! Get the set of layers
283 key_name = "layers"
284 call assert_msg(314292954, &
285 this%property_set%get_property_t(key_name, layers), &
286 "Missing layers for single-particle aerosol "// &
287 "representation '"//this%rep_name//"'")
288 call assert_msg(168669831, layers%size() .gt. 0, &
289 "No Layers specified for single-particle layer "// &
290 "aerosol representation '"//this%rep_name//"'")
291
292 ! Allocate space for the working arrays
293 allocate(phases(layers%size()))
294 allocate(cover_names_unordered(layers%size()))
295 allocate(layer_names_unordered(layers%size()))
296
297 ! Loop through the layers, adding names and counting the spaces needed
298 ! on the condensed data arrays, and counting the total phases instances
299 num_phases = 0
300 call layers%iter_reset()
301 do i_layer = 1, layers%size()
302
303 ! Get the layer properties
304 call assert_msg(303808978, layers%get_property_t(val=layer), &
305 "Invalid structure for layer '"// &
306 layer_names_unordered(i_layer)%string// &
307 "' in single-particle layer representation '"// &
308 this%rep_name//"'")
309
310 ! Get the layer name
311 key_name = "name"
312 call assert_msg(364496472, layer%get_string(key_name, layer_name), &
313 "Missing layer name in single-particle layer aerosol "// &
314 "representation '"//this%rep_name//"'")
315 layer_names_unordered(i_layer)%string = layer_name
316
317 ! Get the cover name
318 key_name = "covers"
319 call assert_msg(350939595, layer%get_string(key_name, layer_covers), &
320 "Missing cover name in layer'"// &
321 layer_names_unordered(i_layer)%string// &
322 "' in single-particle layer aerosol representation '"// &
323 this%rep_name//"'")
324 cover_names_unordered(i_layer)%string = layer_covers
325
326 ! Get the set of phases
327 key_name = "phases"
328 call assert_msg(647756433, &
329 layer%get_property_t(key_name, phases(i_layer)%val_), &
330 "Missing phases for layer '"// &
331 layer_names_unordered(i_layer)%string// &
332 "' in single-particle layer aerosol representation '"// &
333 this%rep_name//"'")
334
335 ! Add the phases to the counter
336 call assert_msg(002679882, phases(i_layer)%val_%size().gt.0, &
337 "No phases specified for layer '"// &
338 layer_names_unordered(i_layer)%string// &
339 "' in single-particle layer aerosol representation '"// &
340 this%rep_name//"'")
341
342 ! add to running total of phase count
343 num_phases = num_phases + phases(i_layer)%val_%size()
344
345 call layers%iter_next()
346 end do
347
348 ! get the map of layer names after reordering
349 ordered_layer_id = ordered_layer_ids(layer_names_unordered, &
350 cover_names_unordered)
351
352 ! set the layer names
353 allocate(this%layer_names_(size(ordered_layer_id)))
354 this%layer_names_(:) = layer_names_unordered(ordered_layer_id(:))
355
356 ! Allocate condensed data arrays
357 num_int_param = num_int_prop_ + 2 * layers%size() + 3 * num_phases
358 num_float_param = num_real_prop_
359 allocate(this%condensed_data_int(num_int_param))
360 allocate(this%condensed_data_real(num_float_param))
361 this%condensed_data_int(:) = int(0, kind=i_kind)
362 this%condensed_data_real(:) = real(0.0, kind=dp)
363
364 ! Save space for the environment-dependent parameters
365 this%num_env_params = num_env_param_per_particle_ * num_particles
366
367 ! Save representation dimensions
368 num_layers_ = layers%size()
369 max_particles_ = num_particles
370
371 ! validate phase names, assign aero_phase pointers for each phase in
372 ! each layer in each particle, and set PHASE_STATE_ID and
373 ! PHASE_MODEL_DATA_ID for each phase
374 allocate(this%aero_phase(num_phases * num_particles))
375 allocate(this%aero_phase_is_at_surface(num_phases * num_particles))
376 curr_phase = 1
377 do i_layer = 1, size(ordered_layer_id)
378 j_layer = ordered_layer_id(i_layer)
379
380 ! Set the starting and ending indices for the phases in this layer
381 layer_phase_start_(i_layer) = curr_phase
382 layer_phase_end_(i_layer) = curr_phase + phases(j_layer)%val_%size() - 1
383
384 curr_phase = curr_phase + phases(j_layer)%val_%size()
385 end do
386
387 curr_id = spec_state_id
388 this%state_id_start = spec_state_id
389 curr_phase = 1
390 do i_layer = 1, size(ordered_layer_id)
391 j_layer = ordered_layer_id(i_layer)
392 ! Loop through the phases and make sure they exist
393 call phases(j_layer)%val_%iter_reset()
394 do i_phase = 1, phases(j_layer)%val_%size()
395
396 ! Get the phase name
397 call assert_msg(566480284, &
398 phases(j_layer)%val_%get_string(val=phase_name), &
399 "Non-string phase name for layer '"// &
400 layer_names_unordered(j_layer)%string// &
401 "' in single-particle layer aerosol representation '"// &
402 this%rep_name//"'")
403 ! find phase and set pointer and indices
404 found = .false.
405 do j_phase = 1, size(aero_phase_set)
406 if (aero_phase_set(j_phase)%val%name() .eq. phase_name) then
407 found = .true.
408 do i_particle = 0, num_particles-1
409 this%aero_phase(i_particle*num_phases + curr_phase) = &
410 aero_phase_set(j_phase)
411 if (i_layer .eq. num_layers_) then
412 this%aero_phase_is_at_surface(i_particle*num_phases + curr_phase) = &
413 .true.
414 else
415 this%aero_phase_is_at_surface(i_particle*num_phases + curr_phase) = &
416 .false.
417 end if
418 end do
419 phase_state_id_(i_layer,i_phase) = curr_id
420 phase_model_data_id_(i_layer,i_phase) = j_phase
421 curr_id = curr_id + aero_phase_set(j_phase)%val%size()
422 curr_phase = curr_phase + 1
423 exit
424 end if
425 end do
426 call assert(373124707, found)
427
428 call phases(j_layer)%val_%iter_next()
429 end do
430 end do
431 particle_state_size_ = curr_id - spec_state_id
432
433 ! Initialize the aerosol representation id
434 aero_rep_id_ = -1
435
436 ! Set the unique names for the chemical species
437 this%unique_names_ = this%unique_names( )
438
439 end subroutine initialize
440
441!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
442
443 !> Returns the maximum nunmber of computational particles
444 integer(kind=i_kind) function maximum_computational_particles(this)
445
446 !> Aerosol representation data
447 class(aero_rep_single_particle_t), intent(in) :: this
448
449 maximum_computational_particles = max_particles_
450
452
453!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
454
455 !> Get the size of the section of the
456 !! \c camp_camp_state::camp_state_t::state_var array required for this
457 !! aerosol representation.
458 !!
459 !! For a single particle representation, the size will correspond to the
460 !! the sum of the sizes of a single instance of each aerosol phase
461 !! provided to \c aero_rep_single_particle::initialize()
462 function get_size(this) result (state_size)
463
464 !> Size on the state array
465 integer(kind=i_kind) :: state_size
466 !> Aerosol representation data
467 class(aero_rep_single_particle_t), intent(in) :: this
468
469 state_size = max_particles_ * particle_state_size_
470
471 end function get_size
472
473!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
474
475 !> Get the number of state variables per-particle
476 !!
477 !! Calling functions can assume each particle has the same size on the
478 !! state array, and that individual particle states are contiguous and
479 !! arranged sequentially
480 function per_particle_size(this) result(state_size)
481
482 !> Size on the state array per particle
483 integer(kind=i_kind) :: state_size
484 !> Aerosol representation data
485 class(aero_rep_single_particle_t), intent(in) :: this
486
487 state_size = particle_state_size_
488
489 end function per_particle_size
490
491!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
492
493 !> Get a list of unique names for each element on the
494 !! \c camp_camp_state::camp_state_t::state_var array for this aerosol
495 !! representation. The list may be restricted to a particular phase and/or
496 !! aerosol species by including the phase_name and spec_name arguments.
497 !!
498 !! For a single particle representation, the unique names will be a 'P'
499 !! followed by the computational particle number, a '.', the phase name,
500 !! another '.', and the species name.
501 function unique_names(this, phase_name, tracer_type, spec_name, &
502 phase_is_at_surface)
503
504 use camp_util, only : integer_to_string
505 !> List of unique names
506 type(string_t), allocatable :: unique_names(:)
507 !> Aerosol representation data
508 class(aero_rep_single_particle_t), intent(in) :: this
509 !> Aerosol phase name
510 character(len=*), optional, intent(in) :: phase_name
511 !> Aerosol-phase species tracer type
512 integer(kind=i_kind), optional, intent(in) :: tracer_type
513 !> Aerosol-phase species name
514 character(len=*), optional, intent(in) :: spec_name
515 !> Indicates if aerosol phase is at the surface of particle
516 logical, optional, intent(in) :: phase_is_at_surface
517
518 integer :: i_particle, i_layer, i_phase, i_spec, j_spec
519 integer :: num_spec, curr_tracer_type
520 type(string_t), allocatable :: spec_names(:)
521
522 ! copy saved unique names when available and no filters are included
523 if (.not. present(phase_name) .and. &
524 .not. present(tracer_type) .and. &
525 .not. present(spec_name) .and. &
526 allocated(this%unique_names_)) then
527 unique_names = this%unique_names_
528 return
529 end if
530
531 ! count the number of unique names
532 num_spec = 0
533 do i_phase = 1, size(this%aero_phase)
534 if (present(phase_name)) then
535 if(phase_name .ne. this%aero_phase(i_phase)%val%name()) cycle
536 end if
537 if (present(phase_is_at_surface)) then
538 if (phase_is_at_surface .neqv. &
539 this%aero_phase_is_at_surface(i_phase)) cycle
540 end if
541 if (present(spec_name) .or. present(tracer_type)) then
542 spec_names = this%aero_phase(i_phase)%val%get_species_names()
543 do j_spec = 1, size(spec_names)
544 if (present(spec_name)) then
545 if (spec_name .ne. spec_names(j_spec)%string) cycle
546 end if
547 if (present(tracer_type)) then
548 curr_tracer_type = &
549 this%aero_phase(i_phase)%val%get_species_type( &
550 spec_names(j_spec)%string)
551 if (tracer_type .ne. curr_tracer_type) cycle
552 end if
553 num_spec = num_spec + 1
554 end do
555 deallocate(spec_names)
556 else
557 num_spec = num_spec + this%aero_phase(i_phase)%val%size()
558 end if
559 end do
560
561 ! allocate space for the unique names and assign them
562 num_spec = num_spec / max_particles_ ! we need per-particle value for indexing
563 allocate(unique_names(num_spec*max_particles_))
564 i_spec = 1
565 do i_layer = 1, num_layers_
566 do i_phase = layer_phase_start_(i_layer), layer_phase_end_(i_layer)
567 if (present(phase_name)) then
568 if(phase_name .ne. this%aero_phase(i_phase)%val%name()) cycle
569 end if
570 if (present(phase_is_at_surface)) then
571 if (phase_is_at_surface .neqv. &
572 this%aero_phase_is_at_surface(i_phase)) cycle
573 end if
574 spec_names = this%aero_phase(i_phase)%val%get_species_names()
575 do j_spec = 1, this%aero_phase(i_phase)%val%size()
576 if (present(spec_name)) then
577 if (spec_name .ne. spec_names(j_spec)%string) cycle
578 end if
579 if (present(tracer_type)) then
580 curr_tracer_type = &
581 this%aero_phase(i_phase)%val%get_species_type( &
582 spec_names(j_spec)%string)
583 if (tracer_type .ne. curr_tracer_type) cycle
584 end if
585 do i_particle = 1, max_particles_
586 unique_names((i_particle-1)*num_spec+i_spec)%string = 'P'// &
587 trim(integer_to_string(i_particle))//"."// &
588 this%layer_names_(i_layer)%string//"."// &
589 this%aero_phase(i_phase)%val%name()//"."// &
590 spec_names(j_spec)%string
591 end do
592 i_spec = i_spec + 1
593 end do
594 deallocate(spec_names)
595 end do
596 end do
597
598 end function unique_names
599
600!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
601
602 !> Get a species id on the \c camp_camp_state::camp_state_t::state_var
603 !! array by its unique name. These are unique ids for each element on the
604 !! state array for this \ref camp_aero_rep "aerosol representation" and
605 !! are numbered:
606 !!
607 !! \f[x_u \in x_f ... (x_f+n-1)\f]
608 !!
609 !! where \f$x_u\f$ is the id of the element corresponding to the species
610 !! with unique name \f$u\f$ on the \c
611 !! camp_camp_state::camp_state_t::state_var array, \f$x_f\f$ is the index
612 !! of the first element for this aerosol representation on the state array
613 !! and \f$n\f$ is the total number of variables on the state array from
614 !! this aerosol representation.
615 function spec_state_id(this, unique_name) result (spec_id)
616
617 !> Species state id
618 integer(kind=i_kind) :: spec_id
619 !> Aerosol representation data
620 class(aero_rep_single_particle_t), intent(in) :: this
621 !> Unique name
622 character(len=*), intent(in) :: unique_name
623
624 integer(kind=i_kind) :: i_spec
625
626 spec_id = this%state_id_start
627 do i_spec = 1, size(this%unique_names_)
628 if (this%unique_names_(i_spec)%string .eq. unique_name) then
629 return
630 end if
631 spec_id = spec_id + 1
632 end do
633 call die_msg( 449087541, "Cannot find species '"//unique_name//"'" )
634
635 end function spec_state_id
636
637!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
638
639 !> Get the non-unique name of a species in this aerosol representation by
640 !! id.
641 function spec_name(this, unique_name)
642
643 !> Chemical species name
644 character(len=:), allocatable :: spec_name
645 !> Aerosol representation data
646 class(aero_rep_single_particle_t), intent(in) :: this
647 !> Unique name of the species in this aerosol representation
648 character(len=*), intent(in) :: unique_name
649
650 type(string_t) :: l_unique_name
651 type(string_t), allocatable :: substrs(:)
652
653 l_unique_name%string = unique_name
654 substrs = l_unique_name%split(".")
655 call assert(407537518, size( substrs ) .eq. 4 )
656 spec_name = substrs(4)%string
657
658 end function spec_name
659
660!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
661
662 !> Get the number of instances of a specified aerosol phase. In the single
663 !! particle representation with layers, a phase can exist in multiple layers
664 !! in one particle.
665 integer(kind=i_kind) function num_phase_instances(this, phase_name, &
666 is_at_surface)
667
668 !> Aerosol representation data
669 class(aero_rep_single_particle_t), intent(in) :: this
670 !> Aerosol phase name
671 character(len=*), intent(in) :: phase_name
672 !> Indicates if aerosol phase is at the surface of particle
673 logical, intent(in), optional :: is_at_surface
674
675 integer(kind=i_kind) :: i_phase, i_layer, phase_index
676
678 if (present(is_at_surface)) then
679 do i_layer = 1, num_layers_
680 do i_phase = layer_phase_start_(i_layer), layer_phase_end_(i_layer)
681 if (this%aero_phase(i_phase)%val%name() .eq. phase_name) then
682 if (this%aero_phase_is_at_surface(i_phase) .eqv. is_at_surface) then
684 end if
685 end if
686 end do
687 end do
688 else
689 do i_layer = 1, num_layers_
690 do i_phase = layer_phase_start_(i_layer), layer_phase_end_(i_layer)
691 if (this%aero_phase(i_phase)%val%name() .eq. phase_name) then
693 end if
694 end do
695 end do
696 end if
698
699 end function num_phase_instances
700
701!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
702
703 !> Get the number of Jacobian elements used in calculations of aerosol mass,
704 !! volume, number, etc. for a particular phase
705 function num_jac_elem(this, phase_id)
706
707 !> Number of Jacobian elements used
708 integer(kind=i_kind) :: num_jac_elem
709 !> Aerosol respresentation data
710 class(aero_rep_single_particle_t), intent(in) :: this
711 !> Aerosol phase id
712 integer(kind=i_kind), intent(in) :: phase_id
713
714 integer(kind=i_kind) :: i_phase
715
716 call assert_msg(927040495, phase_id .ge. 1 .and. &
717 phase_id .le. size( this%aero_phase ), &
718 "Aerosol phase index out of range. Got "// &
719 trim( integer_to_string( phase_id ) )//", expected 1:"// &
720 trim( integer_to_string( size( this%aero_phase ) ) ) )
721 num_jac_elem = 0
722 do i_phase = 1, total_num_phases_
724 this%aero_phase(i_phase)%val%num_jac_elem()
725 end do
726
727 end function num_jac_elem
728
729!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
730
731 !> Returns the number of layers
732 integer function num_layers(this)
733
734 !> Aerosol representation data
735 class(aero_rep_single_particle_t), intent(in) :: this
736
737 num_layers = num_layers_
738
739 end function num_layers
740
741!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
742
743 !> Returns the number of phases in a layer or overall
744 integer function num_phases(this, layer)
745
746 !> Aerosol representation data
747 class(aero_rep_single_particle_t), intent(in) :: this
748 !> Layer id
749 integer, optional, intent(in) :: layer
750
751 if (present(layer)) then
752 num_phases = layer_phase_end_(layer) - layer_phase_start_(layer) + 1
753 else
754 num_phases = layer_phase_end_(num_layers_) - layer_phase_start_(1) + 1
755 end if
756
757 end function num_phases
758
759!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
760
761 !> Returns the number of state variables for a layer and phase
762 integer function phase_state_size(this, layer, phase)
763
764 use camp_util, only : die_msg
765
766 !> Aerosol representation data
767 class(aero_rep_single_particle_t), intent(in) :: this
768 !> Layer id
769 integer, optional, intent(in) :: layer
770 !> Phase id
771 integer, optional, intent(in) :: phase
772
773 if (present(layer) .and. present(phase)) then
774 if (layer .eq. num_layers_ .and. phase .eq. num_phases_(layer)) then
775 phase_state_size = phase_state_id_(1,1) + particle_state_size_ - &
776 phase_state_id_(layer, phase)
777 else if (phase .eq. num_phases_(layer)) then
778 phase_state_size = phase_state_id_(layer+1, 1) - &
779 phase_state_id_(layer, phase)
780 else
781 phase_state_size = phase_state_id_(layer, phase+1) - &
782 phase_state_id_(layer, phase)
783 end if
784 else if (present(layer)) then
785 if (layer .eq. num_layers_) then
786 phase_state_size = phase_state_id_(1,1) + particle_state_size_ - &
787 phase_state_id_(layer, 1)
788 else
789 phase_state_size = phase_state_id_(layer+1, 1) - &
790 phase_state_id_(layer, 1)
791 end if
792 else if (present(phase)) then
793 call die_msg(917793122, "Must specify layer if including phase is "// &
794 "state size request")
795 else
796 phase_state_size = particle_state_size_
797 end if
798
799 end function phase_state_size
800
801!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
802
803 !> Determine if specified phase(s) exist in adjacent layers. Returns array
804 !! of phase_ids for adjacent phases first and second.
805 function adjacent_phases(this, phase_name_first, &
806 phase_name_second) result(index_pairs)
807
808 !> Aerosol representation data
809 class(aero_rep_single_particle_t), intent(in) :: this
810 !> Name of first phase
811 character(len=*), intent(in) :: phase_name_first
812 !> Name of second phase
813 character(len=*), intent(in) :: phase_name_second
814 type(index_pair_t), allocatable :: temp_index_pairs(:), index_pairs(:)
815
816 integer(kind=i_kind), allocatable :: layer_first(:)
817 integer(kind=i_kind), allocatable :: layer_second(:)
818 integer(kind=i_kind), allocatable :: phase_id_first_(:)
819 integer(kind=i_kind), allocatable :: phase_id_second_(:)
820 integer(kind=i_kind) :: i_layer, i_phase, i_instance, j_phase, i_particle, i
821 integer(kind=i_kind) :: offset, num_adjacent_pairs
822
823 allocate(layer_first(num_layers_))
824 allocate(layer_second(num_layers_))
825 allocate(phase_id_first_(num_layers_))
826 allocate(phase_id_second_(num_layers_))
827 layer_first = -9999
828 layer_second = -9999
829 phase_id_first_ = -9999
830 phase_id_second_ = -9999
831
832 ! Loop over layers and phases to determine where each input phase exists
833 i_instance = 1
834 do i_layer = 1, num_layers_
835 do i_phase = 1, num_phases_(i_layer)
836 if (phase_name_first .eq. phase_name_second) then
837 if (this%aero_phase(i_instance)%val%name() .eq. phase_name_first) then
838 layer_first(i_layer) = phase_model_data_id_(i_layer, i_phase)
839 phase_id_first_(i_layer) = i_instance
840 end if
841 else
842 if (this%aero_phase(i_instance)%val%name() .eq. phase_name_first) then
843 layer_first(i_layer) = phase_model_data_id_(i_layer, i_phase)
844 phase_id_first_(i_layer) = i_instance
845 else if (this%aero_phase(i_instance)%val%name() .eq. phase_name_second) then
846 layer_second(i_layer) = phase_model_data_id_(i_layer, i_phase)
847 phase_id_second_(i_layer) = i_instance
848 end if
849 end if
850 i_instance = i_instance + 1
851 end do
852 end do
853
854 ! Find out where the pairs exist and assign to temp_index_pairs
855 allocate(temp_index_pairs(i_instance))
856 i_instance = 1
857 do i_layer = 1, num_layers_-1
858 do i_phase = 1, num_phases_(i_layer)
859 do j_phase = 1, num_phases_(i_layer+1)
860 if (phase_name_first .eq. phase_name_second) then
861 if (layer_first(i_layer) .eq. phase_model_data_id_(i_layer,i_phase) .and. &
862 layer_first(i_layer+1) .eq. phase_model_data_id_(i_layer+1,j_phase)) then
863 temp_index_pairs(i_instance)%first_ = phase_id_first_(i_layer)
864 temp_index_pairs(i_instance)%second_ = phase_id_first_(i_layer+1)
865 i_instance = i_instance + 1
866 end if
867 else
868 if (layer_first(i_layer) .eq. phase_model_data_id_(i_layer, i_phase) .and. &
869 layer_second(i_layer+1) .eq. phase_model_data_id_(i_layer+1, j_phase)) then
870 temp_index_pairs(i_instance)%first_ = phase_id_first_(i_layer)
871 temp_index_pairs(i_instance)%second_ = phase_id_second_(i_layer+1)
872 i_instance = i_instance + 1
873 else if (layer_second(i_layer) .eq. phase_model_data_id_(i_layer, i_phase) .and. &
874 layer_first(i_layer+1) .eq. phase_model_data_id_(i_layer+1, j_phase)) then
875 temp_index_pairs(i_instance)%first_ = phase_id_second_(i_layer)
876 temp_index_pairs(i_instance)%second_ = phase_id_first_(i_layer+1)
877 i_instance = i_instance + 1
878 end if
879 end if
880 end do
881 end do
882 end do
883
884 ! Now expand to all particles
885 allocate(index_pairs((i_instance-1) * max_particles_))
886 num_adjacent_pairs = i_instance - 1
887 do i_particle = 1, max_particles_
888 offset = (i_particle -1) * total_num_phases_
889 do i = 1, num_adjacent_pairs
890 index_pairs((i_particle -1) * num_adjacent_pairs + i)%first_ = &
891 temp_index_pairs(i)%first_ + offset
892 index_pairs((i_particle -1) * num_adjacent_pairs + i)%second_ = &
893 temp_index_pairs(i)%second_ + offset
894 end do
895 end do
896 deallocate(temp_index_pairs)
897
898 end function adjacent_phases
899
900!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
901
902 !> Get the species id on the state array by phase_id and species name
903 function spec_state_id_by_phase(this, phase_id, spec_name) result(spec_id)
904
905 use camp_util, only : integer_to_string
906
907 !> Species state id
908 integer(kind=i_kind) :: spec_id
909 !> Aerosol representation data
910 class(aero_rep_single_particle_t), intent(in) :: this
911 !> Phase id
912 integer(kind=i_kind), intent(in) :: phase_id
913 !> Species name
914 character(len=*), intent(in) :: spec_name
915
916 integer(kind=i_kind) :: particle_number, phase_in_particle, i_layer
917 character(len=:), allocatable :: unique_name, phase_name
918
919 ! Validate phase_id
920 call assert_msg(782814629, phase_id .ge. 1 .and. &
921 phase_id .le. size(this%aero_phase), &
922 "Phase id out of range")
923
924 ! Determine particle number and phase index within particle
925 particle_number = (phase_id - 1) / total_num_phases_ + 1
926 phase_in_particle = mod(phase_id - 1, total_num_phases_) + 1
927 ! Validate particle number
928 call assert_msg(918734061, particle_number .ge. 1 .and. &
929 particle_number .le. max_particles_, &
930 "Invalid particle number from phase_id")
931
932 ! Find which layer contains this phase
933 do i_layer = 1, num_layers_
934 if (phase_in_particle .ge. layer_phase_start_(i_layer) .and. &
935 phase_in_particle .le. layer_phase_end_(i_layer)) then
936 ! Found the layer
937 phase_name = this%aero_phase(phase_in_particle)%val%name()
938 unique_name = 'P' // trim(integer_to_string(particle_number)) // '.' // &
939 this%layer_names_(i_layer)%string // '.' // &
940 phase_name // '.' // trim(spec_name)
941 spec_id = this%spec_state_id(unique_name)
942 return
943 end if
944 end do
945
946 ! Should not reach here
947 call die_msg(649201846, "Could not find layer for phase id "// &
948 trim(integer_to_string(phase_id)))
949
950 end function spec_state_id_by_phase
951
952!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
953
954 !> Finalize the aerosol representation
955 subroutine finalize(this)
956
957 !> Aerosol representation data
958 type(aero_rep_single_particle_t), intent(inout) :: this
959
960 if (allocated(this%rep_name)) deallocate(this%rep_name)
961 if (allocated(this%aero_phase)) then
962 ! The core will deallocate the aerosol phases
963 call this%aero_phase(:)%dereference()
964 deallocate(this%aero_phase)
965 end if
966 if (allocated(this%unique_names_)) deallocate(this%unique_names_)
967 if (allocated(this%layer_names_)) deallocate(this%layer_names_)
968 if (associated(this%property_set)) deallocate(this%property_set)
969 if (allocated(this%condensed_data_real)) &
970 deallocate(this%condensed_data_real)
971 if (allocated(this%condensed_data_int)) &
972 deallocate(this%condensed_data_int)
973
974 end subroutine finalize
975
976!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
977
978 !> Finalize the aerosol representation array
979 subroutine finalize_array(this_array)
980
981 !> Aerosol representation data
982 type(aero_rep_single_particle_t), intent(inout) :: this_array(:)
983
984 integer(kind=i_kind) :: i_aero
985
986 do i_aero = 1, size(this_array)
987 call finalize(this_array(i_aero))
988 end do
989
990 end subroutine finalize_array
991
992!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
993
994 !> Initialize an update data object
995 subroutine update_data_init_number(this, update_data, aero_rep_type)
996
997 use camp_rand, only : generate_int_id
998
999 !> Aerosol representation to update
1000 class(aero_rep_single_particle_t), intent(inout) :: this
1001 !> Update data object
1002 class(aero_rep_update_data_single_particle_number_t), intent(out) :: &
1003 update_data
1004 !> Aerosol representaiton id
1005 integer(kind=i_kind), intent(in) :: aero_rep_type
1006
1007 ! If an aerosol representation id has not been generated, do it now
1008 if (aero_rep_id_.eq.-1) then
1009 aero_rep_id_ = generate_int_id()
1010 end if
1011
1012 update_data%aero_rep_unique_id = aero_rep_id_
1013 update_data%maximum_computational_particles = &
1014 this%maximum_computational_particles( )
1015 update_data%aero_rep_type = int(aero_rep_type, kind=c_int)
1016 update_data%update_data = &
1018 update_data%is_malloced = .true.
1019
1020 end subroutine update_data_init_number
1021
1022!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1023
1024 !> Order layer array from inner most layer to outermost
1025 function ordered_layer_ids(layer_names_unordered, cover_names_unordered)
1026
1027 !> Layer names in original order
1028 type(string_t), intent(in) :: layer_names_unordered(:)
1029 !> Name of "covered" layer for each layer in layer_name_unordered
1030 type(string_t), intent(in) :: cover_names_unordered(:)
1031 !> Index of name in layer_name_unordered for each layer after reordering
1032 integer, allocatable :: ordered_layer_ids(:)
1033
1034 integer(kind=i_kind) :: i_layer, j_layer, i_cover
1035
1036 ! Ensure layer names do not repeat
1037 do i_layer = 1, size(layer_names_unordered)
1038 do j_layer = 1, size(layer_names_unordered)
1039 if (i_layer .eq. j_layer) cycle
1040 call assert_msg(781626922, layer_names_unordered(i_layer)%string .ne. &
1041 layer_names_unordered(j_layer)%string, &
1042 "Duplicate layer name in single particle "// &
1043 "representation: '"// &
1044 trim(layer_names_unordered(i_layer)%string)//"'")
1045 end do
1046 end do
1047
1048 allocate(ordered_layer_ids(size(layer_names_unordered)))
1049
1050 ! Search for innermost layer with cover set to 'none'
1051 do i_layer = 1, size(layer_names_unordered)
1052 if (cover_names_unordered(i_layer)%string == "none") then
1053 ordered_layer_ids(1) = i_layer
1054 end if
1055 end do
1056
1057 ! Assign each layer working outwards from center of particle
1058 do i_cover = 2, size(ordered_layer_ids)
1059 do i_layer = 1, size(layer_names_unordered)
1060 if (layer_names_unordered(ordered_layer_ids(i_cover-1))%string &
1061 .eq. cover_names_unordered(i_layer)%string) then
1062 ordered_layer_ids(i_cover) = i_layer
1063 exit
1064 end if
1065 end do
1066 end do
1067
1068 end function ordered_layer_ids
1069
1070!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1071
1072 !> Set packed update data for particle number (#/m3) for a particular
1073 !! computational particle.
1074 subroutine update_data_set_number__n_m3(this, particle_id, number_conc)
1075
1076 !> Update data
1077 class(aero_rep_update_data_single_particle_number_t), intent(inout) :: &
1078 this
1079 !> Computational particle index
1080 integer(kind=i_kind), intent(in) :: particle_id
1081 !> Updated number
1082 real(kind=dp), intent(in) :: number_conc
1083
1084 call assert_msg(611967802, this%is_malloced, &
1085 "Trying to set number of uninitialized update object.")
1086 call assert_msg(689085496, particle_id .ge. 1 .and. &
1087 particle_id .le. this%maximum_computational_particles, &
1088 "Invalid computational particle index: "// &
1089 trim(integer_to_string(particle_id)))
1091 this%get_data(), this%aero_rep_unique_id, particle_id-1, &
1092 number_conc)
1093
1094 end subroutine update_data_set_number__n_m3
1095
1096!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1097
1098 !> Determine the size of a binary required to pack the reaction data
1099 integer(kind=i_kind) function internal_pack_size_number(this, comm) &
1100 result(pack_size)
1101
1102 !> Aerosol representation update data
1103 class(aero_rep_update_data_single_particle_number_t), intent(in) :: this
1104 !> MPI communicator
1105 integer, intent(in) :: comm
1106
1107 pack_size = &
1108 camp_mpi_pack_size_logical(this%is_malloced, comm) + &
1109 camp_mpi_pack_size_integer(this%maximum_computational_particles, comm) + &
1110 camp_mpi_pack_size_integer(this%aero_rep_unique_id, comm)
1111
1112 end function internal_pack_size_number
1113
1114!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1115
1116 !> Pack the given value to the buffer, advancing position
1117 subroutine internal_bin_pack_number(this, buffer, pos, comm)
1118
1119 !> Aerosol representation update data
1120 class(aero_rep_update_data_single_particle_number_t), intent(in) :: this
1121 !> Memory buffer
1122 character, intent(inout) :: buffer(:)
1123 !> Current buffer position
1124 integer, intent(inout) :: pos
1125 !> MPI communicator
1126 integer, intent(in) :: comm
1127
1128#ifdef CAMP_USE_MPI
1129 integer :: prev_position
1130
1131 prev_position = pos
1132 call camp_mpi_pack_logical(buffer, pos, this%is_malloced, comm)
1133 call camp_mpi_pack_integer(buffer, pos, &
1134 this%maximum_computational_particles, comm)
1135 call camp_mpi_pack_integer(buffer, pos, this%aero_rep_unique_id, comm)
1136 call assert(411585487, &
1137 pos - prev_position <= this%pack_size(comm))
1138#endif
1139
1140 end subroutine internal_bin_pack_number
1141
1142!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1143
1144 !> Unpack the given value from the buffer, advancing position
1145 subroutine internal_bin_unpack_number(this, buffer, pos, comm)
1146
1147 !> Aerosol representation update data
1148 class(aero_rep_update_data_single_particle_number_t), intent(inout) :: this
1149 !> Memory buffer
1150 character, intent(inout) :: buffer(:)
1151 !> Current buffer position
1152 integer, intent(inout) :: pos
1153 !> MPI communicator
1154 integer, intent(in) :: comm
1155
1156#ifdef CAMP_USE_MPI
1157 integer :: prev_position
1158
1159 prev_position = pos
1160 call camp_mpi_unpack_logical(buffer, pos, this%is_malloced, comm)
1161 call camp_mpi_unpack_integer(buffer, pos, &
1162 this%maximum_computational_particles, comm)
1163 call camp_mpi_unpack_integer(buffer, pos, this%aero_rep_unique_id, comm)
1164 call assert(351557153, &
1165 pos - prev_position <= this%pack_size(comm))
1167#endif
1168
1169 end subroutine internal_bin_unpack_number
1170
1171!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1172
1173 !> Finalize a number update data object
1175
1176 !> Update data object to free
1177 type(aero_rep_update_data_single_particle_number_t), intent(inout) :: this
1178
1179 if (this%is_malloced) call aero_rep_free_update_data(this%update_data)
1180
1181 end subroutine update_data_number_finalize
1182
1183!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1184
1185 !> Finalize an array of number update data objects
1187
1188 !> Update data objects to free
1189 type(aero_rep_update_data_single_particle_number_t), intent(inout) :: &
1190 this(:)
1191
1192 integer(kind=i_kind) :: i_aero
1193
1194 do i_aero = 1, size(this)
1195 call update_data_number_finalize(this(i_aero))
1196 end do
1197
1199
1200!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1201
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 aero_rep_single_particle_t type and associated subroutines.
integer(kind=i_kind) function internal_pack_size_number(this, comm)
Determine the size of a binary required to pack the reaction data.
subroutine update_data_init_number(this, update_data, aero_rep_type)
Initialize an update data object.
integer function num_layers(this)
Returns the number of layers.
subroutine update_data_number_finalize_array(this)
Finalize an array of number update data objects.
subroutine internal_bin_unpack_number(this, buffer, pos, comm)
Unpack the given value from the buffer, advancing position.
integer(kind=i_kind) function per_particle_size(this)
Get the number of state variables per-particle.
integer(kind=i_kind), parameter, public update_number_conc
subroutine update_data_number_finalize(this)
Finalize a number update data object.
subroutine update_data_set_number__n_m3(this, particle_id, number_conc)
Set packed update data for particle number (#/m3) for a particular computational particle.
integer function, dimension(:), allocatable, public ordered_layer_ids(layer_names_unordered, cover_names_unordered)
Order layer array from inner most layer to outermost.
subroutine internal_bin_pack_number(this, buffer, pos, comm)
Pack the given value to the buffer, advancing position.
integer function phase_state_size(this, layer, phase)
Returns the number of state variables for a layer and phase.
integer function num_phases(this, layer)
Returns the number of phases in a layer or overall.
integer(kind=i_kind) function maximum_computational_particles(this)
Returns the maximum nunmber of computational particles.
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
character(len=camp_util_convert_string_len) function integer_to_string(val)
Convert an integer to a string format.
Definition: util.F90:839
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