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