@@ -17,6 +17,7 @@ use_derivative(::IgnoreDerivative) = false
17
17
sgs_entr_detr_flag,
18
18
sgs_mass_flux_flag,
19
19
sgs_nh_pressure_flag,
20
+ noneq_cloud_formation_flag,
20
21
approximate_solve_iters,
21
22
)
22
23
@@ -40,16 +41,19 @@ setting their `DerivativeFlag`s to either `UseDerivative` or `IgnoreDerivative`.
40
41
subgrid-scale mass flux tendency should be computed
41
42
- `sgs_nh_pressure_flag::DerivativeFlag`: whether the derivatives of the
42
43
subgrid-scale non-hydrostatic pressure drag tendency should be computed
44
+ - `noneq_cloud_formation_flag::DerivativeFlag`: whether the derivatives
45
+ of the nonequilibrium cloud formation sources should be computed
43
46
- `approximate_solve_iters::Int`: number of iterations to take for the
44
47
approximate linear solve required when the `diffusion_flag` is `UseDerivative`
45
48
"""
46
- struct ApproxJacobian{F1, F2, F3, F4, F5, F6} <: JacobianAlgorithm
49
+ struct ApproxJacobian{F1, F2, F3, F4, F5, F6, F7 } <: JacobianAlgorithm
47
50
topography_flag:: F1
48
51
diffusion_flag:: F2
49
52
sgs_advection_flag:: F3
50
53
sgs_entr_detr_flag:: F4
51
54
sgs_mass_flux_flag:: F5
52
55
sgs_nh_pressure_flag:: F6
56
+ noneq_cloud_formation_flag:: F7
53
57
approximate_solve_iters:: Int
54
58
end
55
59
@@ -59,6 +63,7 @@ function jacobian_cache(alg::ApproxJacobian, Y, atmos)
59
63
diffusion_flag,
60
64
sgs_advection_flag,
61
65
sgs_mass_flux_flag,
66
+ noneq_cloud_formation_flag,
62
67
) = alg
63
68
FT = Spaces. undertype (axes (Y. c))
64
69
CTh = CTh_vector_type (axes (Y. c))
@@ -82,14 +87,12 @@ function jacobian_cache(alg::ApproxJacobian, Y, atmos)
82
87
is_in_Y (@name (c. sgs⁰. ρatke)) ? (@name (c. sgs⁰. ρatke),) : ()
83
88
sfc_if_available = is_in_Y (@name (sfc)) ? (@name (sfc),) : ()
84
89
85
- tracer_names = (
86
- @name (c. ρq_tot),
87
- @name (c. ρq_liq),
88
- @name (c. ρq_ice),
89
- @name (c. ρq_rai),
90
- @name (c. ρq_sno),
91
- )
92
- available_tracer_names = MatrixFields. unrolled_filter (is_in_Y, tracer_names)
90
+ condensate_names =
91
+ (@name (c. ρq_liq), @name (c. ρq_ice), @name (c. ρq_rai), @name (c. ρq_sno))
92
+ available_condensate_names =
93
+ MatrixFields. unrolled_filter (is_in_Y, condensate_names)
94
+ available_tracer_names =
95
+ (ρq_tot_if_available... , available_condensate_names... )
93
96
94
97
sgs_tracer_names = (
95
98
@name (c. sgsʲs.:(1 ). q_tot),
@@ -139,6 +142,17 @@ function jacobian_cache(alg::ApproxJacobian, Y, atmos)
139
142
(@name (f. u₃), @name (f. u₃)) => similar (Y. f, TridiagonalRow_C3xACT3),
140
143
)
141
144
145
+ condensate_blocks =
146
+ if atmos. moisture_model isa NonEquilMoistModel &&
147
+ use_derivative (noneq_cloud_formation_flag)
148
+ (
149
+ (@name (c. ρq_liq), @name (c. ρq_tot)) => similar (Y. c, DiagonalRow),
150
+ (@name (c. ρq_ice), @name (c. ρq_tot)) => similar (Y. c, DiagonalRow),
151
+ )
152
+ else
153
+ ()
154
+ end
155
+
142
156
diffused_scalar_names = (@name (c. ρe_tot), available_tracer_names... )
143
157
diffusion_blocks = if use_derivative (diffusion_flag)
144
158
(
@@ -253,6 +267,7 @@ function jacobian_cache(alg::ApproxJacobian, Y, atmos)
253
267
identity_blocks... ,
254
268
sgs_advection_blocks... ,
255
269
advection_blocks... ,
270
+ condensate_blocks... ,
256
271
diffusion_blocks... ,
257
272
sgs_massflux_blocks... ,
258
273
)
@@ -318,7 +333,7 @@ function jacobian_cache(alg::ApproxJacobian, Y, atmos)
318
333
temp_matrix_column = similar (first_column (temp_matrix))
319
334
320
335
return (;
321
- matrix = MatrixFields. FieldMatrixWithSolver (matrix, Y, solver_alg ),
336
+ matrix = MatrixFields. FieldMatrixWithSolver (matrix, Y, full_alg ),
322
337
temp_matrix,
323
338
temp_matrix_column,
324
339
)
@@ -348,8 +363,9 @@ function update_jacobian!(alg::ApproxJacobian, cache, Y, p, dtγ, t)
348
363
diffusion_flag,
349
364
sgs_advection_flag,
350
365
sgs_entr_detr_flag,
351
- sgs_nh_pressure_flag,
352
366
sgs_mass_flux_flag,
367
+ sgs_nh_pressure_flag,
368
+ noneq_cloud_formation_flag,
353
369
) = alg
354
370
(; matrix) = cache
355
371
(; params) = p
@@ -555,6 +571,183 @@ function update_jacobian!(alg::ApproxJacobian, cache, Y, p, dtγ, t)
555
571
556
572
end
557
573
574
+ if p. atmos. moisture_model isa NonEquilMoistModel &&
575
+ use_derivative (noneq_flag)
576
+ p_vapₛₗ (tps, ts) = TD. saturation_vapor_pressure (tps, ts, TD. Liquid ())
577
+ p_vapₛᵢ (tps, ts) = TD. saturation_vapor_pressure (tps, ts, TD. Ice ())
578
+
579
+ function ∂p_vapₛₗ_∂T (tps, ts)
580
+ T = TD. air_temperature (tps, ts)
581
+ Rᵥ = TD. Parameters. R_v (tps)
582
+ Lᵥ = TD. latent_heat_vapor (tps, ts)
583
+ return p_vapₛₗ (tps, ts) * Lᵥ / (Rᵥ * T^ 2 )
584
+ end
585
+ function ∂p_vapₛᵢ_∂T (tps, ts)
586
+ T = TD. air_temperature (tps, ts)
587
+ Rᵥ = TD. Parameters. R_v (tps)
588
+ Lₛ = TD. latent_heat_sublim (tps, ts)
589
+ return p_vapₛᵢ (tps, ts) * Lₛ / (Rᵥ * T^ 2 )
590
+ end
591
+
592
+ function ∂qₛₗ_∂T (tps, ts)
593
+ T = TD. air_temperature (tps, ts)
594
+ Rᵥ = TD. Parameters. R_v (tps)
595
+ Lᵥ = TD. latent_heat_vapor (tps, ts)
596
+ qᵥ_sat_liq = TD. q_vap_saturation_liquid (tps, ts)
597
+ return qᵥ_sat_liq * (Lᵥ / (Rᵥ * T^ 2 ) - 1 / T)
598
+ end
599
+ function ∂qₛᵢ_∂T (tps, ts)
600
+ T = TD. air_temperature (tps, ts)
601
+ Rᵥ = TD. Parameters. R_v (tps)
602
+ Lₛ = TD. latent_heat_sublim (tps, ts)
603
+ qᵥ_sat_ice = TD. q_vap_saturation_ice (tps, ts)
604
+ return qᵥ_sat_ice * (Lₛ / (Rᵥ * T^ 2 ) - 1 / T)
605
+ end
606
+
607
+ function Γₗ (tps, ts)
608
+ cₚ_air = TD. cp_m (tps, ts)
609
+ Lᵥ = TD. latent_heat_vapor (tps, ts)
610
+ return 1 + (Lᵥ / cₚ_air) * ∂qₛₗ_∂T (tps, ts)
611
+ end
612
+ function Γᵢ (tps, ts)
613
+ cₚ_air = TD. cp_m (tps, ts)
614
+ Lₛ = TD. latent_heat_sublim (tps, ts)
615
+ return 1 + (Lₛ / cₚ_air) * ∂qₛᵢ_∂T (tps, ts)
616
+ end
617
+
618
+ cmc = CAP. microphysics_cloud_params (params)
619
+ τₗ = cmc. liquid. τ_relax
620
+ τᵢ = cmc. ice. τ_relax
621
+ function limit (q, dt, n:: Int )
622
+ return q / float (dt) / n
623
+ end
624
+
625
+ function ∂ρqₗ_err_∂ρqᵪ (tps, ts, cmc, dt, deriv, limit_deriv)
626
+ FT_inner = eltype (tps)
627
+ q = TD. PhasePartition (tps, ts)
628
+ ρ = TD. air_density (tps, ts)
629
+
630
+ S = CMNe. conv_q_vap_to_q_liq_ice_MM2015 (cmc. liquid, thp, q, ρ, Tₐ (tps, ts))
631
+
632
+ if S > FT_inner (0 )
633
+ if S <= limit (qᵥ (tps, ts), dt, 2 )
634
+ if TD. vapor_specific_humidity (q) + TD. liquid_specific_humidity (q) > FT_inner (0 )
635
+ return deriv
636
+ else
637
+ return FT_inner (0 )
638
+ end
639
+ else
640
+ return limit_deriv
641
+ end
642
+ else
643
+ if abs (S) <= limit (qₗ (tps, ts, qₚ (qᵣ)), dt, 2 )
644
+ if TD. vapor_specific_humidity (q) + TD. liquid_specific_humidity (q) > FT_inner (0 )
645
+ return - deriv
646
+ else
647
+ return FT_inner (0 )
648
+ end
649
+ else
650
+ return - limit_deriv
651
+ end
652
+ end
653
+ end
654
+
655
+ function ∂ρqᵢ_err_∂ρqᵪ (tps, ts, cmc, dt, deriv, limit_deriv)
656
+ FT_inner = eltype (tps)
657
+ q = TD. PhasePartition (tps, ts)
658
+ ρ = TD. air_density (tps, ts)
659
+
660
+ S = CMNe. conv_q_vap_to_q_liq_ice_MM2015 (cmc. ice, thp, q, ρ, Tₐ (tps, ts))
661
+
662
+ if S > FT_inner (0 )
663
+ if S <= limit (qᵥ (tps, ts), dt, 2 )
664
+ if TD. vapor_specific_humidity (q) + TD. ice_specific_humidity (q) > FT_inner (0 )
665
+ return deriv
666
+ else
667
+ return FT_inner (0 )
668
+ end
669
+ else
670
+ return limit_deriv
671
+ end
672
+ else
673
+ if abs (S) <= limit (qᵢ (thp, ts, qₚ (qₛ)), dt, 2 )
674
+ if TD. vapor_specific_humidity (q) + TD. ice_specific_humidity (q) > FT_inner (0 )
675
+ return - deriv
676
+ else
677
+ return FT_inner (0 )
678
+ end
679
+ else
680
+ return - limit_deriv
681
+ end
682
+ end
683
+ end
684
+
685
+
686
+ ∂ᶜρqₗ_err_∂ᶜρqₗ = matrix[@name (c. ρq_liq), @name (c. ρq_liq)]
687
+ ∂ᶜρqᵢ_err_∂ᶜρqᵢ = matrix[@name (c. ρq_ice), @name (c. ρq_ice)]
688
+
689
+ ∂ᶜρqₗ_err_∂ᶜρqₜ = matrix[@name (c. ρq_liq), @name (c. ρq_tot)]
690
+ ∂ᶜρqᵢ_err_∂ᶜρqₜ = matrix[@name (c. ρq_ice), @name (c. ρq_tot)]
691
+
692
+ # @. ∂ᶜρqₗ_err_∂ᶜρqₗ -=
693
+ # DiagonalMatrixRow(1 / (τₗ * Γₗ(thermo_params, ᶜts)))
694
+ @. ∂ᶜρqₗ_err_∂ᶜρqₗ +=
695
+ DiagonalMatrixRow (
696
+ ∂ρqₗ_err_∂ρqᵪ (
697
+ thermo_params, ᶜts, cmc, dt, (- 1 / (τₗ * Γₗ (thermo_params, ᶜts))), (1 / (2 * float (dt))),
698
+ )
699
+ )
700
+
701
+ # @. ∂ᶜρqᵢ_err_∂ᶜρqᵢ -=
702
+ # DiagonalMatrixRow(1 / (τᵢ * Γᵢ(thermo_params, ᶜts)))
703
+
704
+ @. ∂ᶜρqᵢ_err_∂ᶜρqᵢ +=
705
+ DiagonalMatrixRow (
706
+ ∂ρqᵢ_err_∂ρqᵪ (
707
+ thermo_params, ᶜts, cmc, dt, (- 1 / (τᵢ * Γᵢ (thermo_params, ᶜts))), (1 / (2 * float (dt))),
708
+ )
709
+ )
710
+
711
+ ᶜp = @. lazy (TD. air_pressure (thermo_params, ᶜts))
712
+ ᶜ∂T_∂p = @. lazy (1 / (ᶜρ * TD. gas_constant_air (thermo_params, ᶜts)))
713
+
714
+ # qₛₗ = p_vapₛₗ / p, qₛᵢ = p_vapₛᵢ / p
715
+ ᶜ∂qₛₗ_∂p = @. lazy (
716
+ - p_vapₛₗ (thermo_params, ᶜts) / ᶜp^ 2 +
717
+ ∂p_vapₛₗ_∂T (thermo_params, ᶜts) * ᶜ∂T_∂p / ᶜp,
718
+ )
719
+ ᶜ∂qₛᵢ_∂p = @. lazy (
720
+ - p_vapₛᵢ (thermo_params, ᶜts) / ᶜp^ 2 +
721
+ ∂p_vapₛᵢ_∂T (thermo_params, ᶜts) * ᶜ∂T_∂p / ᶜp,
722
+ )
723
+
724
+ ᶜ∂p_∂ρqₜ = @. lazy (
725
+ ᶜkappa_m * ∂e_int_∂q_tot +
726
+ ᶜ∂kappa_m∂q_tot * (
727
+ cp_d * T_0 + ᶜspecific. e_tot - ᶜK - ᶜΦ +
728
+ ∂e_int_∂q_tot * ᶜspecific. q_tot
729
+ ),
730
+ )
731
+
732
+ # @. ∂ᶜρqₗ_err_∂ᶜρqₜ = DiagonalMatrixRow(
733
+ # (1 - ᶜρ * ᶜ∂qₛₗ_∂p * ᶜ∂p_∂ρqₜ) / (τₗ * Γₗ(thermo_params, ᶜts)),
734
+ # )
735
+ @. ∂ᶜρqₗ_err_∂ᶜρqₜ = DiagonalMatrixRow (
736
+ ∂ρqₗ_err_∂ρqᵪ (
737
+ thermo_params, ts, cmc, dt, ((1 - ᶜρ * ᶜ∂qₛₗ_∂p * ᶜ∂p_∂ρqₜ) / (τₗ * Γₗ (thermo_params, ᶜts))), FT (0 )
738
+ )
739
+ )
740
+
741
+ # @. ∂ᶜρqᵢ_err_∂ᶜρqₜ = DiagonalMatrixRow(
742
+ # (1 - ᶜρ * ᶜ∂qₛᵢ_∂p * ᶜ∂p_∂ρqₜ) / (τᵢ * Γᵢ(thermo_params, ᶜts)),
743
+ # )
744
+ @. ∂ᶜρqᵢ_err_∂ᶜρqₜ = DiagonalMatrixRow (
745
+ ∂ρqᵢ_err_∂ρqᵪ (
746
+ thermo_params, ts, cmc, dt, ((1 - ᶜρ * ᶜ∂qₛᵢ_∂p * ᶜ∂p_∂ρqₜ) / (τᵢ * Γᵢ (thermo_params, ᶜts))), FT (0 )
747
+ )
748
+ )
749
+ end
750
+
558
751
if use_derivative (diffusion_flag)
559
752
α_vert_diff_tracer = CAP. α_vert_diff_tracer (params)
560
753
(; ᶜK_h, ᶜK_u) = p. precomputed
0 commit comments