PartMC  2.6.1
coag_kernel_additive.F90
Go to the documentation of this file.
1 ! Copyright (C) 2005-2012 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_coag_kernel_additive module.
7 
8 !> Additive coagulation kernel.
10 
11  use pmc_bin_grid
12  use pmc_env_state
13  use pmc_util
14  use pmc_constants
15  use pmc_constants
16  use pmc_aero_binned
17  use pmc_aero_data
18  use pmc_aero_dist
19  use pmc_aero_data
21 
22  !> Scaling coefficient for constant kernel.
23  real(kind=dp), parameter :: beta_1 = 1000d0
24 
25 contains
26 
27 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
28 
29  !> Additive coagulation kernel.
30  subroutine kernel_additive(aero_particle_1, aero_particle_2, &
31  aero_data, env_state, k)
32 
33  !> First particle.
34  type(aero_particle_t), intent(in) :: aero_particle_1
35  !> Second particle.
36  type(aero_particle_t), intent(in) :: aero_particle_2
37  !> Aerosol data.
38  type(aero_data_t), intent(in) :: aero_data
39  !> Environment state.
40  type(env_state_t), intent(in) :: env_state
41  !> Coagulation kernel.
42  real(kind=dp), intent(out) :: k
43 
44  k = beta_1 * (aero_particle_volume(aero_particle_1) &
45  + aero_particle_volume(aero_particle_2))
46 
47  end subroutine kernel_additive
48 
49 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
50 
51  !> Minimum and maximum values of the additive kernel.
52  subroutine kernel_additive_minmax(v1, v2, aero_data, env_state, k_min, k_max)
53 
54  !> Volume of first particle.
55  real(kind=dp), intent(in) :: v1
56  !> Volume of second particle.
57  real(kind=dp), intent(in) :: v2
58  !> Aerosol data.
59  type(aero_data_t), intent(in) :: aero_data
60  !> Environment state.
61  type(env_state_t), intent(in) :: env_state
62  !> Coagulation kernel minimum value.
63  real(kind=dp), intent(out) :: k_min
64  !> Coagulation kernel maximum value.
65  real(kind=dp), intent(out) :: k_max
66 
67  k_min = beta_1 * (v1 + v2)
68  k_max = k_min
69 
70  end subroutine kernel_additive_minmax
71 
72 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
73 
74  !> Exact solution with the additive coagulation kernel and
75  !> exponential initial condition.
76  !!
77  !! Given input paramaters \f$R\f$ and \f$N_0\f$ we let the mean
78  !! volume be \f$v_\mu = \frac{4\pi}{3} R^3\f$ and define the
79  !! rescaled times \f$\tau = N_0 v_\mu \beta_1 t\f$ and \f$T = 1 -
80  !! e^{-\tau}\f$, where \f$\beta_1\f$ is the fixed kernel scaling
81  !! parameter. Then the solution is
82  !! \f[
83  !! n(D,t) \ {\rm d}\ln D
84  !! = \frac{\pi}{2} D^3
85  !! \frac{N_0}{v} \frac{1 - T}{\sqrt{T}}
86  !! \exp\left(-(1 + T) \frac{v}{v_\mu}\right)
87  !! I_1\left(2 \frac{v}{v_\mu} \sqrt{T}\right) {\rm d}\ln D
88  !! \f]
89  !! where \f$I_1(x)\f$ is the <a
90  !! href="http://en.wikipedia.org/wiki/Bessel_function">modified
91  !! Bessel function of the first kind</a> and \f$v = \frac{\pi}{6}
92  !! D^3\f$.
93  !!
94  !! For small \f$x\f$ we have \f$I_1(x) \approx \frac{x}{2}\f$, so
95  !! this solution has initial condition
96  !! \f[
97  !! n(D,t) \ {\rm d}\ln D
98  !! = \frac{\pi}{2} D^3 \frac{N_0}{v_\mu}
99  !! \exp\left(-\frac{v}{v_\mu}\right) {\rm d}\ln D
100  !! \f]
101  subroutine soln_additive_exp(bin_grid, aero_data, time, num_conc, &
102  radius_at_mean_vol, env_state, aero_binned)
103 
104  !> Bin grid.
105  type(bin_grid_t), intent(in) :: bin_grid
106  !> Aerosol data.
107  type(aero_data_t), intent(in) :: aero_data
108  !> Current time.
109  real(kind=dp), intent(in) :: time
110  !> Particle number concentration (#/m^3).
111  real(kind=dp), intent(in) :: num_conc
112  !> Mean init radius (m).
113  real(kind=dp), intent(in) :: radius_at_mean_vol
114  !> Environment state.
115  type(env_state_t), intent(in) :: env_state
116  !> Output state.
117  type(aero_binned_t), intent(inout) :: aero_binned
118 
119  real(kind=dp) :: tau, t, rat_v, nn, b, x, mean_vol
120  integer :: k
121 
122  call aero_binned_set_sizes(aero_binned, bin_grid_size(bin_grid), &
123  aero_data_n_spec(aero_data))
124 
125  mean_vol = aero_data_rad2vol(aero_data, radius_at_mean_vol)
126  if (time .eq. 0d0) then
127  do k = 1,bin_grid_size(bin_grid)
128  aero_binned%num_conc(k) = const%pi/2d0 &
129  * (2d0 * bin_grid%centers(k))**3 * num_conc / mean_vol &
130  * exp(-(aero_data_rad2vol(aero_data, bin_grid%centers(k)) &
131  / mean_vol))
132  end do
133  else
134  tau = num_conc * mean_vol * beta_1 * time
135  t = 1d0 - exp(-tau)
136  do k = 1,bin_grid_size(bin_grid)
137  rat_v = aero_data_rad2vol(aero_data, bin_grid%centers(k)) / mean_vol
138  x = 2d0 * rat_v * sqrt(t)
139  if (x .lt. 500d0) then
140  call bessi1(x, b)
141  nn = num_conc / aero_data_rad2vol(aero_data, &
142  bin_grid%centers(k)) &
143  * (1d0 - t) / sqrt(t) * exp(-((1d0 + t) * rat_v)) * b
144  else
145  ! For very large volumes we can use the asymptotic
146  ! approximation I_1(x) \approx e^x / sqrt(2 pi x) and
147  ! simplify the result to avoid the overflow from
148  ! multiplying a huge bessel function result by a very
149  ! tiny exponential.
150  nn = num_conc / aero_data_rad2vol(aero_data, &
151  bin_grid%centers(k)) &
152  * (1d0 - t) / sqrt(t) &
153  * exp((2d0*sqrt(t) - t - 1d0) * rat_v) &
154  / sqrt(4d0 * const%pi * rat_v * sqrt(t))
155  end if
156  aero_binned%num_conc(k) = const%pi/2d0 &
157  * (2d0 * bin_grid%centers(k))**3 * nn
158  end do
159  end if
160 
161  aero_binned%vol_conc = 0d0
162  do k = 1,bin_grid_size(bin_grid)
163  aero_binned%vol_conc(k,1) = aero_data_rad2vol(aero_data, &
164  bin_grid%centers(k)) * aero_binned%num_conc(k)
165  end do
166 
167  end subroutine soln_additive_exp
168 
169 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
170 
171  !> Modified Bessel function of the first kind \f$ I_1(x) \f$.
172  subroutine bessi1(x, r)
173 
174  !> Function argument.
175  real(kind=dp), intent(in) :: x
176  !> Function value.
177  real(kind=dp), intent(out) :: r
178 
179  call calci1 (x, r, 1 )
180 
181  end subroutine bessi1
182 
183 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
184 
185  !> Calculates modified Bessel functions of the first kind \f$ I_1(x) \f$.
186  subroutine calci1 ( arg, result, jint )
187 
188  !*************************************************************************
189  !
190  !! CALCI1 computes various I1 Bessel functions.
191  !
192  ! Discussion:
193  !
194  ! This routine computes modified Bessel functioons of the first kind
195  ! and order one, I1(X) and EXP(-ABS(X))*I1(X), for real
196  ! arguments X.
197  !
198  ! The main computation evaluates slightly modified forms of
199  ! minimax approximations generated by Blair and Edwards, Chalk
200  ! River (Atomic Energy of Canada Limited) Report AECL-4928,
201  ! October, 1974.
202  !
203  ! Licensing:
204  !
205  ! This code is distributed under the GNU LGPL license.
206  !
207  ! Modified:
208  !
209  ! 03 April 2007
210  !
211  ! Author:
212  !
213  ! Original FORTRAN77 version by William Cody, Laura Stoltz.
214  ! FORTRAN90 version by John Burkardt.
215  !
216  ! Parameters:
217  !
218  ! Input, real ( kind = 8 ) ARG, the argument. If JINT = 1, then
219  ! the argument must be less than XMAX.
220  !
221  ! Output, real ( kind = 8 ) RESULT, the value of the function,
222  ! which depends on the input value of JINT:
223  ! 1, RESULT = I1(x);
224  ! 2, RESULT = exp(-x) * I1(x);
225  !
226  ! Input, integer ( kind = 4 ) JINT, chooses the function to be computed.
227  ! 1, I1(x);
228  ! 2, exp(-x) * I1(x);
229  !
230 
231  real ( kind = 8 ) a
232  real ( kind = 8 ) arg
233  real ( kind = 8 ) b
234  real ( kind = 8 ) exp40
235  real ( kind = 8 ) forty
236  integer ( kind = 4 ) j
237  integer ( kind = 4 ) jint
238  real ( kind = 8 ) one5
239  real ( kind = 8 ) p(15)
240  real ( kind = 8 ) pbar
241  real ( kind = 8 ) pp(8)
242  real ( kind = 8 ) q(5)
243  real ( kind = 8 ) qq(6)
244  real ( kind = 8 ) rec15
245  real ( kind = 8 ) result
246  real ( kind = 8 ) sump
247  real ( kind = 8 ) sumq
248  real ( kind = 8 ) two25
249  real ( kind = 8 ) x
250  real ( kind = 8 ) xinf
251  real ( kind = 8 ) xmax
252  real ( kind = 8 ) xsmall
253  real ( kind = 8 ) xx
254  !
255  ! Mathematical constants
256  !
257  data one5 / 15.0d0 /
258  data exp40 / 2.353852668370199854d17 /
259  data forty / 40.0d0 /
260  data rec15 / 6.6666666666666666666d-2 /
261  data two25 / 225.0d0 /
262  !
263  ! Machine-dependent constants
264  !
265  data xsmall /5.55d-17/
266  data xinf /1.79d308/
267  data xmax /713.987d0/
268  !
269  ! Coefficients for XSMALL <= ABS(ARG) < 15.0
270  !
271  data p/-1.9705291802535139930d-19,-6.5245515583151902910d-16, &
272  -1.1928788903603238754d-12,-1.4831904935994647675d-09, &
273  -1.3466829827635152875d-06,-9.1746443287817501309d-04, &
274  -4.7207090827310162436d-01,-1.8225946631657315931d+02, &
275  -5.1894091982308017540d+04,-1.0588550724769347106d+07, &
276  -1.4828267606612366099d+09,-1.3357437682275493024d+11, &
277  -6.9876779648010090070d+12,-1.7732037840791591320d+14, &
278  -1.4577180278143463643d+15/
279  data q/-4.0076864679904189921d+03, 7.4810580356655069138d+06, &
280  -8.0059518998619764991d+09, 4.8544714258273622913d+12, &
281  -1.3218168307321442305d+15/
282  !
283  ! Coefficients for 15.0 <= ABS(ARG)
284  !
285  data pp/-6.0437159056137600000d-02, 4.5748122901933459000d-01, &
286  -4.2843766903304806403d-01, 9.7356000150886612134d-02, &
287  -3.2457723974465568321d-03,-3.6395264712121795296d-04, &
288  1.6258661867440836395d-05,-3.6347578404608223492d-07/
289  data qq/-3.8806586721556593450d+00, 3.2593714889036996297d+00, &
290  -8.5017476463217924408d-01, 7.4212010813186530069d-02, &
291  -2.2835624489492512649d-03, 3.7510433111922824643d-05/
292  data pbar/3.98437500d-01/
293 
294  x = abs( arg )
295  !
296  ! Return for ABS(ARG) < XSMALL.
297  !
298  if ( x < xsmall ) then
299 
300  result = 0.5d+00 * x
301  !
302  ! XSMALL <= ABS(ARG) < 15.0.
303  !
304  else if ( x < one5 ) then
305 
306  xx = x * x
307  sump = p(1)
308  do j = 2, 15
309  sump = sump * xx + p(j)
310  end do
311  xx = xx - two25
312 
313  sumq = (((( &
314  xx + q(1) ) &
315  * xx + q(2) ) &
316  * xx + q(3) ) &
317  * xx + q(4) ) &
318  * xx + q(5)
319 
320  result = ( sump / sumq ) * x
321 
322  if ( jint == 2 ) then
323  result = result * exp( -x )
324  end if
325 
326  else if ( jint == 1 .and. xmax < x ) then
327 
328  result = xinf
329 
330  else
331  !
332  ! 15.0 <= ABS(ARG).
333  !
334  xx = 1.0d+00 / x - rec15
335 
336  sump = (((((( &
337  pp(1) &
338  * xx + pp(2) ) &
339  * xx + pp(3) ) &
340  * xx + pp(4) ) &
341  * xx + pp(5) ) &
342  * xx + pp(6) ) &
343  * xx + pp(7) ) &
344  * xx + pp(8)
345 
346  sumq = ((((( &
347  xx + qq(1) ) &
348  * xx + qq(2) ) &
349  * xx + qq(3) ) &
350  * xx + qq(4) ) &
351  * xx + qq(5) ) &
352  * xx + qq(6)
353 
354  result = sump / sumq
355 
356  if ( jint /= 1 ) then
357  result = ( result + pbar ) / sqrt( x )
358  else
359  !
360  ! Calculation reformulated to avoid premature overflow.
361  !
362  if ( xmax - one5 < x ) then
363  a = exp( x - forty )
364  b = exp40
365  else
366  a = exp( x )
367  b = 1.0d+00
368  end if
369 
370  result = ( ( result * a + pbar * a ) / sqrt( x ) ) * b
371 
372  end if
373  end if
374 
375  if ( arg < 0.0d+00 ) then
376  result = -result
377  end if
378 
379  return
380 
381  end subroutine calci1
382 
383 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
384 
385 end module pmc_coag_kernel_additive
pmc_aero_particle::aero_particle_t
Single aerosol particle data structure.
Definition: aero_particle.F90:26
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_aero_binned::aero_binned_set_sizes
subroutine aero_binned_set_sizes(aero_binned, n_bin, n_spec)
Set the number of bins and species in an aero_binned_t.
Definition: aero_binned.F90:72
pmc_coag_kernel_additive
Additive coagulation kernel.
Definition: coag_kernel_additive.F90:9
pmc_aero_particle
The aero_particle_t structure and associated subroutines.
Definition: aero_particle.F90:9
pmc_coag_kernel_additive::soln_additive_exp
subroutine soln_additive_exp(bin_grid, aero_data, time, num_conc, radius_at_mean_vol, env_state, aero_binned)
Exact solution with the additive coagulation kernel and exponential initial condition.
Definition: coag_kernel_additive.F90:103
pmc_coag_kernel_additive::kernel_additive
subroutine kernel_additive(aero_particle_1, aero_particle_2, aero_data, env_state, k)
Additive coagulation kernel.
Definition: coag_kernel_additive.F90:32
pmc_constants::dp
integer, parameter dp
Kind of a double precision real number.
Definition: constants.F90:12
pmc_bin_grid::bin_grid_size
elemental integer function bin_grid_size(bin_grid)
Return the number of bins in the grid, or -1 if the bin grid is not allocated.
Definition: bin_grid.F90:51
pmc_env_state::env_state_t
Current environment state.
Definition: env_state.F90:29
pmc_aero_dist
The aero_dist_t structure and associated subroutines.
Definition: aero_dist.F90:18
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_aero_data::aero_data_t
Aerosol material properties and associated data.
Definition: aero_data.F90:49
pmc_constants
Physical constants.
Definition: constants.F90:9
pmc_coag_kernel_additive::calci1
subroutine calci1(arg, result, jint)
Calculates modified Bessel functions of the first kind .
Definition: coag_kernel_additive.F90:187
pmc_util
Common utility subroutines.
Definition: util.F90:9
pmc_coag_kernel_additive::beta_1
real(kind=dp), parameter beta_1
Scaling coefficient for constant kernel.
Definition: coag_kernel_additive.F90:23
pmc_aero_binned
The aero_binned_t structure and associated subroutines.
Definition: aero_binned.F90:9
pmc_aero_binned::aero_binned_t
Aerosol number and volume distributions stored per bin.
Definition: aero_binned.F90:37
pmc_bin_grid
The bin_grid_t structure and associated subroutines.
Definition: bin_grid.F90:9
pmc_aero_data::aero_data_rad2vol
real(kind=dp) elemental function aero_data_rad2vol(aero_data, r)
Convert geometric radius (m) to mass-equivalent volume (m^3).
Definition: aero_data.F90:122
pmc_aero_data
The aero_data_t structure and associated subroutines.
Definition: aero_data.F90:9
pmc_coag_kernel_additive::bessi1
subroutine bessi1(x, r)
Modified Bessel function of the first kind .
Definition: coag_kernel_additive.F90:173
pmc_bin_grid::bin_grid_t
1D grid, either logarithmic or linear.
Definition: bin_grid.F90:33
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_coag_kernel_additive::kernel_additive_minmax
subroutine kernel_additive_minmax(v1, v2, aero_data, env_state, k_min, k_max)
Minimum and maximum values of the additive kernel.
Definition: coag_kernel_additive.F90:53