28 real(kind=dp),
pointer :: vol(:)
31 integer,
pointer :: n_orig_part(:)
33 integer :: weight_group
35 integer :: weight_class
37 real(kind=dp) :: absorb_cross_sect
39 real(kind=dp) :: scatter_cross_sect
41 real(kind=dp) :: asymmetry
43 complex(kind=dc) :: refract_shell
45 complex(kind=dc) :: refract_core
47 real(kind=dp) :: core_vol
49 integer :: water_hyst_leg
53 real(kind=dp) :: least_create_time
55 real(kind=dp) :: greatest_create_time
59 integer,
save :: next_id = 1
71 allocate(aero_particle%vol(0))
72 allocate(aero_particle%n_orig_part(0))
85 integer,
intent(in) :: n_spec
87 integer,
intent(in) :: n_source
89 allocate(aero_particle%vol(n_spec))
90 allocate(aero_particle%n_orig_part(n_source))
103 deallocate(aero_particle%vol)
104 deallocate(aero_particle%n_orig_part)
118 integer :: n_spec, n_source
120 n_spec =
size(aero_particle_from%vol)
121 n_source =
size(aero_particle_from%n_orig_part)
122 if ((n_spec /=
size(aero_particle_to%vol)) &
123 .or. (n_source /=
size(aero_particle_to%n_orig_part)))
then
127 call
assert(651178226,
size(aero_particle_from%vol) &
128 ==
size(aero_particle_to%vol))
129 call
assert(105980551,
size(aero_particle_from%n_orig_part) &
130 ==
size(aero_particle_to%n_orig_part))
131 aero_particle_to%vol = aero_particle_from%vol
132 aero_particle_to%n_orig_part = aero_particle_from%n_orig_part
133 aero_particle_to%weight_group = aero_particle_from%weight_group
134 aero_particle_to%weight_class = aero_particle_from%weight_class
135 aero_particle_to%absorb_cross_sect = aero_particle_from%absorb_cross_sect
136 aero_particle_to%scatter_cross_sect = &
137 aero_particle_from%scatter_cross_sect
138 aero_particle_to%asymmetry = aero_particle_from%asymmetry
139 aero_particle_to%refract_shell = aero_particle_from%refract_shell
140 aero_particle_to%refract_core = aero_particle_from%refract_core
141 aero_particle_to%core_vol = aero_particle_from%core_vol
142 aero_particle_to%water_hyst_leg = aero_particle_from%water_hyst_leg
143 aero_particle_to%id = aero_particle_from%id
144 aero_particle_to%least_create_time = aero_particle_from%least_create_time
145 aero_particle_to%greatest_create_time = &
146 aero_particle_from%greatest_create_time
165 aero_particle_to%vol => aero_particle_from%vol
166 nullify(aero_particle_from%vol)
167 aero_particle_to%n_orig_part => aero_particle_from%n_orig_part
168 nullify(aero_particle_from%n_orig_part)
169 aero_particle_to%weight_group = aero_particle_from%weight_group
170 aero_particle_to%weight_class = aero_particle_from%weight_class
171 aero_particle_to%absorb_cross_sect = aero_particle_from%absorb_cross_sect
172 aero_particle_to%scatter_cross_sect = &
173 aero_particle_from%scatter_cross_sect
174 aero_particle_to%asymmetry = aero_particle_from%asymmetry
175 aero_particle_to%refract_shell = aero_particle_from%refract_shell
176 aero_particle_to%refract_core = aero_particle_from%refract_core
177 aero_particle_to%core_vol = aero_particle_from%core_vol
178 aero_particle_to%water_hyst_leg = aero_particle_from%water_hyst_leg
179 aero_particle_to%id = aero_particle_from%id
180 aero_particle_to%least_create_time = aero_particle_from%least_create_time
181 aero_particle_to%greatest_create_time = &
182 aero_particle_from%greatest_create_time
194 aero_particle%vol = 0d0
195 aero_particle%n_orig_part = 0
196 aero_particle%weight_group = 0
197 aero_particle%weight_class = 0
198 aero_particle%absorb_cross_sect = 0d0
199 aero_particle%scatter_cross_sect = 0d0
200 aero_particle%asymmetry = 0d0
201 aero_particle%refract_shell = (0d0, 0d0)
202 aero_particle%refract_core = (0d0, 0d0)
203 aero_particle%core_vol = 0d0
204 aero_particle%water_hyst_leg = 0
206 aero_particle%least_create_time = 0d0
207 aero_particle%greatest_create_time = 0d0
220 next_id = next_id + 1
232 real(kind=dp),
intent(in) :: create_time
234 aero_particle%least_create_time = create_time
235 aero_particle%greatest_create_time = create_time
247 real(kind=dp),
intent(in) :: vols(size(aero_particle%vol))
249 aero_particle%vol = vols
261 integer,
intent(in) :: i_source
263 aero_particle%n_orig_part(i_source) = 1
275 integer,
intent(in),
optional :: i_group
277 integer,
intent(in),
optional :: i_class
279 if (present(i_group)) aero_particle%weight_group = i_group
280 if (present(i_class)) aero_particle%weight_class = i_class
307 integer,
intent(in) :: i_spec
312 * aero_data%density(i_spec)
344 / aero_data%molec_weight)
374 do i_spec = 1,aero_data%n_spec
375 if (i_spec /= aero_data%i_water)
then
377 + aero_particle%vol(i_spec)
387 aero_particle, aero_data, dry_volume)
394 logical,
intent(in) :: dry_volume
480 aero_particle, aero_data, quantity)
487 real(kind=dp),
intent(in) :: quantity(:)
489 real(kind=dp) :: ones(aero_data%n_spec)
494 aero_data, quantity) &
510 real(kind=dp),
intent(in) :: quantity(:)
516 do i = 1,aero_data%n_spec
517 if (i /= aero_data%i_water)
then
518 total = total + aero_particle%vol(i) * quantity(i)
536 real(kind=dp),
intent(in) :: quantity(:)
538 call
assert(420016623, aero_data%i_water > 0)
554 real(kind=dp),
intent(in) :: quantity(:)
556 call
assert(223343210, aero_data%i_water > 0)
558 = aero_particle%vol(aero_data%i_water) &
559 * quantity(aero_data%i_water)
572 call
assert(772012490, aero_data%i_water > 0)
574 = aero_data%molec_weight(aero_data%i_water)
591 aero_data, aero_data%molec_weight)
608 aero_data,
real(aero_data%num_ions, kind=dp))
620 call
assert(235482108, aero_data%i_water > 0)
638 aero_data, aero_data%density)
652 call
assert(888636139, aero_data%i_water > 0)
654 * aero_data%density(aero_data%i_water)
670 aero_data, aero_data%density)
685 real(kind=dp) :: ones(aero_data%n_spec)
720 real(kind=dp) :: kappa(aero_data%n_spec), m_w, rho_w, m_a, rho_a
725 do i_spec = 1,aero_data%n_spec
726 if (i_spec == aero_data%i_water)
then
728 elseif (aero_data%num_ions(i_spec) > 0)
then
729 call
assert_msg(123681459, aero_data%kappa(i_spec) == 0d0, &
730 "species has nonzero num_ions and kappa: " &
731 // trim(aero_data%name(i_spec)))
732 m_a = aero_data%molec_weight(i_spec)
733 rho_a = aero_data%density(i_spec)
734 kappa(i_spec) = m_w * rho_a / (m_a * rho_w) &
735 *
real(aero_data%num_ions(i_spec), kind=dp)
737 kappa(i_spec) = aero_data%kappa(i_spec)
750 aero_data, env_state)
759 real(kind=dp) :: kappa, diam, c, a
772 aero_data, env_state)
781 real(kind=dp) :: kappa, crit_diam, dry_diam, a
788 if (kappa < 1d-30)
then
792 / (crit_diam**3 - dry_diam**3 * (1 - kappa)) * exp(a / crit_diam)
839 aero_data, env_state)
848 integer,
parameter :: crit_diam_max_iter = 100
850 real(kind=dp) :: kappa, dry_diam, a, c4, c3, c0, d, f, df, dd
856 if (kappa < 1d-30)
then
862 c4 = - 3d0 * dry_diam**3 * kappa / a
863 c3 = - dry_diam**3 * (2d0 - kappa)
864 c0 = dry_diam**6 * (1d0 - kappa)
867 d = max(sqrt(-4d0 / 3d0 * c4), (-c3)**(1d0/3d0))
868 do i_newton = 1,crit_diam_max_iter
869 f = d**6 + c4 * d**4 + c3 * d**3 + c0
870 df = 6 * d**5 + 4 * c4 * d**3 + 3 * c3 * d**2
873 if (abs(dd / d) < 1d-14)
then
878 "critical diameter Newton loop failed to converge")
880 "critical diameter Newton loop converged to invalid solution")
890 aero_particle_2, aero_particle_new)
899 call
assert(203741686,
size(aero_particle_1%vol) &
900 ==
size(aero_particle_new%vol))
901 call
assert(586181003,
size(aero_particle_2%vol) &
902 ==
size(aero_particle_new%vol))
903 call
assert(483452167,
size(aero_particle_1%n_orig_part) &
904 ==
size(aero_particle_new%n_orig_part))
905 call
assert(126911035,
size(aero_particle_2%n_orig_part) &
906 ==
size(aero_particle_new%n_orig_part))
907 aero_particle_new%vol = aero_particle_1%vol + aero_particle_2%vol
908 aero_particle_new%n_orig_part = aero_particle_1%n_orig_part &
909 + aero_particle_2%n_orig_part
910 aero_particle_new%weight_group = 0
911 aero_particle_new%weight_class = 0
912 aero_particle_new%absorb_cross_sect = 0d0
913 aero_particle_new%scatter_cross_sect = 0d0
914 aero_particle_new%asymmetry = 0d0
915 aero_particle_new%refract_shell = (0d0, 0d0)
916 aero_particle_new%refract_core = (0d0, 0d0)
917 aero_particle_new%core_vol = 0d0
918 if ((aero_particle_1%water_hyst_leg == 1) &
919 .and. (aero_particle_2%water_hyst_leg == 1))
then
920 aero_particle_new%water_hyst_leg = 1
922 aero_particle_new%water_hyst_leg = 0
924 aero_particle_new%id = 0
925 aero_particle_new%least_create_time = &
926 min(aero_particle_1%least_create_time, &
927 aero_particle_2%least_create_time)
928 aero_particle_new%greatest_create_time = &
929 max(aero_particle_1%greatest_create_time, &
930 aero_particle_2%greatest_create_time)
966 character,
intent(inout) :: buffer(:)
968 integer,
intent(inout) :: position
973 integer :: prev_position
975 prev_position = position
990 call
assert(810223998, position - prev_position &
1002 character,
intent(inout) :: buffer(:)
1004 integer,
intent(inout) :: position
1009 integer :: prev_position
1011 prev_position = position
1026 call
assert(287447241, position - prev_position &
subroutine aero_particle_set_weight(aero_particle, i_group, i_class)
Sets the aerosol particle weight group.
subroutine pmc_mpi_pack_aero_particle(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine aero_particle_set_vols(aero_particle, vols)
Sets the aerosol particle volumes.
integer function pmc_mpi_pack_size_real(val)
Determines the number of bytes required to pack the given value.
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.
integer function pmc_mpi_pack_size_real_array(val)
Determines the number of bytes required to pack the given value.
elemental real(kind=dp) function aero_particle_moles(aero_particle, aero_data)
Total moles in the particle (1).
The aero_data_t structure and associated subroutines.
integer function pmc_mpi_pack_size_integer(val)
Determines the number of bytes required to pack the given value.
subroutine pmc_mpi_unpack_aero_particle(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
real(kind=dp) function aero_particle_solute_kappa(aero_particle, aero_data)
Returns the average of the solute kappas (1).
real(kind=dp) function aero_particle_crit_diameter(aero_particle, aero_data, env_state)
Returns the critical diameter (m).
subroutine aero_particle_zero(aero_particle)
Resets an aero_particle to be zero.
subroutine pmc_mpi_unpack_real(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
The aero_particle_t structure and associated subroutines.
subroutine aero_particle_deallocate(aero_particle)
Deallocates memory associated with an aero_particle_t.
elemental real(kind=dp) function aero_particle_species_mass(aero_particle, i_spec, aero_data)
Mass of a single species in the particle (kg).
The env_state_t structure and associated subroutines.
subroutine aero_particle_allocate_size(aero_particle, n_spec, n_source)
Allocates an aero_particle_t of the given size.
subroutine aero_particle_set_create_time(aero_particle, create_time)
Sets the creation times for the particle.
real(kind=dp) function aero_particle_solute_mass(aero_particle, aero_data)
Returns the total solute mass (kg).
subroutine aero_particle_shift(aero_particle_from, aero_particle_to)
Shift data from one aero_particle_t to another and free the first one.
elemental real(kind=dp) function aero_particle_dry_radius(aero_particle, aero_data)
Total dry radius of the particle (m).
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
elemental real(kind=dp) function aero_particle_diameter(aero_particle)
Total diameter of the particle (m).
subroutine pmc_mpi_unpack_complex(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
real(kind=dp) function aero_particle_water_molec_weight(aero_data)
Returns the water molecular weight. (kg/mole)
subroutine aero_particle_set_source(aero_particle, i_source)
Sets the aerosol particle source.
elemental real(kind=dp) function aero_particle_radius(aero_particle)
Total radius of the particle (m).
real(kind=dp) function env_state_a(env_state)
Condensation parameter.
subroutine pmc_mpi_pack_integer(buffer, position, val)
Packs the given value into the buffer, advancing position.
real(kind=dp) function aero_particle_water_density(aero_data)
Returns the water density (kg/m^3).
integer function pmc_mpi_size()
Returns the total number of processes.
subroutine warn_assert_msg(code, condition_ok, warning_msg)
Prints a warning message if condition_ok is false.
real(kind=dp) function aero_particle_density(aero_particle, aero_data)
Average density of the particle (kg/m^3).
Common utility subroutines.
subroutine pmc_mpi_unpack_real_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Current environment state.
real(kind=dp) function aero_particle_solute_density(aero_particle, aero_data)
Returns the average of the solute densities (kg/m^3).
real(kind=dp) function aero_particle_total_water_quantity(aero_particle, aero_data, quantity)
Returns the volume-total of the water element of quantity.
subroutine pmc_mpi_unpack_integer(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
integer function pmc_mpi_rank()
Returns the rank of the current process.
Wrapper functions for MPI.
subroutine pmc_mpi_unpack_integer_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
subroutine pmc_mpi_pack_complex(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine aero_particle_allocate(aero_particle)
Allocates memory in an aero_particle_t.
integer function pmc_mpi_pack_size_complex(val)
Determines the number of bytes required to pack the given value.
real(kind=dp) function aero_particle_solute_num_ions(aero_particle, aero_data)
Returns the average of the solute ion number (1).
real(kind=dp) function aero_particle_crit_rel_humid(aero_particle, aero_data, env_state)
Returns the critical relative humidity (1).
Single aerosol particle data structure.
subroutine aero_particle_new_id(aero_particle)
Assigns a globally-unique new ID number to the particle.
elemental real(kind=dp) function aero_particle_dry_volume(aero_particle, aero_data)
Total dry volume of the particle (m^3).
Reading formatted text input.
real(kind=dp) function aero_particle_solute_molec_weight(aero_particle, aero_data)
Returns the average of the solute molecular weight (kg/mole).
subroutine pmc_mpi_pack_real(buffer, position, val)
Packs the given value into the buffer, advancing position.
real(kind=dp) function aero_particle_solute_volume(aero_particle, aero_data)
Returns the total solute volume (m^3).
integer function pmc_mpi_pack_size_integer_array(val)
Determines the number of bytes required to pack the given value.
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...
real(kind=dp) function aero_particle_average_water_quantity(aero_particle, aero_data, quantity)
Returns the water element of 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.
real(kind=dp) function, dimension(aero_data%n_spec) aero_particle_species_masses(aero_particle, aero_data)
Mass of all species in the particle (kg).
elemental real(kind=dp) function aero_particle_mass(aero_particle, aero_data)
Total mass of the particle (kg).
subroutine pmc_mpi_pack_real_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
real(kind=dp) function aero_particle_approx_crit_rel_humid(aero_particle, aero_data, env_state)
Returns the approximate critical relative humidity (1).
real(kind=dp) elemental function vol2rad(v)
Convert volume (m^3) to radius (m).
elemental real(kind=dp) function aero_particle_volume(aero_particle)
Total volume of the particle (m^3).
real(kind=dp) function aero_particle_solute_radius(aero_particle, aero_data)
Returns the total solute radius (m).
integer function pmc_mpi_pack_size_aero_particle(val)
Determines the number of bytes required to pack the given value.
Aerosol material properties and associated data.
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
elemental real(kind=dp) function aero_particle_dry_diameter(aero_particle, aero_data)
Total dry diameter of the particle (m).
subroutine pmc_mpi_pack_integer_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine aero_particle_copy(aero_particle_from, aero_particle_to)
Copies a particle.
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).
real(kind=dp) function aero_particle_water_mass(aero_particle, aero_data)
Returns the water mass (kg).