PartMC  2.3.0
nucleate.F90
Go to the documentation of this file.
1 ! Copyright (C) 2010-2015 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_nucleate module.
7 
8 !> Aerosol nucleation functions.
10 
11  use pmc_env_state
12  use pmc_aero_state
13  use pmc_aero_data
14  use pmc_gas_data
15  use pmc_gas_state
16 
17  !> Type code for unknown or invalid nucleation type.
18  integer, parameter :: NUCLEATE_TYPE_INVALID = 0
19  !> Type code for H2SO4 to SO4 nucleation with quadratic rate.
20  integer, parameter :: NUCLEATE_TYPE_SULF_ACID = 1
21 
22  !> Source name for nucleated particles.
23  character(len=AERO_SOURCE_NAME_LEN), parameter :: NUCLEATE_SOURCE_NAME &
24  = "nucleate"
25 
26 contains
27 
28 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
29 
30  !> Do nucleation of the type given by the first argument.
31  subroutine nucleate(nucleate_type, nucleate_source, env_state, gas_data, &
32  aero_data, aero_state, gas_state, del_t, allow_doubling, allow_halving)
33 
34  !> Type of nucleation.
35  integer, intent(in) :: nucleate_type
36  !> Nucleate source number.
37  integer, intent(in) :: nucleate_source
38  !> Environment state.
39  type(env_state_t), intent(in) :: env_state
40  !> Gas data.
41  type(gas_data_t), intent(in) :: gas_data
42  !> Aerosol data.
43  type(aero_data_t), intent(in) :: aero_data
44  !> Aerosol state.
45  type(aero_state_t), intent(inout) :: aero_state
46  !> Gas state.
47  type(gas_state_t), intent(inout) :: gas_state
48  !> Time to perform nucleation for.
49  real(kind=dp), intent(in) :: del_t
50  !> Whether to allow doubling of the population.
51  logical, intent(in) :: allow_doubling
52  !> Whether to allow halving of the population.
53  logical, intent(in) :: allow_halving
54 
55  if (nucleate_type == nucleate_type_sulf_acid) then
56  call nucleate_sulf_acid(nucleate_source, env_state, gas_data, &
57  aero_data, aero_state, gas_state, del_t, allow_doubling, &
58  allow_halving)
59  else
60  call die_msg(983831728, &
61  "unknown nucleation type: " &
62  // trim(integer_to_string(nucleate_type)))
63  end if
64 
65  end subroutine nucleate
66 
67 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
68 
69  !> Nucleate sulfuric acid into aerosol particles, using a power-law
70  !> dependence, for time \c del_t.
71  !!
72  !! The modeled emission rate is \f$ J = K H^2 \f$, where \f$H\f$ is
73  !! the concentration of \f$ \rm H_2SO_4 \f$ and \f$K\f$ is a
74  !! constant coefficient.
75  !!
76  !! The reference is:
77  !!
78  !! C. Kuang, P. H. McMurry, A. V. McCormick, and F. L. Eisele
79  !! (2008), Dependence of nucleation rates on sulfuric acid vapor
80  !! concentration in diverse atmospheric locations,
81  !! <i>J. Geophys. Res.</i>, 113, D10209, doi:<a
82  !! href="http://dx.doi.org/10.1029/2007JD009253">10.1029/2007JD009253</a>.
83  subroutine nucleate_sulf_acid(nucleate_source, env_state, gas_data, &
84  aero_data, aero_state, gas_state, del_t, allow_doubling, allow_halving)
85 
86  !> Nucleate source number.
87  integer, intent(in) :: nucleate_source
88  !> Environment state.
89  type(env_state_t), intent(in) :: env_state
90  !> Gas data.
91  type(gas_data_t), intent(in) :: gas_data
92  !> Aerosol data.
93  type(aero_data_t), intent(in) :: aero_data
94  !> Aerosol state.
95  type(aero_state_t), intent(inout) :: aero_state
96  !> Gas state.
97  type(gas_state_t), intent(inout) :: gas_state
98  !> Time to perform nucleation for.
99  real(kind=dp), intent(in) :: del_t
100  !> Whether to allow doubling of the population.
101  logical, intent(in) :: allow_doubling
102  !> Whether to allow halving of the population.
103  logical, intent(in) :: allow_halving
104 
105  real(kind=dp), parameter :: nucleate_coeff = 1d-18 ! K (m^3 s^{-1})
106  real(kind=dp), parameter :: nucleate_diam = 1d-9 ! diameter of new
107  ! particles (m)
108 
109  integer :: i_gas_h2so4, i_aero_so4, n_samp, i_samp, i_bin, i_group, n_group
110  integer :: i_class
111  real(kind=dp) :: sulf_acid_conc, nucleate_rate, n_samp_avg
112  real(kind=dp) :: total_so4_vol, so4_vol, h2so4_removed_conc
113  type(aero_particle_t) :: aero_particle
114 
115  ! look up the species numbers
116  i_gas_h2so4 = gas_data_spec_by_name(gas_data, "H2SO4")
117  call assert_msg(886839228, i_gas_h2so4 > 0, &
118  "nucleate_sulf_acid requires H2SO4 as a gas species")
119  i_aero_so4 = aero_data_spec_by_name(aero_data, "SO4")
120  call assert_msg(551966998, i_aero_so4 > 0, &
121  "nucleate_sulf_acid requires SO4 as an aerosol species")
122 
123  ! H2SO4 concentration in molecules / m^3
124  sulf_acid_conc = env_state_ppb_to_conc(env_state, &
125  gas_state%mix_rat(i_gas_h2so4))
126 
127  ! particle nucleation rate in (particles m^{-3} s^{-1})
128  nucleate_rate = nucleate_coeff * sulf_acid_conc**2
129 
130  ! weight class to nucleate into
131  i_class = aero_state_weight_class_for_source(aero_state, nucleate_source)
132 
133  ! add particles to each weight group
134  total_so4_vol = 0d0
135  do i_group = 1,aero_weight_array_n_group(aero_state%awa)
136  ! adjust weight if necessary
137  n_samp_avg = nucleate_rate * del_t / aero_weight_num_conc_at_radius( &
138  aero_state%awa%weight(i_group, i_class), diam2rad(nucleate_diam))
139  call aero_state_prepare_weight_for_add(aero_state, i_group, i_class, &
140  n_samp_avg, allow_doubling, allow_halving)
141 
142  ! determine number of nucleated particles
143  n_samp_avg = nucleate_rate * del_t / aero_weight_num_conc_at_radius( &
144  aero_state%awa%weight(i_group, i_class), diam2rad(nucleate_diam))
145  n_samp = rand_poisson(n_samp_avg)
146 
147  ! create the particles
148  do i_samp = 1,n_samp
149  so4_vol = diam2vol(nucleate_diam)
150  total_so4_vol = total_so4_vol + so4_vol
151 
152  call aero_particle_allocate_size(aero_particle, aero_data%n_spec, &
153  aero_data%n_source)
154  call aero_particle_set_create_time(aero_particle, &
155  env_state%elapsed_time)
156  aero_particle%vol(i_aero_so4) = so4_vol
157  call aero_particle_new_id(aero_particle)
158  call aero_particle_set_weight(aero_particle, i_group, i_class)
159  call aero_state_add_particle(aero_state, aero_particle)
160  call aero_particle_deallocate(aero_particle)
161  end do
162  end do
163 
164  ! remove gases that formed new particles
165  h2so4_removed_conc = &
166  total_so4_vol & ! volume of SO4
167  * aero_weight_array_num_conc_at_radius(aero_state%awa, i_class, &
168  diam2rad(nucleate_diam)) & ! volume conc of SO4
169  * aero_data%density(i_aero_so4) & ! mass conc of SO4
170  / aero_data%molec_weight(i_aero_so4) & ! mole conc of SO4
171  * const%avagadro ! molecule conc of SO4
172  gas_state%mix_rat(i_gas_h2so4) = gas_state%mix_rat(i_gas_h2so4) &
173  - env_state_conc_to_ppb(env_state, h2so4_removed_conc)
174  if (gas_state%mix_rat(i_gas_h2so4) < 0d0) then
175  gas_state%mix_rat(i_gas_h2so4) = 0d0
176  end if
177 
178  end subroutine nucleate_sulf_acid
179 
180 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
181 
182  subroutine spec_file_read_nucleate_type(file, aero_data, nucleate_type, &
183  nucleate_source)
184 
185  !> Spec file.
186  type(spec_file_t), intent(inout) :: file
187  !> Aerosol data.
188  type(aero_data_t), intent(inout) :: aero_data
189  !> Nucleate type.
190  integer, intent(out) :: nucleate_type
191  !> Nucleate source number.
192  integer, intent(out) :: nucleate_source
193 
194  character(len=SPEC_LINE_MAX_VAR_LEN) :: nucleate_type_name
195 
196  !> \page input_format_nucleate Input File Format: Nucleation Parameterization
197  !!
198  !! The nucleation parameterization is specified by the parameter:
199  !! - \b nucleate (string): the type of nucleation
200  !! parameterization --- must be one of: "none" for no
201  !! nucleation; or "sulf_acid" for the nucleate_sulf_acid()
202  !! parameterization
203  !!
204  !! See also:
205  !! - \ref spec_file_format --- the input file text format
206 
207  call spec_file_read_string(file, 'nucleate', nucleate_type_name)
208  if (nucleate_type_name == 'sulf_acid') then
209  nucleate_type = nucleate_type_sulf_acid
210  nucleate_source = aero_data_source_by_name(aero_data, &
211  nucleate_source_name)
212  else
213  call spec_file_die_msg(707263678, file, "unknown nucleate type: " &
214  // trim(nucleate_type_name))
215  end if
216 
217  end subroutine spec_file_read_nucleate_type
218 
219 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
220 
221 end module pmc_nucleate
subroutine aero_particle_set_weight(aero_particle, i_group, i_class)
Sets the aerosol particle weight group.
real(kind=dp) function aero_weight_num_conc_at_radius(aero_weight, radius)
Compute the number concentration at a given radius (m^{-3}).
An input file with extra data for printing messages.
Definition: spec_file.F90:59
The aero_data_t structure and associated subroutines.
Definition: aero_data.F90:9
subroutine die_msg(code, error_msg)
Error immediately.
Definition: util.F90:133
real(kind=dp) elemental function diam2vol(d)
Convert diameter (m) to volume (m^3).
Definition: util.F90:298
integer function aero_data_source_by_name(aero_data, name)
Returns the number of the source in aero_data with the given name, or adds the source if it doesn't e...
Definition: aero_data.F90:189
integer function aero_data_spec_by_name(aero_data, name)
Returns the number of the species in aero_data with the given name, or returns 0 if there is no such ...
Definition: aero_data.F90:160
subroutine aero_particle_deallocate(aero_particle)
Deallocates memory associated with an aero_particle_t.
The env_state_t structure and associated subroutines.
Definition: env_state.F90:9
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.
subroutine aero_state_add_particle(aero_state, aero_particle, allow_resort)
Add the given particle.
Definition: aero_state.F90:330
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Definition: util.F90:76
integer function aero_state_weight_class_for_source(aero_state, source)
Determine the appropriate weight class for a source.
Definition: aero_state.F90:231
The gas_data_t structure and associated subroutines.
Definition: gas_data.F90:9
real(kind=dp) elemental function diam2rad(d)
Convert diameter (m) to radius (m).
Definition: util.F90:286
real(kind=dp) function env_state_conc_to_ppb(env_state, conc)
Convert (molecules m^{-3}) to (ppb).
Definition: env_state.F90:260
Current environment state.
Definition: env_state.F90:26
The aero_state_t structure and assocated subroutines.
Definition: aero_state.F90:9
real(kind=dp) function aero_weight_array_num_conc_at_radius(aero_weight_array, i_class, radius)
Compute the total number concentration at a given radius (m^3).
subroutine spec_file_read_string(file, name, var)
Read a string from a spec file that must have a given name.
Definition: spec_file.F90:625
The gas_state_t structure and associated subroutines.
Definition: gas_state.F90:9
integer function rand_poisson(mean)
Generate a Poisson-distributed random number with the given mean.
Definition: rand.F90:252
character(len=pmc_util_convert_string_len) function integer_to_string(val)
Convert an integer to a string format.
Definition: util.F90:743
The current collection of aerosol particles.
Definition: aero_state.F90:63
integer function gas_data_spec_by_name(gas_data, name)
Returns the number of the species in gas with the given name, or returns 0 if there is no such specie...
Definition: gas_data.F90:89
Aerosol nucleation functions.
Definition: nucleate.F90:9
Single aerosol particle data structure.
subroutine aero_particle_new_id(aero_particle)
Assigns a globally-unique new ID number to the particle.
integer function aero_weight_array_n_group(aero_weight_array)
Return the number of weight groups.
subroutine spec_file_die_msg(code, file, msg)
Exit with an error message containing filename and line number.
Definition: spec_file.F90:73
Current state of the gas mixing ratios in the system.
Definition: gas_state.F90:26
real(kind=dp) function env_state_ppb_to_conc(env_state, ppb)
Convert (ppb) to (molecules m^{-3}).
Definition: env_state.F90:245
Constant gas data.
Definition: gas_data.F90:29
subroutine nucleate_sulf_acid(nucleate_source, env_state, gas_data, aero_data, aero_state, gas_state, del_t, allow_doubling, allow_halving)
Nucleate sulfuric acid into aerosol particles, using a power-law dependence, for time del_t...
Definition: nucleate.F90:83
subroutine nucleate(nucleate_type, nucleate_source, env_state, gas_data, aero_data, aero_state, gas_state, del_t, allow_doubling, allow_halving)
Do nucleation of the type given by the first argument.
Definition: nucleate.F90:31
Aerosol material properties and associated data.
Definition: aero_data.F90:40
subroutine aero_state_prepare_weight_for_add(aero_state, i_group, i_class, n_add, allow_doubling, allow_halving)
Change the weight if necessary to ensure that the addition of about n_add computational particles wil...
Definition: aero_state.F90:651