source: palm/trunk/SOURCE/lpm_droplet_collision.f90 @ 1878

Last change on this file since 1878 was 1861, checked in by hoffmann, 9 years ago

last commit documented

  • Property svn:keywords set to Id
File size: 22.6 KB
RevLine 
[1682]1!> @file lpm_droplet_collision.f90
[1036]2!--------------------------------------------------------------------------------!
3! This file is part of PALM.
4!
5! PALM is free software: you can redistribute it and/or modify it under the terms
6! of the GNU General Public License as published by the Free Software Foundation,
7! either version 3 of the License, or (at your option) any later version.
8!
9! PALM is distributed in the hope that it will be useful, but WITHOUT ANY
10! WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11! A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
12!
13! You should have received a copy of the GNU General Public License along with
14! PALM. If not, see <http://www.gnu.org/licenses/>.
15!
[1818]16! Copyright 1997-2016 Leibniz Universitaet Hannover
[1036]17!--------------------------------------------------------------------------------!
18!
[849]19! Current revisions:
20! ------------------
[1823]21!
[1861]22!
[1321]23! Former revisions:
24! -----------------
25! $Id: lpm_droplet_collision.f90 1861 2016-04-13 13:22:08Z hellstea $
26!
[1861]27! 1860 2016-04-13 13:21:28Z hoffmann
28! Interpolation of dissipation rate adjusted to more reasonable values.
29!
[1823]30! 1822 2016-04-07 07:49:42Z hoffmann
31! Integration of a new collision algortithm based on Shima et al. (2009) and
32! Soelch and Kaercher (2010) called all_or_nothing. The previous implemented
33! collision algorithm is called average_impact. Moreover, both algorithms are
34! now positive definit due to their construction, i.e., no negative weighting
35! factors should occur.
36!
[1683]37! 1682 2015-10-07 23:56:08Z knoop
38! Code annotations made doxygen readable
39!
[1360]40! 1359 2014-04-11 17:15:14Z hoffmann
41! New particle structure integrated.
42! Kind definition added to all floating point numbers.
43!
[1323]44! 1322 2014-03-20 16:38:49Z raasch
45! REAL constants defined as wp_kind
46!
[1321]47! 1320 2014-03-20 08:40:49Z raasch
[1320]48! ONLY-attribute added to USE-statements,
49! kind-parameters added to all INTEGER and REAL declaration statements,
50! kinds are defined in new module kinds,
51! revision history before 2012 removed,
52! comment fields (!:) to be used for variable explanations added to
53! all variable declaration statements
[1072]54!
[1093]55! 1092 2013-02-02 11:24:22Z raasch
56! unused variables removed
57!
[1072]58! 1071 2012-11-29 16:54:55Z franke
[1071]59! Calculation of Hall and Wang kernel now uses collision-coalescence formulation
60! proposed by Wang instead of the continuous collection equation (for more
61! information about new method see PALM documentation)
62! Bugfix: message identifiers added
[849]63!
[1037]64! 1036 2012-10-22 13:43:42Z raasch
65! code put under GPL (PALM 3.9)
66!
[850]67! 849 2012-03-15 10:35:09Z raasch
68! initial revision (former part of advec_particles)
[849]69!
[850]70!
[849]71! Description:
72! ------------
[1682]73!> Calculates change in droplet radius by collision. Droplet collision is
74!> calculated for each grid box seperately. Collision is parameterized by
[1822]75!> using collision kernels. Two different kernels are available:
[1682]76!> Hall kernel: Kernel from Hall (1980, J. Atmos. Sci., 2486-2507), which
77!>              considers collision due to pure gravitational effects.
78!> Wang kernel: Beside gravitational effects (treated with the Hall-kernel) also
79!>              the effects of turbulence on the collision are considered using
80!>              parameterizations of Ayala et al. (2008, New J. Phys., 10,
81!>              075015) and Wang and Grabowski (2009, Atmos. Sci. Lett., 10,
82!>              1-8). This kernel includes three possible effects of turbulence:
83!>              the modification of the relative velocity between the droplets,
84!>              the effect of preferential concentration, and the enhancement of
85!>              collision efficiencies.
[849]86!------------------------------------------------------------------------------!
[1682]87 SUBROUTINE lpm_droplet_collision (i,j,k)
88 
[849]89
[1359]90
[1320]91    USE arrays_3d,                                                             &
[1822]92        ONLY:  diss, ql_v, ql_vp
[849]93
[1320]94    USE cloud_parameters,                                                      &
[1822]95        ONLY:  rho_l
[1320]96
97    USE constants,                                                             &
98        ONLY:  pi
99
100    USE control_parameters,                                                    &
[1822]101        ONLY:  dt_3d, message_string, dz
[1320]102
103    USE cpulog,                                                                &
104        ONLY:  cpu_log, log_point_s
105
106    USE grid_variables,                                                        &
[1822]107        ONLY:  dx, dy
[1320]108
109    USE kinds
110
111    USE lpm_collision_kernels_mod,                                             &
[1822]112        ONLY:  ckernel, recalculate_kernel
[1320]113
114    USE particle_attributes,                                                   &
[1822]115        ONLY:  all_or_nothing, average_impact, dissipation_classes,            &
116               hall_kernel, iran_part, number_of_particles, particles,         &
117               particle_type, prt_count, use_kernel_tables, wang_kernel
[1320]118
[1822]119    USE random_function_mod,                                                   &
120        ONLY:  random_function
121
[1359]122    USE pegrid
123
[849]124    IMPLICIT NONE
125
[1682]126    INTEGER(iwp) ::  eclass   !<
127    INTEGER(iwp) ::  i        !<
128    INTEGER(iwp) ::  j        !<
129    INTEGER(iwp) ::  k        !<
130    INTEGER(iwp) ::  n        !<
[1822]131    INTEGER(iwp) ::  m        !<
[1682]132    INTEGER(iwp) ::  rclass_l !<
133    INTEGER(iwp) ::  rclass_s !<
[849]134
[1822]135    REAL(wp) ::  collection_probability  !< probability for collection
136    REAL(wp) ::  ddV                     !< inverse grid box volume
137    REAL(wp) ::  epsilon                 !< dissipation rate
138    REAL(wp) ::  factor_volume_to_mass   !< 4.0 / 3.0 * pi * rho_l
139    REAL(wp) ::  xm                      !< mean mass of droplet m
140    REAL(wp) ::  xn                      !< mean mass of droplet n
[1359]141
[1822]142    REAL(wp), DIMENSION(:), ALLOCATABLE ::  weight  !< weighting factor
143    REAL(wp), DIMENSION(:), ALLOCATABLE ::  mass    !< total mass of super droplet
[1359]144
[849]145    CALL cpu_log( log_point_s(43), 'lpm_droplet_coll', 'start' )
146
[1822]147    number_of_particles   = prt_count(k,j,i)
148    factor_volume_to_mass = 4.0_wp / 3.0_wp * pi * rho_l 
149    ddV                   = 1 / ( dx * dy * dz )
[849]150!
[1822]151!-- Collision requires at least one super droplet inside the box
152    IF ( number_of_particles > 0 )  THEN
[849]153
154!
[1359]155!--    Now apply the different kernels
[1822]156       IF ( use_kernel_tables )  THEN
[849]157!
[1822]158!--       Fast method with pre-calculated collection kernels for
[1359]159!--       discrete radius- and dissipation-classes.
160!--
161!--       Determine dissipation class index of this gridbox
162          IF ( wang_kernel )  THEN
[1860]163             eclass = INT( diss(k,j,i) * 1.0E4_wp / 600.0_wp * &
[1359]164                           dissipation_classes ) + 1
165             epsilon = diss(k,j,i)
166          ELSE
167             epsilon = 0.0_wp
168          ENDIF
169          IF ( hall_kernel  .OR.  epsilon * 1.0E4_wp < 0.001_wp )  THEN
170             eclass = 0   ! Hall kernel is used
171          ELSE
172             eclass = MIN( dissipation_classes, eclass )
173          ENDIF
174
[849]175!
[1359]176!--       Droplet collision are calculated using collision-coalescence
177!--       formulation proposed by Wang (see PALM documentation)
[1822]178!--       Temporary fields for total mass of super-droplet and weighting factors
179!--       are allocated.
180          ALLOCATE(mass(1:number_of_particles), weight(1:number_of_particles))
[849]181
[1822]182          mass(1:number_of_particles)   = particles(1:number_of_particles)%weight_factor * &
183                                          particles(1:number_of_particles)%radius**3     * &
184                                          factor_volume_to_mass
185          weight(1:number_of_particles) = particles(1:number_of_particles)%weight_factor
[849]186
[1822]187          IF ( average_impact )  THEN  ! select collision algorithm
[1071]188
[1822]189             DO  n = 1, number_of_particles
[1071]190
[1822]191                rclass_l = particles(n)%class
192                xn       = mass(n) / weight(n)
[849]193
[1822]194                DO  m = n, number_of_particles
[849]195
[1822]196                   rclass_s = particles(m)%class
197                   xm       = mass(m) / weight(m)
[849]198
[1822]199                   IF ( xm .LT. xn )  THEN
200                     
201!
202!--                   Particle n collects smaller particle m
203                      collection_probability = ckernel(rclass_l,rclass_s,eclass) * &
204                                               weight(n) * ddV * dt_3d
[849]205
[1822]206                      mass(n)   = mass(n)   + mass(m)   * collection_probability
207                      weight(m) = weight(m) - weight(m) * collection_probability
208                      mass(m)   = mass(m)   - mass(m)   * collection_probability
209                   ELSEIF ( xm .GT. xn )  THEN 
[849]210!
[1822]211!--                   Particle m collects smaller particle n
212                      collection_probability = ckernel(rclass_l,rclass_s,eclass) * &
213                                               weight(m) * ddV * dt_3d
[849]214
[1822]215                      mass(m)   = mass(m)   + mass(n)   * collection_probability
216                      weight(n) = weight(n) - weight(n) * collection_probability
217                      mass(n)   = mass(n)   - mass(n)   * collection_probability
218                   ELSE
[1071]219!
[1822]220!--                   Same-size collections. If n = m, weight is reduced by the
221!--                   number of possible same-size collections; the total mass
222!--                   is not changed during same-size collection.
223!--                   Same-size collections of different
224!--                   particles ( n /= m ) are treated as same-size collections
225!--                   of ONE partilce with weight = weight(n) + weight(m) and
226!--                   mass = mass(n) + mass(m).
227!--                   Accordingly, each particle loses the same number of
228!--                   droplets to the other particle, but this has no effect on
229!--                   total mass mass, since the exchanged droplets have the
230!--                   same radius.
[849]231
[1822]232!--                   Note: For m = n this equation is an approximation only
233!--                   valid for weight >> 1 (which is usually the case). The
234!--                   approximation is weight(n)-1 = weight(n).
235                      weight(n) = weight(n) - 0.5_wp * weight(n) *                &
236                                              ckernel(rclass_l,rclass_s,eclass) * &
237                                              weight(m) * ddV * dt_3d
238                      IF ( n .NE. m )  THEN
239                         weight(m) = weight(m) - 0.5_wp * weight(m) *                &
240                                                 ckernel(rclass_l,rclass_s,eclass) * &
241                                                 weight(n) * ddV * dt_3d
242                      ENDIF
243                   ENDIF
[1071]244
[1822]245                ENDDO
[1071]246
[1822]247                ql_vp(k,j,i) = ql_vp(k,j,i) + mass(n) / factor_volume_to_mass
248
[1359]249             ENDDO
[849]250
[1822]251          ELSEIF ( all_or_nothing )  THEN  ! select collision algorithm
[849]252
[1822]253             DO  n = 1, number_of_particles
[849]254
[1822]255                rclass_l = particles(n)%class
256                xn       = mass(n) / weight(n) ! mean mass of droplet n
[849]257
[1822]258                DO  m = n, number_of_particles
[849]259
[1822]260                   rclass_s = particles(m)%class
261                   xm = mass(m) / weight(m) ! mean mass of droplet m
[849]262
[1822]263                   IF ( weight(n) .LT. weight(m) )  THEN
264!
265!--                   Particle n collects weight(n) droplets of particle m 
266                      collection_probability = ckernel(rclass_l,rclass_s,eclass) * &
267                                               weight(m) * ddV * dt_3d
[1071]268
[1822]269                      IF ( collection_probability .GT. random_function( iran_part ) )  THEN
270                         mass(n)   = mass(n)   + weight(n) * xm
271                         weight(m) = weight(m) - weight(n)
272                         mass(m)   = mass(m)   - weight(n) * xm
273                      ENDIF
274
275                   ELSEIF ( weight(m) .LT. weight(n) )  THEN 
[849]276!
[1822]277!--                   Particle m collects weight(m) droplets of particle n 
278                      collection_probability = ckernel(rclass_l,rclass_s,eclass) * &
279                                               weight(n) * ddV * dt_3d
280
281                      IF ( collection_probability .GT. random_function( iran_part ) )  THEN
282                         mass(m)   = mass(m)   + weight(m) * xn
283                         weight(n) = weight(n) - weight(m)
284                         mass(n)   = mass(n)   - weight(m) * xn
285                      ENDIF
286                   ELSE
[849]287!
[1822]288!--                   Collisions of particles of the same weighting factor.
289!--                   Particle n collects 1/2 weight(n) droplets of particle m,
290!--                   particle m collects 1/2 weight(m) droplets of particle n.
291!--                   The total mass mass changes accordingly.
292!--                   If n = m, the first half of the droplets coalesces with the
293!--                   second half of the droplets; mass is unchanged because
294!--                   xm = xn for n = m.
[849]295
[1822]296!--                   Note: For m = n this equation is an approximation only
297!--                   valid for weight >> 1 (which is usually the case). The
298!--                   approximation is weight(n)-1 = weight(n).
299                      collection_probability = ckernel(rclass_l,rclass_s,eclass) * &
300                                               weight(n) * ddV * dt_3d
[849]301
[1822]302                      IF ( collection_probability .GT. random_function( iran_part ) )  THEN
303                         mass(n)   = mass(n)   + 0.5_wp * weight(n) * ( xm - xn )
304                         mass(m)   = mass(m)   + 0.5_wp * weight(m) * ( xn - xm )
305                         weight(n) = weight(n) - 0.5_wp * weight(m)
306                         weight(m) = weight(n)
307                      ENDIF
308                   ENDIF
[849]309
[1822]310                ENDDO
[849]311
[1822]312                ql_vp(k,j,i) = ql_vp(k,j,i) + mass(n) / factor_volume_to_mass
[849]313
[1822]314             ENDDO
[849]315
[1822]316          ENDIF
[849]317
318
319
320
[1822]321          IF ( ANY(weight < 0.0_wp) )  THEN
322                WRITE( message_string, * ) 'negative weighting'
323                CALL message( 'lpm_droplet_collision', 'PA0028',      &
324                               2, 2, -1, 6, 1 )
325          ENDIF
[849]326
[1822]327          particles(1:number_of_particles)%radius = ( mass(1:number_of_particles) /   &
328                                                      ( weight(1:number_of_particles) &
329                                                        * factor_volume_to_mass       &
330                                                      )                               &
331                                                    )**0.33333333333333_wp
[849]332
[1822]333          particles(1:number_of_particles)%weight_factor = weight(1:number_of_particles)
[849]334
[1822]335          DEALLOCATE(weight, mass)
[849]336
[1822]337       ELSEIF ( .NOT. use_kernel_tables )  THEN
338!
339!--       Collection kernels are calculated for every new
340!--       grid box. First, allocate memory for kernel table.
341!--       Third dimension is 1, because table is re-calculated for
342!--       every new dissipation value.
343          ALLOCATE( ckernel(1:number_of_particles,1:number_of_particles,1:1) )
344!
345!--       Now calculate collection kernel for this box. Note that
346!--       the kernel is based on the previous time step
347          CALL recalculate_kernel( i, j, k )
348!
349!--       Droplet collision are calculated using collision-coalescence
350!--       formulation proposed by Wang (see PALM documentation)
351!--       Temporary fields for total mass of super-droplet and weighting factors
352!--       are allocated.
353          ALLOCATE(mass(1:number_of_particles), weight(1:number_of_particles))
[849]354
[1822]355          mass(1:number_of_particles) = particles(1:number_of_particles)%weight_factor * &
356                                        particles(1:number_of_particles)%radius**3     * &
357                                        factor_volume_to_mass
[849]358
[1822]359          weight(1:number_of_particles) = particles(1:number_of_particles)%weight_factor
[849]360
[1822]361          IF ( average_impact )  THEN  ! select collision algorithm
[849]362
[1822]363             DO  n = 1, number_of_particles
[849]364
[1822]365                xn = mass(n) / weight(n) ! mean mass of droplet n
[849]366
[1822]367                DO  m = n, number_of_particles
[849]368
[1822]369                   xm = mass(m) / weight(m) !mean mass of droplet m
[849]370
[1822]371                   IF ( xm .LT. xn )  THEN
[849]372!
[1822]373!--                   Particle n collects smaller particle m
374                      collection_probability = ckernel(n,m,1) * weight(n) *    &
375                                               ddV * dt_3d
376
377                      mass(n)   = mass(n)   + mass(m)   * collection_probability
378                      weight(m) = weight(m) - weight(m) * collection_probability
379                      mass(m)   = mass(m)   - mass(m)   * collection_probability
380                   ELSEIF ( xm .GT. xn )  THEN 
[849]381!
[1822]382!--                   Particle m collects smaller particle n
383                      collection_probability = ckernel(n,m,1) * weight(m) *    &
384                                               ddV * dt_3d
[849]385
[1822]386                      mass(m)   = mass(m)   + mass(n)   * collection_probability
387                      weight(n) = weight(n) - weight(n) * collection_probability
388                      mass(n)   = mass(n)   - mass(n)   * collection_probability
389                   ELSE
[849]390!
[1822]391!--                   Same-size collections. If n = m, weight is reduced by the
392!--                   number of possible same-size collections; the total mass
393!--                   mass is not changed during same-size collection.
394!--                   Same-size collections of different
395!--                   particles ( n /= m ) are treated as same-size collections
396!--                   of ONE partilce with weight = weight(n) + weight(m) and
397!--                   mass = mass(n) + mass(m).
398!--                   Accordingly, each particle loses the same number of
399!--                   droplets to the other particle, but this has no effect on
400!--                   total mass mass, since the exchanged droplets have the
401!--                   same radius.
402!--
403!--                   Note: For m = n this equation is an approximation only
404!--                   valid for weight >> 1 (which is usually the case). The
405!--                   approximation is weight(n)-1 = weight(n).
406                      weight(n) = weight(n) - 0.5_wp * weight(n) *             &
407                                              ckernel(n,m,1) * weight(m) *     &
408                                              ddV * dt_3d
409                      IF ( n .NE. m )  THEN
410                         weight(m) = weight(m) - 0.5_wp * weight(m) *          &
411                                                 ckernel(n,m,1) * weight(n) *  &
412                                                 ddV * dt_3d
413                      ENDIF
414                   ENDIF
[849]415
416
[1359]417                ENDDO
[849]418
[1822]419                ql_vp(k,j,i) = ql_vp(k,j,i) + mass(n) / factor_volume_to_mass
[849]420
[1822]421             ENDDO
[849]422
[1822]423          ELSEIF ( all_or_nothing )  THEN  ! select collision algorithm
[849]424
[1822]425             DO  n = 1, number_of_particles
[849]426
[1822]427                xn = mass(n) / weight(n) ! mean mass of droplet n
[849]428
[1822]429                DO  m = n, number_of_particles
[849]430
[1822]431                   xm = mass(m) / weight(m) !mean mass of droplet m
[849]432
[1822]433                   IF ( weight(n) .LT. weight(m) )  THEN
434!
435!--                   Particle n collects smaller particle m
436                      collection_probability = ckernel(n,m,1) * weight(m) *    &
437                                               ddV * dt_3d
[1071]438
[1822]439                      IF ( collection_probability .GT. random_function( iran_part ) )  THEN
440                         mass(n) = mass(n) + weight(n) * xm 
441                         weight(m)    = weight(m)    - weight(n)
442                         mass(m) = mass(m) - weight(n) * xm
443                      ENDIF
[1359]444
[1822]445                   ELSEIF ( weight(m) .LT. weight(n) )  THEN
[1071]446!
[1822]447!--                   Particle m collects smaller particle n
448                      collection_probability = ckernel(n,m,1) * weight(n) *    &
449                                               ddV * dt_3d
[1071]450
[1822]451                      IF ( collection_probability .GT. random_function( iran_part ) )  THEN
452                         mass(m) = mass(m) + weight(m) * xn
453                         weight(n)    = weight(n)    - weight(m)
454                         mass(n) = mass(n) - weight(m) * xn
455                      ENDIF
456                   ELSE
457!
458!--                   Collisions of particles of the same weighting factor.
459!--                   Particle n collects 1/2 weight(n) droplets of particle m,
460!--                   particle m collects 1/2 weight(m) droplets of particle n.
461!--                   The total mass mass changes accordingly.
462!--                   If n = m, the first half of the droplets coalesces with the
463!--                   second half of the droplets; mass is unchanged because
464!--                   xm = xn for n = m.
465!--
466!--                   Note: For m = n this equation is an approximation only
467!--                   valid for weight >> 1 (which is usually the case). The
468!--                   approximation is weight(n)-1 = weight(n).
469                      collection_probability = ckernel(n,m,1) * weight(n) *    &
470                                               ddV * dt_3d
[1071]471
[1822]472                      IF ( collection_probability .GT. random_function( iran_part ) )  THEN
473                         mass(n)   = mass(n)   + 0.5_wp * weight(n) * ( xm - xn )
474                         mass(m)   = mass(m)   + 0.5_wp * weight(m) * ( xn - xm )
475                         weight(n) = weight(n) - 0.5_wp * weight(m)
476                         weight(m) = weight(n)
477                      ENDIF
478                   ENDIF
[1071]479
480
[1822]481                ENDDO
[1071]482
[1822]483                ql_vp(k,j,i) = ql_vp(k,j,i) + mass(n) / factor_volume_to_mass
[1071]484
[1822]485             ENDDO
[1071]486
[1822]487          ENDIF
[1071]488
[1822]489          IF ( ANY(weight < 0.0_wp) )  THEN
490                WRITE( message_string, * ) 'negative weighting'
491                CALL message( 'lpm_droplet_collision', 'PA0028',      &
492                               2, 2, -1, 6, 1 )
493          ENDIF
494
495          particles(1:number_of_particles)%radius = ( mass(1:number_of_particles) /   &
496                                                      ( weight(1:number_of_particles) &
497                                                        * factor_volume_to_mass       &
498                                                      )                               &
499                                                    )**0.33333333333333_wp
500
501          particles(1:number_of_particles)%weight_factor = weight(1:number_of_particles)
502
503          DEALLOCATE( weight, mass, ckernel )
504
505       ENDIF
506 
[1359]507    ENDIF
[1822]508   
[849]509
510!
[1822]511!-- Check if LWC is conserved during collision process
[1359]512    IF ( ql_v(k,j,i) /= 0.0_wp )  THEN
[1822]513       IF ( ql_vp(k,j,i) / ql_v(k,j,i) >= 1.0001_wp  .OR.                      &
[1359]514            ql_vp(k,j,i) / ql_v(k,j,i) <= 0.9999_wp )  THEN
[1822]515          WRITE( message_string, * ) ' LWC is not conserved during',           &
516                                     ' collision! ',                           &
517                                     ' LWC after condensation: ', ql_v(k,j,i), &
518                                     ' LWC after collision: ', ql_vp(k,j,i)
519          CALL message( 'lpm_droplet_collision', 'PA0040', 2, 2, -1, 6, 1 )
[1359]520       ENDIF
521    ENDIF
[849]522
523    CALL cpu_log( log_point_s(43), 'lpm_droplet_coll', 'stop' )
524
[1359]525 END SUBROUTINE lpm_droplet_collision
Note: See TracBrowser for help on using the repository browser.