PartMC  2.6.1
coagulation.F90
Go to the documentation of this file.
1 ! Copyright (C) 2005-2012 Nicole Riemer
2 ! Copyright (C) 2005-2015 Matthew West
3 ! Copyright (C) 2015 Jeffrey Curtis
4 ! Licensed under the GNU General Public License version 2 or (at your
5 ! option) any later version. See the file COPYING for details.
6 
7 !> \file
8 !> The pmc_coagulation module.
9 
10 !> Aerosol particle coagulation.
12 
13  use pmc_bin_grid
14  use pmc_aero_data
15  use pmc_util
16  use pmc_stats
17  use pmc_env_state
18  use pmc_aero_state
19  use pmc_aero_weight
21  use pmc_mpi
22  use pmc_coag_kernel
23  use pmc_aero_sorted
24 #ifdef PMC_USE_MPI
25  use mpi
26 #endif
27 
28  !> Minimum number of coagulation events per large particle for which
29  !> accelerated coagulation is used.
30  real(kind=dp), parameter :: coag_accel_n_event = 1d0
31  !> Maximum allowed coefficient-of-variation due to undersampling in
32  !> accelerated coagulation.
33  real(kind=dp), parameter :: coag_accel_max_cv = 0.1d0
34  !> Maximum allowable growth factor of a target particle volume within one
35  !> timestep when using accelerated coagulation.
36  real(kind=dp), parameter :: max_allowable_growth_factor = 1.5d0
37 
38 contains
39 
40 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
41 
42  !> Do coagulation for time del_t.
43  subroutine mc_coag(coag_kernel_type, env_state, aero_data, aero_state, &
44  del_t, tot_n_samp, tot_n_coag)
45 
46  !> Coagulation kernel type.
47  integer, intent(in) :: coag_kernel_type
48  !> Environment state.
49  type(env_state_t), intent(in) :: env_state
50  !> Aerosol data.
51  type(aero_data_t), intent(in) :: aero_data
52  !> Aerosol state.
53  type(aero_state_t), intent(inout) :: aero_state
54  !> Timestep for coagulation.
55  real(kind=dp) :: del_t
56  !> Total number of samples tested.
57  integer, intent(out) :: tot_n_samp
58  !> Number of coagulation events.
59  integer, intent(out) :: tot_n_coag
60 
61  integer :: b1, b2, c1, c2, b2_start
62 
63  call aero_state_sort(aero_state, aero_data)
64  if (.not. aero_state%aero_sorted%coag_kernel_bounds_valid) then
65  call est_k_minmax_binned_unweighted(aero_state%aero_sorted%bin_grid, &
66  coag_kernel_type, aero_data, env_state, &
67  aero_state%aero_sorted%coag_kernel_min, &
68  aero_state%aero_sorted%coag_kernel_max)
69  aero_state%aero_sorted%coag_kernel_bounds_valid = .true.
70  end if
71 
72  tot_n_samp = 0
73  tot_n_coag = 0
74  do c1 = 1,aero_sorted_n_class(aero_state%aero_sorted)
75  do c2 = 1,c1
76  do b1 = 1,aero_sorted_n_bin(aero_state%aero_sorted)
77  if (integer_varray_n_entry( &
78  aero_state%aero_sorted%size_class%inverse(b1, c1)) == 0) &
79  cycle
80  if (c1 == c2) then
81  b2_start = b1
82  else
83  b2_start = 1
84  end if
85  do b2 = b2_start,aero_sorted_n_bin(aero_state%aero_sorted)
86  if (integer_varray_n_entry( &
87  aero_state%aero_sorted%size_class%inverse(b2, c2)) == 0) &
88  cycle
89  call mc_coag_for_bin(coag_kernel_type, env_state, aero_data, &
90  aero_state, del_t, tot_n_samp, tot_n_coag, b1, b2, c1, c2)
91  end do
92  end do
93  end do
94  end do
95 
96  end subroutine mc_coag
97 
98 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
99 
100  !> Do coagulation for time del_t for the given bins.
101  subroutine mc_coag_for_bin(coag_kernel_type, env_state, aero_data, &
102  aero_state, del_t, tot_n_samp, tot_n_coag, b1, b2, c1, c2)
103 
104  !> Coagulation kernel type.
105  integer, intent(in) :: coag_kernel_type
106  !> Environment state.
107  type(env_state_t), intent(in) :: env_state
108  !> Aerosol data.
109  type(aero_data_t), intent(in) :: aero_data
110  !> Aerosol state.
111  type(aero_state_t), intent(inout) :: aero_state
112  !> Timestep for coagulation.
113  real(kind=dp) :: del_t
114  !> Total number of samples tested.
115  integer, intent(inout) :: tot_n_samp
116  !> Number of coagulation events.
117  integer, intent(inout) :: tot_n_coag
118  !> First bin number.
119  integer, intent(in) :: b1
120  !> Second bin number.
121  integer, intent(in) :: b2
122  !> First weight class.
123  integer, intent(in) :: c1
124  !> Second weight class.
125  integer, intent(in) :: c2
126 
127  logical :: per_particle_coag_succeeded
128  integer :: cc
129  real(kind=dp) :: f_max, k_max
130 
131  cc = coag_dest_class(aero_state%awa, aero_data, &
132  aero_state%aero_sorted%bin_grid, b1, b2, c1, c2)
133  call max_coag_num_conc_factor(aero_state%awa, aero_data, &
134  aero_state%aero_sorted%bin_grid, b1, b2, c1, c2, cc, f_max)
135  k_max = aero_state%aero_sorted%coag_kernel_max(b1, b2) * f_max
136 
137  call try_per_particle_coag(coag_kernel_type, k_max, env_state, aero_data, &
138  aero_state, del_t, tot_n_samp, tot_n_coag, b1, b2, c1, c2, cc, &
139  per_particle_coag_succeeded)
140  if (per_particle_coag_succeeded) return
141 
142  call per_set_coag(coag_kernel_type, k_max, env_state, aero_data, &
143  aero_state, del_t, tot_n_samp, tot_n_coag, b1, b2, c1, c2, cc)
144 
145  end subroutine mc_coag_for_bin
146 
147 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
148 
149  !> Attempt per-particle coagulation.
150  subroutine try_per_particle_coag(coag_kernel_type, k_max, env_state, &
151  aero_data, aero_state, del_t, tot_n_samp, tot_n_coag, b1, b2, c1, c2, &
152  cc, per_particle_coag_succeeded)
153 
154  !> Coagulation kernel type.
155  integer, intent(in) :: coag_kernel_type
156  !> Maximum coagulation kernel (s^{-1} m^3).
157  real(kind=dp), intent(in) :: k_max
158  !> Environment state.
159  type(env_state_t), intent(in) :: env_state
160  !> Aerosol data.
161  type(aero_data_t), intent(in) :: aero_data
162  !> Aerosol state.
163  type(aero_state_t), intent(inout) :: aero_state
164  !> Timestep for coagulation.
165  real(kind=dp) :: del_t
166  !> Total number of samples tested.
167  integer, intent(inout) :: tot_n_samp
168  !> Number of coagulation events.
169  integer, intent(inout) :: tot_n_coag
170  !> First bin number.
171  integer, intent(in) :: b1
172  !> Second bin number.
173  integer, intent(in) :: b2
174  !> First weight class.
175  integer, intent(in) :: c1
176  !> Second weight class.
177  integer, intent(in) :: c2
178  !> Coagulated weight class.
179  integer, intent(in) :: cc
180  !> Whether we succeeded in doing per-particle coag.
181  logical, intent(inout) :: per_particle_coag_succeeded
182 
183  logical :: correct_weight_ordering
184  integer :: target_unif_entry, target_part, n_samp, n_coag, n_remove, bt, bs
185  integer :: ct, cs
186  real(kind=dp) :: n_source_per_target, accept_factor
187  real(kind=dp) :: min_target_vol, max_source_vol, max_new_target_vol
188  real(kind=dp) :: max_target_growth_factor
189  type(aero_particle_t) :: target_particle, source_particle
190 
191  call determine_target_and_source(aero_state%awa, &
192  aero_state%aero_sorted%bin_grid, b1, b2, c1, c2, cc, bt, bs, ct, cs, &
193  correct_weight_ordering)
194  if (.not. correct_weight_ordering) then
195  per_particle_coag_succeeded = .false.
196  return
197  end if
198 
199  call compute_n_source(integer_varray_n_entry( &
200  aero_state%aero_sorted%size_class%inverse(bs, cs)), k_max, del_t, &
201  n_source_per_target, accept_factor)
202  if (n_source_per_target < coag_accel_n_event) then
203  per_particle_coag_succeeded = .false.
204  return
205  end if
206 
207  min_target_vol = aero_data_rad2vol(aero_data, &
208  aero_state%aero_sorted%bin_grid%edges(bt))
209  max_source_vol = aero_data_rad2vol(aero_data, &
210  aero_state%aero_sorted%bin_grid%edges(bs+1))
211  max_new_target_vol = min_target_vol + max_source_vol * n_source_per_target
212  ! check for unacceptably large volume change
213  max_target_growth_factor = max_new_target_vol / min_target_vol
214  if (max_target_growth_factor > max_allowable_growth_factor) then
215  per_particle_coag_succeeded = .false.
216  return
217  end if
218 
219  ! work backwards to avoid particle movement issues
220  do target_unif_entry = integer_varray_n_entry( &
221  aero_state%aero_sorted%size_class%inverse(bt, ct)),1,-1
222  target_part = aero_state%aero_sorted%size_class%inverse(bt, &
223  ct)%entry(target_unif_entry)
224  ! need to copy coag_particle as the underlying storage may be
225  ! rearranged due to removals
226  target_particle = aero_state%apa%particle(target_part)
227  call sample_source_particle(aero_state, aero_data, env_state, &
228  coag_kernel_type, bs, cs, target_particle, n_source_per_target, &
229  accept_factor, n_samp, n_coag, n_remove, source_particle)
230  if (n_coag > 0) then
231  call coag_target_with_source(aero_state, aero_data, bt, ct, &
232  target_unif_entry, source_particle, cc)
233  end if
234  tot_n_samp = tot_n_samp + n_samp
235  tot_n_coag = tot_n_coag + n_coag
236  ! we discard n_remove information at present
237  end do
238 
239  per_particle_coag_succeeded = .true.
240 
241  end subroutine try_per_particle_coag
242 
243 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
244 
245  !> Determine the source and target particle bin/group for
246  !> per-particle coagulation, if possible.
247  subroutine determine_target_and_source(aero_weight_array, bin_grid, b1, &
248  b2, c1, c2, cc, bt, bs, ct, cs, correct_weight_ordering)
249 
250  !> Aero weight array.
251  type(aero_weight_array_t), intent(in) :: aero_weight_array
252  !> Bin grid.
253  type(bin_grid_t), intent(in) :: bin_grid
254  !> First bin number.
255  integer, intent(in) :: b1
256  !> Second bin number.
257  integer, intent(in) :: b2
258  !> First weight class.
259  integer, intent(in) :: c1
260  !> Second weight class.
261  integer, intent(in) :: c2
262  !> Coagulated weight class.
263  integer, intent(in) :: cc
264  !> Target bin number.
265  integer, intent(out) :: bt
266  !> Source bin number.
267  integer, intent(out) :: bs
268  !> Target weight class.
269  integer, intent(out) :: ct
270  !> Source weight class.
271  integer, intent(out) :: cs
272  !> Whether the weight ordering is correct for per-particle coagulation.
273  logical, intent(out) :: correct_weight_ordering
274 
275  real(kind=dp) :: nc1_min, nc1_max, nc2_min, nc2_max
276  logical :: monotone_increasing, monotone_decreasing
277 
278  call aero_weight_array_check_monotonicity(aero_weight_array, &
279  monotone_increasing, monotone_decreasing)
280  if (.not. monotone_decreasing) then
281  correct_weight_ordering = .false.
282  return
283  end if
284 
285  call aero_weight_array_minmax_num_conc(aero_weight_array, c1, &
286  bin_grid%edges(b1), bin_grid%edges(b1 + 1), nc1_min, nc1_max)
287  call aero_weight_array_minmax_num_conc(aero_weight_array, c2, &
288  bin_grid%edges(b2), bin_grid%edges(b2 + 1), nc2_min, nc2_max)
289 
290  ! we have already confirmed monotone_decreasing weights above
291  correct_weight_ordering = .false.
292  if ((nc1_max < nc2_min) .and. (cc == c1)) then
293  bt = b1
294  bs = b2
295  ct = c1
296  cs = c2
297  correct_weight_ordering = .true.
298  end if
299  if ((nc2_max < nc1_min) .and. (cc == c2)) then
300  bt = b2
301  bs = b1
302  ct = c2
303  cs = c1
304  correct_weight_ordering = .true.
305  end if
306 
307  end subroutine determine_target_and_source
308 
309 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
310 
311  subroutine compute_n_source(n_part, k_max, del_t, n_source_per_target, &
312  accept_factor)
313 
314  !> Number of particles available as partners.
315  integer, intent(in) :: n_part
316  !> Maximum coagulation kernel (s^{-1} m^3).
317  real(kind=dp), intent(in) :: k_max
318  !> Timestep (s).
319  real(kind=dp), intent(in) :: del_t
320  !> Mean number of source particles per target particle.
321  real(kind=dp), intent(out) :: n_source_per_target
322  !> Accept factor for samples.
323  real(kind=dp), intent(out) :: accept_factor
324 
325  n_source_per_target = k_max * del_t * real(n_part, kind=dp)
326  accept_factor = 1d0 / k_max
327 
328  end subroutine compute_n_source
329 
330 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
331 
332  !> Sample coagulation partners for a single coagulation event.
333  subroutine sample_source_particle(aero_state, aero_data, env_state, &
334  coag_kernel_type, bs, cs, coag_particle, n_samp_mean, &
335  accept_factor, n_samp, n_coag, n_remove, source_particle)
336 
337  !> Aerosol state.
338  type(aero_state_t), intent(inout) :: aero_state
339  !> Aerosol data.
340  type(aero_data_t), intent(in) :: aero_data
341  !> Environment state.
342  type(env_state_t), intent(in) :: env_state
343  !> Coagulation kernel type.
344  integer, intent(in) :: coag_kernel_type
345  !> Bin to sample particles from.
346  integer, intent(in) :: bs
347  !> Weight class to sample particles from.
348  integer, intent(in) :: cs
349  !> Aerosol particle that coagulation will be with.
350  type(aero_particle_t), intent(in) :: coag_particle
351  !> Mean number of samples to use.
352  real(kind=dp), intent(in) :: n_samp_mean
353  !> Probability factor of accepting samples.
354  real(kind=dp), intent(in) :: accept_factor
355  !> Number of samples used.
356  integer, intent(out) :: n_samp
357  !> Number of coagulations performed.
358  integer, intent(out) :: n_coag
359  !> Number of particles removed.
360  integer, intent(out) :: n_remove
361  !> Sampled average coagulation partner particle.
362  type(aero_particle_t), intent(inout) :: source_particle
363 
364  real(kind=dp) :: prob_remove_i, prob_remove_source_max
365  real(kind=dp) :: prob_coag, prob_coag_tot, prob_coag_mean
366  real(kind=dp) :: num_conc_i, num_conc_source_min, num_conc_target, k
367  real(kind=dp) :: vol_sq(aero_data_n_spec(aero_data))
368  real(kind=dp) :: vol_mean(aero_data_n_spec(aero_data))
369  real(kind=dp) :: vol_cv(aero_data_n_spec(aero_data)), vol_cv_max
370  real(kind=dp) :: mean_95_conf_cv
371  integer :: n_samp_remove, n_samp_extra, n_samp_total, n_avg, i_samp
372  integer :: i_unif_entry, i_part, target_id, new_bin, ct
373  type(aero_info_t) :: aero_info
374 
375  if (integer_varray_n_entry( &
376  aero_state%aero_sorted%size_class%inverse(bs, cs)) == 0) then
377  n_samp = 0
378  n_remove = 0
379  n_coag = 0
380  return
381  end if
382 
383  num_conc_target = aero_weight_array_num_conc(aero_state%awa, &
384  coag_particle, aero_data)
385  target_id = coag_particle%id
386  ct = coag_particle%weight_class
387 
388  num_conc_source_min = aero_weight_array_num_conc_at_radius( &
389  aero_state%awa, cs, aero_state%aero_sorted%bin_grid%edges(bs))
390  prob_remove_source_max = num_conc_target / num_conc_source_min
391  call assert(653606684, prob_remove_source_max <= 1d0)
392 
393  n_samp_remove = rand_poisson(prob_remove_source_max * n_samp_mean)
394  n_samp_extra = rand_poisson((1d0 - prob_remove_source_max) * n_samp_mean)
395  n_samp_total = n_samp_remove + n_samp_extra
396 
397  n_avg = 0
398  n_samp = 0
399  n_remove = 0
400  prob_coag_tot = 0d0
401  vol_sq = 0d0
402 
403  call aero_particle_zero(source_particle, aero_data)
404 
405  ! FIXME: Can't we just do n_samp = 1,n_samp_total and shift tests
406  ! to the end?
407  do i_samp = 1,n_samp_total
408  if (integer_varray_n_entry( &
409  aero_state%aero_sorted%size_class%inverse(bs, cs)) == 0) exit
410  if ((n_samp > n_samp_remove) .and. (n_avg >= 2)) then
411  vol_mean = source_particle%vol / real(n_avg, kind=dp)
412  where(vol_mean > 0d0) &
413  vol_cv = sqrt(vol_sq / real(n_avg, kind=dp) - (vol_mean)**2) &
414  / vol_mean
415  vol_cv_max = maxval(vol_cv)
416  mean_95_conf_cv = vol_cv_max / sqrt(real(n_avg, kind=dp)) &
417  * student_t_95_coeff(n_avg)
418  ! FIXME: We are using just the max of the diagonal of the
419  ! covariance matrix. Is this well-justified?
420  if (mean_95_conf_cv < coag_accel_max_cv) exit
421  end if
422  n_samp = n_samp + 1
423  ! FIXME: We are sampling with replacement. Is this a problem?
424  i_unif_entry = pmc_rand_int(integer_varray_n_entry( &
425  aero_state%aero_sorted%size_class%inverse(bs, cs)))
426  i_part = aero_state%aero_sorted%size_class%inverse(bs, &
427  cs)%entry(i_unif_entry)
428  ! re-get j_part as particle ordering may be changing
429  call num_conc_weighted_kernel(coag_kernel_type, &
430  aero_state%apa%particle(i_part), coag_particle, cs, ct, ct, &
431  aero_data, aero_state%awa, env_state, k)
432  prob_coag = k * accept_factor
433  prob_coag_tot = prob_coag_tot + prob_coag
434  if (pmc_random() < prob_coag) then
435  n_avg = n_avg + 1
436  call aero_particle_coagulate(source_particle, &
437  aero_state%apa%particle(i_part), source_particle)
438  vol_sq = vol_sq + aero_state%apa%particle(i_part)%vol**2
439  if (i_samp <= n_samp_remove) then
440  num_conc_i = aero_weight_array_num_conc(aero_state%awa, &
441  aero_state%apa%particle(i_part), aero_data)
442  prob_remove_i = num_conc_target / num_conc_i
443  if (pmc_random() < prob_remove_i / prob_remove_source_max) then
444  n_remove = n_remove + 1
445  aero_info%id = aero_state%apa%particle(i_part)%id
446  aero_info%action = aero_info_coag
447  aero_info%other_id = target_id
448  call aero_state_remove_particle_with_info(aero_state, &
449  i_part, aero_info)
450  end if
451  end if
452  end if
453  end do
454 
455  if (n_avg == 0) then
456  n_coag = 0
457  return
458  end if
459 
460  prob_coag_mean = prob_coag_tot / real(n_samp, kind=dp) ! note not n_avg
461  call warn_assert_msg(383983415, prob_coag_mean <= 1d0, &
462  "kernel upper bound estimation is too tight")
463  n_coag = rand_binomial(n_samp_total, prob_coag_mean)
464  source_particle%vol = source_particle%vol &
465  * (real(n_coag, kind=dp) / real(n_avg, kind=dp))
466 
467  end subroutine sample_source_particle
468 
469 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
470 
471  !> Coagulate a sampled source particle with a target particle.
472  subroutine coag_target_with_source(aero_state, aero_data, bt, ct, &
473  target_unif_entry, source_particle, cc)
474 
475  !> Aerosol state.
476  type(aero_state_t), intent(inout) :: aero_state
477  !> Aerosol data.
478  type(aero_data_t), intent(in) :: aero_data
479  !> Bin of coagulating particle.
480  integer, intent(in) :: bt
481  !> Weight class of coagulating particle.
482  integer, intent(in) :: ct
483  !> Entry-in-bin of coagulating particle.
484  integer, intent(in) :: target_unif_entry
485  !> Sampled particle to coagulate with.
486  type(aero_particle_t), intent(in) :: source_particle
487  !> Weight class for coagulated particle.
488  integer, intent(in) :: cc
489 
490  integer :: target_part, target_id, new_bin, new_group
491  real(kind=dp) :: old_num_conc_target, new_num_conc_target
492 
493  target_part = aero_state%aero_sorted%size_class%inverse(bt, &
494  ct)%entry(target_unif_entry)
495  target_id = aero_state%apa%particle(target_part)%id
496  old_num_conc_target = aero_weight_array_num_conc(aero_state%awa, &
497  aero_state%apa%particle(target_part), aero_data)
498  call aero_particle_coagulate(aero_state%apa%particle(target_part), &
499  source_particle, aero_state%apa%particle(target_part))
500  aero_state%apa%particle(target_part)%id = target_id
501  ! assign to a randomly chosen group
502  new_group = aero_weight_array_rand_group(aero_state%awa, cc, &
503  aero_particle_radius(aero_state%apa%particle(target_part), &
504  aero_data))
505  call aero_particle_set_weight(aero_state%apa%particle(target_part), &
506  new_group, cc)
507  ! fix bin due to composition changes
508  new_bin = aero_sorted_particle_in_bin(aero_state%aero_sorted, &
509  aero_state%apa%particle(target_part), aero_data)
510  if ((new_bin < 1) &
511  .or. (new_bin > bin_grid_size(aero_state%aero_sorted%bin_grid))) then
512  call die_msg(765620746, "particle outside of bin_grid: " &
513  // "try reducing the timestep del_t")
514  end if
515  call aero_sorted_move_particle(aero_state%aero_sorted, target_part, &
516  new_bin, new_group, cc)
517  ! Adjust particle number to account for weight changes
518  ! bt/target_group/target_entry are invalid, but
519  ! target_part is still good. We are treating all particles in all
520  ! groups together, and randomly reassigning between groups above,
521  ! so here we can't use aero_state_reweight_particle(), as that
522  ! assumes we are staying in the same weight group.
523  new_num_conc_target = aero_weight_array_num_conc(aero_state%awa, &
524  aero_state%apa%particle(target_part), aero_data)
525  call aero_state_dup_particle(aero_state, aero_data, target_part, &
526  old_num_conc_target / new_num_conc_target, random_weight_group=.true.)
527  ! we should only be doing this for decreasing weights
528  call assert(654300924, aero_state%apa%particle(target_part)%id &
529  == target_id)
530 
531  end subroutine coag_target_with_source
532 
533 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
534 
535  !> Do set-wise coagulation.
536  subroutine per_set_coag(coag_kernel_type, k_max, env_state, aero_data, &
537  aero_state, del_t, tot_n_samp, tot_n_coag, b1, b2, c1, c2, cc)
538 
539  !> Coagulation kernel type.
540  integer, intent(in) :: coag_kernel_type
541  !> Maximum coagulation kernel (s^{-1} m^3).
542  real(kind=dp), intent(in) :: k_max
543  !> Environment state.
544  type(env_state_t), intent(in) :: env_state
545  !> Aerosol data.
546  type(aero_data_t), intent(in) :: aero_data
547  !> Aerosol state.
548  type(aero_state_t), intent(inout) :: aero_state
549  !> Timestep for coagulation.
550  real(kind=dp) :: del_t
551  !> Total number of samples tested.
552  integer, intent(inout) :: tot_n_samp
553  !> Number of coagulation events.
554  integer, intent(inout) :: tot_n_coag
555  !> First bin number.
556  integer, intent(in) :: b1
557  !> Second bin number.
558  integer, intent(in) :: b2
559  !> First weight class.
560  integer, intent(in) :: c1
561  !> Second weight class.
562  integer, intent(in) :: c2
563  !> Coagulated weight class.
564  integer, intent(in) :: cc
565 
566  real(kind=dp) :: n_samp_mean, accept_factor
567  integer :: i_samp, n_samp, n1, n2
568  logical :: did_coag
569 
570  n1 = integer_varray_n_entry( &
571  aero_state%aero_sorted%size_class%inverse(b1, c1))
572  n2 = integer_varray_n_entry( &
573  aero_state%aero_sorted%size_class%inverse(b2, c2))
574  call compute_n_samp(n1, n2, ((b1 == b2) .and. (c1 == c2)), k_max, del_t, &
575  n_samp_mean, n_samp, accept_factor)
576  tot_n_samp = tot_n_samp + n_samp
577 
578  do i_samp = 1,n_samp
579  ! check we still have enough particles to coagulate
580  n1 = integer_varray_n_entry( &
581  aero_state%aero_sorted%size_class%inverse(b1, c1))
582  n2 = integer_varray_n_entry( &
583  aero_state%aero_sorted%size_class%inverse(b2, c2))
584  if (((n1 < 2) .and. (b1 == b2) .and. (c1 == c2)) &
585  .or. (n1 < 1) .or. (n2 < 1)) &
586  exit
587  call maybe_coag_pair(env_state, aero_data, aero_state, b1, b2, c1, c2, &
588  cc, coag_kernel_type, accept_factor, did_coag)
589  if (did_coag) tot_n_coag = tot_n_coag + 1
590  end do
591 
592  end subroutine per_set_coag
593 
594 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
595 
596  !> Compute the number of samples required for the pair of bins.
597  subroutine compute_n_samp(ni, nj, same_bin, k_max, del_t, n_samp_mean, &
598  n_samp, accept_factor)
599 
600  !> Number particles in first bin.
601  integer, intent(in) :: ni
602  !> Number particles in second bin.
603  integer, intent(in) :: nj
604  !> Whether first bin is second bin.
605  logical, intent(in) :: same_bin
606  !> Maximum kernel value (s^{-1} m^3).
607  real(kind=dp), intent(in) :: k_max
608  !> Timestep (s).
609  real(kind=dp), intent(in) :: del_t
610  !> Mean number of samples per timestep.
611  real(kind=dp), intent(out) :: n_samp_mean
612  !> Number of samples per timestep.
613  integer, intent(out) :: n_samp
614  !> Scale factor for accept probability (1).
615  real(kind=dp), intent(out) :: accept_factor
616 
617  real(kind=dp) :: r_samp
618  real(kind=dp) :: n_possible ! use real(kind=dp) to avoid integer overflow
619  ! could use integer*8 or integer(kind = 8)
620  ! or di = selected_int_kind(18), integer(kind=di)
621  ! to represent 10^{-18} to 10^{18}
622 
623  if (same_bin) then
624  ! don't change this to ni * (ni - 1) as the ni/nj distinction
625  ! is important for coagulation_dist, which also calls this
626  n_possible = real(ni, kind=dp) * (real(nj, kind=dp) - 1d0) / 2d0
627  else
628  n_possible = real(ni, kind=dp) * real(nj, kind=dp)
629  end if
630 
631  r_samp = k_max * del_t
632  n_samp_mean = r_samp * n_possible
633  n_samp = rand_poisson(n_samp_mean)
634  accept_factor = 1d0 / k_max
635 
636  ! possible variants:
637  ! A: accept_factor = 1d0 / k_max
638  ! B: accept_factor = del_t * n_possible / (n_samp * V)
639  ! timings of test suite as of 2010-12-22T17:12:14-0600:
640  ! A with n_samp = prob_round(n_samp_mean):
641  ! 159.82 162.18 156.28
642  ! A with n_samp = rand_poisson(n_samp_mean):
643  ! 151.93 158.38 174.74 157.65
644  ! B with n_samp = ceiling(n_samp_mean):
645  ! 196.06 200.23 192.41
646  ! B with n_samp = ceiling(n_samp_mean + 1 * sqrt(n_samp_mean)):
647  ! 189.78 211.12 195.19
648  ! B with n_samp = ceiling(n_samp_mean + 3 * sqrt(n_samp_mean)):
649  ! 214.60 201.25 203.55
650 
651  end subroutine compute_n_samp
652 
653 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
654 
655  !> Choose a random pair for potential coagulation and test its
656  !> probability of coagulation. If it happens, do the coagulation and
657  !> update all structures.
658  !!
659  !! The probability of a coagulation will be taken as <tt>(kernel /
660  !! k_max)</tt>.
661  subroutine maybe_coag_pair(env_state, aero_data, aero_state, b1, b2, &
662  c1, c2, cc, coag_kernel_type, accept_factor, did_coag)
663 
664  !> Environment state.
665  type(env_state_t), intent(in) :: env_state
666  !> Aerosol data.
667  type(aero_data_t), intent(in) :: aero_data
668  !> Aerosol state.
669  type(aero_state_t), intent(inout) :: aero_state
670  !> Bin of first particle.
671  integer, intent(in) :: b1
672  !> Bin of second particle.
673  integer, intent(in) :: b2
674  !> First weight class.
675  integer, intent(in) :: c1
676  !> Second weight class.
677  integer, intent(in) :: c2
678  !> Coagulated weight class.
679  integer, intent(in) :: cc
680  !> Coagulation kernel type.
681  integer, intent(in) :: coag_kernel_type
682  !> Scale factor for accept probability (1).
683  real(kind=dp), intent(in) :: accept_factor
684  !> Whether a coagulation occured.
685  logical, intent(out) :: did_coag
686 
687  integer :: i1, i2
688  integer :: p1, p2
689  real(kind=dp) :: p, k
690 
691  call find_rand_pair(aero_state%aero_sorted, b1, b2, c1, c2, i1, i2)
692  p1 = aero_state%aero_sorted%size_class%inverse(b1, c1)%entry(i1)
693  p2 = aero_state%aero_sorted%size_class%inverse(b2, c2)%entry(i2)
694  call num_conc_weighted_kernel(coag_kernel_type, &
695  aero_state%apa%particle(p1), aero_state%apa%particle(p2), &
696  c1, c2, cc, aero_data, aero_state%awa, env_state, k)
697  p = k * accept_factor
698  call warn_assert_msg(532446093, p <= 1d0, &
699  "kernel upper bound estimation is too tight, " &
700  // "could be caused by changing env_state")
701 
702  did_coag = .false.
703  if (pmc_random() .lt. p) then
704  call coagulate(aero_data, aero_state, p1, p2, c1, c2, cc)
705  did_coag = .true.
706  end if
707 
708  end subroutine maybe_coag_pair
709 
710 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
711 
712  !> Given <tt>(b1, c1)</tt> and <tt>(b2, c2)</tt>, find a random pair
713  !> of particles <tt>(b1, c1, i1)</tt> and <tt>(b2, c2, i2)</tt> that
714  !> are not the same particle particle as each other.
715  subroutine find_rand_pair(aero_sorted, b1, b2, c1, c2, i1, i2)
716 
717  !> Aerosol sorted data.
718  type(aero_sorted_t), intent(in) :: aero_sorted
719  !> Bin number of first particle.
720  integer, intent(in) :: b1
721  !> Bin number of second particle.
722  integer, intent(in) :: b2
723  !> Weight class of first particle.
724  integer, intent(in) :: c1
725  !> Weight class of second particle.
726  integer, intent(in) :: c2
727  !> First rand particle.
728  integer, intent(out) :: i1
729  !> Second rand particle.
730  integer, intent(out) :: i2
731 
732  call assert(619608562, &
733  integer_varray_n_entry(aero_sorted%size_class%inverse(b1, c1)) >= 1)
734  i1 = pmc_rand_int( &
735  integer_varray_n_entry(aero_sorted%size_class%inverse(b1, c1)))
736 
737  if ((b1 == b2) .and. (c1 == c2)) then
738  call assert(956184336, integer_varray_n_entry( &
739  aero_sorted%size_class%inverse(b2, c2)) >= 2)
740  i2 = pmc_rand_int( &
741  integer_varray_n_entry(aero_sorted%size_class%inverse(b2, c2)) - 1)
742  if (i2 == i1) then
743  i2 = integer_varray_n_entry(aero_sorted%size_class%inverse(b2, c2))
744  end if
745  else
746  call assert(271635751, integer_varray_n_entry( &
747  aero_sorted%size_class%inverse(b2, c2)) >= 1)
748  i2 = pmc_rand_int( &
749  integer_varray_n_entry(aero_sorted%size_class%inverse(b2, c2)))
750  end if
751 
752  end subroutine find_rand_pair
753 
754 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
755 
756  !> Actually coagulate pt1 and pt2 to form ptc and compute weighting
757  !> effects, including which particles should be lost and which
758  !> gained.
759  subroutine coagulate_weighting(pt1, pt2, ptc, c1, c2, cc, aero_data, &
760  aero_weight_array, remove_1, remove_2, create_new, id_1_lost, &
761  id_2_lost, aero_info_1, aero_info_2)
762 
763  !> First coagulating aerosol particle.
764  type(aero_particle_t), intent(in) :: pt1
765  !> Second coagulating aerosol particle.
766  type(aero_particle_t), intent(in) :: pt2
767  !> Combined aerosol particle resulting from coagulation of pt1
768  !> and pt2.
769  type(aero_particle_t), intent(inout) :: ptc
770  !> First weight class.
771  integer, intent(in) :: c1
772  !> Second weight class.
773  integer, intent(in) :: c2
774  !> Coagulated weight class.
775  integer, intent(in) :: cc
776  !> Aerosol data.
777  type(aero_data_t), intent(in) :: aero_data
778  !> Aerosol weight array.
779  type(aero_weight_array_t), intent(in) :: aero_weight_array
780  !> Whether to remove pt1.
781  logical, intent(out) :: remove_1
782  !> Whether to remove pt2.
783  logical, intent(out) :: remove_2
784  !> Whether to create ptc.
785  logical, intent(out) :: create_new
786  !> Whether the ID of pt1 will be lost due to coagulation.
787  logical, intent(out) :: id_1_lost
788  !> Whether the ID of pt2 will be lost due to coagulation.
789  logical, intent(out) :: id_2_lost
790  !> The removal information associated with pt1.
791  type(aero_info_t), intent(inout) :: aero_info_1
792  !> The removal information associated with pt2.
793  type(aero_info_t), intent(inout) :: aero_info_2
794 
795  real(kind=dp) :: r1, r2, rc, nc_min, nc1, nc2, ncc
796  real(kind=dp) :: prob_remove_1, prob_remove_2, prob_create_new
797  integer :: info_other_id, new_group
798 
799  call assert(371947172, pt1%id /= pt2%id)
800 
801  ! decide which old particles are to be removed and whether to
802  ! create the resulting coagulated particle
803  r1 = aero_particle_radius(pt1, aero_data)
804  r2 = aero_particle_radius(pt2, aero_data)
805  rc = aero_data_vol2rad(aero_data, aero_data_rad2vol(aero_data, r1) &
806  + aero_data_rad2vol(aero_data, r2))
807  nc1 = aero_weight_array_num_conc_at_radius(aero_weight_array, c1, r1)
808  nc2 = aero_weight_array_num_conc_at_radius(aero_weight_array, c2, r2)
809  ncc = aero_weight_array_num_conc_at_radius(aero_weight_array, cc, rc)
810  new_group = aero_weight_array_rand_group(aero_weight_array, cc, rc)
811  nc_min = min(nc1, nc2, ncc)
812  prob_remove_1 = nc_min / nc1
813  prob_remove_2 = nc_min / nc2
814  prob_create_new = nc_min / ncc
815  remove_1 = (pmc_random() < prob_remove_1)
816  ! FIXME
817  !if (aero_weight%type == AERO_WEIGHT_TYPE_MFA) then
818  ! remove_2 = .not. remove_1
819  !else
820  remove_2 = (pmc_random() < prob_remove_2)
821  !end if
822  create_new = (pmc_random() < prob_create_new)
823 
824  ! figure out what to do about the ID numbers of the various
825  ! particles --- we try to preserve particle IDs as much as
826  ! possible
827  if (create_new) then
828  id_1_lost = .false.
829  id_2_lost = .false.
830  if (remove_1 .and. remove_2) then
831  if (aero_particle_volume(pt1) > aero_particle_volume(pt2)) then
832  id_2_lost = .true.
833  else
834  id_1_lost = .true.
835  end if
836  end if
837  else
838  id_1_lost = remove_1
839  id_2_lost = remove_2
840  end if
841 
842  ! create a new particle and set its ID
843  if (create_new) then
844  call aero_particle_coagulate(pt1, pt2, ptc)
845  call aero_particle_set_weight(ptc, new_group, cc)
846  if (remove_1 .and. (.not. id_1_lost)) then
847  ptc%id = pt1%id
848  call assert(975059559, id_2_lost .eqv. remove_2)
849  elseif (remove_2 .and. (.not. id_2_lost)) then
850  ptc%id = pt2%id
851  call assert(246529753, id_1_lost .eqv. remove_1)
852  else
853  call aero_particle_new_id(ptc)
854  call assert(852038606, id_1_lost .eqv. remove_1)
855  call assert(254018921, id_2_lost .eqv. remove_2)
856  end if
857  info_other_id = ptc%id
858  else
859  info_other_id = 0
860  end if
861 
862  aero_info_1%id = pt1%id
863  aero_info_1%action = aero_info_coag
864  aero_info_1%other_id = info_other_id
865 
866  aero_info_2%id = pt2%id
867  aero_info_2%action = aero_info_coag
868  aero_info_2%other_id = info_other_id
869 
870  end subroutine coagulate_weighting
871 
872 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
873 
874  !> Join together particles \c p1 and \c p2, updating all particle
875  !> and bin structures to reflect the change.
876  subroutine coagulate(aero_data, aero_state, p1, p2, c1, c2, cc)
877 
878  !> Aerosol data.
879  type(aero_data_t), intent(in) :: aero_data
880  !> Aerosol state.
881  type(aero_state_t), intent(inout) :: aero_state
882  !> First particle index.
883  integer, intent(in) :: p1
884  !> Second particle index.
885  integer, intent(in) :: p2
886  !> First weight class.
887  integer, intent(in) :: c1
888  !> Second weight class.
889  integer, intent(in) :: c2
890  !> Coagulated weight class.
891  integer, intent(in) :: cc
892 
893  type(aero_particle_t) :: ptc
894  integer :: bn
895  type(aero_info_t) :: aero_info_1, aero_info_2
896  logical :: remove_1, remove_2, create_new, id_1_lost, id_2_lost
897 
898  call coagulate_weighting(aero_state%apa%particle(p1), &
899  aero_state%apa%particle(p2), ptc, c1, c2, cc, aero_data, &
900  aero_state%awa, remove_1, remove_2, create_new, id_1_lost, &
901  id_2_lost, aero_info_1, aero_info_2)
902 
903  ! remove old particles
904  if (p2 > p1) then
905  ! handle a tricky corner case where we have to watch for p2 or
906  ! p1 being the last entry in the array and being repacked when
907  ! the other one is removed
908  if (remove_2) then
909  call aero_state_remove_particle(aero_state, p2, &
910  id_2_lost, aero_info_2)
911  end if
912  if (remove_1) then
913  call aero_state_remove_particle(aero_state, p1, &
914  id_1_lost, aero_info_1)
915  end if
916  else
917  if (remove_1) then
918  call aero_state_remove_particle(aero_state, p1, &
919  id_1_lost, aero_info_1)
920  end if
921  if (remove_2) then
922  call aero_state_remove_particle(aero_state, p2, &
923  id_2_lost, aero_info_2)
924  end if
925  end if
926 
927  ! add new particle
928  if (create_new) then
929  call aero_state_add_particle(aero_state, ptc, aero_data, &
930  allow_resort=.false.)
931  end if
932 
933  end subroutine coagulate
934 
935 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
936 
937 end module pmc_coagulation
pmc_coagulation::sample_source_particle
subroutine sample_source_particle(aero_state, aero_data, env_state, coag_kernel_type, bs, cs, coag_particle, n_samp_mean, accept_factor, n_samp, n_coag, n_remove, source_particle)
Sample coagulation partners for a single coagulation event.
Definition: coagulation.F90:336
pmc_aero_state::aero_state_remove_particle
subroutine aero_state_remove_particle(aero_state, i_part, record_removal, aero_info)
Remove the given particle and possibly record the removal.
Definition: aero_state.F90:400
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_coagulation::coagulate_weighting
subroutine coagulate_weighting(pt1, pt2, ptc, c1, c2, cc, aero_data, aero_weight_array, remove_1, remove_2, create_new, id_1_lost, id_2_lost, aero_info_1, aero_info_2)
Actually coagulate pt1 and pt2 to form ptc and compute weighting effects, including which particles s...
Definition: coagulation.F90:762
pmc_mpi
Wrapper functions for MPI.
Definition: mpi.F90:13
pmc_aero_weight
The aero_weight_t structure and associated subroutines.
Definition: aero_weight.F90:9
pmc_coagulation::determine_target_and_source
subroutine determine_target_and_source(aero_weight_array, bin_grid, b1, b2, c1, c2, cc, bt, bs, ct, cs, correct_weight_ordering)
Determine the source and target particle bin/group for per-particle coagulation, if possible.
Definition: coagulation.F90:249
pmc_aero_sorted::aero_sorted_particle_in_bin
integer function aero_sorted_particle_in_bin(aero_sorted, aero_particle, aero_data)
Find the bin number that contains a given particle.
Definition: aero_sorted.F90:380
pmc_rand::rand_poisson
integer function rand_poisson(mean)
Generate a Poisson-distributed random number with the given mean.
Definition: rand.F90:253
pmc_aero_weight_array::aero_weight_array_check_monotonicity
subroutine aero_weight_array_check_monotonicity(aero_weight_array, monotone_increasing, monotone_decreasing)
Determine whether all weight functions in an array are monotone increasing, monotone decreasing,...
Definition: aero_weight_array.F90:306
pmc_coagulation::maybe_coag_pair
subroutine maybe_coag_pair(env_state, aero_data, aero_state, b1, b2, c1, c2, cc, coag_kernel_type, accept_factor, did_coag)
Choose a random pair for potential coagulation and test its probability of coagulation....
Definition: coagulation.F90:663
pmc_util::warn_assert_msg
subroutine warn_assert_msg(code, condition_ok, warning_msg)
Prints a warning message if condition_ok is false.
Definition: util.F90:59
pmc_util::die_msg
subroutine die_msg(code, error_msg)
Error immediately.
Definition: util.F90:134
pmc_aero_sorted::aero_sorted_n_bin
integer function aero_sorted_n_bin(aero_sorted)
Returns the number of size bins.
Definition: aero_sorted.F90:81
pmc_constants::dp
integer, parameter dp
Kind of a double precision real number.
Definition: constants.F90:12
pmc_coag_kernel
Generic coagulation kernel.
Definition: coag_kernel.F90:9
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_aero_weight_array
The aero_weight_array_t structure and associated subroutines.
Definition: aero_weight_array.F90:10
pmc_coagulation::coag_accel_max_cv
real(kind=dp), parameter coag_accel_max_cv
Maximum allowed coefficient-of-variation due to undersampling in accelerated coagulation.
Definition: coagulation.F90:33
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_util::assert
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
Definition: util.F90:103
pmc_aero_state
The aero_state_t structure and assocated subroutines.
Definition: aero_state.F90:9
pmc_aero_weight_array::aero_weight_array_t
An array of aerosol size distribution weighting functions.
Definition: aero_weight_array.F90:35
pmc_coagulation::compute_n_source
subroutine compute_n_source(n_part, k_max, del_t, n_source_per_target, accept_factor)
Definition: coagulation.F90:313
pmc_rand::pmc_rand_int
integer function pmc_rand_int(n)
Returns a random integer between 1 and n.
Definition: rand.F90:173
pmc_coagulation::find_rand_pair
subroutine find_rand_pair(aero_sorted, b1, b2, c1, c2, i1, i2)
Given (b1, c1) and (b2, c2), find a random pair of particles (b1, c1, i1) and (b2,...
Definition: coagulation.F90:716
pmc_aero_weight_array::aero_weight_array_num_conc
real(kind=dp) function aero_weight_array_num_conc(aero_weight_array, aero_particle, aero_data)
Compute the number concentration for a particle (m^{-3}).
Definition: aero_weight_array.F90:259
pmc_aero_weight_array::aero_weight_array_num_conc_at_radius
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).
Definition: aero_weight_array.F90:234
pmc_coagulation::coag_target_with_source
subroutine coag_target_with_source(aero_state, aero_data, bt, ct, target_unif_entry, source_particle, cc)
Coagulate a sampled source particle with a target particle.
Definition: coagulation.F90:474
pmc_coagulation
Aerosol particle coagulation.
Definition: coagulation.F90:11
pmc_coagulation::coag_accel_n_event
real(kind=dp), parameter coag_accel_n_event
Minimum number of coagulation events per large particle for which accelerated coagulation is used.
Definition: coagulation.F90:30
pmc_aero_state::aero_state_remove_particle_with_info
subroutine aero_state_remove_particle_with_info(aero_state, i_part, aero_info)
Remove the given particle and record the removal.
Definition: aero_state.F90:381
pmc_coagulation::per_set_coag
subroutine per_set_coag(coag_kernel_type, k_max, env_state, aero_data, aero_state, del_t, tot_n_samp, tot_n_coag, b1, b2, c1, c2, cc)
Do set-wise coagulation.
Definition: coagulation.F90:538
pmc_coagulation::compute_n_samp
subroutine compute_n_samp(ni, nj, same_bin, k_max, del_t, n_samp_mean, n_samp, accept_factor)
Compute the number of samples required for the pair of bins.
Definition: coagulation.F90:599
pmc_aero_state::aero_state_dup_particle
subroutine aero_state_dup_particle(aero_state, aero_data, i_part, n_part_mean, random_weight_group)
Add copies or remove a particle, with a given mean number of resulting particles.
Definition: aero_state.F90:461
pmc_coag_kernel::est_k_minmax_binned_unweighted
subroutine est_k_minmax_binned_unweighted(bin_grid, coag_kernel_type, aero_data, env_state, k_min, k_max)
Estimate an array of minimum and maximum kernel values. Given particles v1 in bin b1 and v2 in bin b2...
Definition: coag_kernel.F90:255
pmc_aero_weight_array::aero_weight_array_rand_group
integer function aero_weight_array_rand_group(aero_weight_array, i_class, radius)
Choose a random group at the given radius, with probability inversely proportional to group weight at...
Definition: aero_weight_array.F90:376
pmc_env_state
The env_state_t structure and associated subroutines.
Definition: env_state.F90:9
pmc_aero_sorted
The aero_sorted_t structure and assocated subroutines.
Definition: aero_sorted.F90:9
pmc_aero_data::aero_data_vol2rad
real(kind=dp) elemental function aero_data_vol2rad(aero_data, v)
Convert mass-equivalent volume (m^3) to geometric radius (m).
Definition: aero_data.F90:92
pmc_aero_weight_array::aero_weight_array_minmax_num_conc
subroutine aero_weight_array_minmax_num_conc(aero_weight_array, i_class, radius_1, radius_2, num_conc_min, num_conc_max)
Compute the maximum and minimum number concentrations between the given radii.
Definition: aero_weight_array.F90:340
pmc_coagulation::mc_coag
subroutine mc_coag(coag_kernel_type, env_state, aero_data, aero_state, del_t, tot_n_samp, tot_n_coag)
Do coagulation for time del_t.
Definition: coagulation.F90:45
pmc_aero_data::aero_data_t
Aerosol material properties and associated data.
Definition: aero_data.F90:49
pmc_aero_sorted::aero_sorted_t
Sorting of particles into bins.
Definition: aero_sorted.F90:47
pmc_stats::student_t_95_coeff
real(kind=dp) function student_t_95_coeff(n_sample)
Return a fairly tight upper-bound on the Student's t coefficient for the 95% confidence interval.
Definition: stats.F90:511
pmc_util
Common utility subroutines.
Definition: util.F90:9
pmc_coagulation::mc_coag_for_bin
subroutine mc_coag_for_bin(coag_kernel_type, env_state, aero_data, aero_state, del_t, tot_n_samp, tot_n_coag, b1, b2, c1, c2)
Do coagulation for time del_t for the given bins.
Definition: coagulation.F90:103
pmc_coagulation::coagulate
subroutine coagulate(aero_data, aero_state, p1, p2, c1, c2, cc)
Join together particles p1 and p2, updating all particle and bin structures to reflect the change.
Definition: coagulation.F90:877
pmc_coag_kernel::coag_dest_class
integer function coag_dest_class(aero_weight_array, aero_data, bin_grid, i_bin, j_bin, i_class, j_class)
Determine the weight class in which coagulated particles will be placed.
Definition: coag_kernel.F90:384
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_coagulation::max_allowable_growth_factor
real(kind=dp), parameter max_allowable_growth_factor
Maximum allowable growth factor of a target particle volume within one timestep when using accelerate...
Definition: coagulation.F90:36
pmc_aero_sorted::aero_sorted_n_class
integer function aero_sorted_n_class(aero_sorted)
Returns the number of weight classes.
Definition: aero_sorted.F90:105
pmc_coag_kernel::max_coag_num_conc_factor
subroutine max_coag_num_conc_factor(aero_weight_array, aero_data, bin_grid, i_bin, j_bin, i_class, j_class, ij_class, f_max)
Determine the minimum and maximum number concentration factors for coagulation.
Definition: coag_kernel.F90:424
pmc_bin_grid::bin_grid_t
1D grid, either logarithmic or linear.
Definition: bin_grid.F90:33
pmc_stats
The stats_t type and associated subroutines.
Definition: stats.F90:9
pmc_coag_kernel::num_conc_weighted_kernel
subroutine num_conc_weighted_kernel(coag_kernel_type, aero_particle_1, aero_particle_2, i_class, j_class, ij_class, aero_data, aero_weight_array, env_state, k)
Compute the kernel value with the given number concentration weighting.
Definition: coag_kernel.F90:178
pmc_rand::rand_binomial
integer function rand_binomial(n, p)
Generate a Binomial-distributed random number with the given parameters.
Definition: rand.F90:320
pmc_aero_state::aero_state_t
The current collection of aerosol particles.
Definition: aero_state.F90:63
pmc_aero_state::aero_state_sort
subroutine aero_state_sort(aero_state, aero_data, bin_grid, all_procs_same)
Sorts the particles if necessary.
Definition: aero_state.F90:2939
pmc_rand::pmc_random
real(kind=dp) function pmc_random()
Returns a random number between 0 and 1.
Definition: rand.F90:139
pmc_aero_sorted::aero_sorted_move_particle
subroutine aero_sorted_move_particle(aero_sorted, i_part, new_bin, new_group, new_class)
Move a particle to a different bin and group.
Definition: aero_sorted.F90:477
pmc_coagulation::try_per_particle_coag
subroutine try_per_particle_coag(coag_kernel_type, k_max, env_state, aero_data, aero_state, del_t, tot_n_samp, tot_n_coag, b1, b2, c1, c2, cc, per_particle_coag_succeeded)
Attempt per-particle coagulation.
Definition: coagulation.F90:153