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

Last change on this file since 3436 was 3274, checked in by knoop, 6 years ago

Modularization of all bulk cloud physics code components

  • Property svn:keywords set to Id
File size: 15.4 KB
RevLine 
[1682]1!> @file lpm_droplet_collision.f90
[2000]2!------------------------------------------------------------------------------!
[2696]3! This file is part of the PALM model system.
[1036]4!
[2000]5! PALM is free software: you can redistribute it and/or modify it under the
6! terms of the GNU General Public License as published by the Free Software
7! Foundation, either version 3 of the License, or (at your option) any later
8! version.
[1036]9!
10! PALM is distributed in the hope that it will be useful, but WITHOUT ANY
11! WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12! A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13!
14! You should have received a copy of the GNU General Public License along with
15! PALM. If not, see <http://www.gnu.org/licenses/>.
16!
[2718]17! Copyright 1997-2018 Leibniz Universitaet Hannover
[2000]18!------------------------------------------------------------------------------!
[1036]19!
[849]20! Current revisions:
21! ------------------
[2375]22!
23!
[1321]24! Former revisions:
25! -----------------
26! $Id: lpm_droplet_collision.f90 3274 2018-09-24 15:42:55Z gronemeier $
[3274]27! Modularization of all bulk cloud physics code components
28!
29! 3241 2018-09-12 15:02:00Z raasch
[3241]30! unused variables removed
31!
32! 3039 2018-05-24 13:13:11Z schwenkel
[3039]33! bugfix for lcm with grid stretching
34!
35! 2718 2018-01-02 08:49:38Z maronga
[2716]36! Corrected "Former revisions" section
37!
38! 2696 2017-12-14 17:12:51Z kanani
39! Change in file header (GPL part)
40!
41! 2375 2017-08-29 14:10:28Z schwenkel
[2375]42! Changed ONLY-dependencies
43!
44! 2312 2017-07-14 20:26:51Z hoffmann
[2312]45! Consideration of aerosol mass during collision. Average impact algorithm has
46! been removed.
47!
48! 2274 2017-06-09 13:27:48Z Giersch
[2274]49! Changed error messages
[1321]50!
[2274]51! 2123 2017-01-18 12:34:59Z hoffmann
52!
[2123]53! 2122 2017-01-18 12:22:54Z hoffmann
54! Some reformatting of the code.
55!
[2001]56! 2000 2016-08-20 18:09:15Z knoop
57! Forced header and separation lines into 80 columns
58!
[1885]59! 1884 2016-04-21 11:11:40Z hoffmann
60! Conservation of mass should only be checked if collisions took place.
61!
[1861]62! 1860 2016-04-13 13:21:28Z hoffmann
[2312]63! Interpolation of dissipation rate adjusted to more reasonable values.
[1861]64!
[1823]65! 1822 2016-04-07 07:49:42Z hoffmann
66! Integration of a new collision algortithm based on Shima et al. (2009) and
67! Soelch and Kaercher (2010) called all_or_nothing. The previous implemented
68! collision algorithm is called average_impact. Moreover, both algorithms are
69! now positive definit due to their construction, i.e., no negative weighting
70! factors should occur.
71!
[1683]72! 1682 2015-10-07 23:56:08Z knoop
[2312]73! Code annotations made doxygen readable
74!
[1360]75! 1359 2014-04-11 17:15:14Z hoffmann
[2312]76! New particle structure integrated.
[1360]77! Kind definition added to all floating point numbers.
78!
[1323]79! 1322 2014-03-20 16:38:49Z raasch
80! REAL constants defined as wp_kind
81!
[1321]82! 1320 2014-03-20 08:40:49Z raasch
[1320]83! ONLY-attribute added to USE-statements,
84! kind-parameters added to all INTEGER and REAL declaration statements,
85! kinds are defined in new module kinds,
86! revision history before 2012 removed,
87! comment fields (!:) to be used for variable explanations added to
88! all variable declaration statements
[1072]89!
[1093]90! 1092 2013-02-02 11:24:22Z raasch
91! unused variables removed
92!
[1072]93! 1071 2012-11-29 16:54:55Z franke
[1071]94! Calculation of Hall and Wang kernel now uses collision-coalescence formulation
95! proposed by Wang instead of the continuous collection equation (for more
96! information about new method see PALM documentation)
97! Bugfix: message identifiers added
[849]98!
[1037]99! 1036 2012-10-22 13:43:42Z raasch
100! code put under GPL (PALM 3.9)
101!
[850]102! 849 2012-03-15 10:35:09Z raasch
103! initial revision (former part of advec_particles)
[849]104!
[850]105!
[849]106! Description:
107! ------------
[1682]108!> Calculates change in droplet radius by collision. Droplet collision is
109!> calculated for each grid box seperately. Collision is parameterized by
[1822]110!> using collision kernels. Two different kernels are available:
[1682]111!> Hall kernel: Kernel from Hall (1980, J. Atmos. Sci., 2486-2507), which
112!>              considers collision due to pure gravitational effects.
113!> Wang kernel: Beside gravitational effects (treated with the Hall-kernel) also
114!>              the effects of turbulence on the collision are considered using
115!>              parameterizations of Ayala et al. (2008, New J. Phys., 10,
116!>              075015) and Wang and Grabowski (2009, Atmos. Sci. Lett., 10,
117!>              1-8). This kernel includes three possible effects of turbulence:
118!>              the modification of the relative velocity between the droplets,
119!>              the effect of preferential concentration, and the enhancement of
[2312]120!>              collision efficiencies.
[849]121!------------------------------------------------------------------------------!
[1682]122 SUBROUTINE lpm_droplet_collision (i,j,k)
[849]123
[1320]124    USE arrays_3d,                                                             &
[3039]125        ONLY:  diss, dzw, ql_v, ql_vp
[849]126
[3274]127    USE basic_constants_and_equations_mod,                                     &
128        ONLY:  pi, rho_l, rho_s
[1320]129
130    USE control_parameters,                                                    &
[3241]131        ONLY:  dt_3d, message_string
[1320]132
133    USE cpulog,                                                                &
134        ONLY:  cpu_log, log_point_s
135
136    USE grid_variables,                                                        &
[1822]137        ONLY:  dx, dy
[1320]138
139    USE kinds
140
141    USE lpm_collision_kernels_mod,                                             &
[1822]142        ONLY:  ckernel, recalculate_kernel
[1320]143
144    USE particle_attributes,                                                   &
[2312]145        ONLY:  curvature_solution_effects, dissipation_classes, hall_kernel,   &
146               iran_part, number_of_particles, particles, particle_type,       &
[2375]147               prt_count, use_kernel_tables, wang_kernel
[1320]148
[1822]149    USE random_function_mod,                                                   &
150        ONLY:  random_function
151
[1359]152    USE pegrid
153
[849]154    IMPLICIT NONE
155
[1682]156    INTEGER(iwp) ::  eclass   !<
157    INTEGER(iwp) ::  i        !<
158    INTEGER(iwp) ::  j        !<
159    INTEGER(iwp) ::  k        !<
160    INTEGER(iwp) ::  n        !<
[1822]161    INTEGER(iwp) ::  m        !<
[1682]162    INTEGER(iwp) ::  rclass_l !<
163    INTEGER(iwp) ::  rclass_s !<
[849]164
[1822]165    REAL(wp) ::  collection_probability  !< probability for collection
166    REAL(wp) ::  ddV                     !< inverse grid box volume
167    REAL(wp) ::  epsilon                 !< dissipation rate
168    REAL(wp) ::  factor_volume_to_mass   !< 4.0 / 3.0 * pi * rho_l
[2312]169    REAL(wp) ::  xm                      !< droplet mass of super-droplet m
170    REAL(wp) ::  xn                      !< droplet mass of super-droplet n
171    REAL(wp) ::  xsm                     !< aerosol mass of super-droplet m
172    REAL(wp) ::  xsn                     !< aerosol mass of super-droplet n
[1359]173
[2312]174    REAL(wp), DIMENSION(:), ALLOCATABLE ::  weight    !< weighting factor
175    REAL(wp), DIMENSION(:), ALLOCATABLE ::  mass      !< total mass of super droplet
176    REAL(wp), DIMENSION(:), ALLOCATABLE ::  aero_mass !< total aerosol mass of super droplet
[1359]177
[849]178    CALL cpu_log( log_point_s(43), 'lpm_droplet_coll', 'start' )
179
[1822]180    number_of_particles   = prt_count(k,j,i)
[2312]181    factor_volume_to_mass = 4.0_wp / 3.0_wp * pi * rho_l
[3039]182    ddV                   = 1.0_wp / ( dx * dy * dzw(k) )
[849]183!
[1822]184!-- Collision requires at least one super droplet inside the box
185    IF ( number_of_particles > 0 )  THEN
[849]186
[1822]187       IF ( use_kernel_tables )  THEN
[849]188!
[1822]189!--       Fast method with pre-calculated collection kernels for
[1359]190!--       discrete radius- and dissipation-classes.
191          IF ( wang_kernel )  THEN
[1860]192             eclass = INT( diss(k,j,i) * 1.0E4_wp / 600.0_wp * &
[1359]193                           dissipation_classes ) + 1
194             epsilon = diss(k,j,i)
195          ELSE
196             epsilon = 0.0_wp
197          ENDIF
[2312]198
[1359]199          IF ( hall_kernel  .OR.  epsilon * 1.0E4_wp < 0.001_wp )  THEN
200             eclass = 0   ! Hall kernel is used
201          ELSE
202             eclass = MIN( dissipation_classes, eclass )
203          ENDIF
204
[2312]205       ELSE
[849]206!
[2312]207!--       Collection kernels are re-calculated for every new
[1822]208!--       grid box. First, allocate memory for kernel table.
209!--       Third dimension is 1, because table is re-calculated for
210!--       every new dissipation value.
211          ALLOCATE( ckernel(1:number_of_particles,1:number_of_particles,1:1) )
212!
213!--       Now calculate collection kernel for this box. Note that
214!--       the kernel is based on the previous time step
215          CALL recalculate_kernel( i, j, k )
[2312]216
217       ENDIF
[1822]218!
[2312]219!--    Temporary fields for total mass of super-droplet, aerosol mass, and
220!--    weighting factor are allocated.
221       ALLOCATE(mass(1:number_of_particles), weight(1:number_of_particles))
222       IF ( curvature_solution_effects )  ALLOCATE(aero_mass(1:number_of_particles))
[849]223
[2312]224       mass(1:number_of_particles)   = particles(1:number_of_particles)%weight_factor * &
225                                       particles(1:number_of_particles)%radius**3     * &
226                                       factor_volume_to_mass
[849]227
[2312]228       weight(1:number_of_particles) = particles(1:number_of_particles)%weight_factor
[849]229
[2312]230       IF ( curvature_solution_effects )  THEN
231          aero_mass(1:number_of_particles) = particles(1:number_of_particles)%weight_factor * &
232                                             particles(1:number_of_particles)%aux1**3       * &
233                                             4.0 / 3.0 * pi * rho_s
234       ENDIF
235!
236!--    Calculate collision/coalescence
237       DO  n = 1, number_of_particles
[849]238
[2312]239          DO  m = n, number_of_particles
240!
241!--          For collisions, the weighting factor of at least one super-droplet
242!--          needs to be larger or equal to one.
243             IF ( MIN( weight(n), weight(m) ) .LT. 1.0 )  CYCLE
244!
245!--          Get mass of individual droplets (aerosols)
246             xn = mass(n) / weight(n)
247             xm = mass(m) / weight(m)
248             IF ( curvature_solution_effects )  THEN
249                xsn = aero_mass(n) / weight(n)
250                xsm = aero_mass(m) / weight(m)
251             ENDIF
252!
253!--          Probability that the necessary collisions take place
254             IF ( use_kernel_tables )  THEN
255                rclass_l = particles(n)%class
256                rclass_s = particles(m)%class
[849]257
[2312]258                collection_probability  = MAX( weight(n), weight(m) ) *     &
259                                          ckernel(rclass_l,rclass_s,eclass) * ddV * dt_3d
260             ELSE
261                collection_probability  = MAX( weight(n), weight(m) ) *     &
262                                          ckernel(n,m,1) * ddV * dt_3d
263             ENDIF
[849]264!
[2312]265!--          Calculate the number of collections and consider multiple collections.
266!--          (Accordingly, p_crit will be 0.0, 1.0, 2.0, ...)
267             IF ( collection_probability - FLOOR(collection_probability)    &
268                  .GT. random_function( iran_part ) )  THEN
269                collection_probability = FLOOR(collection_probability) + 1.0_wp
270             ELSE
271                collection_probability = FLOOR(collection_probability)
272             ENDIF
[1822]273
[2312]274             IF ( collection_probability .GT. 0.0 )  THEN
[849]275!
[2312]276!--             Super-droplet n collects droplets of super-droplet m
277                IF ( weight(n) .LT. weight(m) )  THEN
[849]278
[2312]279                   mass(n)   = mass(n)   + weight(n) * xm * collection_probability
280                   weight(m) = weight(m) - weight(n)      * collection_probability
281                   mass(m)   = mass(m)   - weight(n) * xm * collection_probability
282                   IF ( curvature_solution_effects )  THEN
283                      aero_mass(n) = aero_mass(n) + weight(n) * xsm * collection_probability
284                      aero_mass(m) = aero_mass(m) - weight(n) * xsm * collection_probability
[1822]285                   ENDIF
[849]286
[2312]287                ELSEIF ( weight(m) .LT. weight(n) )  THEN
[849]288
[2312]289                   mass(m)   = mass(m)   + weight(m) * xn * collection_probability
290                   weight(n) = weight(n) - weight(m)      * collection_probability
291                   mass(n)   = mass(n)   - weight(m) * xn * collection_probability
292                   IF ( curvature_solution_effects )  THEN
293                      aero_mass(m) = aero_mass(m) + weight(m) * xsn * collection_probability
294                      aero_mass(n) = aero_mass(n) - weight(m) * xsn * collection_probability
295                   ENDIF
[849]296
[2312]297                ELSE
[1822]298!
[2312]299!--                Collisions of particles of the same weighting factor.
300!--                Particle n collects 1/2 weight(n) droplets of particle m,
301!--                particle m collects 1/2 weight(m) droplets of particle n.
302!--                The total mass mass changes accordingly.
303!--                If n = m, the first half of the droplets coalesces with the
304!--                second half of the droplets; mass is unchanged because
305!--                xm = xn for n = m.
[1822]306!--
[2312]307!--                Note: For m = n this equation is an approximation only
308!--                valid for weight >> 1 (which is usually the case). The
309!--                approximation is weight(n)-1 = weight(n).
310                   mass(n)   = mass(n)   + 0.5_wp * weight(n) * ( xm - xn )
311                   mass(m)   = mass(m)   + 0.5_wp * weight(m) * ( xn - xm )
312                   IF ( curvature_solution_effects )  THEN
313                      aero_mass(n) = aero_mass(n) + 0.5_wp * weight(n) * ( xsm - xsn )
314                      aero_mass(m) = aero_mass(m) + 0.5_wp * weight(m) * ( xsn - xsm )
[1822]315                   ENDIF
[2312]316                   weight(n) = weight(n) - 0.5_wp * weight(m)
317                   weight(m) = weight(n)
[1071]318
[2312]319                ENDIF
[1071]320
[2312]321             ENDIF
[1071]322
[2312]323          ENDDO
[1071]324
[2312]325          ql_vp(k,j,i) = ql_vp(k,j,i) + mass(n) / factor_volume_to_mass
[1071]326
[2312]327       ENDDO
[1071]328
[2312]329       IF ( ANY(weight < 0.0_wp) )  THEN
330             WRITE( message_string, * ) 'negative weighting factor'
331             CALL message( 'lpm_droplet_collision', 'PA0028',      &
332                            2, 2, -1, 6, 1 )
333       ENDIF
[1822]334
[2312]335       particles(1:number_of_particles)%radius = ( mass(1:number_of_particles) /   &
336                                                   ( weight(1:number_of_particles) &
337                                                     * factor_volume_to_mass       &
338                                                   )                               &
339                                                 )**0.33333333333333_wp
[1822]340
[2312]341       IF ( curvature_solution_effects )  THEN
342          particles(1:number_of_particles)%aux1 = ( aero_mass(1:number_of_particles) / &
343                                                    ( weight(1:number_of_particles)    &
344                                                      * 4.0_wp / 3.0_wp * pi * rho_s   &
345                                                    )                                  &
346                                                  )**0.33333333333333_wp
347       ENDIF
[1822]348
[2312]349       particles(1:number_of_particles)%weight_factor = weight(1:number_of_particles)
[1822]350
[2312]351       DEALLOCATE( weight, mass )
352       IF ( curvature_solution_effects )  DEALLOCATE( aero_mass )
353       IF ( .NOT. use_kernel_tables )  DEALLOCATE( ckernel )
354
[849]355!
[1884]356!--    Check if LWC is conserved during collision process
357       IF ( ql_v(k,j,i) /= 0.0_wp )  THEN
358          IF ( ql_vp(k,j,i) / ql_v(k,j,i) >= 1.0001_wp  .OR.                      &
359               ql_vp(k,j,i) / ql_v(k,j,i) <= 0.9999_wp )  THEN
360             WRITE( message_string, * ) ' LWC is not conserved during',           &
361                                        ' collision! ',                           &
362                                        ' LWC after condensation: ', ql_v(k,j,i), &
363                                        ' LWC after collision: ', ql_vp(k,j,i)
364             CALL message( 'lpm_droplet_collision', 'PA0040', 2, 2, -1, 6, 1 )
365          ENDIF
[1359]366       ENDIF
[1884]367
[1359]368    ENDIF
[2312]369
[849]370    CALL cpu_log( log_point_s(43), 'lpm_droplet_coll', 'stop' )
371
[2312]372 END SUBROUTINE lpm_droplet_collision
Note: See TracBrowser for help on using the repository browser.