1
1
# A set of wrappers for using CloudMicrophysics.jl functions inside EDMFX loops
2
2
3
3
import Thermodynamics as TD
4
+ import ClimaCore. Operators as Operators
4
5
import CloudMicrophysics. Microphysics0M as CM0
5
6
import CloudMicrophysics. Microphysics1M as CM1
6
7
import CloudMicrophysics. Microphysics2M as CM2
7
8
import CloudMicrophysics. MicrophysicsNonEq as CMNe
9
+ import CloudMicrophysics. AerosolModel as CMAM
10
+ import CloudMicrophysics. AerosolActivation as CMAA
8
11
import CloudMicrophysics. Parameters as CMP
9
12
10
13
# Define some aliases and functions to make the code more readable
@@ -25,33 +28,6 @@ function limit(q, dt, n::Int)
25
28
return max (FT (0 ), q) / float (dt) / n
26
29
end
27
30
28
- """
29
- ml_N_cloud_liquid_droplets(cmc, c_dust, c_seasalt, c_SO4, q_liq)
30
-
31
- - cmc - a struct with cloud and aerosol parameters
32
- - c_dust, c_seasalt, c_SO4 - dust, seasalt and ammonium sulfate mass concentrations [kg/kg]
33
- - q_liq - liquid water specific humidity
34
-
35
- Returns the liquid cloud droplet number concentration diagnosed based on the
36
- aerosol loading and cloud liquid water.
37
- """
38
- function ml_N_cloud_liquid_droplets (cmc, c_dust, c_seasalt, c_SO4, q_liq)
39
- # We can also add w, T, RH, w' ...
40
- # Also consider lookind only at around cloud base height
41
- (; α_dust, α_seasalt, α_SO4, α_q_liq) = cmc. aml
42
- (; c₀_dust, c₀_seasalt, c₀_SO4, q₀_liq) = cmc. aml
43
- N₀ = cmc. N_cloud_liquid_droplets
44
-
45
- FT = eltype (N₀)
46
- return N₀ * (
47
- FT (1 ) +
48
- α_dust * (log (max (c_dust, eps (FT))) - log (c₀_dust)) +
49
- α_seasalt * (log (max (c_seasalt, eps (FT))) - log (c₀_seasalt)) +
50
- α_SO4 * (log (max (c_SO4, eps (FT))) - log (c₀_SO4)) +
51
- α_q_liq * (log (max (q_liq, eps (FT))) - log (q₀_liq))
52
- )
53
- end
54
-
55
31
"""
56
32
cloud_sources(cm_params, thp, qₜ, qₗ, qᵢ, qᵣ, qₛ, ρ, Tₐ, dt)
57
33
@@ -373,46 +349,129 @@ end
373
349
# ####
374
350
375
351
"""
376
- aerosol_activation_sources(cm_params, thp, ρ, Tₐ, qₜ, qₗ, qᵢ, qᵣ, qₛ, n_dp, n_dp_prescribed, dt )
352
+ find_cloud_base!(Snₗ, z, cloud_base_Snₗ_and_z )
377
353
378
- - cm_params - CloudMicrophysics parameters struct for cloud water or ice condensate
379
- - thp - Thermodynamics parameters struct
380
- - ρ - air density
381
- - Tₐ - air temperature
382
- - qₜ - total specific humidity
383
- - qₗ - liquid specific humidity
384
- - qᵢ - ice specific humidity
385
- - qᵣ - rain specific humidity
386
- - qₛ - snow specific humidity
387
- - n_dp - number concentration droplets (liquid or ice) per mass
388
- _ n_dp_prescribed - prescribed number concentration of droplets (liquid or ice) per mass
389
- - dt - model time step
354
+ Finds the cloud base in each vertical column based on the first occurrence of aerosol activation.
355
+
356
+ This function performs a vertical column-wise reduction to identify the first level (from bottom to
357
+ top) where `Snₗ > 0`, indicating the onset of cloud droplet activation (i.e., cloud base). The result
358
+ is stored in `cloud_base_Snₗ_and_z` as a tuple `(Snₗ, z)` for each column.
359
+
360
+ # Arguments
361
+ - `Snₗ`: Field of cloud droplet number concentration tendencies [m⁻³/s], from an activation parameterization.
362
+ - `z`: Field of geometric height [m] corresponding to each grid point.
363
+ - `cloud_base_Snₗ_and_z`: Output field to store the `(Snₗ, z)` values at cloud base for each column.
364
+ """
365
+ function find_cloud_base! (Snₗ, z, cloud_base_Snₗ_and_z)
366
+ Operators. column_reduce! (
367
+ ((target_Snₗ_value, target_z_value), (Snₗ_value, z_value)) -> ifelse (
368
+ target_Snₗ_value == 0 && Snₗ_value > 0 ,
369
+ (Snₗ_value, z_value),
370
+ (target_Snₗ_value, target_z_value),
371
+ ), # reduction function
372
+ cloud_base_Snₗ_and_z, # destination for output (a field of tuples)
373
+ Base. broadcasted (tuple, Snₗ, z),
374
+ )
375
+ end
390
376
391
- Returns the activation rate. #TODO This function temporarily computes activation rate
392
- based on mass rates and a prescribed droplet mass (no activation parameterization yet).
377
+ """
378
+ aerosol_activation_sources(
379
+ seasalt_num,
380
+ seasalt_mean_radius,
381
+ sulfate_num,
382
+ nₗ,
383
+ ρ,
384
+ w,
385
+ air_params,
386
+ aerosol_params,
387
+ arg_params,
388
+ thermo_params,
389
+ ts,
390
+ dt,
391
+ )
392
+
393
+ Computes the source term for cloud droplet number concentration per mass due to aerosol activation,
394
+ based on the Abdul-Razzak and Ghan (2000) parameterization.
395
+
396
+ This function estimates the number of aerosols activated into cloud droplets per mass of air per second
397
+ from a bi-modal aerosol distribution (sea salt and sulfate), given local supersaturation and vertical
398
+ velocity. The result is returned as a tendency (per second) of liquid droplet number concentration.
399
+
400
+ # Arguments
401
+ - `seasalt_num`: Number concentration per mass of sea salt aerosols [kg⁻¹].
402
+ - `seasalt_mean_radius`: Mean dry radius of sea salt aerosol mode [m].
403
+ - `sulfate_num`: Number concentration per mass of sulfate aerosols [kg⁻¹].
404
+ - `nₗ`: Cloud droplet number concentration per mass [kg⁻¹].
405
+ - `ρ`: Air density [kg/m³].
406
+ - `w`: Vertical velocity [m/s].
407
+ - `air_params`: Struct containing physical constants related to air.
408
+ - `aerosol_params`: Struct containing aerosol properties, such as hygroscopicity parameters (κ).
409
+ - `arg_params`: Activation scheme parameters specific to Abdul-Razzak and Ghan (2000).
410
+ - `thermo_params`: Thermodynamic parameters for computing saturation, pressure, temperature, etc.
411
+ - `ts`: Thermodynamic state (e.g., prognostic variables) used for evaluating the phase partition.
412
+ - `dt`: Time step (s) over which the activation tendency is applied.
413
+
414
+ # Returns
415
+ - Tendency of cloud droplet number concentration per mass of air due to aerosol activation [m⁻³/s].
393
416
"""
394
417
function aerosol_activation_sources (
395
- cm_params:: CMP.CloudLiquid{FT} ,
396
- thp,
418
+ seasalt_num,
419
+ seasalt_mean_radius,
420
+ sulfate_num,
421
+ nₗ,
397
422
ρ,
398
- Tₐ,
399
- qₜ,
400
- qₗ,
401
- qᵢ,
402
- qᵣ,
403
- qₛ,
404
- n_dp,
405
- n_dp_prescribed,
423
+ w,
424
+ cmc,
425
+ thermo_params,
426
+ ts,
406
427
dt,
407
- ) where {FT}
408
- r_dp = FT (2e-6 ) # 2 μm
409
- m_dp = 4 / 3 * FT (π) * r_dp^ 3 * cm_params. ρw
410
- Sn = cloud_sources (cm_params, thp, qₜ, qₗ, qᵢ, qᵣ, qₛ, ρ, Tₐ, dt) / m_dp
428
+ )
429
+
430
+ FT = eltype (nₗ)
431
+ air_params = cmc. aps
432
+ arg_params = cmc. arg
433
+ aerosol_params = cmc. aerosol
434
+ q = TD. PhasePartition (thermo_params, ts)
435
+ T = TD. air_temperature (thermo_params, ts)
436
+ p = TD. air_pressure (thermo_params, ts)
437
+ S:: FT = TD. supersaturation (thermo_params, q, ρ, T, TD. Liquid ())
438
+
439
+ seasalt_mode = CMAM. Mode_κ (
440
+ seasalt_mean_radius,
441
+ aerosol_params. seasalt_std,
442
+ seasalt_num * ρ,
443
+ (FT (1.0 ),),
444
+ (FT (1.0 ),),
445
+ (FT (0.0 ),),
446
+ (aerosol_params. seasalt_kappa,),
447
+ )
448
+ sulfate_mode = CMAM. Mode_κ (
449
+ aerosol_params. sulfate_radius,
450
+ aerosol_params. sulfate_std,
451
+ sulfate_num * ρ,
452
+ (FT (1.0 ),),
453
+ (FT (1.0 ),),
454
+ (FT (0.0 ),),
455
+ (aerosol_params. sulfate_kappa,),
456
+ )
457
+
458
+ aerosol_dist = CMAM. AerosolDistribution ((seasalt_mode, sulfate_mode))
459
+ n_act:: FT =
460
+ CMAA. total_N_activated (
461
+ arg_params,
462
+ aerosol_dist,
463
+ air_params,
464
+ thermo_params,
465
+ T,
466
+ p,
467
+ w,
468
+ q,
469
+ ) / ρ
411
470
412
471
return ifelse (
413
- Sn > FT ( 0 ),
414
- triangle_inequality_limiter (Sn, limit ((n_dp_prescribed - n_dp), dt, 2 ) ),
415
- - triangle_inequality_limiter (abs (Sn), limit (n_dp, dt, 2 )) ,
472
+ S < 0 || isnan (n_act ),
473
+ FT ( 0 ),
474
+ triangle_inequality_limiter (n_act, n_act - nₗ) / dt ,
416
475
)
417
476
end
418
477
0 commit comments