19#include "scaleFElib.h"
29 use scale_const,
only: &
31 cpdry => const_cpdry, &
34 pres0 => const_pre00, &
36 use scale_atmos_hydrometeor,
only: &
39 use scale_atmos_saturation,
only: &
40 atmos_saturation_psat_liq, &
41 atmos_saturation_pres2qsat_liq
71 integer,
parameter :: MCA_MAX_ADJUST_ITER = 200
72 integer,
parameter :: MCA_MAX_ENERGY_ITER = 50
73 integer,
parameter :: MCA_MAX_WATER_ITER = 60
76 real(RP),
parameter :: MCA_COLUMN_ENERGY_RTOL = 5.0e-7_rp
77 real(RP),
parameter :: MCA_COLUMN_ENERGY_ATOL = 1.0_rp
78 real(RP),
parameter :: MCA_BOUNDARY_ENERGY_RTOL = 1.0e-6_rp
81 real(RP),
parameter :: MCA_LOCAL_HMSE_RTOL = 1.0e-9_rp
82 real(RP),
parameter :: MCA_LOCAL_HMSE_ATOL = 1.0e-4_rp
83 real(RP),
parameter :: MCA_TEMP_TOL = 1.0e-5_rp
86 real(RP),
parameter :: MCA_WATER_RTOL = 1.0e-9_rp
87 real(RP),
parameter :: MCA_WATER_ATOL = 1.0e-10_rp
90 real(RP),
parameter :: MCA_RH_FORCED_SATURATION = 0.999_rp
91 real(RP),
parameter :: MCA_RH_TRIGGER = 0.999_rp
94 real(RP),
parameter :: MCA_HMSE_GRAD_TOL = 1.0e-3_rp
95 real(RP),
parameter :: MCA_HMSE_DIFF_TOL = 1.0_rp
96 real(RP),
parameter :: MCA_MIN_UNSTABLE_DEPTH = 0.0_rp
97 real(RP),
parameter :: MCA_Z_TOL = 100.0_rp * epsilon(1.0_rp)
100 integer,
parameter :: MCA_PROFILE_SUCCESS = 0
101 integer,
parameter :: MCA_PROFILE_NO_ENERGY_ROOT = 1
102 integer,
parameter :: MCA_PROFILE_ADIABAT_FAILURE = 2
103 integer,
parameter :: MCA_PROFILE_ENERGY_MAXITER = 3
104 integer,
parameter :: MCA_PROFILE_NO_ADJUSTED_NODE = 4
105 integer,
parameter :: MCA_PROFILE_NO_WATER_FEASIBLE_STATE = 5
118 DENS_t, RHOT_t, RHOQV_t, SFLX_RAIN, SFLX_ENGI, & ! (out)
119 ddens, drhot, qv, pt, pres, dens_hyd, rtot, cptot, &
120 dtsec, lmesh, elem, elem1d )
122 use scale_tracer,
only: &
124 use scale_atmos_hydrometeor,
only: &
130 real(rp),
intent(out) :: dens_t(elem%np,lmesh%nea)
131 real(rp),
intent(out) :: rhot_t(elem%np,lmesh%nea)
132 real(rp),
intent(out) :: rhoqv_t(elem%np,lmesh%nea)
133 real(rp),
intent(out) :: sflx_rain(elem%nnode_h1d**2,lmesh%ne2da)
134 real(rp),
intent(out) :: sflx_engi(elem%nnode_h1d**2,lmesh%ne2da)
135 real(rp),
intent(in) :: ddens(elem%np,lmesh%nea)
136 real(rp),
intent(in) :: drhot(elem%np,lmesh%nea)
137 real(rp),
intent(in) :: qv(elem%np,lmesh%nea)
138 real(rp),
intent(in) :: pt(elem%np,lmesh%nea)
139 real(rp),
intent(in) :: pres(elem%np,lmesh%nea)
140 real(rp),
intent(in) :: dens_hyd(elem%np,lmesh%nea)
141 real(rp),
intent(in) :: rtot(elem%np,lmesh%nea)
142 real(rp),
intent(in) :: cptot(elem%np,lmesh%nea)
143 real(rp),
intent(in) :: dtsec
145 integer :: ke, ke_xy, ke_z
147 real(rp) :: dens_z(elem%nnode_v,lmesh%nez)
148 real(rp) :: pres_z(elem%nnode_v,lmesh%nez)
149 real(rp) :: zlev_z(elem%nnode_v,lmesh%nez)
150 real(rp) :: temp_z(elem%nnode_v,lmesh%nez)
151 real(rp) :: pott_z(elem%nnode_v,lmesh%nez)
152 real(rp) :: qvap_z(elem%nnode_v,lmesh%nez)
155 real(rp) :: rtot_, cptot_, qdry
157 real(rp) :: elem_width_z
158 real(rp) :: int_weight(elem%nnode_v,lmesh%nez)
160 real(rp) :: pott_ini(elem%nnode_v,lmesh%nez)
161 real(rp) :: qvap_ini(elem%nnode_v,lmesh%nez)
162 real(rp) :: dens_ini(elem%nnode_v,lmesh%nez)
163 real(rp) :: rhoqvap_ini(elem%nnode_v,lmesh%nez)
165 integer :: iter_expand
166 integer :: mca_max_mask_expand
167 integer :: lbase, ltop, lbase_try, ltop_try
168 real(rp) :: zbase_try, ztop_try
169 logical :: mask_expanded
171 logical :: is_unstable
172 logical :: unstable_core_mask(elem%nnode_v,lmesh%nez)
173 logical :: forced_saturation_mask(elem%nnode_v,lmesh%nez)
174 logical :: adjustment_mask(elem%nnode_v,lmesh%nez)
176 logical :: current_saturation_mask(elem%nnode_v,lmesh%nez)
177 logical :: persistent_saturation_mask(elem%nnode_v,lmesh%nez)
179 logical :: physical_active_mask(elem%nnode_v,lmesh%nez)
181 real(rp) :: temp_adj(elem%nnode_v,lmesh%nez)
182 real(rp) :: qvap_adj(elem%nnode_v,lmesh%nez)
183 real(rp) :: rhoqvap_adj(elem%nnode_v,lmesh%nez)
184 real(rp) :: rhoprecip_adj(elem%nnode_v,lmesh%nez)
185 real(rp) :: rhoprecip_accum(elem%nnode_v,lmesh%nez)
186 real(rp) :: precip_engi_accum
188 real(rp),
allocatable :: zlev_diag(:)
191 logical :: profile_converged
192 integer :: profile_status
193 logical :: do_adjustment
194 logical :: adjustment_converged
196 integer :: hslice_b(elem%nnode_h1d**2), hslice_t(elem%nnode_h1d**2)
198 logical :: debug_flag
200 integer :: lactive_base
201 integer :: lactive_top
202 logical :: active_region_initialized
205 nlev_diag = lmesh%NeZ * (elem%Nnode_v-1) + 1
206 allocate( zlev_diag(nlev_diag) )
208 hslice_b(:) = elem%Hslice(:,1)
209 hslice_t(:) = elem%Hslice(:,elem%Nnode_v)
211 mca_max_mask_expand = nlev_diag
223 do ke_xy=1, lmesh%Ne2D
224 do ph=1, elem%Nnode_h1D**2
235 ke = ke_xy + (ke_z-1)*lmesh%Ne2D
237 elem_width_z = lmesh%zlev(hslice_t(ph),ke) - lmesh%zlev(hslice_b(ph),ke)
238 do pz=1, elem%Nnode_v
239 p = ph + (pz-1)*elem%Nnode_h1D**2
240 dens_z(pz,ke_z) = ddens(p,ke) + dens_hyd(p,ke)
241 pres_z(pz,ke_z) = pres(p,ke)
242 zlev_z(pz,ke_z) = lmesh%zlev(p,ke)
243 int_weight(pz,ke_z) = elem1d%IntWeight_lgl(pz) * 0.5_rp * elem_width_z
245 temp_z(pz,ke_z) = pres(p,ke)/ ( dens_z(pz,ke_z) * rtot(p,ke) )
246 qvap_z(pz,ke_z) = qv(p,ke)
247 pott_z(pz,ke_z) = pt(p,ke)
254 dens_ini(:,ke_z) = dens_z(:,ke_z)
255 pott_ini(:,ke_z) = pott_z(:,ke_z)
256 qvap_ini(:,ke_z) = qvap_z(:,ke_z)
257 rhoqvap_ini(:,ke_z) = dens_ini(:,ke_z) * qvap_ini(:,ke_z)
259 temp_adj(:,ke_z) = temp_z(:,ke_z)
260 rhoqvap_adj(:,ke_z) = rhoqvap_ini(:,ke_z)
261 rhoprecip_accum(:,ke_z) = 0.0_rp
267 adjustment_converged = .false.
268 do_adjustment = .false.
270 active_region_initialized = .false.
274 forced_saturation_mask(:,:) = .false.
275 current_saturation_mask(:,:) = .false.
276 persistent_saturation_mask(:,:) = .false.
277 physical_active_mask(:,:) = .false.
279 do iter_adj=1, mca_max_adjust_iter
281 qvap_adj(:,:) = rhoqvap_adj(:,:) / dens_z(:,:)
284 current_saturation_mask(:,:) = .false.
285 forced_saturation_mask(:,:) = .false.
289 call diagnose_convective_layer( lbase, ltop, is_unstable, zlev_diag, &
290 temp_adj, qvap_adj, pres_z, zlev_z, lmesh, elem, nlev_diag, debug_flag )
292 if ( debug_flag )
then
293 write(*,*)
"ke_xy=", ke_xy,
"ph=", ph,
"iter_adj=", iter_adj
294 write(*,*)
" lbase, ltop, is_unstable = ", lbase, ltop, is_unstable
297 if ( .not. is_unstable )
then
298 adjustment_converged = .true.
301 do_adjustment = .true.
306 if ( .not. active_region_initialized )
then
309 active_region_initialized = .true.
310 else if ( lbase <= lactive_top + 1 .and. &
311 ltop >= lactive_base - 1 )
then
314 lactive_base = min(lactive_base, lbase)
315 lactive_top = max(lactive_top, ltop)
321 persistent_saturation_mask(:,:) = .false.
324 if ( debug_flag )
then
325 write(*,*)
" persistent active region=", lactive_base, lactive_top
330 call make_dg_vertical_range_mask( &
331 physical_active_mask, &
332 zlev_z, zlev_diag(lactive_base), zlev_diag(lactive_top), &
333 elem%Nnode_v, lmesh%NeZ )
337 call make_dg_vertical_range_mask( &
338 unstable_core_mask, &
339 zlev_z, zlev_diag(lbase), zlev_diag(ltop), &
340 elem%Nnode_v, lmesh%NeZ )
342 do ke_z = 1, lmesh%NeZ
343 do pz = 1, elem%Nnode_v
344 if ( unstable_core_mask(pz,ke_z) )
then
345 call atmos_saturation_pres2qsat_liq( temp_adj(pz,ke_z), pres_z(pz,ke_z), &
348 rh_z = qvap_adj(pz,ke_z) / max(qsat, eps)
349 current_saturation_mask(pz,ke_z) = rh_z >= mca_rh_forced_saturation
356 forced_saturation_mask(:,:) = persistent_saturation_mask(:,:) .or. current_saturation_mask(:,:)
361 lbase_try = lactive_base
362 ltop_try = lactive_top
364 profile_converged = .false.
365 profile_status = mca_profile_energy_maxiter
367 do iter_expand=0, mca_max_mask_expand
368 zbase_try = zlev_diag(lbase_try)
369 ztop_try = zlev_diag(ltop_try)
372 call make_dg_vertical_range_mask( adjustment_mask, &
373 zlev_z, zbase_try, ztop_try, elem%Nnode_v, lmesh%NeZ )
375 if ( debug_flag )
then
376 write(*,*)
"* Adjustment-profile attempt: iter_expand=", iter_expand
377 write(*,*)
" lactive_base, lactive_top=", lactive_base, lactive_top
378 write(*,*)
" lbase_try, ltop_try=", lbase_try, ltop_try
379 write(*,*)
" zbase_try, ztop_try=", zbase_try, ztop_try
380 write(*,*)
" saturation, mixing nodes=", count(forced_saturation_mask), count(adjustment_mask)
385 call solve_moist_neutral_adjustment( &
386 temp_adj, qvap_adj, rhoqvap_adj, rhoprecip_adj, profile_converged, profile_status, &
387 qvap_z, pres_z, zlev_z, dens_z, temp_z, &
388 int_weight, adjustment_mask, forced_saturation_mask, elem%Nnode_v, lmesh%NeZ, debug_flag )
390 if ( profile_converged )
then
392 do ke_z = 1, lmesh%NeZ
393 do pz = 1, elem%Nnode_v
394 if ( physical_active_mask(pz,ke_z) )
then
396 call atmos_saturation_pres2qsat_liq( temp_adj(pz,ke_z), pres_z(pz,ke_z), &
399 rh_z = qvap_adj(pz,ke_z) / qsat
400 if ( rh_z >= mca_rh_forced_saturation )
then
401 persistent_saturation_mask(pz,ke_z) = .true.
407 if ( debug_flag )
then
408 write(*,*)
"Moist-neutral profile converged: iter_expand=", iter_expand
409 write(*,*)
"final solve region: lbase, ltop=", lbase_try, ltop_try
410 write(*,*)
"physical active region=", lactive_base, lactive_top
411 write(*,*)
"persistent saturated nodes=", count(persistent_saturation_mask)
416 select case ( profile_status )
417 case ( mca_profile_no_energy_root )
418 call expand_adjustment_layer( lbase_try, ltop_try, mask_expanded, nlev_diag )
419 if ( .not. mask_expanded )
then
428 if ( .not. profile_converged )
then
429 log_info(
"atm_phy_cp_dgm_mconv_adjustment_calc_tendency",*)
"iter_adj=", iter_adj,
"ph=", ph,
"ke_xy=", ke_xy,
"iter_expand=", iter_expand
430 select case ( profile_status )
431 case ( mca_profile_no_energy_root )
432 log_info(
"atm_phy_cp_dgm_mconv_adjustment_calc_tendency",*)
"No energy-conserving root exists in the water-feasible temperature interval, even after adjustment-layer expansion."
433 log_info(
"atm_phy_cp_dgm_mconv_adjustment_calc_tendency",*)
"original lbase,ltop=", lbase, ltop,
"final lbase,ltop=", lbase_try, ltop_try
434 do_adjustment = .false.
437 case ( mca_profile_no_water_feasible_state )
438 log_info(
"atm_phy_cp_dgm_mconv_adjustment_calc_tendency",*)
"No water-feasible trial moist-neutral profile exists."
440 case ( mca_profile_adiabat_failure )
441 log_info(
"atm_phy_cp_dgm_mconv_adjustment_calc_tendency",*)
"Moist-adiabat profile integration failed."
443 case ( mca_profile_energy_maxiter )
444 log_info(
"atm_phy_cp_dgm_mconv_adjustment_calc_tendency",*)
"Energy root was bracketed, but bisection did not converge."
446 case ( mca_profile_no_adjusted_node )
447 log_info(
"atm_phy_cp_dgm_mconv_adjustment_calc_tendency",*)
"No adjusted DG node was found."
450 log_info(
"atm_phy_cp_dgm_mconv_adjustment_calc_tendency",*)
"Unknown moist-neutral-profile construction error."
456 rhoprecip_accum(:,:) = rhoprecip_accum(:,:) + rhoprecip_adj(:,:)
459 temp_z(:,:) = temp_adj(:,:)
460 qvap_z(:,:) = qvap_adj(:,:)
462 do ke_z = 1, lmesh%NeZ
463 do pz = 1, elem%Nnode_v
464 qdry = 1.0_rp - qvap_z(pz,ke_z)
465 rtot_ = rdry * qdry &
466 + rvap * qvap_z(pz,ke_z)
467 pres_z(pz,ke_z) = dens_z(pz,ke_z) * rtot_ * temp_z(pz,ke_z)
472 if ( do_adjustment .and. ( .not. adjustment_converged ) )
then
473 log_info(
"atm_phy_cp_dgm_mconv_adjustment_calc_tendency",*)
"Moist convective adjustment did not converge: ph=", ph,
"ke_xy=", ke_xy
480 sflx_rain(ph,ke_xy) = 0.0_rp
481 sflx_engi(ph,ke_xy) = 0.0_rp
483 if ( do_adjustment )
then
486 ke = ke_xy + (ke_z-1)*lmesh%Ne2D
488 dens_z(:,ke_z) = dens_ini(:,ke_z) - rhoprecip_accum(:,ke_z)
489 qvap_z(:,ke_z) = rhoqvap_adj(:,ke_z) / dens_z(:,ke_z)
491 do pz=1, elem%Nnode_v
492 qdry = 1.0_rp - qvap_z(pz,ke_z)
493 rtot_ = rdry * qdry + rvap * qvap_z(pz,ke_z)
494 cptot_ = cpdry * qdry + cp_vapor * qvap_z(pz,ke_z)
496 pres_z(pz,ke_z) = dens_z(pz,ke_z) * rtot_ * temp_z(pz,ke_z)
497 pott_z(pz,ke_z) = temp_adj(pz,ke_z) * ( pres0 / pres_z(pz,ke_z) )**( rtot_ / cptot_ )
499 sflx_rain(ph,ke_xy) = sflx_rain(ph,ke_xy) &
500 - rhoprecip_accum(pz,ke_z) * int_weight(pz,ke_z) / dtsec
501 sflx_engi(ph,ke_xy) = sflx_engi(ph,ke_xy) &
502 - temp_adj(pz,ke_z) * rhoprecip_accum(pz,ke_z) * int_weight(pz,ke_z) * cptot_ / dtsec
505 do pz=1, elem%Nnode_v
506 p = ph + (pz-1)*elem%Nnode_h1D**2
507 dens_t(p,ke) = ( dens_z(pz,ke_z) - dens_ini(pz,ke_z) ) / dtsec
508 rhot_t(p,ke) = ( dens_z(pz,ke_z) * pott_z(pz,ke_z) - dens_ini(pz,ke_z) * pott_ini(pz,ke_z) ) / dtsec
509 rhoqv_t(p,ke) = ( dens_z(pz,ke_z) * qvap_z(pz,ke_z) - rhoqvap_ini(pz,ke_z) ) / dtsec
513 if ( debug_flag )
then
514 write(*,*)
" MCA summary:"
515 write(*,*)
" del_DENS: ", dens_z(:,:) - dens_ini(:,:)
516 write(*,*)
" del_RHOT: ", dens_z(:,:) * pott_z(:,:) - dens_ini(:,:) * pott_ini(:,:)
517 write(*,*)
" del_RHOQV: ", dens_z(:,:) * qvap_z(:,:) - rhoqvap_ini(:,:)
518 write(*,*)
"----------------------------------------------------------------"
522 ke = ke_xy + (ke_z-1)*lmesh%Ne2D
523 do pz=1, elem%Nnode_v
524 p = ph + (pz-1)*elem%Nnode_h1D**2
525 dens_t(p,ke) = 0.0_rp
526 rhot_t(p,ke) = 0.0_rp
527 rhoqv_t(p,ke) = 0.0_rp
549 subroutine build_diagnostic_profile_from_dg( &
550 hmse_diag, rh_diag, zlev_diag, & ! (out)
551 hmse_z, rh_z, zlev_z, lmesh, elem, nlev )
555 integer,
intent(in) :: nlev
556 real(rp),
intent(out) :: hmse_diag(nlev)
557 real(rp),
intent(out) :: rh_diag(nlev)
558 real(rp),
intent(out) :: zlev_diag(nlev)
559 real(rp),
intent(in) :: hmse_z(elem%nnode_v,lmesh%nez)
560 real(rp),
intent(in) :: rh_z(elem%nnode_v,lmesh%nez)
561 real(rp),
intent(in) :: zlev_z(elem%nnode_v,lmesh%nez)
568 nnode_v = elem%Nnode_v
571 hmse_diag(l) = hmse_z(1,1)
572 rh_diag(l) = rh_z(1,1)
573 zlev_diag(l) = zlev_z(1,1)
577 hmse_diag(l) = hmse_z(pz,ke_z)
578 rh_diag(l) = rh_z(pz,ke_z)
579 zlev_diag(l) = zlev_z(pz,ke_z)
582 if ( ke_z < lmesh%NeZ )
then
583 hmse_diag(l) = 0.5_rp * ( hmse_z(nnode_v,ke_z) + hmse_z(1,ke_z+1) )
584 rh_diag(l) = 0.5_rp * ( rh_z(nnode_v,ke_z) + rh_z(1,ke_z+1) )
585 zlev_diag(l) = 0.5_rp * ( zlev_z(nnode_v,ke_z) + zlev_z(1,ke_z+1) )
587 hmse_diag(l) = hmse_z(nnode_v,ke_z)
588 rh_diag(l) = rh_z(nnode_v,ke_z)
589 zlev_diag(l) = zlev_z(nnode_v,ke_z)
593 end subroutine build_diagnostic_profile_from_dg
596 subroutine diagnose_convective_layer( lbase, ltop, is_unstable, zlev_diag, & ! (out)
597 temp_z, qvap_z, pres_z, zlev_z, lmesh, elem, nlev, debug_flag )
601 integer,
intent(in) :: nlev
602 integer,
intent(out) :: lbase
603 integer,
intent(out) :: ltop
604 logical,
intent(out) :: is_unstable
605 real(rp),
intent(out) :: zlev_diag(nlev)
606 real(rp),
intent(in) :: temp_z(elem%nnode_v,lmesh%nez)
607 real(rp),
intent(in) :: qvap_z(elem%nnode_v,lmesh%nez)
608 real(rp),
intent(in) :: pres_z(elem%nnode_v,lmesh%nez)
609 real(rp),
intent(in) :: zlev_z(elem%nnode_v,lmesh%nez)
610 logical,
intent(in) :: debug_flag
615 real(rp) :: hmse_sat_z(elem%nnode_v,lmesh%nez)
616 real(rp) :: rh_z(elem%nnode_v,lmesh%nez)
617 real(rp) :: qsat, cptot
620 real(rp) :: hmse_sat(nlev)
623 real(rp) :: dhmse_sat, dhmse_sat_dz
625 logical :: unstable_pair
631 nnode_v = elem%Nnode_v
636 call atmos_saturation_pres2qsat_liq( temp_z(pz,ke_z), pres_z(pz,ke_z), &
639 rh_z(pz,ke_z) = qvap_z(pz,ke_z) / max(qsat, eps)
641 cptot = cpdry * (1.0_rp - qsat) + cp_vapor * qsat
642 hmse_sat_z(pz,ke_z) = cptot * temp_z(pz,ke_z) + grav * zlev_z(pz,ke_z) + lhv * qsat
646 call build_diagnostic_profile_from_dg( hmse_sat, rh, zlev_diag, &
647 hmse_sat_z, rh_z, zlev_z, &
652 is_unstable = .false.
657 dz = zlev_diag(l+1) - zlev_diag(l)
658 dhmse_sat = hmse_sat(l+1) - hmse_sat(l)
659 dhmse_sat_dz = dhmse_sat / dz
660 rh_lyr = 0.5_rp * ( rh(l) + rh(l+1) )
664 ( min(rh(l), rh(l+1)) >= mca_rh_trigger ) &
665 .and. ( dhmse_sat < -mca_hmse_diff_tol ) &
666 .and. ( dhmse_sat_dz < -mca_hmse_grad_tol )
669 if ( unstable_pair )
then
670 if ( .not. is_inside )
then
675 else if ( is_inside )
then
680 if ( is_inside )
then
681 if ( zlev_diag(ltop) - zlev_diag(lbase) >= mca_min_unstable_depth ) is_unstable = .true.
684 if ( debug_flag .and. is_unstable )
then
685 write(*,*)
"Diagnose convective layer:"
686 write(*,*)
"hmse_sat=", hmse_sat(lbase:ltop)
687 write(*,*)
"rh=", rh(lbase:ltop)
688 write(*,*)
"hmse_sat_dg=", hmse_sat_z(:,:)
689 write(*,*)
"rh_dg=", rh_z(:,:)
693 end subroutine diagnose_convective_layer
696 subroutine make_dg_vertical_range_mask( adjustment_mask, & ! (out)
697 zlev, zbase, ztop, npz, nez )
699 integer,
intent(in) :: npz
700 integer,
intent(in) :: nez
701 logical,
intent(out) :: adjustment_mask(npz,nez)
702 real(rp),
intent(in) :: zlev(npz,nez)
703 real(rp),
intent(in) :: zbase
704 real(rp),
intent(in) :: ztop
709 adjustment_mask(:,:) = .false.
712 if ( zlev(pz,ke_z) >= zbase - mca_z_tol .and. &
713 zlev(pz,ke_z) <= ztop + mca_z_tol )
then
714 adjustment_mask(pz,ke_z) = .true.
719 end subroutine make_dg_vertical_range_mask
724 subroutine expand_adjustment_layer( &
725 lbase, ltop, expanded, & ! (inout,out)
729 integer,
intent(inout) :: lbase
730 integer,
intent(inout) :: ltop
731 logical,
intent(out) :: expanded
732 integer,
intent(in) :: nlev
734 logical :: can_expand_below
735 logical :: can_expand_above
738 can_expand_below = lbase > 1
739 can_expand_above = ltop < nlev
745 if ( can_expand_below )
then
750 if ( can_expand_above )
then
755 end subroutine expand_adjustment_layer
764 subroutine solve_moist_neutral_adjustment( &
765 temp_adj, qvap_adj, rhoqvap_adj, rhoprecip_adj, converged, profile_status, & ! (out)
766 qvap, pres, zlev, dens, temp, &
767 int_weight, mix_mask, saturation_mask, npz, nez, debug_flag )
770 integer,
intent(in) :: npz
771 integer,
intent(in) :: nez
772 real(rp),
intent(out) :: temp_adj(npz,nez)
773 real(rp),
intent(out) :: qvap_adj(npz,nez)
774 real(rp),
intent(out) :: rhoqvap_adj(npz,nez)
775 real(rp),
intent(out) :: rhoprecip_adj(npz,nez)
776 logical,
intent(out) :: converged
777 integer,
intent(out) :: profile_status
778 real(rp),
intent(in) :: qvap(npz,nez)
779 real(rp),
intent(in) :: pres(npz,nez)
780 real(rp),
intent(in) :: zlev(npz,nez)
781 real(rp),
intent(in) :: dens(npz,nez)
782 real(rp),
intent(in) :: temp(npz,nez)
783 real(rp),
intent(in) :: int_weight(npz,nez)
784 logical,
intent(in) :: mix_mask(npz,nez)
785 logical,
intent(in) :: saturation_mask(npz,nez)
786 logical,
intent(in) :: debug_flag
789 real(rp) :: energy_target
790 real(rp) :: water_mass_ini
793 real(rp) :: energy_trial
794 real(rp) :: water_trial
798 real(rp) :: tbase_lo, tbase_mid, tbase_hi
799 real(rp) :: residual_lo, residual_hi
801 real(rp) :: water_tmin, energy_tmin
802 real(rp) :: water_wlo, water_whi
803 real(rp) :: energy_wlo, energy_whi
805 real(rp) :: energy_lo, energy_hi
806 real(rp) :: water_lo, water_hi
809 real(rp) :: twater_lo, twater_mid, twater_hi
810 real(rp) :: water_mid, energy_mid
813 real(rp) :: temp_trial(npz,nez)
814 real(rp) :: pres_trial(npz,nez)
815 real(rp) :: qvap_trial(npz,nez)
818 real(rp) :: water_mass_adj
819 real(rp) :: precip_mass_local
820 real(rp) :: precip_mass_total
821 real(rp) :: positive_cond_mass
822 real(rp) :: precip_scale
825 real(rp) :: energy_tol
826 real(rp) :: boundary_energy_tol
827 real(rp) :: water_tol
831 integer :: iter_water
833 logical :: found_base
834 logical :: adiabat_profile_ok
836 logical :: water_lo_feasible
837 logical :: water_hi_feasible
839 real(rp),
parameter :: mca_tbase_range = 40.0_rp
843 profile_status = mca_profile_energy_maxiter
847 temp_adj(:,:) = temp(:,:)
848 qvap_adj(:,:) = qvap(:,:)
849 rhoqvap_adj(:,:) = dens(:,:) * qvap(:,:)
850 rhoprecip_adj(:,:) = 0.0_rp
854 call integ_masked_column_mse( energy_target, &
855 temp, qvap, zlev, dens, &
856 int_weight, mix_mask, npz, nez )
858 energy_tol = mca_column_energy_atol + mca_column_energy_rtol * abs(energy_target)
859 boundary_energy_tol = mca_column_energy_atol + mca_boundary_energy_rtol * abs(energy_target)
868 if ( mix_mask(pz,ke_z) )
then
869 tbase_mid = temp(pz,ke_z)
874 if ( found_base )
exit
877 if ( .not. found_base )
then
878 profile_status = mca_profile_no_adjusted_node
879 if ( debug_flag )
then
880 write(*,*)
"solve_moist_neutral_adjustment: No adjusted DG node was found."
887 water_mass_ini = 0.0_rp
891 if ( mix_mask(pz,ke_z) )
then
892 water_mass_ini = water_mass_ini + int_weight(pz,ke_z) * dens(pz,ke_z) * qvap(pz,ke_z)
897 water_tol = mca_water_atol + mca_water_rtol * max(abs(water_mass_ini),1.0_rp)
903 twater_lo = tbase_mid - mca_tbase_range
904 twater_hi = tbase_mid + mca_tbase_range
908 pres_trial(:,:) = pres(:,:)
909 call evaluate_trial_moist_neutral_profile( temp_trial, qvap_trial, water_tmin, energy_tmin, adiabat_profile_ok, &
911 twater_lo, temp, qvap, dens, zlev, int_weight, mix_mask, saturation_mask, nez, npz, debug_flag )
913 if ( .not. adiabat_profile_ok )
then
914 profile_status = mca_profile_adiabat_failure
915 if ( debug_flag )
then
916 write(*,*)
"solve_moist_neutral_adjustment: Moist-adiabat integration failed. tbase_lo=", twater_lo
921 water_lo_feasible = ( water_tmin <= water_mass_ini + water_tol )
922 if ( .not. water_lo_feasible )
then
923 profile_status = mca_profile_no_water_feasible_state
925 if ( debug_flag )
then
926 write(*,*)
"No water-feasible saturated profile exists."
927 write(*,*)
" tbase_lo=", twater_lo,
"water_mass_lo=", water_tmin,
"water_mass_ini =", water_mass_ini
933 water_wlo = water_tmin
934 energy_wlo = energy_tmin
939 pres_trial(:,:) = pres(:,:)
940 call evaluate_trial_moist_neutral_profile( temp_trial, qvap_trial, water_whi, energy_whi, adiabat_profile_ok, &
942 twater_hi, temp, qvap, dens, zlev, int_weight, mix_mask, saturation_mask, nez, npz, debug_flag )
944 if ( adiabat_profile_ok )
then
945 water_hi_feasible = ( water_whi <= water_mass_ini + water_tol )
947 water_hi_feasible = .false.
948 water_whi = huge(1.0_rp)
950 if ( debug_flag )
then
951 write(*,*)
"High-temperature trial profile is not admissible."
952 write(*,*)
" Treating it as the infeasible upper bracket: twater_hi=", twater_hi
958 if ( debug_flag )
then
959 write(*,*)
"Water feasibility at initial bounds:"
960 write(*,*)
" t_lo, water_lo =", twater_lo, water_tmin
961 write(*,*)
" t_hi, water_hi =", twater_hi, water_whi
962 write(*,*)
" lower feasible =", water_lo_feasible
963 write(*,*)
" upper feasible =", water_hi_feasible
964 write(*,*)
" water_mass_ini =", water_mass_ini
965 write(*,*)
" water_tol =", water_tol
969 if ( .not. water_hi_feasible )
then
980 pres_trial(:,:) = pres(:,:)
982 do iter_water = 1, mca_max_water_iter
983 twater_mid = 0.5_rp * ( twater_lo + twater_hi )
985 call evaluate_trial_moist_neutral_profile( temp_trial, qvap_trial, water_mid, energy_mid, adiabat_profile_ok, &
987 twater_mid, temp, qvap, dens, zlev, int_weight, mix_mask, saturation_mask, nez, npz, debug_flag )
989 if ( .not. adiabat_profile_ok )
then
992 twater_hi = twater_mid
993 water_whi = huge(1.0_rp)
994 energy_whi = huge(1.0_rp)
1001 if ( abs(twater_hi - twater_lo) <= mca_temp_tol )
exit
1005 if ( water_mid <= water_mass_ini + water_tol )
then
1007 twater_lo = twater_mid
1008 water_wlo = water_mid
1009 energy_wlo = energy_mid
1012 twater_hi = twater_mid
1013 water_whi = water_mid
1014 energy_whi = energy_mid
1021 if ( abs(twater_hi - twater_lo) <= mca_temp_tol )
exit
1022 if ( abs(water_mid - water_mass_ini) <= water_tol )
exit
1027 tbase_lo = tbase_mid - mca_tbase_range
1028 water_lo = water_tmin
1029 energy_lo = energy_tmin
1031 if ( water_hi_feasible )
then
1033 tbase_hi = twater_hi
1034 water_hi = water_whi
1035 energy_hi = energy_whi
1039 tbase_hi = twater_lo
1040 water_hi = water_wlo
1041 energy_hi = energy_wlo
1047 residual_lo = energy_lo - energy_target
1048 residual_hi = energy_hi - energy_target
1050 if ( debug_flag )
then
1051 write(*,*)
"Energy-root feasibility check:"
1052 write(*,*)
" energy_target =", energy_target
1053 write(*,*)
" energy_tol =", energy_tol
1054 write(*,*)
" tbase_lo =", tbase_lo
1055 write(*,*)
" energy_lo =", energy_lo
1056 write(*,*)
" residual_lo =", residual_lo
1057 write(*,*)
" tbase_water_max =", tbase_hi
1058 write(*,*)
" energy_water_max =", energy_hi
1059 write(*,*)
" residual_water_max =", residual_hi
1060 write(*,*)
" water_at_upper =", water_hi
1061 write(*,*)
" water_mass_ini =", water_mass_ini
1065 if ( abs(residual_lo) <= boundary_energy_tol )
then
1066 pres_trial(:,:) = pres(:,:)
1067 call evaluate_trial_moist_neutral_profile( temp_adj, qvap_adj, water_mass_adj, energy_trial, adiabat_profile_ok, &
1069 tbase_lo, temp, qvap, dens, zlev, int_weight, mix_mask, saturation_mask, nez, npz, debug_flag )
1071 if ( .not. adiabat_profile_ok )
then
1072 profile_status = mca_profile_adiabat_failure
1076 profile_status = mca_profile_success
1078 else if ( abs(residual_hi) <= boundary_energy_tol )
then
1079 pres_trial(:,:) = pres(:,:)
1080 call evaluate_trial_moist_neutral_profile( temp_adj, qvap_adj, water_mass_adj, energy_trial, adiabat_profile_ok, &
1082 tbase_hi, temp, qvap, dens, zlev, int_weight, mix_mask, saturation_mask, nez, npz, debug_flag )
1084 if ( .not. adiabat_profile_ok )
then
1085 profile_status = mca_profile_adiabat_failure
1090 profile_status = mca_profile_success
1092 else if ( residual_lo * residual_hi > 0.0_rp )
then
1093 profile_status = mca_profile_no_energy_root
1094 if ( debug_flag )
then
1095 write(*,*)
"No energy root exists in the water-feasible interval."
1096 write(*,*)
" tbase_lo =", tbase_lo
1097 write(*,*)
" tbase_water_max =", tbase_hi
1098 write(*,*)
" residual_lo =", residual_lo
1099 write(*,*)
" residual_upper =", residual_hi
1100 write(*,*)
" water_mass_ini =", water_mass_ini
1101 write(*,*)
" water_mass_upper =", water_hi
1109 if ( .not. converged )
then
1111 pres_trial(:,:) = pres(:,:)
1113 do iter=1, mca_max_energy_iter
1115 tbase_mid = 0.5_rp * ( tbase_lo + tbase_hi )
1117 call evaluate_trial_moist_neutral_profile( temp_adj, qvap_adj, water_trial, energy_trial, adiabat_profile_ok, &
1119 tbase_mid, temp, qvap, dens, zlev, int_weight, mix_mask, saturation_mask, nez, npz, debug_flag )
1121 if ( .not. adiabat_profile_ok )
then
1122 profile_status = mca_profile_adiabat_failure
1124 if ( debug_flag )
then
1125 write(*,*)
"Moist-adiabat integration failed during"
1126 write(*,*)
"energy-root search: iteration=", iter,
", tbase=", tbase_mid
1133 if ( water_trial > water_mass_ini + water_tol )
then
1134 profile_status = mca_profile_no_energy_root
1135 if ( debug_flag )
then
1136 write(*,*)
"Energy bisection entered a water-infeasible state."
1137 write(*,*)
" tbase =", tbase_mid
1138 write(*,*)
" water_trial =", water_trial
1139 write(*,*)
" water_mass_ini =", water_mass_ini
1144 residual = energy_trial - energy_target
1154 if ( abs(residual) <= energy_tol )
then
1155 water_mass_adj = water_trial
1157 profile_status = mca_profile_success
1163 if ( residual_lo * residual <= 0.0_rp )
then
1164 tbase_hi = tbase_mid
1165 residual_hi = residual
1167 tbase_lo = tbase_mid
1168 residual_lo = residual
1174 if ( .not. converged )
then
1175 profile_status = mca_profile_energy_maxiter
1177 if ( debug_flag )
then
1178 write(*,*)
"Energy bisection did not converge."
1179 write(*,*)
" tbase_lo=", tbase_lo,
", tbase_hi=", tbase_hi
1180 write(*,*)
" residual_lo=", residual_lo,
", residual_hi=", residual_hi
1181 write(*,*)
" energy_tol=", energy_tol
1189 rhoqvap_adj(:,:) = dens(:,:) * qvap_adj(:,:)
1191 precip_mass_total = max( 0.0_rp, water_mass_ini - water_mass_adj )
1192 positive_cond_mass = 0.0_rp
1195 if ( mix_mask(pz,ke_z) )
then
1196 precip_mass_local = max( 0.0_rp, dens(pz,ke_z) * qvap(pz,ke_z) - rhoqvap_adj(pz,ke_z) )
1198 positive_cond_mass = positive_cond_mass + precip_mass_local * int_weight(pz,ke_z)
1205 if ( positive_cond_mass > eps )
then
1206 precip_scale = precip_mass_total / positive_cond_mass
1209 if ( mix_mask(pz,ke_z) )
then
1210 precip_mass_local = max( 0.0_rp, dens(pz,ke_z) * qvap(pz,ke_z) - rhoqvap_adj(pz,ke_z) )
1211 rhoprecip_adj(pz,ke_z) = precip_scale * precip_mass_local
1218 end subroutine solve_moist_neutral_adjustment
1221 subroutine evaluate_trial_moist_neutral_profile( &
1222 temp_work, qvap_work, water_mass, energy, profile_ok, & ! (out)
1224 tbase, temp, qvap, dens, zlev, int_weight, &
1225 adj_mask, forced_saturation_mask, nez, npz, debug_flag )
1228 integer,
intent(in) :: nez
1229 integer,
intent(in) :: npz
1230 real(rp),
intent(out) :: temp_work(npz,nez)
1231 real(rp),
intent(out) :: qvap_work(npz,nez)
1232 real(rp),
intent(out) :: water_mass
1233 real(rp),
intent(out) :: energy
1234 logical,
intent(out) :: profile_ok
1235 real(rp),
intent(inout) :: pres_work(npz,nez)
1236 real(rp),
intent(in) :: tbase
1237 real(rp),
intent(in) :: temp(npz,nez)
1238 real(rp),
intent(in) :: qvap(npz,nez)
1239 real(rp),
intent(in) :: zlev(npz,nez)
1240 real(rp),
intent(in) :: dens(npz,nez)
1241 real(rp),
intent(in) :: int_weight(npz,nez)
1242 logical,
intent(in) :: adj_mask(npz,nez)
1243 logical,
intent(in) :: forced_saturation_mask(npz,nez)
1244 logical,
intent(in) :: debug_flag
1246 real(rp) :: qsat_work(npz,nez)
1248real(rp) :: pres_new(npz,nez)
1249real(rp) :: qdry_work
1250real(rp) :: rtot_work
1252integer,
parameter :: mca_max_pres_iter = 5
1253real(rp),
parameter :: mca_pres_rtol = 1.0e-6_rp
1259 temp_work(:,:) = temp(:,:)
1260 qvap_work(:,:) = qvap(:,:)
1261 qsat_work(:,:) = 0.0_rp
1263do iter_pres = 1, mca_max_pres_iter
1265temp_work(:,:) = temp(:,:)
1266qvap_work(:,:) = qvap(:,:)
1267qsat_work(:,:) = 0.0_rp
1269pres_new(:,:) = pres_work(:,:)
1273 call build_moist_adiabat_temperature( &
1274 temp_work, qsat_work, profile_ok, &
1275 tbase, pres_work, zlev, adj_mask, npz, nez, debug_flag )
1277 if ( .not. profile_ok )
then
1278 water_mass = huge(1.0_rp)
1279 energy = huge(1.0_rp)
1293 if ( adj_mask(pz,ke_z) )
then
1294 if ( forced_saturation_mask(pz,ke_z) )
then
1295 qvap_work(pz,ke_z) = qsat_work(pz,ke_z)
1297 qvap_work(pz,ke_z) = min(qvap(pz,ke_z), qsat_work(pz,ke_z))
1300 qvap_work(pz,ke_z) = max(0.0_rp, qvap_work(pz,ke_z))
1310 if ( adj_mask(pz,ke_z) )
then
1311 qdry_work = 1.0_rp - qvap_work(pz,ke_z)
1312 rtot_work = rdry * qdry_work &
1313 + rvap * qvap_work(pz,ke_z)
1314 pres_new(pz,ke_z) = dens(pz,ke_z) &
1316 * temp_work(pz,ke_z)
1318 pres_err = max( pres_err, &
1319 abs( pres_new(pz,ke_z) - pres_work(pz,ke_z) ) &
1320 / max( abs(pres_work(pz,ke_z)), 1.0_rp ) )
1325pres_work(:,:) = pres_new(:,:)
1326if ( pres_err <= mca_pres_rtol )
exit
1327if ( iter_pres == mca_max_pres_iter )
then
1328 profile_ok = .false.
1329 water_mass = huge(1.0_rp)
1330 energy = huge(1.0_rp)
1331 if ( debug_flag )
then
1332 write(*,*)
"evaluate_trial_moist_neutral_profile: Pressure iteration failed to converge."
1333 write(*,*)
" pres_err=", pres_err,
"MCA_PRES_RTOL=", mca_pres_rtol
1345 if ( adj_mask(pz,ke_z) )
then
1346 water_mass = water_mass + int_weight(pz,ke_z) * dens(pz,ke_z) * qvap_work(pz,ke_z)
1353 call integ_masked_column_mse( energy, &
1354 temp_work, qvap_work, zlev, dens, &
1355 int_weight, adj_mask, npz, nez )
1358 end subroutine evaluate_trial_moist_neutral_profile
1364 subroutine integ_masked_column_mse( energy, & ! (out)
1365 temp, qv, zlev, dens, &
1366 int_weight, integ_mask, npz, nez )
1368 integer,
intent(in) :: npz
1369 integer,
intent(in) :: nez
1370 real(rp),
intent(out) :: energy
1371 real(rp),
intent(in) :: temp(npz,nez)
1372 real(rp),
intent(in) :: qv(npz,nez)
1373 real(rp),
intent(in) :: zlev(npz,nez)
1374 real(rp),
intent(in) :: dens(npz,nez)
1375 real(rp),
intent(in) :: int_weight(npz,nez)
1376 logical,
intent(in) :: integ_mask(npz,nez)
1387 if ( integ_mask(pz,ke_z) )
then
1388 qdry = 1.0_rp - qv(pz,ke_z)
1390 cptot = cpdry * qdry &
1391 + cp_vapor * qv(pz,ke_z)
1394 energy = energy + int_weight(pz,ke_z) * dens(pz,ke_z) * &
1395 ( cptot * temp(pz,ke_z) + grav * zlev(pz,ke_z) &
1396 + lhv * qv(pz,ke_z) )
1401 end subroutine integ_masked_column_mse
1405 subroutine build_moist_adiabat_temperature( &
1406 temp_profile, qsat_profile, profile_converged, & ! (out)
1407 tbase, pres, zlev, mask, npz, nez, debug_flag )
1409 integer,
intent(in) :: npz
1410 integer,
intent(in) :: nez
1411 real(rp),
intent(inout) :: temp_profile(npz,nez)
1412 real(rp),
intent(inout) :: qsat_profile(npz,nez)
1413 logical,
intent(out) :: profile_converged
1414 real(rp),
intent(in) :: tbase
1415 real(rp),
intent(in) :: pres(npz,nez)
1416 real(rp),
intent(in) :: zlev(npz,nez)
1417 logical,
intent(in) :: mask(npz,nez)
1418 logical,
intent(in) :: debug_flag
1422 real(rp) :: t_prev, p_prev, z_prev
1423 real(rp) :: t_now, p_now, z_now
1426 logical :: is_converge_local
1430 profile_converged = .true.
1434 if ( .not. mask(pz,ke_z) ) cycle
1436 z_now = zlev(pz,ke_z)
1437 p_now = pres(pz,ke_z)
1439 if ( .not. started )
then
1445 call solve_next_moist_adiabat_temp( t_now, is_converge_local, &
1446 t_prev, p_prev, z_prev, p_now, z_now )
1448 if ( .not. is_converge_local )
then
1449 profile_converged = .false.
1454 temp_profile(pz,ke_z) = t_now
1455 call atmos_saturation_pres2qsat_liq( t_now, p_now, &
1456 qsat_profile(pz,ke_z) )
1465 end subroutine build_moist_adiabat_temperature
1469 subroutine solve_next_moist_adiabat_temp( temp1, converged, & ! (out)
1470 temp0, pres0, zlev0, pres1, zlev1 )
1472 real(rp),
intent(out) :: temp1
1473 logical,
intent(out) :: converged
1474 real(rp),
intent(in) :: temp0
1475 real(rp),
intent(in) :: pres0
1476 real(rp),
intent(in) :: zlev0
1477 real(rp),
intent(in) :: pres1
1478 real(rp),
intent(in) :: zlev1
1480 real(rp) :: temp_lo, temp_mid, temp_hi
1481 real(rp) :: temp_cur, temp_new
1482 real(rp) :: f_lo, f_hi, f_cur
1483 real(rp) :: hs_target, hs_cur
1484 real(rp) :: dhs_dtemp
1485 real(rp) :: temp_tol, energy_tol
1489 integer,
parameter :: max_iter = 60
1490 real(rp),
parameter :: temp_range = 40.0_rp
1492 logical :: use_newton
1497 call saturated_mse_point( temp0, pres0, zlev0, &
1500 temp_lo = temp0 - temp_range
1501 temp_hi = temp0 + temp_range
1503 call saturated_mse_point( temp_lo, pres1, zlev1, &
1505 f_lo = hs_cur - hs_target
1507 call saturated_mse_point( temp_hi, pres1, zlev1, &
1509 f_hi = hs_cur - hs_target
1511 if ( f_lo * f_hi > 0.0_rp )
then
1515 energy_tol = mca_local_hmse_atol + mca_local_hmse_rtol * abs(hs_target)
1516 temp_tol = mca_temp_tol
1518 temp_cur = min( max(temp0, temp_lo), temp_hi )
1520 do iter = 1, max_iter
1522 call saturated_mse_point_with_derivative( temp_cur, pres1, zlev1, &
1525 f_cur = hs_cur - hs_target
1526 if ( abs(f_cur) <= energy_tol )
then
1533 if ( f_lo * f_cur <= 0.0_rp )
then
1542 if ( abs(temp_hi - temp_lo) <= temp_tol )
then
1543 temp1 = 0.5_rp * (temp_lo + temp_hi)
1550 use_newton = .false.
1551 if ( abs(dhs_dtemp) > eps )
then
1552 temp_new = temp_cur - f_cur / dhs_dtemp
1553 if ( temp_new > temp_lo .and. temp_new < temp_hi )
then
1558 if ( .not. use_newton )
then
1559 temp_new = 0.5_rp * (temp_lo + temp_hi)
1568 subroutine saturated_mse_point( &
1569 temp, pres, zlev, hmse_sat )
1571 real(rp),
intent(in) :: temp
1572 real(rp),
intent(in) :: pres
1573 real(rp),
intent(in) :: zlev
1574 real(rp),
intent(out) :: hmse_sat
1579 call atmos_saturation_pres2qsat_liq( &
1582 cptot = cpdry * ( 1.0_rp - qsat ) + cp_vapor * qsat
1584 hmse_sat = cptot * temp + grav * zlev + lhv * qsat
1586 end subroutine saturated_mse_point
1587 end subroutine solve_next_moist_adiabat_temp
1589 subroutine saturated_mse_point_with_derivative( &
1590 temp, pres, zlev, hmse_sat, dhmse_dtemp )
1591 use scale_atmos_saturation,
only: atmos_saturation_dqs_dtem_dpre_liq
1593 real(rp),
intent(in) :: temp
1594 real(rp),
intent(in) :: pres
1595 real(rp),
intent(in) :: zlev
1596 real(rp),
intent(out) :: hmse_sat
1597 real(rp),
intent(out) :: dhmse_dtemp
1600 real(rp) :: dqsat_dtemp
1601 real(rp) :: dqsat_dpres
1603 real(rp) :: qdry_dummy
1606 call atmos_saturation_pres2qsat_liq( temp, pres, &
1608 call atmos_saturation_dqs_dtem_dpre_liq( temp, pres, qdry_dummy, &
1609 dqsat_dtemp, dqsat_dpres )
1611 cptot = cpdry * (1.0_rp - qsat) &
1614 hmse_sat = cptot * temp + grav * zlev + lhv * qsat
1621 dhmse_dtemp = cptot &
1622 + ( ( cp_vapor - cpdry ) * temp + lhv ) * dqsat_dtemp
1624 end subroutine saturated_mse_point_with_derivative
module FElib / Atmosphere / Physics cumulus parameterization
subroutine, public atm_phy_cp_dgm_mconv_adjustment_calc_tendency(dens_t, rhot_t, rhoqv_t, sflx_rain, sflx_engi, ddens, drhot, qv, pt, pres, dens_hyd, rtot, cptot, dtsec, lmesh, elem, elem1d)
Calculate tendencies with moist convective adjustment scheme.
subroutine, public atm_phy_cp_dgm_mconv_adjustment_setup()
Setup a module for moist convective adjustment scheme.
subroutine, public atm_phy_cp_dgm_mconv_adjustment_finalize()
Finalize a module for moist convective adjustment scheme.
module FElib / Element / Base
module FElib / Mesh / Local 2D
module FElib / Mesh / Local 3D
Derived type representing a 1D reference element.
Derived type representing a 2D reference element.
Derived type representing a 3D reference element.
Derived type representing a local mesh for 2D domain.
Derived type to manage a local 3D computational domain.