@@ -234,6 +234,7 @@ This is a pure function of local thermodynamic state, suitable for:
234234 dq_sno_dt += ifelse (is_warm, zero (T), S_accr_lcl_sno)
235235 dq_rai_dt += ifelse (is_warm, S_accr_lcl_sno, zero (T))
236236 # Thermal melting (α=0 when cold, so these terms vanish)
237+ # Physical consistency: melt is mass of snow melted, which is α * mass of warm liquid
237238 α = warm_accretion_melt_factor (tps, sno, T)
238239 S_accr_melt = α * S_accr_lcl_sno
239240 dq_sno_dt -= S_accr_melt
@@ -269,7 +270,8 @@ This is a pure function of local thermodynamic state, suitable for:
269270 dq_sno_dt -= ifelse (is_warm, S_accr_sno_rai, zero (T))
270271 dq_rai_dt += ifelse (is_warm, S_accr_sno_rai, zero (T))
271272 # Thermal melting from warm rain (α=0 when cold)
272- S_accr_melt = α * S_accr_sno_rai
273+ # Physical consistency: melt is mass of snow melted, which is α * mass of warm rain
274+ S_accr_melt = α * S_accr_rai_sno
273275 dq_sno_dt -= ifelse (is_warm, S_accr_melt, zero (T))
274276 dq_rai_dt += ifelse (is_warm, S_accr_melt, zero (T))
275277
@@ -350,21 +352,61 @@ as `bulk_microphysics_tendencies`.
350352 aps = mp. air_properties
351353 vel = mp. terminal_velocity
352354
353- # Condensation/evaporation of cloud liquid
355+ # --- Cloud liquid: condensation + sink self-derivatives ---
354356 ∂tendency_∂q_lcl = CMNonEq.∂conv_q_vap_to_q_lcl_icl_MM2015_∂q_cld (lcl, tps, q_tot, q_lcl, q_icl, q_rai, q_sno, ρ, T)
357+ # Autoconversion q_lcl → q_rai (sink, derivative ∂/∂q_lcl is conservative and safe for linear-above-threshold)
358+ S_acnv_lcl = CM1. conv_q_lcl_to_q_rai (rai. acnv1M, q_lcl, true )
359+ # Accretion q_lcl + q_rai → q_rai (rate is exactly linear in q_lcl)
360+ S_accr_lcl_rai = CM1. accretion (lcl, rai, vel. rain, ce, q_lcl, q_rai, ρ)
361+ # Accretion q_lcl + q_sno → q_sno (rate is exactly linear in q_lcl)
362+ S_accr_lcl_sno = CM1. accretion (lcl, sno, vel. snow, ce, q_lcl, q_sno, ρ)
363+ ∂tendency_∂q_lcl -=
364+ (S_acnv_lcl + S_accr_lcl_rai + S_accr_lcl_sno) /
365+ max (q_lcl, UT. ϵ_numerics (typeof (q_lcl)))
355366
356- # Deposition/sublimation of cloud ice (INP limiter applied inside ∂conv_q_vap_to_q_lcl_icl_MM2015_∂q_cld)
367+ # --- Cloud ice: deposition + sink self-derivatives ---
357368 ∂tendency_∂q_icl = CMNonEq.∂conv_q_vap_to_q_lcl_icl_MM2015_∂q_cld (icl, tps, q_tot, q_lcl, q_icl, q_rai, q_sno, ρ, T)
369+ # Autoconversion q_icl → q_sno
370+ S_acnv_icl = CM1. conv_q_icl_to_q_sno_no_supersat (sno. acnv1M, q_icl, true )
371+ # Accretion q_icl + q_rai → q_sno (rate is exactly linear in q_icl)
372+ S_accr_icl_rai = CM1. accretion (icl, rai, vel. rain, ce, q_icl, q_rai, ρ)
373+ # Accretion q_icl + q_sno → q_sno (rate is exactly linear in q_icl)
374+ S_accr_icl_sno = CM1. accretion (icl, sno, vel. snow, ce, q_icl, q_sno, ρ)
375+ ∂tendency_∂q_icl -=
376+ (S_acnv_icl + S_accr_icl_rai + S_accr_icl_sno) /
377+ max (q_icl, UT. ϵ_numerics (typeof (q_icl)))
358378
359- # Rain evaporation
379+ # --- Rain: evaporation + sink self-derivatives ---
360380 ∂tendency_∂q_rai =
361381 CM1.∂evaporation_sublimation_∂q_precip (rai, vel. rain, aps, tps, q_tot, q_lcl, q_icl, q_rai, q_sno, ρ, T)
382+ # Accretion rain_sink: ice + rain → snow (rate/q_rai approximation)
383+ S_accr_rai_icl = CM1. accretion_rain_sink (rai, icl, vel. rain, ce, q_icl, q_rai, ρ)
384+ # Snow-rain accretion (cold): rain → snow
385+ is_warm = T >= sno. T_freeze
386+ S_accr_rai_sno = ifelse (is_warm, zero (T),
387+ CM1. accretion_snow_rain (sno, rai, vel. snow, vel. rain, ce, q_sno, q_rai, ρ))
388+ ∂tendency_∂q_rai -=
389+ (S_accr_rai_icl + S_accr_rai_sno) /
390+ max (q_rai, UT. ϵ_numerics (typeof (q_rai)))
362391
363- # Snow sublimation/deposition and melting
392+ # --- Snow: sublimation/deposition + melting + sink self-derivatives ---
364393 dS_subl_sno =
365394 CM1.∂evaporation_sublimation_∂q_precip (sno, vel. snow, aps, tps, q_tot, q_lcl, q_icl, q_rai, q_sno, ρ, T)
366395 dS_melt_sno = CM1.∂snow_melt_∂q_sno (sno, vel. snow, aps, tps, q_sno, ρ, T)
367396 ∂tendency_∂q_sno = dS_subl_sno - dS_melt_sno
397+ # Snow-rain accretion (warm): snow → rain
398+ S_accr_sno_rai = ifelse (is_warm,
399+ CM1. accretion_snow_rain (rai, sno, vel. rain, vel. snow, ce, q_rai, q_sno, ρ), zero (T))
400+ # Thermal melting from warm rain collision -> snow sink proportional to S_accr_rai_sno
401+ # (Since this is a diagonal derivative, we approximate ∂/∂q_sno by rate/q_sno, using the rain sink form S_accr_rai_sno)
402+ S_accr_sno_rai_melt = ifelse (is_warm,
403+ CM1. accretion_snow_rain (sno, rai, vel. snow, vel. rain, ce, q_sno, q_rai, ρ), zero (T))
404+ # Accretion melt from warm liquid-snow collision
405+ α = warm_accretion_melt_factor (tps, sno, T)
406+ S_accr_lcl_sno_melt = α * CM1. accretion (lcl, sno, vel. snow, ce, q_lcl, q_sno, ρ)
407+ ∂tendency_∂q_sno -=
408+ (S_accr_sno_rai + α * S_accr_sno_rai_melt + S_accr_lcl_sno_melt) /
409+ max (q_sno, UT. ϵ_numerics (typeof (q_sno)))
368410
369411 return (; ∂tendency_∂q_lcl, ∂tendency_∂q_icl, ∂tendency_∂q_rai, ∂tendency_∂q_sno)
370412end
0 commit comments