PartMC  2.6.1
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, aero_data, &
140  i_group, i_class, 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 = aero_data_diam2vol(aero_data, nucleate_diam)
150  total_so4_vol = total_so4_vol + so4_vol
151 
152  call aero_particle_zero(aero_particle, aero_data)
153  call aero_particle_set_create_time(aero_particle, &
154  env_state%elapsed_time)
155  aero_particle%vol(i_aero_so4) = so4_vol
156  call aero_particle_new_id(aero_particle)
157  call aero_particle_set_weight(aero_particle, i_group, i_class)
158  call aero_state_add_particle(aero_state, aero_particle, aero_data)
159  end do
160  end do
161 
162  ! remove gases that formed new particles
163  h2so4_removed_conc = &
164  total_so4_vol & ! volume of SO4
165  * aero_weight_array_num_conc_at_radius(aero_state%awa, i_class, &
166  diam2rad(nucleate_diam)) & ! volume conc of SO4
167  * aero_data%density(i_aero_so4) & ! mass conc of SO4
168  / aero_data%molec_weight(i_aero_so4) & ! mole conc of SO4
169  * const%avagadro ! molecule conc of SO4
170  gas_state%mix_rat(i_gas_h2so4) = gas_state%mix_rat(i_gas_h2so4) &
171  - env_state_conc_to_ppb(env_state, h2so4_removed_conc)
172  if (gas_state%mix_rat(i_gas_h2so4) < 0d0) then
173  gas_state%mix_rat(i_gas_h2so4) = 0d0
174  end if
175 
176  end subroutine nucleate_sulf_acid
177 
178 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
179 
180  subroutine spec_file_read_nucleate_type(file, aero_data, nucleate_type, &
181  nucleate_source)
182 
183  !> Spec file.
184  type(spec_file_t), intent(inout) :: file
185  !> Aerosol data.
186  type(aero_data_t), intent(inout) :: aero_data
187  !> Nucleate type.
188  integer, intent(out) :: nucleate_type
189  !> Nucleate source number.
190  integer, intent(out) :: nucleate_source
191 
192  character(len=SPEC_LINE_MAX_VAR_LEN) :: nucleate_type_name
193 
194  !> \page input_format_nucleate Input File Format: Nucleation Parameterization
195  !!
196  !! The nucleation parameterization is specified by the parameter:
197  !! - \b nucleate (string): the type of nucleation
198  !! parameterization --- must be one of: "none" for no
199  !! nucleation; or "sulf_acid" for the nucleate_sulf_acid()
200  !! parameterization
201  !!
202  !! See also:
203  !! - \ref spec_file_format --- the input file text format
204 
205  call spec_file_read_string(file, 'nucleate', nucleate_type_name)
206  if (nucleate_type_name == 'sulf_acid') then
207  nucleate_type = nucleate_type_sulf_acid
208  nucleate_source = aero_data_source_by_name(aero_data, &
210  else
211  call spec_file_die_msg(707263678, file, "unknown nucleate type: " &
212  // trim(nucleate_type_name))
213  end if
214 
215  end subroutine spec_file_read_nucleate_type
216 
217 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
218 
219 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_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:298
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:134
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:338
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:208
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:766
pmc_util::assert_msg
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Definition: util.F90:77
pmc_util::diam2rad
real(kind=dp) elemental function diam2rad(d)
Convert diameter (m) to radius (m).
Definition: util.F90:277
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:240
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:73
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_nucleate::nucleate
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:33
pmc_aero_data::aero_data_t
Aerosol material properties and associated data.
Definition: aero_data.F90:49
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_nucleate::nucleate_sulf_acid
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:85
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:671
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:193
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:63
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:269
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:137