PartMC  2.6.1
aero_particle.F90
Go to the documentation of this file.
1 ! Copyright (C) 2005-2012, 2016 Nicole Riemer and Matthew West
2 ! Licensed under the GNU General Public License version 2 or (at your
3 ! option) any later version. See the file COPYING for details.
4 
5 !> \file
6 !> The pmc_aero_particle module.
7 
8 !> The aero_particle_t structure and associated subroutines.
10 
11  use pmc_util
12  use pmc_aero_data
13  use pmc_spec_file
14  use pmc_env_state
15  use pmc_mpi
16 #ifdef PMC_USE_MPI
17  use mpi
18 #endif
19 
20  !> Single aerosol particle data structure.
21  !!
22  !! The \c vol array stores the total volumes of the different
23  !! species that make up the particle. This array must have length
24  !! equal to aero_data%%n_spec, so that \c vol(i) is the volume (in
25  !! m^3) of the i'th aerosol species.
27  !> Constituent species volumes [length aero_data_n_spec()] (m^3).
28  real(kind=dp), allocatable :: vol(:)
29  !> Number of original particles from each source that coagulated
30  !> to form this one [length aero_data_n_source()].
31  integer, allocatable :: n_orig_part(:)
32  !> Weighting function group number (see \c aero_weight_array_t).
33  integer :: weight_group
34  !> Weighting function class number (see \c aero_weight_array_t).
35  integer :: weight_class
36  !> Absorption cross-section (m^2).
37  real(kind=dp) :: absorb_cross_sect
38  !> Scattering cross-section (m^2).
39  real(kind=dp) :: scatter_cross_sect
40  !> Asymmetry parameter (1).
41  real(kind=dp) :: asymmetry
42  !> Refractive index of the shell (1).
43  complex(kind=dc) :: refract_shell
44  !> Refractive index of the core (1).
45  complex(kind=dc) :: refract_core
46  !> Volume of the core (m^3).
47  real(kind=dp) :: core_vol
48  !> Water hysteresis curve section (0 = lower, 1 = upper)
49  integer :: water_hyst_leg
50  !> Unique ID number.
51  integer :: id
52  !> First time a constituent was created (s).
53  real(kind=dp) :: least_create_time
54  !> Last time a constituent was created (s).
55  real(kind=dp) :: greatest_create_time
56  end type aero_particle_t
57 
58  !> Next unique ID number to use for a particle.
59  integer, save :: next_id = 1
60 
61 contains
62 
63 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
64 
65  !> Shift data from one aero_particle_t to another and free the first
66  !> one.
67  subroutine aero_particle_shift(aero_particle_from, aero_particle_to)
68 
69  !> Reference particle (will be deallocated on return).
70  type(aero_particle_t), intent(inout) :: aero_particle_from
71  !> Destination particle (not allocated on entry).
72  type(aero_particle_t), intent(inout) :: aero_particle_to
73 
74  call move_alloc(aero_particle_from%vol, aero_particle_to%vol)
75  call move_alloc(aero_particle_from%n_orig_part, &
76  aero_particle_to%n_orig_part)
77  aero_particle_to%weight_group = aero_particle_from%weight_group
78  aero_particle_to%weight_class = aero_particle_from%weight_class
79  aero_particle_to%absorb_cross_sect = aero_particle_from%absorb_cross_sect
80  aero_particle_to%scatter_cross_sect = &
81  aero_particle_from%scatter_cross_sect
82  aero_particle_to%asymmetry = aero_particle_from%asymmetry
83  aero_particle_to%refract_shell = aero_particle_from%refract_shell
84  aero_particle_to%refract_core = aero_particle_from%refract_core
85  aero_particle_to%core_vol = aero_particle_from%core_vol
86  aero_particle_to%water_hyst_leg = aero_particle_from%water_hyst_leg
87  aero_particle_to%id = aero_particle_from%id
88  aero_particle_to%least_create_time = aero_particle_from%least_create_time
89  aero_particle_to%greatest_create_time = &
90  aero_particle_from%greatest_create_time
91 
92  end subroutine aero_particle_shift
93 
94 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
95 
96  !> Resets an aero_particle to be zero.
97  subroutine aero_particle_zero(aero_particle, aero_data)
98 
99  !> Particle to zero.
100  type(aero_particle_t), intent(inout) :: aero_particle
101  !> Aerosol data.
102  type(aero_data_t), intent(in) :: aero_data
103 
104  call ensure_real_array_size(aero_particle%vol, aero_data_n_spec(aero_data))
105  aero_particle%vol = 0d0
106  call ensure_integer_array_size(aero_particle%n_orig_part, &
107  aero_data_n_source(aero_data))
108  aero_particle%n_orig_part = 0
109  aero_particle%weight_group = 0
110  aero_particle%weight_class = 0
111  aero_particle%absorb_cross_sect = 0d0
112  aero_particle%scatter_cross_sect = 0d0
113  aero_particle%asymmetry = 0d0
114  aero_particle%refract_shell = (0d0, 0d0)
115  aero_particle%refract_core = (0d0, 0d0)
116  aero_particle%core_vol = 0d0
117  aero_particle%water_hyst_leg = 0
118  aero_particle%id = 0
119  aero_particle%least_create_time = 0d0
120  aero_particle%greatest_create_time = 0d0
121 
122  end subroutine aero_particle_zero
123 
124 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
125 
126  !> Assigns a globally-unique new ID number to the particle.
127  subroutine aero_particle_new_id(aero_particle)
128 
129  !> Particle to set ID for.
130  type(aero_particle_t), intent(inout) :: aero_particle
131 
132  aero_particle%id = (next_id - 1) * pmc_mpi_size() + pmc_mpi_rank() + 1
133  next_id = next_id + 1
134 
135  end subroutine aero_particle_new_id
136 
137 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
138 
139  !> Sets the creation times for the particle.
140  subroutine aero_particle_set_create_time(aero_particle, create_time)
141 
142  !> Particle to set time for.
143  type(aero_particle_t), intent(inout) :: aero_particle
144  !> Creation time.
145  real(kind=dp), intent(in) :: create_time
146 
147  aero_particle%least_create_time = create_time
148  aero_particle%greatest_create_time = create_time
149 
150  end subroutine aero_particle_set_create_time
151 
152 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
153 
154  !> Sets the aerosol particle volumes.
155  subroutine aero_particle_set_vols(aero_particle, vols)
156 
157  !> Particle.
158  type(aero_particle_t), intent(inout) :: aero_particle
159  !> New volumes.
160  real(kind=dp), intent(in) :: vols(:)
161 
162  aero_particle%vol = vols
163 
164  end subroutine aero_particle_set_vols
165 
166 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
167 
168  !> Sets the aerosol particle source.
169  subroutine aero_particle_set_source(aero_particle, i_source)
170 
171  !> Particle.
172  type(aero_particle_t), intent(inout) :: aero_particle
173  !> Source number for the particle.
174  integer, intent(in) :: i_source
175 
176  aero_particle%n_orig_part = 0
177  aero_particle%n_orig_part(i_source) = 1
178 
179  end subroutine aero_particle_set_source
180 
181 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
182 
183  !> Sets the aerosol particle weight group.
184  subroutine aero_particle_set_weight(aero_particle, i_group, i_class)
185 
186  !> Particle.
187  type(aero_particle_t), intent(inout) :: aero_particle
188  !> Weight group number for the particle.
189  integer, intent(in), optional :: i_group
190  !> Weight class number for the particle.
191  integer, intent(in), optional :: i_class
192 
193  if (present(i_group)) aero_particle%weight_group = i_group
194  if (present(i_class)) aero_particle%weight_class = i_class
195 
196  end subroutine aero_particle_set_weight
197 
198 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
199 
200  !> Total mass of the particle (kg).
201  elemental real(kind=dp) function aero_particle_mass(aero_particle, aero_data)
202 
203  !> Particle.
204  type(aero_particle_t), intent(in) :: aero_particle
205  !> Aerosol data.
206  type(aero_data_t), intent(in) :: aero_data
207 
208  aero_particle_mass = sum(aero_particle%vol * aero_data%density)
209 
210  end function aero_particle_mass
211 
212 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
213 
214  !> Mass of a single species in the particle (kg).
215  elemental real(kind=dp) function aero_particle_species_mass(aero_particle, &
216  i_spec, aero_data)
217 
218  !> Particle.
219  type(aero_particle_t), intent(in) :: aero_particle
220  !> Species number to find mass of.
221  integer, intent(in) :: i_spec
222  !> Aerosol data.
223  type(aero_data_t), intent(in) :: aero_data
224 
225  aero_particle_species_mass = aero_particle%vol(i_spec) &
226  * aero_data%density(i_spec)
227 
228  end function aero_particle_species_mass
229 
230 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
231 
232  !> Mass of all species in the particle (kg).
233  function aero_particle_species_masses(aero_particle, aero_data)
234 
235  !> Particle.
236  type(aero_particle_t), intent(in) :: aero_particle
237  !> Aerosol data.
238  type(aero_data_t), intent(in) :: aero_data
239  !> Return value.
240  real(kind=dp) :: aero_particle_species_masses(aero_data_n_spec(aero_data))
241 
242  aero_particle_species_masses = aero_particle%vol * aero_data%density
243 
244  end function aero_particle_species_masses
245 
246 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
247 
248  !> Total moles in the particle (1).
249  elemental real(kind=dp) function aero_particle_moles(aero_particle, &
250  aero_data)
251 
252  !> Particle.
253  type(aero_particle_t), intent(in) :: aero_particle
254  !> Aerosol data.
255  type(aero_data_t), intent(in) :: aero_data
256 
257  aero_particle_moles = sum(aero_particle%vol * aero_data%density &
258  / aero_data%molec_weight)
259 
260  end function aero_particle_moles
261 
262 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
263 
264  !> Total volume of the particle (m^3).
265  elemental real(kind=dp) function aero_particle_volume(aero_particle)
266 
267  !> Particle.
268  type(aero_particle_t), intent(in) :: aero_particle
269 
270  aero_particle_volume = sum(aero_particle%vol)
271 
272  end function aero_particle_volume
273 
274 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
275 
276  !> Volume of a single species in the particle (m^3).
277  elemental real(kind=dp) function aero_particle_species_volume( &
278  aero_particle, i_spec)
279 
280  !> Particle.
281  type(aero_particle_t), intent(in) :: aero_particle
282  !> Species number to find volume of.
283  integer, intent(in) :: i_spec
284 
285  aero_particle_species_volume = aero_particle%vol(i_spec)
286 
287  end function aero_particle_species_volume
288 
289 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
290 
291  !> Total dry volume of the particle (m^3).
292  elemental real(kind=dp) function aero_particle_dry_volume(aero_particle, &
293  aero_data)
294 
295  !> Particle.
296  type(aero_particle_t), intent(in) :: aero_particle
297  !> Aerosol data.
298  type(aero_data_t), intent(in) :: aero_data
299 
300  integer :: i_spec
301 
303  do i_spec = 1,aero_data_n_spec(aero_data)
304  if (i_spec /= aero_data%i_water) then
306  + aero_particle%vol(i_spec)
307  end if
308  end do
309 
310  end function aero_particle_dry_volume
311 
312 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
313 
314  !> Total volume (dry or wet) of the particle (m^3).
315  elemental real(kind=dp) function aero_particle_volume_maybe_dry( &
316  aero_particle, aero_data, dry_volume)
317 
318  !> Particle.
319  type(aero_particle_t), intent(in) :: aero_particle
320  !> Aerosol data.
321  type(aero_data_t), intent(in) :: aero_data
322  !> Whether the desired volume is dry (otherwise wet).
323  logical, intent(in) :: dry_volume
324 
325  if (dry_volume) then
327  = aero_particle_dry_volume(aero_particle, aero_data)
328  else
330  end if
331 
332  end function aero_particle_volume_maybe_dry
333 
334 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
335 
336  !> Total radius of the particle (m).
337  elemental real(kind=dp) function aero_particle_radius(aero_particle, &
338  aero_data)
339 
340  !> Particle.
341  type(aero_particle_t), intent(in) :: aero_particle
342  !> Aerosol data.
343  type(aero_data_t), intent(in) :: aero_data
344 
346  aero_particle_volume(aero_particle))
347 
348  end function aero_particle_radius
349 
350 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
351 
352  !> Total dry radius of the particle (m).
353  elemental real(kind=dp) function aero_particle_dry_radius(aero_particle, &
354  aero_data)
355 
356  !> Particle.
357  type(aero_particle_t), intent(in) :: aero_particle
358  !> Aerosol data.
359  type(aero_data_t), intent(in) :: aero_data
360 
362  aero_particle_dry_volume(aero_particle, aero_data))
363 
364  end function aero_particle_dry_radius
365 
366 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
367 
368  !> Total diameter of the particle (m).
369  elemental real(kind=dp) function aero_particle_diameter(aero_particle, &
370  aero_data)
371 
372  !> Particle.
373  type(aero_particle_t), intent(in) :: aero_particle
374  !> Aerosol data.
375  type(aero_data_t), intent(in) :: aero_data
376 
377  aero_particle_diameter = 2d0 * aero_particle_radius(aero_particle, &
378  aero_data)
379 
380  end function aero_particle_diameter
381 
382 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
383 
384  !> Total dry diameter of the particle (m).
385  elemental real(kind=dp) function aero_particle_dry_diameter(aero_particle, &
386  aero_data)
387 
388  !> Particle.
389  type(aero_particle_t), intent(in) :: aero_particle
390  !> Aerosol data.
391  type(aero_data_t), intent(in) :: aero_data
392 
394  = 2d0 * aero_particle_dry_radius(aero_particle, aero_data)
395 
396  end function aero_particle_dry_diameter
397 
398 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
399 
400  !> Mobility diameter of the particle (m).
401  real(kind=dp) function aero_particle_mobility_diameter(aero_particle, &
402  aero_data, env_state)
403 
404  !> Particle.
405  type(aero_particle_t), intent(in) :: aero_particle
406  !> Aerosol data.
407  type(aero_data_t), intent(in) :: aero_data
408  !> Environment state.
409  type(env_state_t), intent(in) :: env_state
410 
411  real(kind=dp) :: volume, mobility_radius
412 
413  volume = aero_particle_volume(aero_particle)
414  mobility_radius = fractal_vol_to_mobility_rad(aero_data%fractal, &
415  volume, env_state%temp, env_state%pressure)
416  aero_particle_mobility_diameter = rad2diam(mobility_radius)
417 
419 
420 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
421 
422  !> Average density of the particle (kg/m^3).
423  real(kind=dp) function aero_particle_density(aero_particle, aero_data)
424 
425  !> Particle.
426  type(aero_particle_t), intent(in) :: aero_particle
427  !> Aerosol data.
428  type(aero_data_t), intent(in) :: aero_data
429 
430  aero_particle_density = aero_particle_mass(aero_particle, aero_data) &
431  / aero_particle_volume(aero_particle)
432 
433  end function aero_particle_density
434 
435 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
436 
437  !> Returns the volume-average of the non-water elements of quantity.
439  aero_particle, aero_data, quantity)
440 
441  !> Aerosol particle.
442  type(aero_particle_t), intent(in) :: aero_particle
443  !> Aerosol data.
444  type(aero_data_t), intent(in) :: aero_data
445  !> Quantity to average.
446  real(kind=dp), intent(in) :: quantity(:)
447 
448  real(kind=dp) :: ones(aero_data_n_spec(aero_data))
449 
450  ones = 1d0
452  aero_particle_total_solute_quantity(aero_particle, &
453  aero_data, quantity) &
454  / aero_particle_total_solute_quantity(aero_particle, aero_data, ones)
455 
457 
458 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
459 
460  !> Returns the volume-total of the non-water elements of quantity.
461  real(kind=dp) function aero_particle_total_solute_quantity(aero_particle, &
462  aero_data, quantity)
463 
464  !> Aerosol particle.
465  type(aero_particle_t), intent(in) :: aero_particle
466  !> Aerosol data.
467  type(aero_data_t), intent(in) :: aero_data
468  !> Quantity to total.
469  real(kind=dp), intent(in) :: quantity(:)
470 
471  real(kind=dp) total
472  integer i
473 
474  total = 0d0
475  do i = 1,aero_data_n_spec(aero_data)
476  if (i /= aero_data%i_water) then
477  total = total + aero_particle%vol(i) * quantity(i)
478  end if
479  end do
481 
483 
484 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
485 
486  !> Returns the water element of quantity.
487  real(kind=dp) function aero_particle_average_water_quantity(aero_particle, &
488  aero_data, quantity)
489 
490  !> Aerosol particle.
491  type(aero_particle_t), intent(in) :: aero_particle
492  !> Aerosol data.
493  type(aero_data_t), intent(in) :: aero_data
494  !> Quantity to average.
495  real(kind=dp), intent(in) :: quantity(:)
496 
497  call assert(420016623, aero_data%i_water > 0)
498  aero_particle_average_water_quantity = quantity(aero_data%i_water)
499 
501 
502 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
503 
504  !> Returns the volume-total of the water element of quantity.
505  real(kind=dp) function aero_particle_total_water_quantity(aero_particle, &
506  aero_data, quantity)
507 
508  !> Aerosol particle.
509  type(aero_particle_t), intent(in) :: aero_particle
510  !> Aerosol data.
511  type(aero_data_t), intent(in) :: aero_data
512  !> Quantity to total.
513  real(kind=dp), intent(in) :: quantity(:)
514 
515  call assert(223343210, aero_data%i_water > 0)
517  = aero_particle%vol(aero_data%i_water) &
518  * quantity(aero_data%i_water)
519 
521 
522 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
523 
524  !> Returns the water molecular weight.
525  !> (kg/mole)
526  real(kind=dp) function aero_particle_water_molec_weight(aero_data)
527 
528  !> Aerosol data.
529  type(aero_data_t), intent(in) :: aero_data
530 
531  call assert(772012490, aero_data%i_water > 0)
533  = aero_data%molec_weight(aero_data%i_water)
534 
536 
537 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
538 
539  !> Returns the average of the solute molecular weight (kg/mole).
540  real(kind=dp) function aero_particle_solute_molec_weight(aero_particle, &
541  aero_data)
542 
543  !> Aerosol particle.
544  type(aero_particle_t), intent(in) :: aero_particle
545  !> Aerosol data.
546  type(aero_data_t), intent(in) :: aero_data
547 
549  = aero_particle_average_solute_quantity(aero_particle, &
550  aero_data, aero_data%molec_weight)
551 
553 
554 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
555 
556  !> Returns the average of the solute ion number (1).
557  real(kind=dp) function aero_particle_solute_num_ions(aero_particle, &
558  aero_data)
559 
560  !> Aerosol data.
561  type(aero_data_t), intent(in) :: aero_data
562  !> Aerosol particle.
563  type(aero_particle_t), intent(in) :: aero_particle
564 
566  = aero_particle_average_solute_quantity(aero_particle, &
567  aero_data, real(aero_data%num_ions, kind=dp))
568 
569  end function aero_particle_solute_num_ions
570 
571 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
572 
573  !> Returns the water density (kg/m^3).
574  real(kind=dp) function aero_particle_water_density(aero_data)
575 
576  !> Aerosol data.
577  type(aero_data_t), intent(in) :: aero_data
578 
579  call assert(235482108, aero_data%i_water > 0)
580  aero_particle_water_density = aero_data%density(aero_data%i_water)
581 
582  end function aero_particle_water_density
583 
584 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
585 
586  !> Returns the average of the solute densities (kg/m^3).
587  real(kind=dp) function aero_particle_solute_density(aero_particle, &
588  aero_data)
589 
590  !> Aerosol data.
591  type(aero_data_t), intent(in) :: aero_data
592  !> Aerosol particle.
593  type(aero_particle_t), intent(in) :: aero_particle
594 
596  = aero_particle_average_solute_quantity(aero_particle, &
597  aero_data, aero_data%density)
598 
599  end function aero_particle_solute_density
600 
601 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
602 
603  !> Returns the water mass (kg).
604  real(kind=dp) function aero_particle_water_mass(aero_particle, aero_data)
605 
606  !> Aerosol data.
607  type(aero_data_t), intent(in) :: aero_data
608  !> Aerosol particle.
609  type(aero_particle_t), intent(in) :: aero_particle
610 
611  call assert(888636139, aero_data%i_water > 0)
612  aero_particle_water_mass = aero_particle%vol(aero_data%i_water) &
613  * aero_data%density(aero_data%i_water)
614 
615  end function aero_particle_water_mass
616 
617 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
618 
619  !> Returns the total solute mass (kg).
620  real(kind=dp) function aero_particle_solute_mass(aero_particle, aero_data)
621 
622  !> Aerosol data.
623  type(aero_data_t), intent(in) :: aero_data
624  !> Aerosol particle.
625  type(aero_particle_t), intent(in) :: aero_particle
626 
628  = aero_particle_total_solute_quantity(aero_particle, &
629  aero_data, aero_data%density)
630 
631  end function aero_particle_solute_mass
632 
633 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
634 
635  !> Returns the total solute volume (m^3).
636  real(kind=dp) function aero_particle_solute_volume(aero_particle, &
637  aero_data)
638 
639  !> Aerosol data.
640  type(aero_data_t), intent(in) :: aero_data
641  !> Aerosol particle.
642  type(aero_particle_t), intent(in) :: aero_particle
643 
644  real(kind=dp) :: ones(aero_data_n_spec(aero_data))
645 
646  ones = 1d0
648  = aero_particle_total_solute_quantity(aero_particle, &
649  aero_data, ones)
650 
651  end function aero_particle_solute_volume
652 
653 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
654 
655  !> Returns the total solute radius (m).
656  real(kind=dp) function aero_particle_solute_radius(aero_particle, &
657  aero_data)
658 
659  !> Aerosol particle.
660  type(aero_particle_t), intent(in) :: aero_particle
661  !> Aerosol data.
662  type(aero_data_t), intent(in) :: aero_data
663 
665  = aero_data_vol2rad(aero_data, &
666  aero_particle_solute_volume(aero_particle, aero_data))
667 
668  end function aero_particle_solute_radius
669 
670 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
671 
672  !> Returns the average of the solute kappas (1).
673  real(kind=dp) function aero_particle_solute_kappa(aero_particle, aero_data)
674 
675  !> Aerosol data.
676  type(aero_data_t), intent(in) :: aero_data
677  !> Aerosol particle.
678  type(aero_particle_t), intent(in) :: aero_particle
679 
680  real(kind=dp) :: kappa(aero_data_n_spec(aero_data)), m_w, rho_w, m_a, rho_a
681  integer :: i_spec
682 
683  m_w = aero_particle_water_molec_weight(aero_data)
684  rho_w = aero_particle_water_density(aero_data)
685  do i_spec = 1,aero_data_n_spec(aero_data)
686  if (i_spec == aero_data%i_water) then
687  kappa(i_spec) = 0d0
688  elseif (aero_data%num_ions(i_spec) > 0) then
689  call assert_msg(123681459, aero_data%kappa(i_spec) == 0d0, &
690  "species has nonzero num_ions and kappa: " &
691  // trim(aero_data%name(i_spec)))
692  m_a = aero_data%molec_weight(i_spec)
693  rho_a = aero_data%density(i_spec)
694  kappa(i_spec) = m_w * rho_a / (m_a * rho_w) &
695  * real(aero_data%num_ions(i_spec), kind=dp)
696  else
697  kappa(i_spec) = aero_data%kappa(i_spec)
698  end if
699  end do
701  = aero_particle_average_solute_quantity(aero_particle, &
702  aero_data, kappa)
703 
704  end function aero_particle_solute_kappa
705 
706 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
707 
708  !> Returns the approximate critical relative humidity (1).
709  real(kind=dp) function aero_particle_approx_crit_rel_humid(aero_particle, &
710  aero_data, env_state)
711 
712  !> Aerosol particle.
713  type(aero_particle_t), intent(in) :: aero_particle
714  !> Aerosol data.
715  type(aero_data_t), intent(in) :: aero_data
716  !> Environment state.
717  type(env_state_t), intent(in) :: env_state
718 
719  real(kind=dp) :: kappa, diam, c, a
720 
721  kappa = aero_particle_solute_kappa(aero_particle, aero_data)
722  c = sqrt(4d0 * env_state_a(env_state)**3 / 27d0)
723  diam = aero_particle_diameter(aero_particle, aero_data)
724  aero_particle_approx_crit_rel_humid = c / sqrt(kappa * diam**3) + 1d0
725 
727 
728 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
729 
730  !> Returns the critical relative humidity (1).
731  real(kind=dp) function aero_particle_crit_rel_humid(aero_particle, &
732  aero_data, env_state)
733 
734  !> Aerosol particle.
735  type(aero_particle_t), intent(in) :: aero_particle
736  !> Aerosol data.
737  type(aero_data_t), intent(in) :: aero_data
738  !> Environment state.
739  type(env_state_t), intent(in) :: env_state
740 
741  real(kind=dp) :: kappa, crit_diam, dry_diam, a
742 
743  a = env_state_a(env_state)
744  dry_diam = aero_particle_dry_diameter(aero_particle, aero_data)
745  crit_diam = aero_particle_crit_diameter(aero_particle, aero_data, &
746  env_state)
747  kappa = aero_particle_solute_kappa(aero_particle, aero_data)
748  if (kappa < 1d-30) then
749  aero_particle_crit_rel_humid = exp(a / crit_diam)
750  else
751  aero_particle_crit_rel_humid = (crit_diam**3 - dry_diam**3) &
752  / (crit_diam**3 - dry_diam**3 * (1 - kappa)) * exp(a / crit_diam)
753  end if
754 
755  end function aero_particle_crit_rel_humid
756 
757 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
758 
759  !> Returns the critical diameter (m).
760  !!
761  !! The method is as follows. We need to solve the polynomial
762  !! equation \f$f(D)\f$ given in Eq. (7) of
763  !!
764  !! N. Riemer, M. West, R. Zaveri, D. Easter, "Estimating black
765  !! carbon aging time-scales with a particle-resolved aerosol
766  !! model", Aerosol Science 41, 143-158, 2010.
767  !!
768  !! This is the equation:
769  !! \f[
770  !! f(D) = D^6 + c_4 D^4 + c_3 D^3 + c_0,
771  !! \f]
772  !! where \f$c_4 < 0\f$, \f$c_3 < 0\f$, and \f$c_0 > 0\f$. There is
773  !! unique solution for \f$D > D_{\rm dry}\f$, as shown in the above
774  !! paper.
775  !!
776  !! The polynomial has first derivative which factors like
777  !! \f[
778  !! f'(D) = 6 D^5 + 4 c_4 D^3 + 3 c_3 D^2
779  !! = (3 D^2 + 4 c_4) D^3 + (D^3 + c_3) 3 D^2.
780  !! \f]
781  !! The first term is positive for \f$D > (-4 c_4 / 3)^{1/2}\f$ and
782  !! the second is positive for \f$D > (-c_3)^{1/3}\f$. If we take
783  !! \f[
784  !! D_0 = max((-4 c_4 / 3)^{1/2}, (-c_3)^{1/3})
785  !! \f]
786  !! then we have that \f$f'(D) > 0\f$ for \f$D > D_0\f$. Similarly,
787  !! \f[
788  !! f''(D) = 30 D^4 + 12 c_4 D^2 + 6 c_3 D
789  !! = (5 D^2 + 4 c_4) 3 D^2 + (5 D^3 + 2 c_3) 3 D,
790  !! \f]
791  !! so \f$f''(D) > 0\f$ for \f$D > D_0\f$ (as this ensures that \f$D
792  !! > (-4 c_4 / 5)^{1/2}\f$ and \f$D > (-2 c_3 / 5)^{1/3}\f$).
793  !!
794  !! Thus for $D > D_0$ we have that the first and second derivatives
795  !! of $f(D)$ are positive, so Newton's method starting from
796  !! \f$D_0\f$ will converge quadratically. This is the scheme used
797  !! here.
798  real(kind=dp) function aero_particle_crit_diameter(aero_particle, &
799  aero_data, env_state)
800 
801  !> Aerosol particle.
802  type(aero_particle_t), intent(in) :: aero_particle
803  !> Aerosol data.
804  type(aero_data_t), intent(in) :: aero_data
805  !> Environment state.
806  type(env_state_t), intent(in) :: env_state
807 
808  integer, parameter :: crit_diam_max_iter = 100
809 
810  real(kind=dp) :: kappa, dry_diam, a, c4, c3, c0, d, f, df, dd
811  integer :: i_newton
812 
813  a = env_state_a(env_state)
814  dry_diam = aero_particle_dry_diameter(aero_particle, aero_data)
815  kappa = aero_particle_solute_kappa(aero_particle, aero_data)
816  if (kappa < 1d-30) then
817  ! bail out early for hydrophobic particles
818  aero_particle_crit_diameter = dry_diam
819  return
820  end if
821 
822  c4 = - 3d0 * dry_diam**3 * kappa / a
823  c3 = - dry_diam**3 * (2d0 - kappa)
824  c0 = dry_diam**6 * (1d0 - kappa)
825 
826  ! Newton's method for f(d) = d^6 + c4 d^4 + c3 d^3 + c0
827  d = max(sqrt(-4d0 / 3d0 * c4), (-c3)**(1d0/3d0))
828  do i_newton = 1,crit_diam_max_iter
829  f = d**6 + c4 * d**4 + c3 * d**3 + c0
830  df = 6 * d**5 + 4 * c4 * d**3 + 3 * c3 * d**2
831  dd = f / df
832  d = d - dd
833  if (abs(dd / d) < 1d-14) then
834  exit
835  end if
836  end do
837  call warn_assert_msg(408545686, i_newton < crit_diam_max_iter, &
838  "critical diameter Newton loop failed to converge")
839  call warn_assert_msg(353290871, d >= dry_diam, &
840  "critical diameter Newton loop converged to invalid solution")
842 
843  end function aero_particle_crit_diameter
844 
845 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
846 
847  !> Coagulate two particles together to make a new one. The new
848  !> particle will not have its ID set.
849  subroutine aero_particle_coagulate(aero_particle_1, &
850  aero_particle_2, aero_particle_new)
851 
852  !> First particle.
853  type(aero_particle_t), intent(in) :: aero_particle_1
854  !> Second particle.
855  type(aero_particle_t), intent(in) :: aero_particle_2
856  !> Result particle.
857  type(aero_particle_t), intent(inout) :: aero_particle_new
858 
859  call assert(203741686, size(aero_particle_1%vol) &
860  == size(aero_particle_2%vol))
861  call assert(483452167, size(aero_particle_1%n_orig_part) &
862  == size(aero_particle_2%n_orig_part))
863  aero_particle_new%vol = aero_particle_1%vol + aero_particle_2%vol
864  aero_particle_new%n_orig_part = aero_particle_1%n_orig_part &
865  + aero_particle_2%n_orig_part
866  aero_particle_new%weight_group = 0
867  aero_particle_new%weight_class = 0
868  aero_particle_new%absorb_cross_sect = 0d0
869  aero_particle_new%scatter_cross_sect = 0d0
870  aero_particle_new%asymmetry = 0d0
871  aero_particle_new%refract_shell = (0d0, 0d0)
872  aero_particle_new%refract_core = (0d0, 0d0)
873  aero_particle_new%core_vol = 0d0
874  if ((aero_particle_1%water_hyst_leg == 1) &
875  .and. (aero_particle_2%water_hyst_leg == 1)) then
876  aero_particle_new%water_hyst_leg = 1
877  else
878  aero_particle_new%water_hyst_leg = 0
879  end if
880  aero_particle_new%id = 0
881  aero_particle_new%least_create_time = &
882  min(aero_particle_1%least_create_time, &
883  aero_particle_2%least_create_time)
884  aero_particle_new%greatest_create_time = &
885  max(aero_particle_1%greatest_create_time, &
886  aero_particle_2%greatest_create_time)
887 
888  end subroutine aero_particle_coagulate
889 
890 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
891 
892  !> Determines the number of bytes required to pack the given value.
893  integer function pmc_mpi_pack_size_aero_particle(val)
894 
895  !> Value to pack.
896  type(aero_particle_t), intent(in) :: val
897 
900  + pmc_mpi_pack_size_integer_array(val%n_orig_part) &
901  + pmc_mpi_pack_size_integer(val%weight_group) &
902  + pmc_mpi_pack_size_integer(val%weight_class) &
903  + pmc_mpi_pack_size_real(val%absorb_cross_sect) &
904  + pmc_mpi_pack_size_real(val%scatter_cross_sect) &
905  + pmc_mpi_pack_size_real(val%asymmetry) &
906  + pmc_mpi_pack_size_complex(val%refract_shell) &
907  + pmc_mpi_pack_size_complex(val%refract_core) &
908  + pmc_mpi_pack_size_real(val%core_vol) &
909  + pmc_mpi_pack_size_integer(val%water_hyst_leg) &
910  + pmc_mpi_pack_size_integer(val%id) &
911  + pmc_mpi_pack_size_real(val%least_create_time) &
912  + pmc_mpi_pack_size_real(val%greatest_create_time)
913 
915 
916 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
917 
918  !> Packs the given value into the buffer, advancing position.
919  subroutine pmc_mpi_pack_aero_particle(buffer, position, val)
920 
921  !> Memory buffer.
922  character, intent(inout) :: buffer(:)
923  !> Current buffer position.
924  integer, intent(inout) :: position
925  !> Value to pack.
926  type(aero_particle_t), intent(in) :: val
927 
928 #ifdef PMC_USE_MPI
929  integer :: prev_position
930 
931  prev_position = position
932  call pmc_mpi_pack_real_array(buffer, position, val%vol)
933  call pmc_mpi_pack_integer_array(buffer, position, val%n_orig_part)
934  call pmc_mpi_pack_integer(buffer, position, val%weight_group)
935  call pmc_mpi_pack_integer(buffer, position, val%weight_class)
936  call pmc_mpi_pack_real(buffer, position, val%absorb_cross_sect)
937  call pmc_mpi_pack_real(buffer, position, val%scatter_cross_sect)
938  call pmc_mpi_pack_real(buffer, position, val%asymmetry)
939  call pmc_mpi_pack_complex(buffer, position, val%refract_shell)
940  call pmc_mpi_pack_complex(buffer, position, val%refract_core)
941  call pmc_mpi_pack_real(buffer, position, val%core_vol)
942  call pmc_mpi_pack_integer(buffer, position, val%water_hyst_leg)
943  call pmc_mpi_pack_integer(buffer, position, val%id)
944  call pmc_mpi_pack_real(buffer, position, val%least_create_time)
945  call pmc_mpi_pack_real(buffer, position, val%greatest_create_time)
946  call assert(810223998, position - prev_position &
948 #endif
949 
950  end subroutine pmc_mpi_pack_aero_particle
951 
952 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
953 
954  !> Unpacks the given value from the buffer, advancing position.
955  subroutine pmc_mpi_unpack_aero_particle(buffer, position, val)
956 
957  !> Memory buffer.
958  character, intent(inout) :: buffer(:)
959  !> Current buffer position.
960  integer, intent(inout) :: position
961  !> Value to pack.
962  type(aero_particle_t), intent(inout) :: val
963 
964 #ifdef PMC_USE_MPI
965  integer :: prev_position
966 
967  prev_position = position
968  call pmc_mpi_unpack_real_array(buffer, position, val%vol)
969  call pmc_mpi_unpack_integer_array(buffer, position, val%n_orig_part)
970  call pmc_mpi_unpack_integer(buffer, position, val%weight_group)
971  call pmc_mpi_unpack_integer(buffer, position, val%weight_class)
972  call pmc_mpi_unpack_real(buffer, position, val%absorb_cross_sect)
973  call pmc_mpi_unpack_real(buffer, position, val%scatter_cross_sect)
974  call pmc_mpi_unpack_real(buffer, position, val%asymmetry)
975  call pmc_mpi_unpack_complex(buffer, position, val%refract_shell)
976  call pmc_mpi_unpack_complex(buffer, position, val%refract_core)
977  call pmc_mpi_unpack_real(buffer, position, val%core_vol)
978  call pmc_mpi_unpack_integer(buffer, position, val%water_hyst_leg)
979  call pmc_mpi_unpack_integer(buffer, position, val%id)
980  call pmc_mpi_unpack_real(buffer, position, val%least_create_time)
981  call pmc_mpi_unpack_real(buffer, position, val%greatest_create_time)
982  call assert(287447241, position - prev_position &
984 #endif
985 
986  end subroutine pmc_mpi_unpack_aero_particle
987 
988 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
989 
990  !> Check that the particle data is consistent.
991  subroutine aero_particle_check(aero_particle, aero_data, &
992  continue_on_error)
993 
994  !> Aerosol particle to check.
995  type(aero_particle_t), intent(in) :: aero_particle
996  !> Aerosol data.
997  type(aero_data_t), intent(in) :: aero_data
998  !> Whether to continue despite error.
999  logical, intent(in) :: continue_on_error
1000 
1001  if (allocated(aero_particle%vol)) then
1002  if (size(aero_particle%vol) /= aero_data_n_spec(aero_data)) then
1003  write(0, *) 'ERROR aero_particle A:'
1004  write(0, *) 'size(aero_particle%vol)', size(aero_particle%vol)
1005  write(0, *) 'aero_data_n_spec(aero_data)', &
1006  aero_data_n_spec(aero_data)
1007  call assert(185878626, continue_on_error)
1008  end if
1009  end if
1010  if (allocated(aero_particle%n_orig_part)) then
1011  if (size(aero_particle%n_orig_part) &
1012  /= aero_data_n_source(aero_data)) then
1013  write(0, *) 'ERROR aero_particle A:'
1014  write(0, *) 'size(aero_particle%n_orig_part)', &
1015  size(aero_particle%n_orig_part)
1016  write(0, *) 'aero_data_n_source(aero_data)', &
1017  aero_data_n_source(aero_data)
1018  call assert(625490639, continue_on_error)
1019  end if
1020  end if
1021 
1022  end subroutine aero_particle_check
1023 
1024 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1025 
1026 end module pmc_aero_particle
pmc_aero_particle::aero_particle_solute_molec_weight
real(kind=dp) function aero_particle_solute_molec_weight(aero_particle, aero_data)
Returns the average of the solute molecular weight (kg/mole).
Definition: aero_particle.F90:542
pmc_aero_particle::aero_particle_t
Single aerosol particle data structure.
Definition: aero_particle.F90:26
pmc_aero_particle::aero_particle_set_weight
subroutine aero_particle_set_weight(aero_particle, i_group, i_class)
Sets the aerosol particle weight group.
Definition: aero_particle.F90:185
pmc_mpi::pmc_mpi_pack_size_complex
integer function pmc_mpi_pack_size_complex(val)
Determines the number of bytes required to pack the given value.
Definition: mpi.F90:427
pmc_util::rad2diam
real(kind=dp) elemental function rad2diam(r)
Convert radius (m) to diameter (m).
Definition: util.F90:252
pmc_aero_data::aero_data_n_spec
elemental integer function aero_data_n_spec(aero_data)
Return the number of aerosol species, or -1 if uninitialized.
Definition: aero_data.F90:236
pmc_mpi::pmc_mpi_size
integer function pmc_mpi_size()
Returns the total number of processes.
Definition: mpi.F90:134
pmc_aero_particle::aero_particle_average_solute_quantity
real(kind=dp) function aero_particle_average_solute_quantity(aero_particle, aero_data, quantity)
Returns the volume-average of the non-water elements of quantity.
Definition: aero_particle.F90:440
pmc_mpi
Wrapper functions for MPI.
Definition: mpi.F90:13
pmc_mpi::pmc_mpi_unpack_complex
subroutine pmc_mpi_unpack_complex(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: mpi.F90:921
pmc_aero_particle::aero_particle_solute_kappa
real(kind=dp) function aero_particle_solute_kappa(aero_particle, aero_data)
Returns the average of the solute kappas (1).
Definition: aero_particle.F90:674
pmc_aero_particle::aero_particle_crit_rel_humid
real(kind=dp) function aero_particle_crit_rel_humid(aero_particle, aero_data, env_state)
Returns the critical relative humidity (1).
Definition: aero_particle.F90:733
pmc_aero_particle::aero_particle_solute_num_ions
real(kind=dp) function aero_particle_solute_num_ions(aero_particle, aero_data)
Returns the average of the solute ion number (1).
Definition: aero_particle.F90:559
pmc_mpi::pmc_mpi_pack_size_real
integer function pmc_mpi_pack_size_real(val)
Determines the number of bytes required to pack the given value.
Definition: mpi.F90:365
pmc_aero_particle::aero_particle_total_solute_quantity
real(kind=dp) function aero_particle_total_solute_quantity(aero_particle, aero_data, quantity)
Returns the volume-total of the non-water elements of quantity.
Definition: aero_particle.F90:463
pmc_mpi::pmc_mpi_unpack_integer_array
subroutine pmc_mpi_unpack_integer_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: mpi.F90:946
pmc_aero_particle::aero_particle_set_create_time
subroutine aero_particle_set_create_time(aero_particle, create_time)
Sets the creation times for the particle.
Definition: aero_particle.F90:141
pmc_aero_particle
The aero_particle_t structure and associated subroutines.
Definition: aero_particle.F90:9
pmc_aero_particle::aero_particle_moles
elemental real(kind=dp) function aero_particle_moles(aero_particle, aero_data)
Total moles in the particle (1).
Definition: aero_particle.F90:251
pmc_aero_particle::aero_particle_new_id
subroutine aero_particle_new_id(aero_particle)
Assigns a globally-unique new ID number to the particle.
Definition: aero_particle.F90:128
pmc_aero_particle::aero_particle_species_volume
elemental real(kind=dp) function aero_particle_species_volume(aero_particle, i_spec)
Volume of a single species in the particle (m^3).
Definition: aero_particle.F90:279
pmc_mpi::pmc_mpi_pack_integer_array
subroutine pmc_mpi_pack_integer_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: mpi.F90:688
pmc_aero_particle::aero_particle_solute_density
real(kind=dp) function aero_particle_solute_density(aero_particle, aero_data)
Returns the average of the solute densities (kg/m^3).
Definition: aero_particle.F90:589
pmc_aero_particle::aero_particle_crit_diameter
real(kind=dp) function aero_particle_crit_diameter(aero_particle, aero_data, env_state)
Returns the critical diameter (m).
Definition: aero_particle.F90:800
pmc_aero_particle::aero_particle_diameter
elemental real(kind=dp) function aero_particle_diameter(aero_particle, aero_data)
Total diameter of the particle (m).
Definition: aero_particle.F90:371
pmc_aero_particle::aero_particle_water_density
real(kind=dp) function aero_particle_water_density(aero_data)
Returns the water density (kg/m^3).
Definition: aero_particle.F90:575
pmc_aero_particle::aero_particle_solute_radius
real(kind=dp) function aero_particle_solute_radius(aero_particle, aero_data)
Returns the total solute radius (m).
Definition: aero_particle.F90:658
pmc_util::warn_assert_msg
subroutine warn_assert_msg(code, condition_ok, warning_msg)
Prints a warning message if condition_ok is false.
Definition: util.F90:59
pmc_env_state::env_state_a
real(kind=dp) function env_state_a(env_state)
Condensation parameter.
Definition: env_state.F90:180
pmc_mpi::pmc_mpi_rank
integer function pmc_mpi_rank()
Returns the rank of the current process.
Definition: mpi.F90:117
pmc_aero_particle::aero_particle_solute_volume
real(kind=dp) function aero_particle_solute_volume(aero_particle, aero_data)
Returns the total solute volume (m^3).
Definition: aero_particle.F90:638
pmc_constants::dp
integer, parameter dp
Kind of a double precision real number.
Definition: constants.F90:12
pmc_spec_file
Reading formatted text input.
Definition: spec_file.F90:43
pmc_util::ensure_real_array_size
subroutine ensure_real_array_size(x, n, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1041
pmc_aero_data::aero_data_n_source
elemental integer function aero_data_n_source(aero_data)
Return the number of aerosol sources, or -1 if uninitialized.
Definition: aero_data.F90:252
pmc_env_state::env_state_t
Current environment state.
Definition: env_state.F90:29
pmc_mpi::pmc_mpi_pack_real
subroutine pmc_mpi_pack_real(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: mpi.F90:586
pmc_util::assert
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
Definition: util.F90:103
pmc_aero_particle::aero_particle_density
real(kind=dp) function aero_particle_density(aero_particle, aero_data)
Average density of the particle (kg/m^3).
Definition: aero_particle.F90:424
pmc_mpi::pmc_mpi_pack_size_real_array
integer function pmc_mpi_pack_size_real_array(val)
Determines the number of bytes required to pack the given value.
Definition: mpi.F90:477
pmc_aero_particle::aero_particle_solute_mass
real(kind=dp) function aero_particle_solute_mass(aero_particle, aero_data)
Returns the total solute mass (kg).
Definition: aero_particle.F90:621
pmc_aero_particle::aero_particle_mobility_diameter
real(kind=dp) function aero_particle_mobility_diameter(aero_particle, aero_data, env_state)
Mobility diameter of the particle (m).
Definition: aero_particle.F90:403
pmc_mpi::pmc_mpi_pack_complex
subroutine pmc_mpi_pack_complex(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: mpi.F90:663
pmc_aero_particle::aero_particle_set_vols
subroutine aero_particle_set_vols(aero_particle, vols)
Sets the aerosol particle volumes.
Definition: aero_particle.F90:156
pmc_aero_particle::aero_particle_shift
subroutine aero_particle_shift(aero_particle_from, aero_particle_to)
Shift data from one aero_particle_t to another and free the first one.
Definition: aero_particle.F90:68
pmc_util::assert_msg
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Definition: util.F90:77
pmc_aero_particle::aero_particle_approx_crit_rel_humid
real(kind=dp) function aero_particle_approx_crit_rel_humid(aero_particle, aero_data, env_state)
Returns the approximate critical relative humidity (1).
Definition: aero_particle.F90:711
pmc_aero_particle::aero_particle_species_masses
real(kind=dp) function, dimension(aero_data_n_spec(aero_data)) aero_particle_species_masses(aero_particle, aero_data)
Mass of all species in the particle (kg).
Definition: aero_particle.F90:234
pmc_aero_particle::next_id
integer, save next_id
Next unique ID number to use for a particle.
Definition: aero_particle.F90:59
pmc_aero_particle::aero_particle_water_mass
real(kind=dp) function aero_particle_water_mass(aero_particle, aero_data)
Returns the water mass (kg).
Definition: aero_particle.F90:605
pmc_aero_particle::pmc_mpi_unpack_aero_particle
subroutine pmc_mpi_unpack_aero_particle(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: aero_particle.F90:956
pmc_aero_particle::aero_particle_zero
subroutine aero_particle_zero(aero_particle, aero_data)
Resets an aero_particle to be zero.
Definition: aero_particle.F90:98
pmc_env_state
The env_state_t structure and associated subroutines.
Definition: env_state.F90:9
pmc_aero_data::aero_data_vol2rad
real(kind=dp) elemental function aero_data_vol2rad(aero_data, v)
Convert mass-equivalent volume (m^3) to geometric radius (m).
Definition: aero_data.F90:92
pmc_aero_data::aero_data_t
Aerosol material properties and associated data.
Definition: aero_data.F90:49
pmc_mpi::pmc_mpi_unpack_integer
subroutine pmc_mpi_unpack_integer(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: mpi.F90:818
pmc_aero_particle::pmc_mpi_pack_size_aero_particle
integer function pmc_mpi_pack_size_aero_particle(val)
Determines the number of bytes required to pack the given value.
Definition: aero_particle.F90:894
pmc_aero_particle::aero_particle_volume_maybe_dry
elemental real(kind=dp) function aero_particle_volume_maybe_dry(aero_particle, aero_data, dry_volume)
Total volume (dry or wet) of the particle (m^3).
Definition: aero_particle.F90:317
pmc_aero_particle::aero_particle_dry_diameter
elemental real(kind=dp) function aero_particle_dry_diameter(aero_particle, aero_data)
Total dry diameter of the particle (m).
Definition: aero_particle.F90:387
pmc_mpi::pmc_mpi_pack_size_integer_array
integer function pmc_mpi_pack_size_integer_array(val)
Determines the number of bytes required to pack the given value.
Definition: mpi.F90:447
pmc_aero_particle::aero_particle_check
subroutine aero_particle_check(aero_particle, aero_data, continue_on_error)
Check that the particle data is consistent.
Definition: aero_particle.F90:993
pmc_aero_particle::aero_particle_dry_radius
elemental real(kind=dp) function aero_particle_dry_radius(aero_particle, aero_data)
Total dry radius of the particle (m).
Definition: aero_particle.F90:355
pmc_util
Common utility subroutines.
Definition: util.F90:9
pmc_aero_particle::aero_particle_dry_volume
elemental real(kind=dp) function aero_particle_dry_volume(aero_particle, aero_data)
Total dry volume of the particle (m^3).
Definition: aero_particle.F90:294
pmc_aero_particle::aero_particle_radius
elemental real(kind=dp) function aero_particle_radius(aero_particle, aero_data)
Total radius of the particle (m).
Definition: aero_particle.F90:339
pmc_mpi::pmc_mpi_pack_size_integer
integer function pmc_mpi_pack_size_integer(val)
Determines the number of bytes required to pack the given value.
Definition: mpi.F90:345
pmc_aero_particle::aero_particle_species_mass
elemental real(kind=dp) function aero_particle_species_mass(aero_particle, i_spec, aero_data)
Mass of a single species in the particle (kg).
Definition: aero_particle.F90:217
pmc_mpi::pmc_mpi_pack_integer
subroutine pmc_mpi_pack_integer(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: mpi.F90:561
pmc_aero_particle::aero_particle_water_molec_weight
real(kind=dp) function aero_particle_water_molec_weight(aero_data)
Returns the water molecular weight. (kg/mole)
Definition: aero_particle.F90:527
pmc_aero_data
The aero_data_t structure and associated subroutines.
Definition: aero_data.F90:9
pmc_mpi::pmc_mpi_pack_real_array
subroutine pmc_mpi_pack_real_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: mpi.F90:720
pmc_aero_particle::aero_particle_set_source
subroutine aero_particle_set_source(aero_particle, i_source)
Sets the aerosol particle source.
Definition: aero_particle.F90:170
pmc_mpi::pmc_mpi_unpack_real
subroutine pmc_mpi_unpack_real(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: mpi.F90:843
pmc_mpi::pmc_mpi_unpack_real_array
subroutine pmc_mpi_unpack_real_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: mpi.F90:978
pmc_aero_particle::aero_particle_coagulate
subroutine aero_particle_coagulate(aero_particle_1, aero_particle_2, aero_particle_new)
Coagulate two particles together to make a new one. The new particle will not have its ID set.
Definition: aero_particle.F90:851
pmc_aero_particle::aero_particle_mass
elemental real(kind=dp) function aero_particle_mass(aero_particle, aero_data)
Total mass of the particle (kg).
Definition: aero_particle.F90:202
pmc_aero_particle::pmc_mpi_pack_aero_particle
subroutine pmc_mpi_pack_aero_particle(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: aero_particle.F90:920
pmc_aero_particle::aero_particle_volume
elemental real(kind=dp) function aero_particle_volume(aero_particle)
Total volume of the particle (m^3).
Definition: aero_particle.F90:266
pmc_aero_particle::aero_particle_total_water_quantity
real(kind=dp) function aero_particle_total_water_quantity(aero_particle, aero_data, quantity)
Returns the volume-total of the water element of quantity.
Definition: aero_particle.F90:507
pmc_util::ensure_integer_array_size
subroutine ensure_integer_array_size(x, n, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1115
pmc_aero_particle::aero_particle_average_water_quantity
real(kind=dp) function aero_particle_average_water_quantity(aero_particle, aero_data, quantity)
Returns the water element of quantity.
Definition: aero_particle.F90:489