diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..d62de163a Binary files /dev/null and b/.DS_Store differ diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/CMakeLists.txt b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/CMakeLists.txt index 9da3c11cb..2cfe394ad 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/CMakeLists.txt +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/CMakeLists.txt @@ -36,7 +36,7 @@ if (BUILD_PYMOIST_INTERFACE) find_package(Python3 COMPONENTS Interpreter REQUIRED) # Set up some variables in case names change - set(PYMOIST_INTERFACE_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/libpyMoist_interface_py.so) + set(PYMOIST_INTERFACE_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/libpyMoist_interface_py${CMAKE_SHARED_LIBRARY_SUFFIX}) set(PYMOIST_INTERFACE_HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/pymoist_interface_py.h) set(PYMOIST_INTERFACE_FLAG_HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/pyMoist/pyMoist/interface/cffi_lib/moist.h) set(PYMOIST_INTERFACE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/pyMoist/pyMoist/interface/cffi_lib/interface.py) diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/GEOS_GFDL_1M_InterfaceMod.F90 b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/GEOS_GFDL_1M_InterfaceMod.F90 index 00b2fa801..134ba89db 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/GEOS_GFDL_1M_InterfaceMod.F90 +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/GEOS_GFDL_1M_InterfaceMod.F90 @@ -19,6 +19,7 @@ module GEOS_GFDL_1M_InterfaceMod use gfdl2_cloud_microphys_mod #ifdef PYMOIST_INTEGRATION use pymoist_interface_mod + use ieee_exceptions, only: ieee_get_halting_mode, ieee_set_halting_mode, ieee_all #endif implicit none @@ -62,8 +63,9 @@ module GEOS_GFDL_1M_InterfaceMod logical :: LPHYS_HYDROSTATIC logical :: LMELTFRZ #ifdef PYMOIST_INTEGRATION - integer :: C_LMELTFRZ - logical :: USE_PYMOIST_GFDL1M = .FALSE. ! Replace Aer Activation with pyMoist port + integer :: C_LMELTFRZ, C_LHYDROSTATIC, C_LPHYS_HYDROSTATIC + logical :: USE_PYMOIST_GFDL1M_EVAP = .FALSE. ! Replace EVAP with pyMoist port + logical :: USE_PYMOIST_GFDL1M_DRIVER = .FALSE. ! Replace Aer Activation with pyMoist port #endif public :: GFDL_1M_Setup, GFDL_1M_Initialize, GFDL_1M_Run @@ -296,7 +298,8 @@ subroutine GFDL_1M_Initialize (MAPL, RC) call MAPL_GetResource( MAPL, CNV_FRACTION_MAX, 'CNV_FRACTION_MAX:', DEFAULT= 1500.0, RC=STATUS); VERIFY_(STATUS) call MAPL_GetResource( MAPL, CNV_FRACTION_EXP, 'CNV_FRACTION_EXP:', DEFAULT= 1.0, RC=STATUS); VERIFY_(STATUS) #ifdef PYMOIST_INTEGRATION - call MAPL_GetResource(MAPL, USE_PYMOIST_GFDL1M, 'USE_PYMOIST_GFDL1M:', default=.FALSE., RC=STATUS); VERIFY_(STATUS); + call MAPL_GetResource(MAPL, USE_PYMOIST_GFDL1M_EVAP, 'USE_PYMOIST_GFDL1M_EVAP:', default=.FALSE., RC=STATUS); VERIFY_(STATUS); + call MAPL_GetResource(MAPL, USE_PYMOIST_GFDL1M_DRIVER, 'USE_PYMOIST_GFDL1M_DRIVER:', default=.FALSE., RC=STATUS); VERIFY_(STATUS); #endif end subroutine GFDL_1M_Initialize @@ -371,6 +374,16 @@ subroutine GFDL_1M_Run (GC, IMPORT, EXPORT, CLOCK, RC) integer :: IM,JM,LM integer :: I, J, L +#ifdef PYMOIST_INTEGRATION + integer :: NX, NY + type(gfdl_1m_flags_interface_type) :: gfdl_1m_flags + logical :: init_gfdl_1m_flags = .true. + ! IEEE trapping see below + logical :: halting_mode(5) + real :: start, finish + integer :: comm, rank, mpierr +#endif + call ESMF_GridCompGet( GC, CONFIG=CF, RC=STATUS ) VERIFY_(STATUS) @@ -592,7 +605,7 @@ subroutine GFDL_1M_Run (GC, IMPORT, EXPORT, CLOCK, RC) ! evap/subl/pdf call MAPL_GetPointer(EXPORT, RHCRIT3D, 'RHCRIT', ALLOC=.TRUE., RC=STATUS); VERIFY_(STATUS) #ifdef PYMOIST_INTEGRATION - IF (USE_PYMOIST_GFDL1M) THEN + IF (USE_PYMOIST_GFDL1M_EVAP) THEN call pymoist_interface_f_run_GFDL1M( & dw_land, dw_ocean, PDFSHAPE, TURNRHCRIT_PARAM, & DT_MOIST, CCW_EVAP_EFF, CCI_EVAP_EFF, & @@ -821,6 +834,47 @@ subroutine GFDL_1M_Run (GC, IMPORT, EXPORT, CLOCK, RC) ! GRAUPEL RAD_QG = QGRAUPEL ! Run the driver +#ifdef PYMOIST_INTEGRATION + if (init_gfdl_1m_flags) then + init_gfdl_1m_flags = .false. + call make_gfdl_1m_flags_C_interop(LPHYS_HYDROSTATIC, LHYDROSTATIC, do_qa, fix_negative, fast_sat_adj, & + const_vi, const_vs, const_vg, const_vr, use_ccn, do_bigg, do_evap, & + do_subl, z_slope_liq, z_slope_ice, prog_ccn, preciprad, use_ppm, & + mono_prof, do_sedi_heat, sedi_transport, do_sedi_w, de_ice, mp_print, & + dt_moist, mp_time, t_min, t_sub, tau_r2g, tau_smlt, tau_g2r, & + dw_land, dw_ocean, vi_fac, vr_fac, vs_fac, vg_fac, ql_mlt, vi_max, & + vs_max, vg_max, vr_max, qs_mlt, qs0_crt, qi_gen, ql0_max, qi0_max, & + qi0_crt, qr0_crt, rh_inc, rh_ins, rh_inr, rthreshu, rthreshs, ccn_l, & + ccn_o, qc_crt, tau_g2v, tau_v2g, tau_s2v, tau_v2s, tau_revp, tau_frz, & + sat_adj0, c_piacr, tau_imlt, tau_v2l, tau_l2v, tau_i2v, tau_i2s, & + tau_l2r, qi_lim, ql_gen, c_paut, c_psaci, c_pgacs, c_pgaci, c_cracw, & + alin, clin, cld_min, icloud_f, irain_f, gfdl_1m_flags) + call gfdl_1m_interface_f_init(gfdl_1m_flags) + endif + IF (USE_PYMOIST_GFDL1M_DRIVER) THEN + C_LHYDROSTATIC = LHYDROSTATIC + C_LPHYS_HYDROSTATIC = LPHYS_HYDROSTATIC + call pymoist_interface_f_run_GFDL_1M_driver( & + ! Input water/cloud species and liquid+ice CCN [NACTL+NACTI (#/m^3)] + RAD_QV, RAD_QL, RAD_QR, RAD_QI, RAD_QS, RAD_QG, RAD_CF, (NACTL+NACTI), & + ! Output tendencies + DQVDTmic, DQLDTmic, DQRDTmic, DQIDTmic, & + DQSDTmic, DQGDTmic, DQADTmic, DTDTmic, & + ! Input fields + T, W, U, V, DUDTmic, DVDTmic, DZ, DP, & + ! constant inputs + AREA, DT_MOIST, FRLAND, CNV_FRC, SRF_TYPE, EIS, & + RHCRIT3D, ANV_ICEFALL, LS_ICEFALL, & + ! Output rain re-evaporation and sublimation + REV_LS, RSU_LS, & + ! Output precipitates + PRCP_RAIN, PRCP_SNOW, PRCP_ICE, PRCP_GRAUPEL, & + ! Output mass flux during sedimentation (Pa kg/kg) + PFL_LS(:,:,1:LM), PFI_LS(:,:,1:LM), & + ! constant grid/time information + C_LHYDROSTATIC, C_LPHYS_HYDROSTATIC) + ELSE +#endif call gfdl_cloud_microphys_driver( & ! Input water/cloud species and liquid+ice CCN [NACTL+NACTI (#/m^3)] RAD_QV, RAD_QL, RAD_QR, RAD_QI, RAD_QS, RAD_QG, RAD_CF, (NACTL+NACTI), & @@ -841,6 +895,9 @@ subroutine GFDL_1M_Run (GC, IMPORT, EXPORT, CLOCK, RC) ! constant grid/time information LHYDROSTATIC, LPHYS_HYDROSTATIC, & 1,IM, 1,JM, 1,LM, 1, LM) +#ifdef PYMOIST_INTEGRATION + ENDIF ! USE_PYMOIST_GFDL1M_DRIVER +#endif ! Apply tendencies T = T + DTDTmic * DT_MOIST U = U + DUDTmic * DT_MOIST diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/GEOS_MoistGridComp.F90 b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/GEOS_MoistGridComp.F90 index a8d015193..eb1cd2761 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/GEOS_MoistGridComp.F90 +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/GEOS_MoistGridComp.F90 @@ -5334,7 +5334,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) ! to run initialization call MAPL_GetResource(MAPL, USE_PYMOIST_AER, 'USE_PYMOIST_AER:', default=.false., RC=STATUS); VERIFY_(STATUS); call ESMF_AttributeGet(AERO, name='number_of_aerosol_modes', value=n_modes, __RC__) - if (USE_PYMOIST_AER .and. init_pymoist) then + if (init_pymoist) then call cpu_time(start) init_pymoist = .false. call MAPL_Get(MAPL, IM=IM, JM=JM, LM=LM, INTERNAL_ESMF_STATE=INTERNAL, RC=STATUS ); VERIFY_(STATUS) diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver.py new file mode 100644 index 000000000..452f7524b --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver.py @@ -0,0 +1,1257 @@ +"""GFDL_1M driver""" + +import numpy as np +from gt4py.cartesian.gtscript import i32 + +import pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_constants as driver_constants +from ndsl import QuantityFactory, StencilFactory, orchestrate +from ndsl.constants import X_DIM, Y_DIM, Z_DIM, Z_INTERFACE_DIM +from ndsl.dsl.typing import Float, FloatField, FloatFieldIJ, Int +from pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_core import ( + fall_speed, + fix_negative_values, + icloud_update, + init_temporaries, + terminal_fall_update, + update_tendencies, + warm_rain_update, +) +from pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_tables import get_tables +from pyMoist.GFDL_1M.GFDL_1M_driver.icloud import icloud +from pyMoist.GFDL_1M.GFDL_1M_driver.terminal_fall import terminal_fall +from pyMoist.GFDL_1M.GFDL_1M_driver.warm_rain import warm_rain + + +class GFDL_1M_driver: + def __init__( + self, + stencil_factory: StencilFactory, + quantity_factory: QuantityFactory, + phys_hydrostatic: bool, + hydrostatic: bool, + dt_moist: Float, + mp_time: Float, + t_min: Float, + t_sub: Float, + tau_r2g: Float, + tau_smlt: Float, + tau_g2r: Float, + dw_land: Float, + dw_ocean: Float, + vi_fac: Float, + vr_fac: Float, + vs_fac: Float, + vg_fac: Float, + ql_mlt: Float, + do_qa: bool, + fix_negative: bool, + vi_max: Float, + vs_max: Float, + vg_max: Float, + vr_max: Float, + qs_mlt: Float, + qs0_crt: Float, + qi_gen: Float, + ql0_max: Float, + qi0_max: Float, + qi0_crt: Float, + qr0_crt: Float, + fast_sat_adj: bool, + rh_inc: Float, + rh_ins: Float, + rh_inr: Float, + const_vi: bool, + const_vs: bool, + const_vg: bool, + const_vr: bool, + use_ccn: bool, + rthreshu: Float, + rthreshs: Float, + ccn_l: Float, + ccn_o: Float, + qc_crt: Float, + tau_g2v: Float, + tau_v2g: Float, + tau_s2v: Float, + tau_v2s: Float, + tau_revp: Float, + tau_frz: Float, + do_bigg: bool, + do_evap: bool, + do_subl: bool, + sat_adj0: Float, + c_piacr: Float, + tau_imlt: Float, + tau_v2l: Float, + tau_l2v: Float, + tau_i2v: Float, + tau_i2s: Float, + tau_l2r: Float, + qi_lim: Float, + ql_gen: Float, + c_paut: Float, + c_psaci: Float, + c_pgacs: Float, + c_pgaci: Float, + z_slope_liq: bool, + z_slope_ice: bool, + prog_ccn: bool, + c_cracw: Float, + alin: Float, + clin: Float, + preciprad: bool, + cld_min: Float, + use_ppm: bool, + mono_prof: bool, + do_sedi_heat: bool, + sedi_transport: bool, + do_sedi_w: bool, + de_ice: bool, + icloud_f: Float, + irain_f: Float, + mp_print: bool, + ): + self.dt_moist = dt_moist + self.fix_negative = fix_negative + self.sedi_transport = sedi_transport + + self.namelist_constants = namelist_setup( + phys_hydrostatic, + hydrostatic, + dt_moist, + mp_time, + t_min, + t_sub, + tau_r2g, + tau_smlt, + tau_g2r, + dw_land, + dw_ocean, + vi_fac, + vr_fac, + vs_fac, + vg_fac, + ql_mlt, + do_qa, + fix_negative, + vi_max, + vs_max, + vg_max, + vr_max, + qs_mlt, + qs0_crt, + qi_gen, + ql0_max, + qi0_max, + qi0_crt, + qr0_crt, + fast_sat_adj, + rh_inc, + rh_ins, + rh_inr, + const_vi, + const_vs, + const_vg, + const_vr, + use_ccn, + rthreshu, + rthreshs, + ccn_l, + ccn_o, + qc_crt, + tau_g2v, + tau_v2g, + tau_s2v, + tau_v2s, + tau_revp, + tau_frz, + do_bigg, + do_evap, + do_subl, + sat_adj0, + c_piacr, + tau_imlt, + tau_v2l, + tau_l2v, + tau_i2v, + tau_i2s, + tau_l2r, + qi_lim, + ql_gen, + c_paut, + c_psaci, + c_pgacs, + c_pgaci, + z_slope_liq, + z_slope_ice, + prog_ccn, + c_cracw, + alin, + clin, + preciprad, + cld_min, + use_ppm, + mono_prof, + do_sedi_heat, + sedi_transport, + do_sedi_w, + de_ice, + icloud_f, + irain_f, + mp_print, + ) + + # Check values for untested code paths + self.check_flags( + phys_hydrostatic, + hydrostatic, + const_vi, + const_vs, + const_vg, + const_vr, + use_ppm, + use_ccn, + do_qa, + fix_negative, + fast_sat_adj, + do_bigg, + do_evap, + do_subl, + z_slope_liq, + z_slope_ice, + prog_ccn, + preciprad, + mono_prof, + do_sedi_heat, + sedi_transport, + do_sedi_w, + de_ice, + mp_print, + self.namelist_constants.DTS, + ) + + # ----------------------------------------------------------------------- + # initialize precipitation outputs + # ----------------------------------------------------------------------- + + self.rain = quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.snow = quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.ice = quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.graupel = quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.m2_rain = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.m2_sol = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.revap = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.isubl = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + + # ----------------------------------------------------------------------- + # initialize temporaries + # ----------------------------------------------------------------------- + + self.t1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.dp1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.omq = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qv0 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.ql0 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qr0 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qi0 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qs0 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qg0 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qa0 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qv1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.ql1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qr1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qi1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qs1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qg1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qa1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.dz1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.den = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.den1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.denfac = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.p_dry = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.m1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.u1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.v1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.w1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.onemsig = quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.ccn = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.c_praut = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.rh_limited = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.ze = quantity_factory.zeros([X_DIM, Y_DIM, Z_INTERFACE_DIM], "n/a") + self.zt = quantity_factory.zeros([X_DIM, Y_DIM, Z_INTERFACE_DIM], "n/a") + self.lhi = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.icpk = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.hold_data = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.vti = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.vts = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.vtg = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.vtr = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.m1_sol = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.m1_rain = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.rain1 = quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.graupel1 = quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.snow1 = quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.ice1 = quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.evap1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.subl1 = quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + + # ----------------------------------------------------------------------- + # initialize masks + # ----------------------------------------------------------------------- + self.is_frozen = quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=bool + ) + self.precip_fall = quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.melting_mask_1 = quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=bool + ) + self.melting_mask_2 = quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=bool + ) + self.current_k_level = quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=Int + ) + for k in range(self.current_k_level.view[:].shape[2]): + self.current_k_level.view[:, :, k] = k + + # ----------------------------------------------------------------------- + # generate saturation specific humidity tables + # ----------------------------------------------------------------------- + + self.sat_tables = get_tables(stencil_factory.backend) + + # ----------------------------------------------------------------------- + # initialize stencils + # ----------------------------------------------------------------------- + + orchestrate(obj=self, config=stencil_factory.config.dace_config) + self._init_temporaries = stencil_factory.from_dims_halo( + func=init_temporaries, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "cpaut": self.namelist_constants.CPAUT, + }, + ) + + self._gfdl_1m_driver_preloop = stencil_factory.from_dims_halo( + func=fix_negative_values, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "c_air": self.namelist_constants.C_AIR, + "c_vap": self.namelist_constants.C_VAP, + "p_nonhydro": self.namelist_constants.P_NONHYDRO, + "d0_vap": self.namelist_constants.D0_VAP, + "lv00": self.namelist_constants.LV00, + "latv": self.namelist_constants.LATV, + "lati": self.namelist_constants.LATI, + "lats": self.namelist_constants.LATS, + "lat2": self.namelist_constants.LAT2, + "lcp": self.namelist_constants.LCP, + "icp": self.namelist_constants.ICP, + "tcp": self.namelist_constants.TCP, + "mpdt": self.namelist_constants.MPDT, + "rdt": self.namelist_constants.RDT, + "ntimes": self.namelist_constants.NTIMES, + "dts": self.namelist_constants.DTS, + "do_sedi_w": do_sedi_w, + "cpaut": self.namelist_constants.CPAUT, + "hydrostatic": hydrostatic, + "phys_hydrostatic": phys_hydrostatic, + "fix_negative": fix_negative, + "sedi_transport": sedi_transport, + "const_vi": const_vi, + "const_vs": const_vs, + "const_vg": const_vg, + }, + ) + + self._fall_speed = stencil_factory.from_dims_halo( + func=fall_speed, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "p_nonhydro": self.namelist_constants.P_NONHYDRO, + "const_vi": const_vi, + "const_vs": const_vs, + "const_vg": const_vg, + "vi_fac": vi_fac, + "vi_max": vi_max, + "vs_fac": vs_fac, + "vs_max": vs_max, + "vg_fac": vg_fac, + "vg_max": vg_max, + }, + ) + + self._terminal_fall = stencil_factory.from_dims_halo( + func=terminal_fall, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "dts": self.namelist_constants.DTS, + "tau_imlt": tau_imlt, + "ql_mlt": ql_mlt, + "vi_fac": vi_fac, + "do_sedi_w": do_sedi_w, + "use_ppm": use_ppm, + "tau_smlt": tau_smlt, + "tau_g2r": tau_g2r, + "c_air": self.namelist_constants.C_AIR, + "c_vap": self.namelist_constants.C_VAP, + "d0_vap": self.namelist_constants.D0_VAP, + "lv00": self.namelist_constants.LV00, + }, + ) + + self._terminal_fall_update = stencil_factory.from_dims_halo( + func=terminal_fall_update, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + ) + + self._warm_rain = stencil_factory.from_dims_halo( + func=warm_rain, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "dts": self.namelist_constants.DTS, + "do_qa": do_qa, + "rthreshs": rthreshs, + "rthreshu": rthreshu, + "irain_f": irain_f, + "ql0_max": ql0_max, + "z_slope_liq": z_slope_liq, + "vr_fac": vr_fac, + "const_vr": const_vr, + "vr_max": vr_max, + "tau_revp": tau_revp, + "lv00": self.namelist_constants.LV00, + "d0_vap": self.namelist_constants.D0_VAP, + "c_air": self.namelist_constants.C_AIR, + "c_vap": self.namelist_constants.C_VAP, + "crevp_0": self.namelist_constants.CREVP_0, + "crevp_1": self.namelist_constants.CREVP_1, + "crevp_2": self.namelist_constants.CREVP_2, + "crevp_3": self.namelist_constants.CREVP_3, + "crevp_4": self.namelist_constants.CREVP_4, + "cracw": self.namelist_constants.CRACW, + "do_sedi_w": do_sedi_w, + "use_ppm": use_ppm, + }, + ) + + self._warm_rain_update = stencil_factory.from_dims_halo( + func=warm_rain_update, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + ) + + self._icloud = stencil_factory.from_dims_halo( + func=icloud, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "c_air": self.namelist_constants.C_AIR, + "c_vap": self.namelist_constants.C_VAP, + "dts": self.namelist_constants.DTS, + "rdts": self.namelist_constants.RDTS, + "const_vi": const_vi, + "fac_g2v": self.namelist_constants.FAC_G2V, + "fac_i2s": self.namelist_constants.FAC_I2S, + "fac_imlt": self.namelist_constants.FAC_IMLT, + "fac_frz": self.namelist_constants.FAC_FRZ, + "fac_l2v": self.namelist_constants.FAC_L2V, + "fac_s2v": self.namelist_constants.FAC_S2V, + "fac_v2s": self.namelist_constants.FAC_V2S, + "fac_v2g": self.namelist_constants.FAC_V2G, + "cgacs": self.namelist_constants.CGACS, + "csacw": self.namelist_constants.CSACW, + "csaci": self.namelist_constants.CSACI, + "cgacw": self.namelist_constants.CGACW, + "cgaci": self.namelist_constants.CGACI, + "cgfr_0": self.namelist_constants.CGFR_0, + "cgfr_1": self.namelist_constants.CGFR_1, + "csmlt_0": self.namelist_constants.CSMLT_0, + "csmlt_1": self.namelist_constants.CSMLT_1, + "csmlt_2": self.namelist_constants.CSMLT_2, + "csmlt_3": self.namelist_constants.CSMLT_3, + "csmlt_4": self.namelist_constants.CSMLT_4, + "cgmlt_0": self.namelist_constants.CGMLT_0, + "cgmlt_1": self.namelist_constants.CGMLT_1, + "cgmlt_2": self.namelist_constants.CGMLT_2, + "cgmlt_3": self.namelist_constants.CGMLT_3, + "cgmlt_4": self.namelist_constants.CGMLT_4, + "cssub_0": self.namelist_constants.CSSUB_0, + "cssub_1": self.namelist_constants.CSSUB_1, + "cssub_2": self.namelist_constants.CSSUB_2, + "cssub_3": self.namelist_constants.CSSUB_3, + "cssub_4": self.namelist_constants.CSSUB_4, + "qi0_crt": qi0_crt, + "qs0_crt": qs0_crt, + "qs_mlt": qs_mlt, + "ql_mlt": ql_mlt, + "z_slope_ice": z_slope_ice, + "lv00": self.namelist_constants.LV00, + "d0_vap": self.namelist_constants.D0_VAP, + "lat2": self.namelist_constants.LAT2, + "do_qa": do_qa, + "do_evap": do_evap, + "do_bigg": do_bigg, + "qc_crt": qc_crt, + "qi_lim": qi_lim, + "rh_inc": rh_inc, + "rh_inr": rh_inr, + "t_min": t_min, + "t_sub": t_sub, + "preciprad": preciprad, + "icloud_f": icloud_f, + }, + ) + + self._icloud_update = stencil_factory.from_dims_halo( + func=icloud_update, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + ) + + self._update_tendencies = stencil_factory.from_dims_halo( + func=update_tendencies, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "c_air": self.namelist_constants.C_AIR, + "c_vap": self.namelist_constants.C_VAP, + "rdt": self.namelist_constants.RDT, + "do_sedi_w": do_sedi_w, + "sedi_transport": sedi_transport, + "do_qa": do_qa, + }, + ) + + def __call__( + self, + qv: FloatField, + ql: FloatField, + qr: FloatField, + qi: FloatField, + qs: FloatField, + qg: FloatField, + qa: FloatField, + qn: FloatField, # NACTL + NACTI + qv_dt: FloatField, + ql_dt: FloatField, + qr_dt: FloatField, + qi_dt: FloatField, + qs_dt: FloatField, + qg_dt: FloatField, + qa_dt: FloatField, + t_dt: FloatField, + t: FloatField, + w: FloatField, + uin: FloatField, + vin: FloatField, + udt: FloatField, + vdt: FloatField, + dz: FloatField, + dp: FloatField, + area: FloatFieldIJ, + fr_land: FloatFieldIJ, + cnv_frc: FloatFieldIJ, + srf_type: FloatFieldIJ, + eis: FloatFieldIJ, + rhcrit3d: FloatField, + anv_icefall: Float, + ls_icefall: Float, + ): + # The driver modifies a number of variables (t, p, qX) but does not pass + # the changes back to the rest of the model. To replicate this behavior, + # temporary copies of these variables are used throughout the driver. + self._init_temporaries( + t, + dp, + rhcrit3d, + qv, + ql, + qi, + qr, + qs, + qg, + qa, + qn, + self.qv0, + self.ql0, + self.qr0, + self.qi0, + self.qs0, + self.qg0, + self.qa0, + self.qv1, + self.ql1, + self.qr1, + self.qi1, + self.qs1, + self.qg1, + self.qa1, + dz, + uin, + vin, + w, + area, + self.t1, + self.dp1, + self.omq, + self.den, + self.p_dry, + self.m1, + self.u1, + self.v1, + self.w1, + self.onemsig, + self.ccn, + self.c_praut, + self.rh_limited, + self.rain, + self.snow, + self.graupel, + self.ice, + self.m2_rain, + self.m2_sol, + self.revap, + self.isubl, + ) + + self._gfdl_1m_driver_preloop( + self.t1, + self.qv1, + self.ql1, + self.qr1, + self.qi1, + self.qs1, + self.qg1, + self.dp1, + ) + + for n in range(self.namelist_constants.NTIMES): + self._fall_speed( + self.ql1, + self.qi1, + self.qs1, + self.qg1, + t, + self.t1, + dz, + self.dz1, + self.den, + self.den1, + self.denfac, + self.p_dry, + self.vti, + self.vts, + self.vtg, + cnv_frc, + anv_icefall, + ls_icefall, + ) + + self._terminal_fall( + self.t1, + self.qv1, + self.ql1, + self.qr1, + self.qg1, + self.qs1, + self.qi1, + self.dz1, + self.dp1, + self.den1, + self.vtg, + self.vts, + self.vti, + self.rain1, + self.graupel1, + self.snow1, + self.ice1, + self.m1_sol, + self.w1, + self.ze, + self.zt, + self.is_frozen, + self.precip_fall, + self.melting_mask_1, + self.melting_mask_2, + self.current_k_level, + ) + + self._terminal_fall_update( + self.rain, + self.graupel, + self.snow, + self.ice, + self.rain1, + self.graupel1, + self.snow1, + self.ice1, + ) + + self._warm_rain( + self.dp1, + self.dz1, + self.t1, + self.qv1, + self.ql1, + self.qr1, + self.qi1, + self.qs1, + self.qg1, + self.qa1, + self.ccn, + self.den, + self.denfac, + self.c_praut, + self.vtr, + self.evap1, + self.m1_rain, + self.w1, + self.rh_limited, + eis, + self.onemsig, + self.rain1, + self.ze, + self.zt, + self.precip_fall, + self.sat_tables.table1, + self.sat_tables.table2, + self.sat_tables.table3, + self.sat_tables.table4, + self.sat_tables.des1, + self.sat_tables.des2, + self.sat_tables.des3, + self.sat_tables.des4, + ) + + self._warm_rain_update( + self.rain, + self.rain1, + self.evap1, + self.revap, + self.m1_rain, + self.m2_rain, + self.m1_sol, + self.m2_sol, + self.m1, + ) + + self._icloud( + self.t1, + self.p_dry, + self.dp1, + self.qv1, + self.ql1, + self.qr1, + self.qi1, + self.qs1, + self.qg1, + self.qa1, + self.den1, + self.denfac, + self.vts, + self.vtg, + self.vtr, + self.subl1, + self.rh_limited, + self.ccn, + cnv_frc, + srf_type, + self.sat_tables.table1, + self.sat_tables.table2, + self.sat_tables.table3, + self.sat_tables.table4, + self.sat_tables.des1, + self.sat_tables.des2, + self.sat_tables.des3, + self.sat_tables.des4, + ) + + self._icloud_update( + self.isubl, + self.subl1, + ) + + self._update_tendencies( + self.qv0, + self.ql0, + self.qr0, + self.qi0, + self.qs0, + self.qg0, + self.qa0, + self.qv1, + self.ql1, + self.qr1, + self.qi1, + self.qs1, + self.qg1, + self.qa1, + self.ccn, + qv_dt, + ql_dt, + qr_dt, + qi_dt, + qs_dt, + qg_dt, + qa_dt, + t, + self.t1, + t_dt, + w, + self.w1, + uin, + self.u1, + udt, + vin, + self.v1, + vdt, + dz, + dp, + self.dp1, + self.den, + self.p_dry, + area, + self.dt_moist, + fr_land, + cnv_frc, + srf_type, + eis, + self.rh_limited, + self.m1, + anv_icefall, + ls_icefall, + self.revap, + self.isubl, + self.rain, + self.snow, + self.ice, + self.graupel, + self.m2_rain, + self.m2_sol, + ) + + def check_flags( + self, + phys_hydrostatic: bool, + hydrostatic: bool, + const_vi: bool, + const_vs: bool, + const_vg: bool, + const_vr: bool, + use_ppm: bool, + use_ccn: bool, + do_qa: bool, + fix_negative: bool, + fast_set_adj: bool, + do_bigg: bool, + do_evap: bool, + do_subl: bool, + z_slope_liq: bool, + z_slope_ice: bool, + prog_ccn: bool, + preciprad: bool, + mono_prof: bool, + do_sedi_heat: bool, + sedi_transport: bool, + do_sedi_w: bool, + de_ice: bool, + mp_print: bool, + dts: Float, + ): + failed_keywords = [] + if not phys_hydrostatic: + failed_keywords.append("phys_hydrostatic") + if hydrostatic: + failed_keywords.append("hydrostatic") + if const_vi: + failed_keywords.append("const_vi") + if const_vs: + failed_keywords.append("const_vs") + if const_vg: + failed_keywords.append("const_vg") + if const_vr: + failed_keywords.append("const_vr") + if use_ppm: + failed_keywords.append("use_ppm") + if not use_ccn: + failed_keywords.append("use_ccn") + if do_qa: + failed_keywords.append("do_qa") + if not fix_negative: + failed_keywords.append("fix_negative") + if fast_set_adj: + failed_keywords.append("fast_set_adj") + if do_bigg: + failed_keywords.append("do_bigg") + if do_evap: + failed_keywords.append("do_evap") + if do_subl: + failed_keywords.append("do_subl") + if not z_slope_liq: + failed_keywords.append("z_slope_liq") + if not z_slope_ice: + failed_keywords.append("z_slope_ice") + if not prog_ccn: + failed_keywords.append("prog_ccn") + if not preciprad: + failed_keywords.append("preciprad") + if not mono_prof: + failed_keywords.append("mono_prof") + if do_sedi_heat: + failed_keywords.append("do_sedi_heat") + if not sedi_transport: + failed_keywords.append("sedi_transport") + if do_sedi_w: + failed_keywords.append("do_sedi_w") + if de_ice: + failed_keywords.append("de_ice") + if mp_print: + failed_keywords.append("mp_print") + if dts >= 300: + failed_keywords.append("dts") + + if len(failed_keywords) > 0: + raise ValueError( + "One or more namelist parameters do not meet \ + expected values. Failing parameters: ", + failed_keywords, + ) + + +class namelist_setup: + def __init__( + self, + phys_hydrostatic: bool, + hydrostatic: bool, + dt_moist: Float, + mp_time: Float, + t_min: Float, + t_sub: Float, + tau_r2g: Float, + tau_smlt: Float, + tau_g2r: Float, + dw_land: Float, + dw_ocean: Float, + vi_fac: Float, + vr_fac: Float, + vs_fac: Float, + vg_fac: Float, + ql_mlt: Float, + do_qa: bool, + fix_negative: bool, + vi_max: Float, + vs_max: Float, + vg_max: Float, + vr_max: Float, + qs_mlt: Float, + qs0_crt: Float, + qi_gen: Float, + ql0_max: Float, + qi0_max: Float, + qi0_crt: Float, + qr0_crt: Float, + fast_sat_adj: bool, + rh_inc: Float, + rh_ins: Float, + rh_inr: Float, + const_vi: bool, + const_vs: bool, + const_vg: bool, + const_vr: bool, + use_ccn: bool, + rthreshu: Float, + rthreshs: Float, + ccn_l: Float, + ccn_o: Float, + qc_crt: Float, + tau_g2v: Float, + tau_v2g: Float, + tau_s2v: Float, + tau_v2s: Float, + tau_revp: Float, + tau_frz: Float, + do_bigg: bool, + do_evap: bool, + do_subl: bool, + sat_adj0: Float, + c_piacr: Float, + tau_imlt: Float, + tau_v2l: Float, + tau_l2v: Float, + tau_i2v: Float, + tau_i2s: Float, + tau_l2r: Float, + qi_lim: Float, + ql_gen: Float, + c_paut: Float, + c_psaci: Float, + c_pgacs: Float, + c_pgaci: Float, + z_slope_liq: bool, + z_slope_ice: bool, + prog_ccn: bool, + c_cracw: Float, + alin: Float, + clin: Float, + preciprad: bool, + cld_min: Float, + use_ppm: bool, + mono_prof: bool, + do_sedi_heat: bool, + sedi_transport: bool, + do_sedi_w: bool, + de_ice: bool, + icloud_f: Float, + irain_f: Float, + mp_print: bool, + ): + # ----------------------------------------------------------------------- + # define heat capacity of dry air and water vap based on hydrostatical property + # ----------------------------------------------------------------------- + + if phys_hydrostatic or hydrostatic: + self.C_AIR = driver_constants.CP_AIR + self.C_VAP = driver_constants.CP_VAP + self.P_NONHYDRO = False + else: + self.C_AIR = driver_constants.CV_AIR + self.C_VAP = driver_constants.CV_VAP + self.P_NONHYDRO = True + self.D0_VAP = self.C_VAP - driver_constants.C_LIQ + self.LV00 = driver_constants.HLV0 - self.D0_VAP * driver_constants.T_ICE + + if hydrostatic: + self.DO_SEDI_W = False + + # ----------------------------------------------------------------------- + # define latent heat coefficient used in wet bulb and bigg mechanism + # ----------------------------------------------------------------------- + + self.LATV = driver_constants.HLV + self.LATI = driver_constants.HLF + self.LATS = self.LATV + self.LATI + self.LAT2 = self.LATS * self.LATS + + self.LCP = self.LATV / driver_constants.CP_AIR + self.ICP = self.LATI / driver_constants.CP_AIR + self.TCP = (self.LATV + self.LATI) / driver_constants.CP_AIR + + # ----------------------------------------------------------------------- + # define cloud microphysics sub time step + # ----------------------------------------------------------------------- + + self.MPDT = min(dt_moist, mp_time) + self.RDT = Float(1.0) / dt_moist + self.NTIMES = i32(np.round(dt_moist / self.MPDT)) + + # small time step: + self.DTS = dt_moist / Float(self.NTIMES) + + # ----------------------------------------------------------------------- + # calculate cloud condensation nuclei (ccn) + # the following is based on klein eq. 15 + # ----------------------------------------------------------------------- + + self.CPAUT = c_paut * Float(0.104) * driver_constants.GRAV / Float(1.717e-5) + + # ----------------------------------------------------------------------- + # define conversion scalar / factor for icloud + # ----------------------------------------------------------------------- + self.RDTS = Float(1.0) / self.DTS + self.FAC_IMLT = Float(1.0) - np.exp(-self.DTS / tau_imlt, dtype=Float) + self.FAC_I2S = Float(1.0) - np.exp(-self.DTS / tau_i2s, dtype=Float) + self.FAC_V2L = Float(1.0) - np.exp(-self.DTS / tau_v2l, dtype=Float) + self.FAC_L2V = Float(1.0) - np.exp(-self.DTS / tau_l2v, dtype=Float) + self.FAC_I2V = Float(1.0) - np.exp(-self.DTS / tau_i2v, dtype=Float) + self.FAC_S2V = Float(1.0) - np.exp(-self.DTS / tau_s2v, dtype=Float) + self.FAC_V2S = Float(1.0) - np.exp(-self.DTS / tau_v2s, dtype=Float) + self.FAC_G2V = Float(1.0) - np.exp(-self.DTS / tau_g2v, dtype=Float) + self.FAC_V2G = Float(1.0) - np.exp(-self.DTS / tau_v2g, dtype=Float) + self.FAC_FRZ = Float(1.0) - np.exp(-self.DTS / tau_frz, dtype=Float) + + # ----------------------------------------------------------------------- + # constatns from setupm + # ----------------------------------------------------------------------- + + self.CGACS = ( + driver_constants.PISQ + * driver_constants.RNZG + * driver_constants.RNZS + * driver_constants.RHOS + ) + self.CGACS = self.CGACS * c_pgacs + + self.CSACW = ( + driver_constants.PIE + * driver_constants.RNZS + * clin + * driver_constants.GAM325 + / (Float(4.0) * np.power(driver_constants.ACT[0], 0.8125, dtype=Float)) + ) + # decreasing csacw to reduce cloud water --- > snow + + self.CRACI = ( + driver_constants.PIE + * driver_constants.RNZR + * alin + * driver_constants.GAM380 + / (Float(4.0) * np.power(driver_constants.ACT[1], 0.95, dtype=Float)) + ) + self.CSACI = self.CSACW * c_psaci + + self.CGACW = ( + driver_constants.PIE + * driver_constants.RNZG + * driver_constants.GAM350 + * driver_constants.GCON + / (Float(4.0) * np.power(driver_constants.ACT[5], 0.875, dtype=Float)) + ) + + self.CGACI = self.CGACW * c_pgaci + + self.CRACW = self.CRACI # cracw = 3.27206196043822 + self.CRACW = c_cracw * self.CRACW + + self.CSSUB = np.zeros(5) + self.CGSUB = np.zeros(5) + self.CREVP = np.zeros(5) + + self.CSSUB[0] = ( + Float(2.0) + * driver_constants.PIE + * driver_constants.VDIFU + * driver_constants.TCOND + * driver_constants.RVGAS + * driver_constants.RNZS + ) + self.CGSUB[0] = ( + Float(2.0) + * driver_constants.PIE + * driver_constants.VDIFU + * driver_constants.TCOND + * driver_constants.RVGAS + * driver_constants.RNZG + ) + self.CREVP[0] = ( + Float(2.0) + * driver_constants.PIE + * driver_constants.VDIFU + * driver_constants.TCOND + * driver_constants.RVGAS + * driver_constants.RNZR + ) + self.CSSUB[1] = Float(0.78) / np.sqrt(driver_constants.ACT[0], dtype=Float) + self.CGSUB[1] = Float(0.78) / np.sqrt(driver_constants.ACT[5], dtype=Float) + self.CREVP[1] = Float(0.78) / np.sqrt(driver_constants.ACT[1], dtype=Float) + self.CSSUB[2] = ( + Float(0.31) + * driver_constants.SCM3 + * driver_constants.GAM263 + * np.sqrt(clin / driver_constants.VISK, dtype=Float) + / np.power(driver_constants.ACT[0], Float(0.65625), dtype=Float) + ) + self.CGSUB[2] = ( + Float(0.31) + * driver_constants.SCM3 + * driver_constants.GAM275 + * np.sqrt(driver_constants.GCON / driver_constants.VISK, dtype=Float) + / np.power(driver_constants.ACT[5], Float(0.6875), dtype=Float) + ) + self.CREVP[2] = ( + Float(0.31) + * driver_constants.SCM3 + * driver_constants.GAM209 + * np.sqrt(alin / driver_constants.VISK, dtype=Float) + / np.power(driver_constants.ACT[1], Float(0.725), dtype=Float) + ) + self.CSSUB[3] = driver_constants.TCOND * driver_constants.RVGAS + self.CSSUB[4] = ( + np.power(driver_constants.HLTS, 2, dtype=Float) * driver_constants.VDIFU + ) + self.CGSUB[3] = self.CSSUB[3] + self.CREVP[3] = self.CSSUB[3] + self.CGSUB[4] = self.CSSUB[4] + self.CREVP[4] = ( + np.power(driver_constants.HLTC, 2, dtype=Float) * driver_constants.VDIFU + ) + + self.CGFR_0 = ( + Float(20.0e2) + * driver_constants.PISQ + * driver_constants.RNZR + * driver_constants.RHOR + / np.power(driver_constants.ACT[1], Float(1.75), dtype=Float) + ) + self.CGFR_1 = Float(0.66) + + self.CSSUB_0 = self.CSSUB[0] + self.CSSUB_1 = self.CSSUB[1] + self.CSSUB_2 = self.CSSUB[2] + self.CSSUB_3 = self.CSSUB[3] + self.CSSUB_4 = self.CSSUB[4] + + self.CGSUB_0 = self.CGSUB[0] + self.CGSUB_1 = self.CGSUB[1] + self.CGSUB_2 = self.CGSUB[2] + self.CGSUB_3 = self.CGSUB[3] + self.CGSUB_4 = self.CGSUB[4] + + self.CREVP_0 = self.CREVP[0] + self.CREVP_1 = self.CREVP[1] + self.CREVP_2 = self.CREVP[2] + self.CREVP_3 = self.CREVP[3] + self.CREVP_4 = self.CREVP[4] + + # smlt: five constants (lin et al. 1983) + + self.CSMLT = np.zeros(5) + self.CSMLT[0] = ( + Float(2.0) + * driver_constants.PIE + * driver_constants.TCOND + * driver_constants.RNZS + / driver_constants.HLTF + ) + self.CSMLT[1] = ( + Float(2.0) + * driver_constants.PIE + * driver_constants.VDIFU + * driver_constants.RNZS + * driver_constants.HLTC + / driver_constants.HLTF + ) + self.CSMLT[2] = self.CSSUB[1] + self.CSMLT[3] = self.CSSUB[2] + self.CSMLT[4] = driver_constants.CH2O / driver_constants.HLTF + + self.CSMLT_0 = self.CSMLT[0] + self.CSMLT_1 = self.CSMLT[1] + self.CSMLT_2 = self.CSMLT[2] + self.CSMLT_3 = self.CSMLT[3] + self.CSMLT_4 = self.CSMLT[4] + + # gmlt: five constants + + self.CGMLT = np.zeros(5) + self.CGMLT[0] = ( + Float(2.0) + * driver_constants.PIE + * driver_constants.TCOND + * driver_constants.RNZG + / driver_constants.HLTF + ) + self.CGMLT[1] = ( + Float(2.0) + * driver_constants.PIE + * driver_constants.VDIFU + * driver_constants.RNZG + * driver_constants.HLTC + / driver_constants.HLTF + ) + self.CGMLT[2] = self.CGSUB[1] + self.CGMLT[3] = self.CGSUB[2] + self.CGMLT[4] = driver_constants.CH2O / driver_constants.HLTF + + self.CGMLT_0 = self.CGMLT[0] + self.CGMLT_1 = self.CGMLT[1] + self.CGMLT_2 = self.CGMLT[2] + self.CGMLT_3 = self.CGMLT[3] + self.CGMLT_4 = self.CGMLT[4] diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver_constants.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver_constants.py new file mode 100644 index 000000000..5c0defb55 --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver_constants.py @@ -0,0 +1,233 @@ +""" +Constants for GFDL_1M Driver. Some of these are redefined +(with different values) from the generic GFDL constants, +others are duplicated. Both of these need a proper solution +Commented comments are defined in namelist and set at stencil init. +""" + +import numpy as np +from gt4py.cartesian.gtscript import i32 + +from ndsl.dsl.typing import Float + + +# constants from gfdl_1m_driver module + +GRAV = Float(9.80665) # gfs: acceleration due to gravity +RDGAS = Float(287.05) # gfs: gas constant for dry air +RVGAS = Float(461.50) # gfs: gas constant for water vapor +CP_AIR = Float(1004.6) # gfs: heat capacity of dry air at constant pressure +HLV = Float(2.5e6) # gfs: latent heat of evaporation +HLF = Float(3.3358e5) # gfs: latent heat of fusion +PI = Float(3.1415926535897931) # gfs: ratio of circle circumference to diameter +CP_VAP = ( + Float(4.0) * RVGAS +) # 1846.0, heat capacity of water vapore at constnat pressure +CV_AIR = CP_AIR - RDGAS # 717.55, heat capacity of dry air at constant volume +CV_VAP = Float(3.0) * RVGAS # 1384.5, heat capacity of water vapor at constant volume + +C_ICE = Float(1972.0) # gfdl: heat capacity of ice at - 15 deg c +C_LIQ = Float(4185.5) # gfdl: heat capacity of water at 15 deg c + +EPS = RDGAS / RVGAS # 0.6219934995 +ZVIR = RVGAS / RDGAS - Float(1.0) # 0.6077338443 + +T_ICE = Float(273.16) # freezing temperature +TABLE_ICE = Float(273.16) # freezing point for qs table + +E_00 = Float(611.21) # ifs: saturation vapor pressure at 0 deg c + +DC_VAP = CP_VAP - C_LIQ # - 2339.5, isobaric heating / cooling +DC_ICE = C_LIQ - C_ICE # 2213.5, isobaric heating / colling + +HLV0 = HLV # gfs: evaporation latent heat coefficient at 0 deg c +HLF0 = HLF # gfs: fussion latent heat coefficient at 0 deg c + +LV0 = ( + HLV0 - DC_VAP * T_ICE +) # 3.13905782e6, evaporation latent heat coefficient at 0 deg k +LI00 = HLF0 - DC_ICE * T_ICE # - 2.7105966e5, fusion latent heat coefficient at 0 deg k + +D2ICE = DC_VAP + DC_ICE # - 126, isobaric heating / cooling +LI2 = LV0 + LI00 # 2.86799816e6, sublimation latent heat coefficient at 0 deg k + +QPMIN = Float(1.0e-8) # min value for suspended rain/snow/liquid/ice precip +QVMIN = Float(1.0e-20) # min value for water vapor (treated as zero) +QCMIN = Float(1.0e-12) # min value for cloud condensates + +VR_MIN = Float(1.0e-3) # min fall speed for rain +VF_MIN = Float(1.0e-5) # min fall speed for cloud ice, snow, graupel + +DZ_MIN = Float(1.0e-2) # use for correcting flipped height + +SFCRHO = Float(1.2) # surface air density +RHOR = Float(1.0e3) # density of rain water, lin83 + +RC = (Float(4.0) / Float(3.0)) * PI * RHOR + +# cloud microphysics switchers + +DO_SETUP = True # setup constants and parameters +P_NONHYDRO = False # perform hydrosatic adjustment on air density + +DT_FR = Float(8.0) # epsilon on homogeneous freezing of cloud water at t_wfr + dt_fr +# minimum temperature water can exist (moore & molinero nov. 2011, nature) +# dt_fr can be considered as the error bar + +P_MIN = Float(100.0) # minimum pressure (pascal) for mp to operate + +# ----------------------------------------------------------------------- +# namelist parameters +# ----------------------------------------------------------------------- + +TICE = Float(273.16) # set tice = 165. to trun off ice - phase phys (kessler emulator) + +LOG_10 = np.log(10.0, dtype=Float) +TICE0 = Float(273.16) - Float(0.01) +T_WFR = Float(273.16) - Float( + 40.0 +) # supercooled water can exist down to - 40 c, which is the "absolute" + +# Constants moved from setup functions +RGRAV = Float(1.0) / GRAV + +# fall velocity constants: + +THI = Float(1.0e-8) # cloud ice threshold for terminal fall +THG = Float(1.0e-8) +THS = Float(1.0e-8) +AAC = Float(-4.18334e-5) +BBC = Float(-0.00525867) +CCC = Float(-0.0486519) +DDC = Float(0.00251197) +EEC = Float(1.91523) +AAL = Float(-1.70704e-5) +BBL = Float(-0.00319109) +CCL = Float(-0.0169876) +DDL = Float(0.00410839) +EEL = Float(1.93644) + +# marshall - palmer constants + +VCONS = Float(6.6280504) +VCONG = Float(87.2382675) +NORMS = Float(942477796.076938) +NORMG = Float(5026548245.74367) + + +# From setupm + +GAM263 = Float(1.456943) +GAM275 = Float(1.608355) +GAM209 = Float(1.827363) +GAM325 = Float(2.54925) +GAM350 = Float(3.323363) +GAM380 = Float(4.694155) +GAM425 = Float(8.285063) +GAM450 = Float(11.631769) +GAM480 = Float(17.837789) +GAM625 = Float(184.860962) +GAM680 = Float(496.604067) + +# intercept parameters + +RNZR = Float(8.0e6) # lin83 +RNZS = Float(3.0e6) # lin83 +RNZG = Float(4.0e6) # rh84 + +# density parameters + +RHOS = Float(0.1e3) # lin83 (snow density; 1 / 10 of water) +RHOG = Float(0.4e3) # rh84 (graupel density) +ACC = [Float(5.0), Float(2.0), Float(0.5)] + +# computed constants + +PIE = Float(4.0) * np.arctan(1.0, dtype=Float) + +VDIFU = Float(2.11e-5) +TCOND = Float(2.36e-2) + +VISK = Float(1.259e-5) +HLTS = Float(2.8336e6) +HLTC = Float(2.5e6) +HLTF = Float(3.336e5) + +CH2O = Float(4.1855e3) +RI50 = Float(1.0e-4) + +PISQ = PIE * PIE +SCM3 = (VISK / VDIFU) ** (Float(1.0) / Float(3.0)) + +CRACS = PISQ * RNZR * RNZS * RHOS +CSARC = PISQ * RNZR * RNZS * RHOR +CGARC = PISQ * RNZR * RNZG * RHOR + +ACT = np.zeros(8) + +ACT[0] = PIE * RNZS * RHOS +ACT[1] = PIE * RNZR * RHOR +ACT[5] = PIE * RNZG * RHOG +ACT[2] = ACT[1] +ACT[3] = ACT[0] +ACT[4] = ACT[1] +ACT[6] = ACT[0] +ACT[7] = ACT[5] + +ACT_0 = ACT[0] +ACT_1 = ACT[1] +ACT_2 = ACT[2] +ACT_3 = ACT[3] +ACT_4 = ACT[4] +ACT_5 = ACT[5] +ACT_6 = ACT[6] +ACT_7 = ACT[7] + +ACCO = np.zeros([3, 4]) +for i in range(1, 4): + for k in range(1, 5): + ACCO[i - 1, k - 1] = ACC[i - 1] / ( + ACT[2 * k - 2] ** ((7 - i) * Float(0.25)) + * ACT[2 * k - 1] ** (i * Float(0.25)) + ) + +ACCO_00 = ACCO[0, 0] +ACCO_01 = ACCO[0, 1] +ACCO_02 = ACCO[0, 2] +ACCO_03 = ACCO[0, 3] +ACCO_10 = ACCO[1, 0] +ACCO_11 = ACCO[1, 1] +ACCO_12 = ACCO[1, 2] +ACCO_13 = ACCO[1, 3] +ACCO_20 = ACCO[2, 0] +ACCO_21 = ACCO[2, 1] +ACCO_22 = ACCO[2, 2] +ACCO_23 = ACCO[2, 3] + + +GCON = Float(40.74) * np.sqrt(SFCRHO) # 44.628 + +# subl and revp: five constants for three separate processes + + +ES0 = Float(6.107799961e2) # ~6.1 mb +CES0 = EPS * ES0 + + +# terinal_fall / warm_rain constants + +ZS = Float(0) + + +# warm_rain constants: + +VCONR = Float(2503.23638966667) +NORMR = Float(25132741228.7183) +THR = Float(1.0e-8) + +SO3 = Float(7.0) / Float(3.0) + + +# q table constants + +LENGTH = i32(2621) diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver_core.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver_core.py new file mode 100644 index 000000000..772fe6b2f --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver_core.py @@ -0,0 +1,613 @@ +"""Core functions and stencils of the GFDL_1M driver""" + +import gt4py.cartesian.gtscript as gtscript +from gt4py.cartesian.gtscript import ( + FORWARD, + PARALLEL, + computation, + exp, + interval, + log, + log10, + sqrt, +) + +import pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_constants as driver_constants +from ndsl.dsl.typing import Float, FloatField, FloatFieldIJ +from pyMoist.shared_generic_math import sigma + + +GlobalTable_driver_qsat = gtscript.GlobalTable[(Float, (driver_constants.LENGTH))] + + +def init_temporaries( + t: FloatField, + dp: FloatField, + rhcrit3d: FloatField, + qv: FloatField, + ql: FloatField, + qi: FloatField, + qr: FloatField, + qs: FloatField, + qg: FloatField, + qa: FloatField, + qn: FloatField, + qv0: FloatField, + ql0: FloatField, + qr0: FloatField, + qi0: FloatField, + qs0: FloatField, + qg0: FloatField, + qa0: FloatField, + qv1: FloatField, + ql1: FloatField, + qr1: FloatField, + qi1: FloatField, + qs1: FloatField, + qg1: FloatField, + qa1: FloatField, + dz: FloatField, + uin: FloatField, + vin: FloatField, + w: FloatField, + area: FloatFieldIJ, + t1: FloatField, + dp1: FloatField, + omq: FloatField, + den: FloatField, + p_dry: FloatField, + m1: FloatField, + u1: FloatField, + v1: FloatField, + w1: FloatField, + onemsig: FloatFieldIJ, + ccn: FloatField, + c_praut: FloatField, + rh_limited: FloatField, + rain: FloatFieldIJ, + snow: FloatFieldIJ, + graupel: FloatFieldIJ, + ice: FloatFieldIJ, + m2_rain: FloatField, + m2_sol: FloatField, + revap: FloatField, + isubl: FloatField, +): + """ + initalize temporary copies of many quantities + + modification to quantities (t, p, q, etc.) made inside of the driver + are not returned outside of the driver. these copies are necessary + to ensure that no changes make it to the rest of the model + + reference Fortran: gfdl_cloud_microphys.F90: subroutine mpdrv + """ + from __externals__ import cpaut + + with computation(PARALLEL), interval(...): + t1 = t + dp1 = dp # moist air mass * grav + + # ----------------------------------------------------------------------- + # import horizontal subgrid variability with pressure dependence + # total water subgrid deviation in horizontal direction + # default area dependent form: use dx ~ 100 km as the base + # ----------------------------------------------------------------------- + rh_limited = min(0.30, 1.0 - rhcrit3d) # restricted to 70% + + # ----------------------------------------------------------------------- + # convert moist mixing ratios to dry mixing ratios + # ----------------------------------------------------------------------- + + dp1 = dp1 * (1.0 - qv) # gfs + omq = dp / dp1 + + qv0 = qv * omq + ql0 = ql * omq + qr0 = qr * omq + qi0 = qi * omq + qs0 = qs * omq + qg0 = qg * omq + + qv1 = qv0 + ql1 = ql0 + qr1 = qr0 + qi1 = qi0 + qs1 = qs0 + qg1 = qg0 + + qa0 = qa + qa1 = qa + + den = -dp1 / (driver_constants.GRAV * dz) # density of dry air + p_dry = den * driver_constants.RDGAS * t # dry air pressure + + # ----------------------------------------------------------------------- + # for sedi_momentum + # ----------------------------------------------------------------------- + + m1 = 0.0 + u1 = uin + v1 = vin + w1 = w + + # ccn needs units #/m^3 + ccn = qn + c_praut = cpaut * (ccn * driver_constants.RHOR) ** (-1.0 / 3.0) + + # Reset precipitation aggregates to zero + m2_rain = 0 + m2_sol = 0 + revap = 0 + isubl = 0 + + with computation(FORWARD), interval(0, 1): + # 1 minus sigma used to control minimum cloud + # fraction needed to autoconvert ql->qr + onemsig = 1.0 - sigma(sqrt(area)) + + # Reset precipitation aggregates to zero + rain = 0 + snow = 0 + graupel = 0 + ice = 0 + + +@gtscript.function +def fix_negative_core( + t: Float, + qv: Float, + ql: Float, + qr: Float, + qi: Float, + qs: Float, + qg: Float, + c_air: Float, + c_vap: Float, + lv00: Float, + d0_vap: Float, +): + """ + adjusts/removes negative mixing ratios + + reference Fortran: gfdl_cloud_microphys.F90: subroutine neg_adj + """ + # ----------------------------------------------------------------------- + # define heat capacity and latent heat coefficient + # ----------------------------------------------------------------------- + + cvm = ( + c_air + + qv * c_vap + + (qr + ql) * driver_constants.C_LIQ + + (qi + qs + qg) * driver_constants.C_ICE + ) + lcpk = (lv00 + d0_vap * t) / cvm + icpk = (driver_constants.LI00 + driver_constants.DC_ICE * t) / cvm + + # ----------------------------------------------------------------------- + # ice phase: + # ----------------------------------------------------------------------- + + # if cloud ice < 0, borrow from snow + if qi < 0.0: + qs = qs + qi + qi = 0.0 + # if snow < 0, borrow from graupel + if qs < 0.0: + qg = qg + qs + qs = 0.0 + # if graupel < 0, borrow from rain + if qg < 0.0: + qr = qr + qg + t = t - qg * icpk # heating + qg = 0.0 + + # ----------------------------------------------------------------------- + # liquid phase: + # ----------------------------------------------------------------------- + + # if rain < 0, borrow from cloud water + if qr < 0.0: + ql = ql + qr + qr = 0.0 + # if cloud water < 0, borrow from water vapor + if ql < 0.0: + qv = qv + ql + t = t - ql * lcpk # heating + ql = 0.0 + + return t, qv, ql, qr, qi, qs, qg + + +def fix_negative_values( + t: FloatField, + qv: FloatField, + ql: FloatField, + qr: FloatField, + qi: FloatField, + qs: FloatField, + qg: FloatField, + dp: FloatField, +): + """ + stencil wrapper for fix_negative_core + + adjusts/removes negative mixing ratios + updates qv based on new values + + refernce Fortran: gfdl_cloud_microphys.F90: subroutine mpdrv + """ + from __externals__ import c_air, c_vap, d0_vap, lv00 + + # ----------------------------------------------------------------------- + # fix all negative water species + # ----------------------------------------------------------------------- + + with computation(FORWARD), interval(0, -1): + t, qv, ql, qr, qi, qs, qg = fix_negative_core( + t, qv, ql, qr, qi, qs, qg, c_air, c_vap, lv00, d0_vap + ) + if qv < 0.0: + qv[0, 0, 1] = qv[0, 0, 1] + qv * dp / dp[0, 0, 1] + qv = 0.0 + + with computation(FORWARD), interval(-1, None): + t, qv, ql, qr, qi, qs, qg = fix_negative_core( + t, qv, ql, qr, qi, qs, qg, c_air, c_vap, lv00, d0_vap + ) + + if qv < 0.0 and qv[0, 0, -1] > 0.0: + dq = min(-qv * dp, qv[0, 0, -1] * dp[0, 0, -1]) + qv[0, 0, -1] = qv[0, 0, -1] - dq / dp[0, 0, -1] + qv = qv + dq / dp + + +@gtscript.function +def fall_speed_core( + p_dry: Float, + cnv_frc: Float, + anv_icefall: Float, + lsc_icefall: Float, + den: Float, + qs: Float, + qi: Float, + qg: Float, + ql: Float, + t: Float, +): + """ + calculate the vertical fall speed of precipitation + + reference Fortran: gfdl_cloud_microphys.F90: subroutine fall_speed + """ + from __externals__ import ( + const_vg, + const_vi, + const_vs, + vg_fac, + vg_max, + vi_fac, + vi_max, + vs_fac, + vs_max, + ) + + rhof = sqrt(min(10.0, driver_constants.SFCRHO / den)) + if const_vi == True: # noqa + vti = vi_fac + else: + if qi < driver_constants.THI: + vti = driver_constants.VF_MIN + else: + # ----------------------------------------------------------------------- + # ice: + # ----------------------------------------------------------------------- + + vi1 = 0.01 * vi_fac + tc = t - driver_constants.TICE # deg C + IWC = qi * den * 1.0e3 # Units are g/m3 + # ----------------------------------------------------------------------- + # use deng and mace (2008, grl) + # https://doi.org/10.1029/2008GL035054 + # ----------------------------------------------------------------------- + viLSC = lsc_icefall * 10.0 ** ( + log10(IWC) + * ( + tc * (driver_constants.AAL * tc + driver_constants.BBL) + + driver_constants.CCL + ) + + driver_constants.DDL * tc + + driver_constants.EEL + ) + viCNV = anv_icefall * 10.0 ** ( + log10(IWC) + * ( + tc * (driver_constants.AAC * tc + driver_constants.BBC) + + driver_constants.CCC + ) + + driver_constants.DDC * tc + + driver_constants.EEC + ) + # Combine + vti = viLSC * (1.0 - cnv_frc) + viCNV * (cnv_frc) + # Update units from cm/s to m/s + vti = vi1 * vti + # Limits + vti = min(vi_max, max(driver_constants.VF_MIN, vti)) + + # ----------------------------------------------------------------------- + # snow: + # ----------------------------------------------------------------------- + + if const_vs == True: # noqa + vts = vs_fac # 1. ifs_2016 + else: + if qs < driver_constants.THS: + vts = driver_constants.VF_MIN + else: + vts = ( + vs_fac + * driver_constants.VCONS + * rhof + * exp(0.0625 * log(qs * den / driver_constants.NORMS)) + ) + vts = min(vs_max, max(driver_constants.VF_MIN, vts)) + + # ----------------------------------------------------------------------- + # graupel: + # ----------------------------------------------------------------------- + + if const_vg == True: # noqa + vtg = vg_fac # 2. + else: + if qg < driver_constants.THG: + vtg = driver_constants.VF_MIN + else: + vtg = ( + vg_fac + * driver_constants.VCONG + * rhof + * sqrt(sqrt(sqrt(qg * den / driver_constants.NORMG))) + ) + vtg = min(vg_max, max(driver_constants.VF_MIN, vtg)) + + return vti, vts, vtg + + +def fall_speed( + ql1: FloatField, + qi1: FloatField, + qs1: FloatField, + qg1: FloatField, + t: FloatField, + t1: FloatField, + dz: FloatField, + dz1: FloatField, + den: FloatField, + den1: FloatField, + denfac: FloatField, + p_dry: FloatField, + vti: FloatField, + vts: FloatField, + vtg: FloatField, + cnv_frc: FloatFieldIJ, + anv_icefall: Float, + lsc_icefall: Float, +): + """ + stencil wrapper for fall_speed_core + + calculate the vertical fall speed of precipitation + + reference Fortran: gfdl_cloud_microphys.F90: subroutine mpdrv + """ + from __externals__ import p_nonhydro + + with computation(PARALLEL), interval(...): + if p_nonhydro: + dz1 = dz + den1 = den # dry air density remains the same + denfac = sqrt(driver_constants.SFCRHO / den1) + else: + dz1 = dz * t1 / t # hydrostatic balance + den1 = den * dz / dz1 + denfac = sqrt(driver_constants.SFCRHO / den1) + + vti, vts, vtg = fall_speed_core( + p_dry, cnv_frc, anv_icefall, lsc_icefall, den1, qs1, qi1, qg1, ql1, t1 + ) + + +def terminal_fall_update( + rain: FloatFieldIJ, + graupel: FloatFieldIJ, + snow: FloatFieldIJ, + ice: FloatFieldIJ, + rain1: FloatFieldIJ, + graupel1: FloatFieldIJ, + snow1: FloatFieldIJ, + ice1: FloatFieldIJ, +): + """ + update precipitation totals with results of terminal_fall stencil + + reference Fortran: gfdl_cloud_microphys.F90: subroutine mpdrv + """ + with computation(FORWARD), interval(0, 1): + rain = rain + rain1 # from melted snow & ice that reached the ground + snow = snow + snow1 + graupel = graupel + graupel1 + ice = ice + ice1 + + rain1 = 0 + snow1 = 0 + graupel1 = 0 + ice1 = 0 + + +def warm_rain_update( + rain: FloatFieldIJ, + rain1: FloatFieldIJ, + evap1: FloatField, + revap: FloatField, + m1_rain: FloatField, + m2_rain: FloatField, + m1_sol: FloatField, + m2_sol: FloatField, + m1: FloatField, +): + """ + update precipitation totals with results of warm_rain stencil + + reference Fortran: gfdl_cloud_microphys.F90: subroutine mpdrv + """ + with computation(PARALLEL), interval(...): + revap = revap + evap1 + m2_rain = m2_rain + m1_rain + m2_sol = m2_sol + m1_sol + m1 = m1 + m1_rain + m1_sol + + evap1 = 0 + m1_rain = 0 + m1_sol = 0 + + with computation(FORWARD), interval(0, 1): + rain = rain + rain1 + + rain1 = 0 + + +def icloud_update( + isubl: FloatField, + subl1: FloatField, +): + """ + update precipitation totals with results of icloud stencil + + reference Fortran: gfdl_cloud_microphys.F90: subroutine mpdrv + """ + with computation(PARALLEL), interval(...): + isubl = isubl + subl1 + + subl1 = 0 + + +def update_tendencies( + qv0: FloatField, + ql0: FloatField, + qr0: FloatField, + qi0: FloatField, + qs0: FloatField, + qg0: FloatField, + qa0: FloatField, + qv1: FloatField, + ql1: FloatField, + qr1: FloatField, + qi1: FloatField, + qs1: FloatField, + qg1: FloatField, + qa1: FloatField, + qn: FloatField, # NACTL + NACTI + qv_dt: FloatField, + ql_dt: FloatField, + qr_dt: FloatField, + qi_dt: FloatField, + qs_dt: FloatField, + qg_dt: FloatField, + qa_dt: FloatField, + t: FloatField, + t1: FloatField, + t_dt: FloatField, + w: FloatField, + w1: FloatField, + uin: FloatField, + u1: FloatField, + udt: FloatField, + vin: FloatField, + v1: FloatField, + vdt: FloatField, + dz: FloatField, + dp: FloatField, + dp1: FloatField, + den: FloatField, + p_dry: FloatField, + area: FloatFieldIJ, + dt_moist: Float, + fr_land: FloatFieldIJ, + cnv_frc: FloatFieldIJ, + srf_type: FloatFieldIJ, + eis: FloatFieldIJ, + rh_limited: FloatField, + m1: FloatField, + anv_icefall: Float, + lsc_icefall: Float, + revap: FloatField, # strict output + isubl: FloatField, # strict output + rain: FloatFieldIJ, # strict output + snow: FloatFieldIJ, # strict output + ice: FloatFieldIJ, # strict output + graupel: FloatFieldIJ, # strict output + m2_rain: FloatField, # strict output + m2_sol: FloatField, # strict output +): + """ + compute output tendencies of the microphysics driver + + reference Fortran: gfdl_cloud_microphys.F90: + subroutine mpdrv, subroutine gfdl_cloud_microphys_driver + """ + from __externals__ import c_air, c_vap, do_qa, do_sedi_w, rdt, sedi_transport + + # ----------------------------------------------------------------------- + # momentum transportation during sedimentation + # note: dp1 is dry mass; dp0 is the old moist (total) mass + # ----------------------------------------------------------------------- + + with computation(PARALLEL), interval(1, None): + if sedi_transport == True: # noqa + u1 = (dp * u1 + m1[0, 0, -1] * u1[0, 0, -1]) / (dp + m1[0, 0, -1]) + v1 = (dp * v1 + m1[0, 0, -1] * v1[0, 0, -1]) / (dp + m1[0, 0, -1]) + udt = udt + (u1 - uin) * rdt + vdt = vdt + (v1 - vin) * rdt + + with computation(PARALLEL), interval(...): + if do_sedi_w: + w = w1 + + # ----------------------------------------------------------------------- + # update moist air mass (actually hydrostatic pressure) + # convert to dry mixing ratios + # ----------------------------------------------------------------------- + + with computation(PARALLEL), interval(...): + omq = dp1 / dp + qv_dt = qv_dt + rdt * (qv1 - qv0) * omq + ql_dt = ql_dt + rdt * (ql1 - ql0) * omq + qr_dt = qr_dt + rdt * (qr1 - qr0) * omq + qi_dt = qi_dt + rdt * (qi1 - qi0) * omq + qs_dt = qs_dt + rdt * (qs1 - qs0) * omq + qg_dt = qg_dt + rdt * (qg1 - qg0) * omq + cvm = ( + c_air + + qv1 * c_vap + + (qr1 + ql1) * driver_constants.C_LIQ + + (qi1 + qs1 + qg1) * driver_constants.C_ICE + ) + t_dt = t_dt + rdt * (t1 - t) * cvm / driver_constants.CP_AIR + + # ----------------------------------------------------------------------- + # update cloud fraction tendency + # ----------------------------------------------------------------------- + if do_qa == False: # noqa + qa_dt = qa_dt + rdt * ( + qa0 * sqrt((qi1 + ql1) / max(qi0 + ql0, driver_constants.QCMIN)) - qa0 + ) # New Cloud - Old CloudCloud + + with computation(FORWARD), interval(0, 1): + # convert to mm / day + conversion_factor = 86400.0 * rdt * driver_constants.RGRAV + rain = rain * conversion_factor + snow = snow * conversion_factor + ice = ice * conversion_factor + graupel = graupel * conversion_factor diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver_tables.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver_tables.py new file mode 100644 index 000000000..80ebd68b8 --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/GFDL_1M_driver_tables.py @@ -0,0 +1,400 @@ +import gt4py.cartesian.gtscript as gtscript +from gt4py.cartesian.gtscript import ( + PARALLEL, + computation, + exp, + i32, + interval, + log, + log10, +) + +import pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_constants as driver_constants +from ndsl.boilerplate import get_factories_single_tile +from ndsl.constants import X_DIM, Y_DIM, Z_DIM +from ndsl.dsl.typing import Float +from pyMoist.shared_incloud_processes import ice_fraction + + +_FloatField_data_dim = gtscript.Field[ + gtscript.IJK, (Float, (int(driver_constants.LENGTH))) +] +GlobalTable_driver_qsat = gtscript.GlobalTable[(Float, (driver_constants.LENGTH))] + + +def qs_table_1(length: i32, table1: _FloatField_data_dim, esupc: _FloatField_data_dim): + """ + compute saturation water vapor pressure table 1 + three phase table + + reference Fortran: gfdl_cloud_microphys.F90: subroutine qs_table + """ + with computation(PARALLEL), interval(...): + delt = 0.1 + tmin = driver_constants.TABLE_ICE - 160.0 + + # ----------------------------------------------------------------------- + # compute es over ice between - 160 deg c and 0 deg c. + # ----------------------------------------------------------------------- + + i = 0 + while i < 1600: + tem = tmin + delt * i + fac0 = (tem - driver_constants.T_ICE) / (tem * driver_constants.T_ICE) + fac1 = fac0 * driver_constants.LI2 + fac2 = ( + driver_constants.D2ICE * log(tem / driver_constants.T_ICE) + fac1 + ) / driver_constants.RVGAS + table1[0, 0, 0][i] = driver_constants.E_00 * exp(fac2) + i = i + 1 + + # ----------------------------------------------------------------------- + # compute es over water between - 40 deg c and 102 deg c. + # ----------------------------------------------------------------------- + + i = 0 + while i < 1421: + tem = 233.16 + delt * i + fac0 = (tem - driver_constants.T_ICE) / (tem * driver_constants.T_ICE) + fac1 = fac0 * driver_constants.LV0 + fac2 = ( + driver_constants.DC_VAP * log(tem / driver_constants.T_ICE) + fac1 + ) / driver_constants.RVGAS + esh40 = driver_constants.E_00 * exp(fac2) + if i < 400: + esupc[0, 0, 0][i] = esh40 + else: + table1[0, 0, 0][i + 1200] = esh40 + i = i + 1 + + # ----------------------------------------------------------------------- + # derive blended es over ice and supercooled + # water between - 40 deg c and 0 deg c + # ----------------------------------------------------------------------- + + i = 0 + while i < 400: + tem = 233.16 + delt * i + # GEOS ! WMP impose CALIPSO ice polynomial from 0 C to -40 C + wice = ice_fraction(tem, 0.0, 0.0) + wh2o = 1.0 - wice + table1[0, 0, 0][i + 1200] = ( + wice * table1[0, 0, 0][i + 1200] + wh2o * esupc[0, 0, 0][i] + ) + i = i + 1 + + +def qs_table_2(length: i32, table2: _FloatField_data_dim): + """ + compute saturation water vapor pressure table 2 + one phase table + + reference Fortran: gfdl_cloud_microphys.F90: subroutine qs_tablew + """ + with computation(PARALLEL), interval(...): + delt = 0.1 + tmin = driver_constants.TABLE_ICE - 160.0 + + i = 0 + while i < length: + tem = tmin + delt * i + fac0 = (tem - driver_constants.T_ICE) / (tem * driver_constants.T_ICE) + fac1 = fac0 * driver_constants.LV0 + fac2 = ( + driver_constants.DC_VAP * log(tem / driver_constants.T_ICE) + fac1 + ) / driver_constants.RVGAS + table2[0, 0, 0][i] = driver_constants.E_00 * exp(fac2) + i = i + 1 + + +def qs_table_3(length: i32, table3: _FloatField_data_dim, table1: _FloatField_data_dim): + """ + compute saturation water vapor pressure table 3 + two phase table + + reference Fortran: gfdl_cloud_microphys.F90: subroutine qs_table2 + """ + with computation(PARALLEL), interval(...): + delt = 0.1 + tmin = driver_constants.TABLE_ICE - 160.0 + + i = 0 + while i < length: + tem0 = tmin + delt * i + fac0 = (tem0 - driver_constants.T_ICE) / (tem0 * driver_constants.T_ICE) + if i < 1600: + # ----------------------------------------------------------------------- + # compute es over ice between - 160 deg c and 0 deg c. + # ----------------------------------------------------------------------- + fac1 = fac0 * driver_constants.LI2 + fac2 = ( + driver_constants.D2ICE * log(tem0 / driver_constants.T_ICE) + fac1 + ) / driver_constants.RVGAS + else: + # ----------------------------------------------------------------------- + # compute es over water between 0 deg c and 102 deg c. + # ----------------------------------------------------------------------- + fac1 = fac0 * driver_constants.LV0 + fac2 = ( + driver_constants.DC_VAP * log(tem0 / driver_constants.T_ICE) + fac1 + ) / driver_constants.RVGAS + table3[0, 0, 0][i] = driver_constants.E_00 * exp(fac2) + i = i + 1 + + # ----------------------------------------------------------------------- + # smoother around 0 deg c + # ----------------------------------------------------------------------- + + i0 = 1599 + i1 = 1600 + tem0 = 0.25 * ( + table3[0, 0, 0][i0 - 1] + + 2.0 * table1[0, 0, 0][i0] + + table3[0, 0, 0][i0 + 1] + ) + tem1 = 0.25 * ( + table3[0, 0, 0][i1 - 1] + + 2.0 * table1[0, 0, 0][i1] + + table3[0, 0, 0][i1 + 1] + ) + table3[0, 0, 0][i0] = tem0 + table3[0, 0, 0][i1] = tem1 + + +def qs_table_4(length: i32, table4: _FloatField_data_dim, table1: _FloatField_data_dim): + """ + compute saturation water vapor pressure table 4 + two phase table with " - 2 c" as the transition point + + reference Fortran: gfdl_cloud_microphys.F90: subroutine qs_table3 + """ + with computation(PARALLEL), interval(...): + delt = 0.1 + esbasw = 1013246.0 + tbasw = driver_constants.TABLE_ICE + 100.0 + esbasi = 6107.1 + tmin = driver_constants.TABLE_ICE - 160.0 + + i = 0 + while i < length: + tem = tmin + delt * i + if i < 1580: # change to - 2 c + # ----------------------------------------------------------------------- + # compute es over ice between - 160 deg c and 0 deg c. + # see smithsonian meteorological tables page 350. + # ----------------------------------------------------------------------- + aa = -9.09718 * (driver_constants.TABLE_ICE / tem - 1.0) + b = -3.56654 * log10(driver_constants.TABLE_ICE / tem) + c = 0.876793 * (1.0 - tem / driver_constants.TABLE_ICE) + e = log10(esbasi) + table4[0, 0, 0][i] = 0.1 * 10 ** (aa + b + c + e) + else: + # ----------------------------------------------------------------------- + # compute es over water between - 2 deg c and 102 deg c. + # see smithsonian meteorological tables page 350. + # ----------------------------------------------------------------------- + aa = -7.90298 * (tbasw / tem - 1.0) + b = 5.02808 * log10(tbasw / tem) + c = -1.3816e-7 * (10 ** ((1.0 - tem / tbasw) * 11.344) - 1.0) + d = 8.1328e-3 * (10 ** ((tbasw / tem - 1.0) * (-3.49149)) - 1.0) + e = log10(esbasw) + table4[0, 0, 0][i] = 0.1 * 10 ** (aa + b + c + d + e) + i = i + 1 + + # ----------------------------------------------------------------------- + # smoother around - 2 deg c + # ----------------------------------------------------------------------- + + i0 = 1579 + i1 = 1580 + tem0 = 0.25 * ( + table4[0, 0, 0][i0 - 1] + + 2.0 * table1[0, 0, 0][i0] + + table4[0, 0, 0][i0 + 1] + ) + tem1 = 0.25 * ( + table4[0, 0, 0][i1 - 1] + + 2.0 * table1[0, 0, 0][i1] + + table4[0, 0, 0][i1 + 1] + ) + table4[0, 0, 0][i0] = tem0 + table4[0, 0, 0][i1] = tem1 + + +def des_tables( + length: i32, + des1: _FloatField_data_dim, + des2: _FloatField_data_dim, + des3: _FloatField_data_dim, + des4: _FloatField_data_dim, + table1: _FloatField_data_dim, + table2: _FloatField_data_dim, + table3: _FloatField_data_dim, + table4: _FloatField_data_dim, +): + with computation(PARALLEL), interval(...): + i = 0 + while i < length - 1: + des1[0, 0, 0][i] = max(0.0, table1[0, 0, 0][i + 1] - table1[0, 0, 0][i]) + des2[0, 0, 0][i] = max(0.0, table2[0, 0, 0][i + 1] - table2[0, 0, 0][i]) + des3[0, 0, 0][i] = max(0.0, table3[0, 0, 0][i + 1] - table3[0, 0, 0][i]) + des4[0, 0, 0][i] = max(0.0, table4[0, 0, 0][i + 1] - table4[0, 0, 0][i]) + i = i + 1 + + des1[0, 0, 0][length - 1] = des1[0, 0, 0][length - 2] + des2[0, 0, 0][length - 1] = des2[0, 0, 0][length - 2] + des3[0, 0, 0][length - 1] = des3[0, 0, 0][length - 2] + des4[0, 0, 0][length - 1] = des4[0, 0, 0][length - 2] + + +class GFDL_driver_tables: + """ + Initializes lookup tables for saturation water vapor pressure + for the utility routines that are designed to return qs + consistent with the assumptions in FV3. + + Reference Fortran: gfdl_cloud_microphys.F90: qsmith_init.py + """ + + def __init__(self, backend): + qsat_domain = (1, 1, 1) + + stencil_factory, quantity_factory_data_dim = get_factories_single_tile( + qsat_domain[0], qsat_domain[1], qsat_domain[2], 0, backend=backend + ) + quantity_factory_data_dim.set_extra_dim_lengths( + **{ + "table_axis": driver_constants.LENGTH, + } + ) + + self._table1 = quantity_factory_data_dim.zeros( + [X_DIM, Y_DIM, Z_DIM, "table_axis"], "n/a" + ) + self._table2 = quantity_factory_data_dim.zeros( + [X_DIM, Y_DIM, Z_DIM, "table_axis"], "n/a" + ) + self._table3 = quantity_factory_data_dim.zeros( + [X_DIM, Y_DIM, Z_DIM, "table_axis"], "n/a" + ) + self._table4 = quantity_factory_data_dim.zeros( + [X_DIM, Y_DIM, Z_DIM, "table_axis"], "n/a" + ) + self._des1 = quantity_factory_data_dim.zeros( + [X_DIM, Y_DIM, Z_DIM, "table_axis"], "n/a" + ) + self._des2 = quantity_factory_data_dim.zeros( + [X_DIM, Y_DIM, Z_DIM, "table_axis"], "n/a" + ) + self._des3 = quantity_factory_data_dim.zeros( + [X_DIM, Y_DIM, Z_DIM, "table_axis"], "n/a" + ) + self._des4 = quantity_factory_data_dim.zeros( + [X_DIM, Y_DIM, Z_DIM, "table_axis"], "n/a" + ) + self._esupc = quantity_factory_data_dim.zeros( + [X_DIM, Y_DIM, Z_DIM, "table_axis"], "n/a" + ) + + compute_qs_table_1 = stencil_factory.from_origin_domain( + func=qs_table_1, + origin=(0, 0, 0), + domain=qsat_domain, + ) + compute_qs_table_2 = stencil_factory.from_origin_domain( + func=qs_table_2, + origin=(0, 0, 0), + domain=qsat_domain, + ) + compute_qs_table_3 = stencil_factory.from_origin_domain( + func=qs_table_3, + origin=(0, 0, 0), + domain=qsat_domain, + ) + compute_qs_table_4 = stencil_factory.from_origin_domain( + func=qs_table_4, + origin=(0, 0, 0), + domain=qsat_domain, + ) + compute_des_tables = stencil_factory.from_origin_domain( + func=des_tables, + origin=(0, 0, 0), + domain=qsat_domain, + ) + + compute_qs_table_1(driver_constants.LENGTH, self._table1, self._esupc) + compute_qs_table_2(driver_constants.LENGTH, self._table2) + compute_qs_table_3(driver_constants.LENGTH, self._table3, self._table1) + compute_qs_table_4(driver_constants.LENGTH, self._table4, self._table1) + compute_des_tables( + driver_constants.LENGTH, + self._des1, + self._des2, + self._des3, + self._des4, + self._table1, + self._table2, + self._table3, + self._table4, + ) + + @property + def table1( + self, + ): + return self._table1.view[0, 0, 0, :] + + @property + def table2( + self, + ): + return self._table2.view[0, 0, 0, :] + + @property + def table3( + self, + ): + return self._table3.view[0, 0, 0, :] + + @property + def table4( + self, + ): + return self._table4.view[0, 0, 0, :] + + @property + def des1( + self, + ): + return self._des1.view[0, 0, 0, :] + + @property + def des2( + self, + ): + return self._des2.view[0, 0, 0, :] + + @property + def des3( + self, + ): + return self._des3.view[0, 0, 0, :] + + @property + def des4( + self, + ): + return self._des4.view[0, 0, 0, :] + + +# Table needs to be calculated only once +_cached_table = { + "driver_qsat": None, +} + + +def get_tables(backend): + if _cached_table["driver_qsat"] is None: + _cached_table["driver_qsat"] = GFDL_driver_tables(backend) + + return _cached_table["driver_qsat"] diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/icloud.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/icloud.py new file mode 100644 index 000000000..16a5ac1df --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/icloud.py @@ -0,0 +1,1662 @@ +import gt4py.cartesian.gtscript as gtscript +from gt4py.cartesian.gtscript import ( + FORWARD, + PARALLEL, + computation, + exp, + i32, + interval, + log, + max, + sqrt, + trunc, +) + +import pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_constants as driver_constants +from ndsl.dsl.typing import Float, FloatField, FloatFieldIJ +from pyMoist.shared_incloud_processes import ice_fraction + + +GlobalTable_driver_qsat = gtscript.GlobalTable[(Float, (int(driver_constants.LENGTH)))] + + +@gtscript.function +def new_ice_condensate(t, ql, qi, cnv_frc, srf_type): + """ + calculate amount of new ice to be frozen at a given point + + reference Fortran: gfdl_cloud_microphys.F90: function new_ice_condensate + """ + ifrac = ice_fraction(t, cnv_frc, srf_type) + new_ice_condensate = min(max(0.0, ifrac * (ql + qi) - qi), ql) + + return new_ice_condensate + + +@gtscript.function +def icloud_melt_freeze( + t: Float, + qv: Float, + ql: Float, + qr: Float, + qi: Float, + qs: Float, + qg: Float, + qa: Float, + den: Float, + cnv_frc: Float, + srf_type: Float, +): + """ + melting and freezing of cloud ice/water within the icloud subroutine + + reference Fortran: gfdl_cloud_microphys.F90: subroutine icloud + """ + from __externals__ import c_air, c_vap, fac_frz, fac_imlt, qi0_crt, ql_mlt + + # ----------------------------------------------------------------------- + # define heat capacity and latent heat coefficient + # ----------------------------------------------------------------------- + + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t + q_liq = ql + qr + q_sol = qi + qs + qg + cvm = ( + c_air + + qv * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + icpk = lhi / cvm + + newice = max(0.0, qi + new_ice_condensate(t, ql, qi, cnv_frc, srf_type)) + newliq = max(0.0, ql + qi - newice) + + melt = fac_imlt * max(0.0, newliq - ql) + frez = fac_frz * max(0.0, newice - qi) + + if melt > 0.0 and t > driver_constants.TICE and qi > driver_constants.QCMIN: + # ----------------------------------------------------------------------- + # pimlt: melting of cloud ice + # ----------------------------------------------------------------------- + if ql_mlt - ql > 0: + ans = ql_mlt - ql + else: + ans = 0 + tmp = min(melt, ans) # max ql amount + + # new total condensate / old condensate + qa = max( + 0.0, + min( + 1.0, + qa + * max(qi + ql - melt + tmp, 0.0) + / max(qi + ql, driver_constants.QCMIN), + ), + ) + + ql = ql + tmp + qr = qr + melt - tmp + qi = qi - melt + q_liq = q_liq + melt + q_sol = q_sol - melt + cvm = ( + c_air + + qv * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t = t - melt * lhi / cvm + elif frez > 0.0 and t <= driver_constants.TICE and ql > driver_constants.QCMIN: + # ----------------------------------------------------------------------- + # pihom: homogeneous freezing of cloud water into cloud ice + # this is the 1st occurance of liquid water freezing in the split mp process + # ----------------------------------------------------------------------- + qi_crt = ice_fraction(t, cnv_frc, srf_type) * qi0_crt / den + if qi_crt - qi > 0: + ans = qi_crt + else: + ans = 0 + tmp = min(frez, ans) + + # new total condensate / old condensate + qa = max( + 0.0, + min( + 1.0, + qa + * max(qi + ql - frez + tmp, 0.0) + / max(qi + ql, driver_constants.QCMIN), + ), + ) + + ql = ql - frez + qs = qs + frez - tmp + qi = qi + tmp + q_liq = q_liq - frez + q_sol = q_sol + frez + cvm = ( + c_air + + qv * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t = t + frez * lhi / cvm + + return t, qv, ql, qr, qi, qs, qg, qa, cvm, q_liq, q_sol + + +@gtscript.function +def acr3d( + v1: Float, + v2: Float, + q1: Float, + q2: Float, + c: Float, + cac_1: Float, + cac_2: Float, + cac_3: Float, + rho: Float, +): + """ + compute accretion according to Lin et al. 1983 + + reference Fortran: gfdl_cloud_microphys.F90: function acr3d + """ + t1 = sqrt(q1 * rho) + s1 = sqrt(q2 * rho) + s2 = sqrt(s1) # s1 = s2 ** 2 + acr3d = ( + c * abs(v1 - v2) * q1 * s2 * (cac_1 * t1 + cac_2 * sqrt(t1) * s2 + cac_3 * s1) + ) + + return acr3d + + +@gtscript.function +def smow_melt( + tc: Float, + dqs: Float, + qsrho: Float, + psacw: Float, + psacr: Float, + c_0: Float, + c_1: Float, + c_2: Float, + c_3: Float, + c_4: Float, + rho: Float, + rhofac: Float, +): + """ + melting of snow function (lin et al. 1983) + note: psacw and psacr must be calc before smlt is called + + reference Fortran: gfdl_cloud_microphys.F90: function smlt + """ + smow_melt = (c_0 * tc / rho - c_1 * dqs) * ( + c_2 * sqrt(qsrho) + c_3 * qsrho**0.65625 * sqrt(rhofac) + ) + c_4 * tc * (psacw + psacr) + + return smow_melt + + +@gtscript.function +def graupel_melt( + tc: Float, + dqs: Float, + qgrho: Float, + pgacw: Float, + pgacr: Float, + c_0: Float, + c_1: Float, + c_2: Float, + c_3: Float, + c_4: Float, + rho: Float, +): + """ + melting of graupel function (lin et al. 1983) + note: pgacw and pgacr must be calc before gmlt is called + + reference Fortran: gfdl_cloud_microphys.F90: function gmlt + """ + graupel_melt = (c_0 * tc / rho - c_1 * dqs) * ( + c_2 * sqrt(qgrho) + c_3 * qgrho**0.6875 / rho**0.25 + ) + c_4 * tc * (pgacw + pgacr) + + return graupel_melt + + +@gtscript.function +def snow_graupel_coldrain( + t1: Float, + qv1: Float, + ql1: Float, + qi1: Float, + qr1: Float, + qs1: Float, + qg1: Float, + qa1: Float, + p_dry: Float, + den1: Float, + denfac: Float, + vtr: Float, + vts: Float, + vtg: Float, + cvm: Float, + lhl: Float, + lhi: Float, + lcpk: Float, + icpk: Float, + tcpk: Float, + q_liq: Float, + q_sol: Float, + di: Float, + cnv_frc: Float, + srf_type: Float, +): + """ + snow, graupel, cold rain microphysics + melting, freezing, accretion + + reference Fortran: gfdl_cloud_microphys.F90: subroutine icloud + """ + from __externals__ import ( + c_air, + c_vap, + cgaci, + cgacs, + cgacw, + cgfr_0, + cgfr_1, + cgmlt_0, + cgmlt_1, + cgmlt_2, + cgmlt_3, + cgmlt_4, + const_vi, + csaci, + csacw, + csmlt_0, + csmlt_1, + csmlt_2, + csmlt_3, + csmlt_4, + dts, + fac_i2s, + qi0_crt, + qs0_crt, + qs_mlt, + rdts, + ) + + t2 = t1 + qv2 = qv1 + ql2 = ql1 + qi2 = qi1 + qr2 = qr1 + qs2 = qs1 + qg2 = qg1 + + pgacr = 0.0 + pgacw = 0.0 + tc = t2 - driver_constants.TICE + + if tc >= 0.0: + # ----------------------------------------------------------------------- + # melting of snow + # ----------------------------------------------------------------------- + + dqs0 = driver_constants.CES0 / p_dry - qv2 + + if qs2 > driver_constants.QPMIN: + + # ----------------------------------------------------------------------- + # psacw: accretion of cloud water by snow + # only rate is used (for snow melt) since tc > 0. + # ----------------------------------------------------------------------- + + if ql2 > driver_constants.QCMIN: + factor = denfac * csacw * exp(0.8125 * log(qs2 * den1)) + psacw = factor / (1.0 + dts * factor) * ql2 # rate + else: + psacw = 0.0 + + # ----------------------------------------------------------------------- + # psacr: accretion of rain by melted snow + # pracs: accretion of snow by rain + # ----------------------------------------------------------------------- + + if qr2 > driver_constants.QPMIN: + psacr = min( + acr3d( + vts, + vtr, + qr2, + qs2, + driver_constants.CSARC, + driver_constants.ACCO_01, + driver_constants.ACCO_11, + driver_constants.ACCO_21, + den1, + ), + qr2 * rdts, + ) + pracs = acr3d( + vtr, + vts, + qs2, + qr2, + driver_constants.CRACS, + driver_constants.ACCO_00, + driver_constants.ACCO_10, + driver_constants.ACCO_20, + den1, + ) + else: + psacr = 0.0 + pracs = 0.0 + + # ----------------------------------------------------------------------- + # total snow sink: + # psmlt: snow melt (due to rain accretion) + # ----------------------------------------------------------------------- + + psmlt = max( + 0.0, + smow_melt( + tc, + dqs0, + qs2 * den1, + psacw, + psacr, + csmlt_0, + csmlt_1, + csmlt_2, + csmlt_3, + csmlt_4, + den1, + denfac, + ), + ) + sink = min(qs2, min(dts * (psmlt + pracs), tc / icpk)) + qs2 = qs2 - sink + # sjl, 20170321: + if qs_mlt - ql2 > 0: + ans = qs_mlt - ql2 + else: + ans = 0 + tmp = min(sink, ans) # max ql due to snow melt + + # new total condensate / old condensate + qa1 = max( + 0.0, + min( + 1.0, + qa1 + * max(qi2 + ql2 + tmp, 0.0) + / max(qi2 + ql2, driver_constants.QCMIN), + ), + ) + + ql2 = ql2 + tmp + qr2 = qr2 + sink - tmp + # sjl, 20170321: + q_liq = q_liq + sink + q_sol = q_sol - sink + cvm = ( + c_air + + qv2 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t2 = t2 - sink * lhi / cvm + tc = t2 - driver_constants.TICE + + # ----------------------------------------------------------------------- + # update capacity heat and latent heat coefficient + # ----------------------------------------------------------------------- + + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t2 + icpk = lhi / cvm + + # ----------------------------------------------------------------------- + # melting of graupel + # ----------------------------------------------------------------------- + + if qg2 > driver_constants.QPMIN and tc > 0.0: + + # ----------------------------------------------------------------------- + # pgacr: accretion of rain by graupel + # ----------------------------------------------------------------------- + + if qr2 > driver_constants.QPMIN: + pgacr = min( + acr3d( + vtg, + vtr, + qr2, + qg2, + driver_constants.CGARC, + driver_constants.ACCO_02, + driver_constants.ACCO_12, + driver_constants.ACCO_22, + den1, + ), + rdts * qr2, + ) + + # ----------------------------------------------------------------------- + # pgacw: accretion of cloud water by graupel + # ----------------------------------------------------------------------- + + qden = qg2 * den1 + if ql2 > driver_constants.QCMIN: + factor = cgacw * qden / sqrt(den1 * sqrt(sqrt(qden))) + pgacw = factor / (1.0 + dts * factor) * ql2 # rate + + # ----------------------------------------------------------------------- + # pgmlt: graupel melt + # ----------------------------------------------------------------------- + + pgmlt = dts * graupel_melt( + tc, + dqs0, + qden, + pgacw, + pgacr, + cgmlt_0, + cgmlt_1, + cgmlt_2, + cgmlt_3, + cgmlt_4, + den1, + ) + pgmlt = min(max(0.0, pgmlt), min(qg2, tc / icpk)) + qg2 = qg2 - pgmlt + qr2 = qr2 + pgmlt + q_liq = q_liq + pgmlt + q_sol = q_sol - pgmlt + cvm = ( + c_air + + qv2 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t2 = t2 - pgmlt * lhi / cvm + + else: + + # ----------------------------------------------------------------------- + # cloud ice proc: + # ----------------------------------------------------------------------- + + # ----------------------------------------------------------------------- + # psaci: accretion of cloud ice by snow + # ----------------------------------------------------------------------- + + if qi2 > 3.0e-7: # cloud ice sink terms + if qs2 > driver_constants.QPMIN: + # ----------------------------------------------------------------------- + # sjl added (following lin eq. 23) the temperature dependency + # to reduce accretion, use esi = exp (0.05 * tc) as in hong et al 2004 + # ----------------------------------------------------------------------- + factor = ( + dts * denfac * csaci * exp(0.05 * tc + 0.8125 * log(qs2 * den1)) + ) + psaci = factor / (1.0 + factor) * qi2 + else: + psaci = 0.0 + + # ----------------------------------------------------------------------- + # psaut: autoconversion: cloud ice -- > snow + # ----------------------------------------------------------------------- + + # ----------------------------------------------------------------------- + # similar to lfo 1983: eq. 21 solved implicitly + # threshold from wsm6 scheme, hong et al 2004, eq (13) : qi0_crt ~0.8e-4 + # ----------------------------------------------------------------------- + + qim = ice_fraction(t2, cnv_frc, srf_type) * qi0_crt / den1 + + # ----------------------------------------------------------------------- + # assuming linear subgrid vertical distribution of cloud ice + # the mismatch computation following lin et al. 1994, mwr + # ----------------------------------------------------------------------- + + if const_vi: + tmp = fac_i2s + else: + tmp = fac_i2s * exp(0.025 * tc) + + di = max(di, driver_constants.QCMIN) + q_plus = qi2 + di + if q_plus > (qim + driver_constants.QCMIN): + if qim > (qi2 - di): + dq = (0.25 * (q_plus - qim) ** 2) / di + else: + dq = qi2 - qim + psaut = tmp * dq + else: + psaut = 0.0 + sink = min(qi2, psaci + psaut) + + # new total condensate / old condensate + qa1 = max( + 0.0, + min( + 1.0, + qa1 + * max(qi2 + ql2 - sink + tmp, 0.0) + / max(qi2 + ql2, driver_constants.QCMIN), + ), + ) + + qi2 = qi2 - sink + qs2 = qs2 + sink + + # ----------------------------------------------------------------------- + # pgaci: accretion of cloud ice by graupel + # ----------------------------------------------------------------------- + + if qg2 > driver_constants.QPMIN: + # ----------------------------------------------------------------------- + # factor = dts * cgaci / sqrt (den (k)) * + # exp (0.05 * tc + 0.875 * log (qg * den (k))) + # simplified form: remove temp dependency & set the exponent 0.875 -> 1 + # ----------------------------------------------------------------------- + factor = dts * cgaci * sqrt(den1) * qg2 + pgaci = factor / (1.0 + factor) * qi2 + qi2 = qi2 - pgaci + qg2 = qg2 + pgaci + + # ----------------------------------------------------------------------- + # cold - rain proc: + # ----------------------------------------------------------------------- + + # ----------------------------------------------------------------------- + # rain to ice, snow, graupel processes: + # ----------------------------------------------------------------------- + + tc = t2 - driver_constants.TICE + + if qr2 > driver_constants.QPMIN and tc < 0.0: + + # ----------------------------------------------------------------------- + # * sink * terms to qr: psacr + pgfr + # source terms to qs: psacr + # source terms to qg: pgfr + # ----------------------------------------------------------------------- + + # ----------------------------------------------------------------------- + # psacr accretion of rain by snow + # ----------------------------------------------------------------------- + + if qs2 > driver_constants.QPMIN: # if snow exists + psacr = dts * acr3d( + vts, + vtr, + qr2, + qs2, + driver_constants.CSARC, + driver_constants.ACCO_01, + driver_constants.ACCO_11, + driver_constants.ACCO_21, + den1, + ) + else: + psacr = 0.0 + + # ----------------------------------------------------------------------- + # pgfr: rain freezing -- > graupel + # ----------------------------------------------------------------------- + + pgfr = ( + dts + * cgfr_0 + / den1 + * (exp(-cgfr_1 * tc) - 1.0) + * exp(1.75 * log(qr2 * den1)) + ) + + # ----------------------------------------------------------------------- + # total sink to qr + # ----------------------------------------------------------------------- + + sink = psacr + pgfr + factor = min(sink, min(qr2, -tc / icpk)) / max(sink, driver_constants.QPMIN) + + psacr = factor * psacr + pgfr = factor * pgfr + + sink = psacr + pgfr + qr2 = qr2 - sink + qs2 = qs2 + psacr + qg2 = qg2 + pgfr + q_liq = q_liq - sink + q_sol = q_sol + sink + cvm = ( + c_air + + qv2 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t2 = t2 + sink * lhi / cvm + + # # ----------------------------------------------------------------------- + # # update capacity heat and latent heat coefficient + # # ----------------------------------------------------------------------- + + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t2 + icpk = lhi / cvm + + # # ----------------------------------------------------------------------- + # # graupel production terms: + # # ----------------------------------------------------------------------- + + if qs2 > driver_constants.QPMIN: + + # ----------------------------------------------------------------------- + # accretion: snow -- > graupel + # ----------------------------------------------------------------------- + + if qg2 > driver_constants.QPMIN: + sink = dts * acr3d( + vtg, + vts, + qs2, + qs2, + cgacs, + driver_constants.ACCO_03, + driver_constants.ACCO_13, + driver_constants.ACCO_23, + den1, + ) + else: + sink = 0.0 + + # ----------------------------------------------------------------------- + # autoconversion snow -- > graupel + # ----------------------------------------------------------------------- + + qsm = qs0_crt / den1 + if qs2 > qsm: + factor = dts * 1.0e-3 * exp(0.09 * (t2 - driver_constants.TICE)) + sink = sink + factor / (1.0 + factor) * (qs2 - qsm) + sink = min(qs2, sink) + + # snow existed + qs2 = qs2 - sink + qg2 = qg2 + sink + + if qg2 > driver_constants.QPMIN and t2 < (driver_constants.TICE - 0.01): + + # ----------------------------------------------------------------------- + # pgacw: accretion of cloud water by graupel + # ----------------------------------------------------------------------- + + if ql2 > driver_constants.QCMIN: + qden = qg2 * den1 + factor = dts * cgacw * qden / sqrt(den1 * sqrt(sqrt(qden))) + pgacw = factor / (1.0 + factor) * ql2 + else: + pgacw = 0.0 + + # ----------------------------------------------------------------------- + # pgacr: accretion of rain by graupel + # ----------------------------------------------------------------------- + + if qr2 > driver_constants.QPMIN: + pgacr = min( + dts + * acr3d( + vtg, + vtr, + qr2, + qg2, + driver_constants.CGARC, + driver_constants.ACCO_02, + driver_constants.ACCO_12, + driver_constants.ACCO_22, + den1, + ), + qr2, + ) + else: + pgacr = 0.0 + + sink = pgacr + pgacw + if driver_constants.TICE - t2 > 0: + ans = driver_constants.TICE - t2 + else: + ans = 0 + factor = min(sink, ans / icpk) / max(sink, driver_constants.QPMIN) + pgacr = factor * pgacr + pgacw = factor * pgacw + + sink = pgacr + pgacw + qg2 = qg2 + sink + qr2 = qr2 - pgacr + ql2 = ql2 - pgacw + q_liq = q_liq - sink + q_sol = q_sol + sink + cvm = ( + c_air + + qv2 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t2 = t2 + sink * lhi / cvm + + t1 = t2 + qv1 = qv2 + ql1 = ql2 + qi1 = qi2 + qr1 = qr2 + qs1 = qs2 + qg1 = qg2 + + return ( + t1, + qv1, + ql1, + qi1, + qr1, + qs1, + qg1, + qa1, + p_dry, + den1, + denfac, + vtr, + vts, + vtg, + cvm, + lhl, + lhi, + lcpk, + icpk, + tcpk, + ) + + +@gtscript.function +def iqs1( + ta: Float, + den: Float, + table3: GlobalTable_driver_qsat, + des3: GlobalTable_driver_qsat, +): + """ + compute saturation specific humidity from table3 + + water - ice phase; universal dry / moist formular using air density + input "den" can be either dry or moist air density + + reference Fortran: gfdl_cloud_microphys.F90: function iqs1 + """ + tmin = driver_constants.TABLE_ICE - 160.0 + if ta - tmin > 0: + ans = ta - tmin + else: + ans = 0 + ap1 = 10.0 * ans + 1.0 + ap1 = min(2621.0, ap1) + it = i32(trunc(ap1)) + es = table3.A[it - 1] + (ap1 - it) * des3.A[it - 1] + iqs1 = es / (driver_constants.RVGAS * ta * den) + + return iqs1 + + +@gtscript.function +def iqs2( + ta: Float, + den: Float, + table3: GlobalTable_driver_qsat, + des3: GlobalTable_driver_qsat, +): + """ + compute saturation specific humidity from table3 + with additional calculation of gradient (dq/dt) + + water - ice phase; universal dry / moist formular using air density + input "den" can be either dry or moist air density + + reference Fortran: gfdl_cloud_microphys.F90: function iqs2 + """ + tmin = driver_constants.TABLE_ICE - 160.0 + if ta - tmin > 0: + ans = ta - tmin + else: + ans = 0 + ap1 = 10.0 * ans + 1.0 + ap1 = min(2621.0, ap1) + it = i32(trunc(ap1)) + es = table3.A[it - 1] + (ap1 - it) * des3.A[it - 1] + iqs2 = es / (driver_constants.RVGAS * ta * den) + it = i32(trunc(ap1 - 0.5)) + dqdt = ( + 10.0 + * (des3.A[it - 1] + (ap1 - it) * (des3.A[it] - des3.A[it - 1])) + / (driver_constants.RVGAS * ta * den) + ) + + return iqs2, dqdt + + +@gtscript.function +def wqs1( + ta: Float, + den: Float, + table2: GlobalTable_driver_qsat, + des2: GlobalTable_driver_qsat, +): + """ + compute the saturated specific humidity for table2 + + pure water phase; universal dry / moist formular using air density + input "den" can be either dry or moist air density + + reference Fortran: gfdl_cloud_microphys.F90: function wqs1 + """ + tmin = driver_constants.TABLE_ICE - 160.0 + if ta - tmin > 0: + ans = ta - tmin + else: + ans = 0 + ap1 = 10.0 * ans + 1.0 + ap1 = min(2621.0, ap1) + it = i32(trunc(ap1)) + es = table2.A[it - 1] + (ap1 - it) * des2.A[it - 1] + wqs1 = es / (driver_constants.RVGAS * ta * den) + + return wqs1 + + +@gtscript.function +def wqs2( + ta: Float, + den: Float, + table2: GlobalTable_driver_qsat, + des2: GlobalTable_driver_qsat, +): + """ + compute the saturated specific humidity for table2 + with additional calculation of gradient (dq/dt) + + pure water phase; universal dry / moist formular using air density + input "den" can be either dry or moist air density + + reference Fortran: gfdl_cloud_microphys.F90: function wqs2 + """ + tmin = driver_constants.TABLE_ICE - 160.0 + + if ta - tmin > 0: + ans = ta - tmin + else: + ans = 0 + ap1 = 10.0 * ans + 1.0 + ap1 = min(2621.0, ap1) + it = i32(trunc(ap1)) + es = table2.A[it - 1] + (ap1 - it) * des2.A[it - 1] + qsat = es / (driver_constants.RVGAS * ta * den) + it = i32(trunc(ap1 - 0.5)) + # finite diff, del_t = 0.1: + dqdt = ( + 10.0 + * (des2.A[it - 1] + (ap1 - it) * (des2.A[it] - des2.A[it - 1])) + / (driver_constants.RVGAS * ta * den) + ) + + return qsat, dqdt + + +@gtscript.function +def subgrid_z_proc( + p_dry: Float, + den1: Float, + denfac: Float, + t1: Float, + qv1: Float, + ql1: Float, + qr1: Float, + qi1: Float, + qs1: Float, + qg1: Float, + qa1: Float, + rh_limited: Float, + ccn: Float, + cnv_frc: Float, + srf_type: Float, + table1: GlobalTable_driver_qsat, + table2: GlobalTable_driver_qsat, + table3: GlobalTable_driver_qsat, + table4: GlobalTable_driver_qsat, + des1: GlobalTable_driver_qsat, + des2: GlobalTable_driver_qsat, + des3: GlobalTable_driver_qsat, + des4: GlobalTable_driver_qsat, +): + from __externals__ import ( + c_air, + c_vap, + cssub_0, + cssub_1, + cssub_2, + cssub_3, + cssub_4, + d0_vap, + do_bigg, + do_evap, + do_qa, + dts, + fac_frz, + fac_g2v, + fac_l2v, + fac_s2v, + fac_v2g, + fac_v2s, + icloud_f, + lat2, + lv00, + preciprad, + qc_crt, + qi_lim, + rh_inc, + rh_inr, + t_min, + t_sub, + ) + + """ + temperature sensitive high vertical resolution processes + + reference Fortran: gfdl_cloud_microphys.F90: subroutine subgrid_z_proc + """ + + # ----------------------------------------------------------------------- + # define heat capacity and latent heat coefficient + # ----------------------------------------------------------------------- + + lhl = lv00 + d0_vap * t1 + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t1 + q_liq = ql1 + qr1 + q_sol = qi1 + qs1 + qg1 + cvm = ( + c_air + + qv1 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + lcpk = lhl / cvm + icpk = lhi / cvm + tcpk = lcpk + icpk + if driver_constants.TICE - t1 > 0: + ans = driver_constants.TICE - t1 + else: + ans = 0 + tcp3 = lcpk + icpk * min( + 1.0, ans / (driver_constants.TICE - driver_constants.T_WFR) + ) + + rh_adj = 1.0 - rh_limited - rh_inc + rh_rain = max(0.35, rh_adj - rh_inr) + + subl1 = 0.0 + + cycle = False + if p_dry < driver_constants.P_MIN: + cycle = True + + # ----------------------------------------------------------------------- + # instant deposit all water vapor to cloud ice when temperature is super low + # ----------------------------------------------------------------------- + + if t1 < t_min and cycle == False: # noqa + if qv1 - driver_constants.QVMIN > 0: + sink = qv1 - driver_constants.QVMIN + else: + sink = 0 + qv1 = qv1 - sink + qi1 = qi1 + sink + q_sol = q_sol + sink + cvm = ( + c_air + + qv1 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t1 = t1 + sink * (lhl + lhi) / cvm + if do_qa == True: # noqa + qa1 = 1.0 # air fully saturated; 100 % cloud cover + cycle = True + + if cycle == False: # noqa + # ----------------------------------------------------------------------- + # update heat capacity and latent heat coefficient + # ----------------------------------------------------------------------- + lhl = lv00 + d0_vap * t1 + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t1 + lcpk = lhl / cvm + icpk = lhi / cvm + tcpk = lcpk + icpk + if driver_constants.TICE - t1 > 0: + ans = driver_constants.TICE - t1 + else: + ans = 0 + tcp3 = lcpk + icpk * min( + 1.0, ans / (driver_constants.TICE - driver_constants.T_WFR) + ) + + # ----------------------------------------------------------------------- + # instant evaporation / sublimation of all clouds if rh < rh_adj -- > cloud free + # ----------------------------------------------------------------------- + qpz = qv1 + ql1 + qi1 + tin = t1 - (lhl * (ql1 + qi1) + lhi * qi1) / ( + c_air + + qpz * c_vap + + qr1 * driver_constants.C_LIQ + + (qs1 + qg1) * driver_constants.C_ICE + ) + if tin > t_sub + 6.0: + rh = qpz / iqs1(tin, den1, table3, des3) + if rh < rh_adj: # qpz / rh_adj < qs + t1 = tin + qv1 = qpz + ql1 = 0.0 + qi1 = 0.0 + if do_qa == True: # noqa + qa = 0.0 + cycle = True # cloud free + + if cycle == False: # noqa + # ----------------------------------------------------------------------- + # cloud water < -- > vapor adjustment: LS evaporation + # ----------------------------------------------------------------------- + if do_evap == True: # noqa + qsw, dwsdt = wqs2(t1, den1, table2, des2) + dq0 = qsw - qv1 + if dq0 > driver_constants.QVMIN: + factor = min(1.0, fac_l2v * (10.0 * dq0 / qsw)) + evap = min(ql1, factor * ql1 / (1.0 + tcp3 * dwsdt)) + else: + evap = 0.0 + qv1 = qv1 + evap + ql1 = ql1 - evap + q_liq = q_liq - evap + cvm = ( + c_air + + qv1 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t1 = t1 - evap * lhl / cvm + + # ----------------------------------------------------------------------- + # update heat capacity and latent heat coefficient + # ----------------------------------------------------------------------- + + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t1 + icpk = lhi / cvm + + # ----------------------------------------------------------------------- + # enforce complete freezing when ice_fraction==1 + # ----------------------------------------------------------------------- + + ifrac = ice_fraction(t1, cnv_frc, srf_type) + if ifrac == 1.0 and ql1 > driver_constants.QCMIN: + sink = ql1 + ql1 = ql1 - sink + qi1 = qi1 + sink + q_liq = q_liq - sink + q_sol = q_sol + sink + cvm = ( + c_air + + qv1 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t1 = t1 + sink * lhi / cvm + + # ----------------------------------------------------------------------- + # update heat capacity and latent heat coefficient + # ----------------------------------------------------------------------- + + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t1 + icpk = lhi / cvm + + # ----------------------------------------------------------------------- + # bigg mechanism heterogeneous freezing on existing cloud nuclei + # ----------------------------------------------------------------------- + + tc = driver_constants.TICE - t1 + if do_bigg == True and ql1 > driver_constants.QCMIN and tc > 0.0: # noqa + sink = ( + fac_frz + * (100.0 / driver_constants.RHOR / ccn) + * dts + * (exp(0.66 * tc) - 1.0) + * den1 + * ql1 + * ql1 + ) + sink = min(ql1, min(tc / icpk, sink)) + ql1 = ql1 - sink + qi1 = qi1 + sink + q_liq = q_liq - sink + q_sol = q_sol + sink + cvm = ( + c_air + + qv1 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t1 = t1 + sink * lhi / cvm + # significant ql existed + + # ----------------------------------------------------------------------- + # update capacity heat and latent heat coefficient + # ----------------------------------------------------------------------- + + lhl = lv00 + d0_vap * t1 + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t1 + lcpk = lhl / cvm + icpk = lhi / cvm + tcpk = lcpk + icpk + + # ----------------------------------------------------------------------- + # sublimation / deposition of LS ice + # ----------------------------------------------------------------------- + + if t1 < driver_constants.TICE: + qsi, dqsdt = iqs2(t1, den1, table3, des3) + dq = qv1 - qsi + sink = min(qi1, dq / (1.0 + tcpk * dqsdt)) + if qi1 > driver_constants.QCMIN: + # eq 9, hong et al. 2004, mwr + # for a and b, see dudhia 1989: page 3103 eq (b7) and (b8) + pidep = ( + dts + * dq + * 349138.78 + * exp(0.875 * log(qi1 * den1)) + / ( + qsi * den1 * lat2 / (0.0243 * driver_constants.RVGAS * t1**2) + + 4.42478e4 + ) + ) + else: + pidep = 0.0 + if dq > 0.0: # vapor - > ice + # deposition + ifrac = ice_fraction(t1, cnv_frc, srf_type) + tmp = driver_constants.TICE - t1 + qi_crt = 4.92e-11 * exp(1.33 * log(1.0e3 * exp(0.1 * tmp))) + qi_crt = max(qi_crt, 1.82e-6) * qi_lim * ifrac / den1 + sink = min(sink, min(max(qi_crt - qi1, pidep), tmp / tcpk)) + else: # ice -- > vapor + # NOTE sublimation option is False in test case, not implemented + # b/c unsure how to handle pssub. In Fortran this variable is + # initalized to nan then used here (at least when do_subl is False, + # maybe do_subl has other unknown effects) + # # sublimation + # if do_subl == True: #noqa + # if t1 - t_sub > 0: + # ans = t1 - t_sub + # else: + # ans = 0 + # pidep = pidep * min(1.0, ans * 0.2) + # sink = fac_i2v * max(pidep, sink, -qi1) + # subl1 = subl1 + pssub / dts + # else: + # sink = 0.0 + sink = 0 + qv1 = qv1 - sink + qi1 = qi1 + sink + q_sol = q_sol + sink + cvm = ( + c_air + + qv1 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t1 = t1 + sink * (lhl + lhi) / cvm + + # ----------------------------------------------------------------------- + # update capacity heat and latend heat coefficient + # ----------------------------------------------------------------------- + + lhl = lv00 + d0_vap * t1 + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t1 + lcpk = lhl / cvm + icpk = lhi / cvm + tcpk = lcpk + icpk + + # ----------------------------------------------------------------------- + # sublimation / deposition of snow + # this process happens for all temp rage + # ----------------------------------------------------------------------- + + if qs1 > driver_constants.QPMIN: + qsi, dqsdt = iqs2(t1, den1, table3, des3) + qden = qs1 * den1 + tmp = exp(0.65625 * log(qden)) + tsq = t1 * t1 + dq = (qsi - qv1) / (1.0 + tcpk * dqsdt) + pssub = ( + cssub_0 + * tsq + * (cssub_1 * sqrt(qden) + cssub_2 * tmp * sqrt(denfac)) + / (cssub_3 * tsq + cssub_4 * qsi * den1) + ) + pssub = (qsi - qv1) * dts * pssub + if pssub > 0.0: # qs -- > qv, sublimation + if t1 - t_sub > 0: + ans = t1 - t_sub + else: + ans = 0 + pssub = min(fac_s2v * pssub * min(1.0, ans * 0.2), qs1) + subl1 = subl1 + pssub / dts + else: + if t1 > driver_constants.TICE: + pssub = 0.0 # no deposition + else: + pssub = max( + fac_v2s * pssub, max(dq, (t1 - driver_constants.TICE) / tcpk) + ) + qs1 = qs1 - pssub + qv1 = qv1 + pssub + q_sol = q_sol - pssub + cvm = ( + c_air + + qv1 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t1 = t1 - pssub * (lhl + lhi) / cvm + + # ----------------------------------------------------------------------- + # update capacity heat and latend heat coefficient + # ----------------------------------------------------------------------- + + lhl = lv00 + d0_vap * t1 + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t1 + lcpk = lhl / cvm + icpk = lhi / cvm + tcpk = lcpk + icpk + + # ----------------------------------------------------------------------- + # simplified 2 - way grapuel sublimation - deposition mechanism + # ----------------------------------------------------------------------- + + if qg1 > driver_constants.QPMIN: + qsi, dqsdt = iqs2(t1, den1, table3, des3) + dq = (qv1 - qsi) / (1.0 + tcpk * dqsdt) + pgsub = (qv1 / qsi - 1.0) * qg1 + if pgsub > 0.0: # deposition + if t1 > driver_constants.TICE: + pgsub = 0.0 # no deposition + else: + pgsub = min( + fac_v2g * pgsub, + min( + 0.2 * dq, + min(ql1 + qr1, (driver_constants.TICE - t1) / tcpk), + ), + ) + else: # submilation + if t1 - t_sub > 0: + ans = t1 - t_sub + else: + ans = 0 + pgsub = max(fac_g2v * pgsub, dq) * min(1.0, ans * 0.1) + subl1 = subl1 + pgsub / dts + qg1 = qg1 + pgsub + qv1 = qv1 - pgsub + q_sol = q_sol + pgsub + cvm = ( + c_air + + qv1 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t1 = t1 + pgsub * (lhl + lhi) / cvm + + # Fortran ifdef USE_MIN_EVAP goes in here. + # Not currently executed, so not included + + # ----------------------------------------------------------------------- + # update capacity heat and latend heat coefficient + # ----------------------------------------------------------------------- + + lhl = lv00 + d0_vap * t1 + cvm = c_air + (qv1 + q_liq + q_sol) * c_vap + lcpk = lhl / cvm + + # ----------------------------------------------------------------------- + # compute cloud fraction + # ----------------------------------------------------------------------- + if do_qa == False: # noqa + cycle = True + + if cycle == False: # noqa + # ----------------------------------------------------------------------- + # combine water species + # ----------------------------------------------------------------------- + if preciprad == True: # noqa + q_sol = qi1 + qs1 + qg1 + q_liq = ql1 + qr1 + else: + q_sol = qi1 + q_liq = ql1 + q_cond = q_liq + q_sol + + qpz = qv1 + q_cond # qpz is conserved + + # ----------------------------------------------------------------------- + # use the "liquid - frozen water temperature" (tin) + # to compute saturated specific humidity + # ----------------------------------------------------------------------- + + tin = t1 - (lcpk * q_cond + icpk * q_sol) # minimum temperature + + # ----------------------------------------------------------------------- + # determine saturated specific humidity + # ----------------------------------------------------------------------- + + if tin <= driver_constants.T_WFR: + # ice phase: + qstar = iqs1(tin, den1, table3, des3) + elif tin >= driver_constants.TICE: + # liquid phase: + qstar = wqs1(tin, den1, table2, des2) + else: + # mixed phase: + qsi = iqs1(tin, den1, table3, des3) + qsw = wqs1(tin, den1, table2, des2) + if q_cond > 3.0e-6: + rqi = q_sol / q_cond + else: + # WMP impose CALIPSO ice polynomial from 0 C to -40 C + rqi = ice_fraction(tin, cnv_frc, srf_type) + qstar = rqi * qsi + (1.0 - rqi) * qsw + + # ----------------------------------------------------------------------- + # assuming subgrid linear distribution in horizontal; + # this is effectively a smoother for the binary cloud scheme + # ----------------------------------------------------------------------- + if qpz > driver_constants.QCMIN: + # partial cloudiness by pdf: + dq = max(driver_constants.QCMIN, rh_limited * qpz) + q_plus = qpz + dq # cloud free if qstar > q_plus + q_minus = qpz - dq + if icloud_f == 3: + # triangular + if q_plus <= qstar: + # little/no cloud cover + do_nothing = True + elif qpz <= qstar and qstar < q_plus: # partial cloud cover + qa1 = max( + driver_constants.QCMIN, + min( + 1.0, + qa1 + + (q_plus - qstar) + * (q_plus - qstar) + / ((q_plus - q_minus) * (q_plus - qpz)), + ), + ) + elif q_minus <= qstar and qstar < qpz: # partial cloud cover + qa1 = max( + driver_constants.QCMIN, + min( + 1.0, + qa1 + + 1.0 + - ( + (qstar - q_minus) + * (qstar - q_minus) + / ((q_plus - q_minus) * (qpz - q_minus)) + ), + ), + ) + elif qstar <= q_minus: + qa1 = 1.0 # air fully saturated; 100 % cloud cover + else: + # top-hat + if q_plus <= qstar: + # little/no cloud cover + do_nothing = True + elif qstar < q_plus and q_cond > qc_crt: + qa1 = max( + driver_constants.QCMIN, + min(1.0, qa1 + (q_plus - qstar) / (dq + dq)), + ) # partial cloud cover + elif qstar <= q_minus: + qa1 = 1.0 # air fully saturated; 100 % cloud cover + + return t1, qv1, ql1, qr1, qi1, qs1, qg1, qa1, subl1 + + +def icloud( + t1: FloatField, + p_dry: FloatField, + dp1: FloatField, + qv1: FloatField, + ql1: FloatField, + qr1: FloatField, + qi1: FloatField, + qs1: FloatField, + qg1: FloatField, + qa1: FloatField, + den1: FloatField, + denfac: FloatField, + vts: FloatField, + vtg: FloatField, + vtr: FloatField, + subl1: FloatField, + rh_limited: FloatField, + ccn: FloatField, + cnv_frc: FloatFieldIJ, + srf_type: FloatFieldIJ, + table1: GlobalTable_driver_qsat, + table2: GlobalTable_driver_qsat, + table3: GlobalTable_driver_qsat, + table4: GlobalTable_driver_qsat, + des1: GlobalTable_driver_qsat, + des2: GlobalTable_driver_qsat, + des3: GlobalTable_driver_qsat, + des4: GlobalTable_driver_qsat, +): + """ + ice cloud microphysics processes + bulk cloud micro - physics; processes splitting + with some un - split sub - grouping + time implicit (when possible) accretion and autoconversion + + reference Fortran: gfdl_cloud_microphys.F90: subroutine icloud + + Fortran author: Shian-Jiann lin, gfdl + """ + from __externals__ import d0_vap, lv00, z_slope_ice + + # begin reference Fortran: gfdl_cloud_microphys.F90: subroutine icloud + with computation(FORWARD), interval(0, 1): + # initalize vtr in place of the warm rain calculations + vtr = 0 + + # ----------------------------------------------------------------------- + # sources of cloud ice: pihom, cold rain, and the sat_adj + # (initiation plus deposition) + # sources of snow: cold rain, auto conversion + accretion (from cloud ice) + # sat_adj (deposition; requires pre - existing snow); + # initial snow comes from auto conversion + # ----------------------------------------------------------------------- + + with computation(PARALLEL), interval(...): + t1, qv1, ql1, qr1, qi1, qs1, qg1, qa1, cvm, q_liq, q_sol = icloud_melt_freeze( + t1, + qv1, + ql1, + qr1, + qi1, + qs1, + qg1, + qa1, + den1, + cnv_frc, + srf_type, + ) + + # begin reference Fortran: gfdl_cloud_microphys.F90: subroutine linear_prof + # still within reference Fortran gfdl_cloud_microphys.F90: subroutine icloud + # set up inputs to "function" + with computation(PARALLEL), interval(...): + if z_slope_ice == True: # noqa + q_linear_prof = qi1 + h_var_linear_prof = rh_limited + dm_linear_prof = ( + q_linear_prof # initalized here to ensure it is created as a 3d field + ) + + with computation(FORWARD), interval(1, None): + if z_slope_ice == True: # noqa + dq_linear_prof = 0.5 * (q_linear_prof - q_linear_prof[0, 0, -1]) + + # ----------------------------------------------------------------------- + # use twice the strength of the positive definiteness limiter (lin et al 1994) + # ----------------------------------------------------------------------- + with computation(FORWARD), interval(0, 1): + if z_slope_ice == True: # noqa + dm_linear_prof = 0 + + with computation(FORWARD), interval(1, -1): + if z_slope_ice == True: # noqa + dm_linear_prof = 0.5 * min( + abs(dq_linear_prof + dq_linear_prof[0, 0, 1]), 0.5 * q_linear_prof + ) + if dq_linear_prof * dq_linear_prof[0, 0, 1] <= 0.0: + if dq_linear_prof > 0.0: # local max + dm_linear_prof = min( + dm_linear_prof, min(dq_linear_prof, -dq_linear_prof[0, 0, 1]) + ) + else: + dm_linear_prof = 0.0 + + with computation(FORWARD), interval(-1, None): + if z_slope_ice == True: # noqa + dm_linear_prof = 0 + + # ----------------------------------------------------------------------- + # impose a presumed background horizontal variability + # that is proportional to the value itself + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + if z_slope_ice == True: # noqa + dm_linear_prof = max( + dm_linear_prof, + max(driver_constants.QVMIN, h_var_linear_prof * q_linear_prof), + ) + if z_slope_ice == False: # noqa + dm_linear_prof = max( + driver_constants.QVMIN, h_var_linear_prof * q_linear_prof + ) + + # handle outputs of "function" + with computation(PARALLEL), interval(...): + di = dm_linear_prof + + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine linear_prof + + with computation(PARALLEL), interval(...): + # ----------------------------------------------------------------------- + # update capacity heat and latent heat coefficient + # ----------------------------------------------------------------------- + lhl = lv00 + d0_vap * t1 + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t1 + lcpk = lhl / cvm + icpk = lhi / cvm + tcpk = lcpk + icpk + + # ----------------------------------------------------------------------- + # do nothing above p_min + # ----------------------------------------------------------------------- + if p_dry >= driver_constants.P_MIN: + ( + t1, + qv1, + ql1, + qi1, + qr1, + qs1, + qg1, + qa1, + p_dry, + den1, + denfac, + vtr, + vts, + vtg, + cvm, + lhl, + lhi, + lcpk, + icpk, + tcpk, + ) = snow_graupel_coldrain( + t1, + qv1, + ql1, + qi1, + qr1, + qs1, + qg1, + qa1, + p_dry, + den1, + denfac, + vtr, + vts, + vtg, + cvm, + lhl, + lhi, + lcpk, + icpk, + tcpk, + q_liq, + q_sol, + di, + cnv_frc, + srf_type, + ) + + t1, qv1, ql1, qr1, qi1, qs1, qg1, qa1, subl1 = subgrid_z_proc( + p_dry, + den1, + denfac, + t1, + qv1, + ql1, + qr1, + qi1, + qs1, + qg1, + qa1, + rh_limited, + ccn, + cnv_frc, + srf_type, + table1, + table2, + table3, + table4, + des1, + des2, + des3, + des4, + ) + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine icloud diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/terminal_fall.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/terminal_fall.py new file mode 100644 index 000000000..58e04ebc9 --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/terminal_fall.py @@ -0,0 +1,784 @@ +import gt4py.cartesian.gtscript as gtscript +from gt4py.cartesian.gtscript import ( + BACKWARD, + FORWARD, + PARALLEL, + computation, + exp, + i32, + interval, +) + +import pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_constants as driver_constants +from ndsl.dsl.typing import BoolField, Float, FloatField, FloatFieldIJ, IntField + + +@gtscript.function +def prefall_melting( + t: Float, + qv: Float, + ql: Float, + qr: Float, + qg: Float, + qs: Float, + qi: Float, + m1_sol: Float, + is_frozen: bool, +): + from __externals__ import ql_mlt, tau_imlt + + """ + melt cloud ice before fall + + reference Fortran: gfdl_cloud_microphys.F90: subroutine terminal_fall + """ + from __externals__ import c_air, c_vap, d0_vap, dts, lv00 + + fac_imlt = 1.0 - exp(-dts / tau_imlt) + + # ----------------------------------------------------------------------- + # define heat capacity and latent heat coefficient + # ----------------------------------------------------------------------- + + m1_sol = 0.0 + lhl = lv00 + d0_vap * t + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t + q_liq = ql + qr + q_sol = qi + qs + qg + cvm = ( + c_air + + qv * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + lcpk = lhl / cvm + icpk = lhi / cvm + + # ----------------------------------------------------------------------- + # melting of cloud_ice (before fall) : + # ----------------------------------------------------------------------- + + tc = t - driver_constants.TICE + if is_frozen == False and (qi > driver_constants.QCMIN and tc > 0.0): # noqa + sink = min(qi, fac_imlt * tc / icpk) + if ql_mlt - ql > 0: + ans = ql_mlt - ql + else: + ans = 0 + tmp = min(sink, ans) + ql = ql + tmp + qr = qr + sink - tmp + qi = qi - sink + q_liq = q_liq + sink + q_sol = q_sol - sink + cvm = ( + c_air + + qv * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t = t - sink * lhi / cvm + + return t, ql, qr, qi, cvm, lhi, icpk, m1_sol + + +def terminal_fall( + t1: FloatField, + qv1: FloatField, + ql1: FloatField, + qr1: FloatField, + qg1: FloatField, + qs1: FloatField, + qi1: FloatField, + dz1: FloatField, + dp1: FloatField, + den1: FloatField, + vtg: FloatField, + vts: FloatField, + vti: FloatField, + precip_rain: FloatFieldIJ, + precip_graupel: FloatFieldIJ, + precip_snow: FloatFieldIJ, + precip_ice: FloatFieldIJ, + m1_sol: FloatField, + w1: FloatField, + ze: FloatField, + zt: FloatField, + is_frozen: BoolField, + precip_fall: FloatFieldIJ, + melting_mask_1: BoolField, + melting_mask_2: BoolField, + current_k_level: IntField, +): + """ + calculate terminal fall speed, accounting for + melting of ice, snow, and graupel during fall + + reference Fortran: gfdl_cloud_microphys.F90: subroutine terminal_fall + """ + from __externals__ import do_sedi_w, dts, k_end, use_ppm, vi_fac + + # determine frozen levels + # later operations will only be executed if frozen/melted + # initalized to is_frozen = False, True = frozen, False = melted + with computation(PARALLEL), interval(...): + if t1 <= driver_constants.TICE: + is_frozen = True + + # we only want the melting layer closest to the surface + with computation(BACKWARD), interval(0, -1): + if is_frozen[0, 0, 1] == True and is_frozen[0, 0, 0] == False: # noqa + is_frozen = True + + # force surface to "melt" for later calculations + with computation(PARALLEL), interval(-1, None): + is_frozen = False + + with computation(PARALLEL), interval(...): + t1, ql1, qr1, qi1, cvm, lhi, icpk, m1_sol = prefall_melting( + t1, + qv1, + ql1, + qr1, + qg1, + qs1, + qi1, + m1_sol, + is_frozen, + ) + + # if timestep is too small turn off melting + with computation(PARALLEL), interval(0, -1): + if dts < 300.0: + is_frozen = True + disable_melt = True + else: + disable_melt = False + + with computation(PARALLEL), interval(-1, None): + if dts < 300.0: + is_frozen = False + disable_melt = True + else: + disable_melt = False + + with computation(BACKWARD), interval(...): + ze = ze[0, 0, 1] - dz1 # dz < 0 + + with computation(FORWARD), interval(0, 1): + zt = ze + + # ----------------------------------------------------------------------- + # update capacity heat and latend heat coefficient + # ----------------------------------------------------------------------- + + with computation(PARALLEL), interval(...): + if is_frozen == False: # noqa + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t1 + icpk = lhi / cvm + + with computation(FORWARD), interval(-1, None): + lhi = driver_constants.LI00 + driver_constants.DC_ICE * t1 + icpk = lhi / cvm + + # ----------------------------------------------------------------------- + # ----------------------------------------------------------------------- + # melting of falling cloud ice into rain + # ----------------------------------------------------------------------- + # ----------------------------------------------------------------------- + + # reference Fortran: gfdl_cloud_microphys.F90: subroutine check_column + # determine if any precip falls in the column + # if it falls anywhere in the column, the entire column becomes true + # initalized to 0 (false), potentially changed to 1 (true) + with computation(FORWARD), interval(...): + if qi1 > driver_constants.QPMIN: + precip_fall = 1 + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine check_column + + with computation(FORWARD), interval(0, 1): + if vi_fac < 1.0e-5 or precip_fall == 0: + precip_ice = 0 + + with computation(FORWARD), interval(1, None): + if vi_fac >= 1.0e-5 and precip_fall == 1: + zt = ze - dts * (vti[0, 0, -1] + vti) / 2.0 + + with computation(FORWARD), interval(-1, None): + if vi_fac >= 1.0e-5 and precip_fall == 1: + zt[0, 0, 1] = driver_constants.ZS - dts * vti + + with computation(FORWARD), interval(...): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if zt[0, 0, 1] >= zt: + zt[0, 0, 1] = zt - driver_constants.DZ_MIN + + with computation(PARALLEL), interval(...): + if vi_fac >= 1.0e-5 and precip_fall == 1 and disable_melt == False: # noqa + # copy frozen mask to make modifyable version + melting_mask_1 = is_frozen + # flip logic for clarity + if melting_mask_1 == True: # noqa + melting_mask_1 = False + else: + melting_mask_1 = True + + with computation(BACKWARD), interval(-1, None): + if vi_fac >= 1.0e-5 and precip_fall == 1 and disable_melt == False: # noqa + # ensure no operations are performed on the surface + melting_mask_1 = False + + with computation(BACKWARD), interval(...): + # THIS HAS NEVER BEEN TESTED B/C DTS WAS LESS THAN 300 IN THE TEST CASE + if vi_fac >= 1.0e-5 and precip_fall == 1 and disable_melt == False: # noqa + # only operate on melted layers + if melting_mask_1 == True and qi1 > driver_constants.QCMIN: # noqa + # initalize exit trigger + stop_melting = False + m: i32 = 0 + while m < k_end and stop_melting == False: # noqa + mplus1: i32 = ( + m + 1 + ) # TODO remove this line only, replace with better solution + # only opterate on previously iterated k-levels + # if melting_mask_2 == True: #noqa + # if zt[0, 0, 1] >= ze.at(K=m): + # stop_melting = ( + # True # if true exit early for ONLY this k level + # ) + # if stop_melting == False: #noqa + # dtime = min( + # 1.0, + # (ze.at(K=m) - ze.at(K=mplus1)) + # / (max(driver_constants.vr_min, vti) * tau_imlt), + # ) + # sink = min( + # qi1 * dp1 / dp1.at(K=m), + # dtime + # * (t1.at(K=m) - driver_constants.tice) + # / icpk.at(K=m), + # ) + # if ql_mlt - ql1.at(K=m) > 0: + # ans = ql_mlt - ql1.at(K=m) + # else: + # ans = 0 + # tmp = min(sink, ans) + # offset = i32(m - current_k_level) + # hold_ql1 = ql1.at(K=m) + # ql1[0, 0, offset] = hold_ql1 + tmp + # hold_qr1 = qr1.at(K=m) + # qr1[0, 0, offset] = hold_qr1 - tmp + sink + # hold_t1 = t1.at(K=m) + # t1[0, 0, offset] = hold_t1 - sink * icpk.at(K=m) + # qi1 = qi1 - sink * dp1.at(K=m) / dp1 + m = m + 1 + # set current layer as iterated layer + melting_mask_2 = True + + with computation(PARALLEL), interval(...): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if do_sedi_w == True: # noqa + dm = dp1 * (1.0 + qv1 + ql1 + qr1 + qi1 + qs1 + qg1) + + # begin reference Fortran: gfdl_cloud_microphys.F90: subroutine implicit_fall + # this code computes the time-implicit monotonic scheme + # Fortran author: Shian-Jiann Lin, 2016 + # set up inputs to the "function" + with computation(PARALLEL), interval(...): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + q_implicit_fall = qi1 + vt_implicit_fall = vti + + with computation(PARALLEL), interval(...): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + hold_data = ze - ze[0, 0, 1] + dd = dts * vt_implicit_fall + q_implicit_fall = q_implicit_fall * dp1 + + # ----------------------------------------------------------------------- + # sedimentation: non - vectorizable loop + # ----------------------------------------------------------------------- + with computation(FORWARD), interval(0, 1): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + qm = q_implicit_fall / (hold_data + dd) + + with computation(FORWARD), interval(1, None): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + qm = (q_implicit_fall + dd[0, 0, -1] * qm[0, 0, -1]) / (hold_data + dd) + + # ----------------------------------------------------------------------- + # qm is density at this stage + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + qm = qm * hold_data + + # ----------------------------------------------------------------------- + # output mass fluxes: non - vectorizable loop + # ----------------------------------------------------------------------- + with computation(FORWARD), interval(0, 1): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + m1 = q_implicit_fall - qm + + with computation(FORWARD), interval(1, None): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + m1 = m1[0, 0, -1] + q_implicit_fall - qm + + with computation(FORWARD), interval(-1, None): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + precip = m1 + + # ----------------------------------------------------------------------- + # update: + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + q_implicit_fall = qm / dp1 + + # update "outputs" after "function" + with computation(PARALLEL), interval(...): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + qi1 = q_implicit_fall + m1_sol = ( + m1_sol + m1 + ) # NOTE: setting this to just m1_sol = m1 gives WILD values (1e31) + + with computation(FORWARD), interval(-1, None): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if use_ppm == False: # noqa + precip_ice = precip + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine implicit_fall + + with computation(FORWARD), interval(0, 1): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if do_sedi_w: + w1 = (dm * w1 + m1_sol * vti) / (dm - m1_sol) + + with computation(FORWARD), interval(1, None): + if vi_fac >= 1.0e-5 and precip_fall == 1: + if do_sedi_w: + w1 = (dm * w1 - m1_sol[0, 0, -1] * vti[0, 0, -1] + m1_sol * vti) / ( + dm + m1_sol[0, 0, -1] - m1_sol + ) + + # reset masks + with computation(FORWARD), interval(0, 1): + precip_fall = 0 + + with computation(PARALLEL), interval(...): + melting_mask_1 = False + melting_mask_2 = False + m1 = 0.0 + + # ----------------------------------------------------------------------- + # ----------------------------------------------------------------------- + # melting of falling snow into rain + # ----------------------------------------------------------------------- + # ----------------------------------------------------------------------- + + # reference Fortran: gfdl_cloud_microphys.F90: subroutine check_column + # determine if any precip falls in the column + # if it falls anywhere in the column, the entire column becomes true + # initalized to 0 (false), potentially changed to 1 (true) + with computation(FORWARD), interval(...): + if qs1 > driver_constants.QPMIN: + precip_fall = 1 + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine check_column + + with computation(FORWARD), interval(0, 1): + if precip_fall == 0: + precip_snow = 0 + + with computation(FORWARD), interval(1, None): + if precip_fall == 1: + zt = ze - dts * (vts[0, 0, -1] + vts) / 2.0 + + with computation(FORWARD), interval(-1, None): + if precip_fall == 1: + zt[0, 0, 1] = driver_constants.ZS - dts * vts + + with computation(FORWARD), interval(...): + if precip_fall == 1: + if zt[0, 0, 1] >= zt: + zt[0, 0, 1] = zt - driver_constants.DZ_MIN + + with computation(PARALLEL), interval(...): + if precip_fall == 1 and disable_melt == False: # noqa + # copy frozen mask to make modifyable version + melting_mask_1 = is_frozen + # flip logic for clarity + if melting_mask_1 == True: # noqa + melting_mask_1 = False + else: + melting_mask_1 = True + + with computation(BACKWARD), interval(-1, None): + if precip_fall == 1 and disable_melt == False: # noqa + # ensure no operations are performed on the surface + melting_mask_1 = False + + with computation(BACKWARD), interval(...): + # THIS HAS NEVER BEEN TESTED B/C DTS WAS LESS THAN 300 IN THE TEST CASE + if precip_fall == 1 and disable_melt == False: # noqa + # only operate on melted layers + if melting_mask_1 == True and qs1 > driver_constants.QPMIN: # noqa + # initalize exit trigger + stop_melting = False + m: i32 = 0 + while m < k_end and stop_melting == False: # noqa + mplus1: i32 = ( + m + 1 + ) # TODO remove this line only, replace with better solution + # only opterate on previously iterated k-levels + # if melting_mask_2 == True: #noqa + # if zt[0, 0, 1] >= ze.at(K=m): + # stop_melting = ( + # True # if true exit early for ONLY this k level + # ) + # if stop_melting == False: #noqa + # dtime = min( + # dts, + # (ze.at(K=m) - ze.at(K=mplus1)) + # / (driver_constants.vr_min + vts), + # ) + # if ( + # zt < ze.at(K=mplus1) + # and t1.at(K=m) > driver_constants.tice + # ): + # dtime = min(1.0, dtime / tau_smlt) + # sink = min( + # qs1 * dp1 / dp1.at(K=m), + # dtime + # * (t1.at(K=m) - driver_constants.tice) + # / icpk.at(K=m), + # ) + # offset = i32(m - current_k_level) + # hold_t1 = t1.at(K=m) + # t1[0, 0, offset] = hold_t1 - sink * icpk.at(K=m) + # qs1 = qs1 - sink * dp1.at(K=m) / dp1 + # if zt < 0: + # precip_rain = precip_rain + sink * dp1.at( + # K=m + # ) # precip as rain + # else: + # # qr source here will fall next time step + # # (therefore, can evap) + # hold_qr1 = qr1.at(K=m) + # qr1[0, 0, offset] = hold_qr1 + sink + # if stop_melting == False: #noqa + # if qs1 < driver_constants.qpmin: + # stop_melting = True + m = m + 1 + # set current layer as iterated layer + melting_mask_2 = True + + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if do_sedi_w == True: # noqa + dm = dp1 * (1.0 + qv1 + ql1 + qr1 + qi1 + qs1 + qg1) + + # begin reference Fortran: gfdl_cloud_microphys.F90: subroutine implicit_fall + # this code computes the time-implicit monotonic scheme + # Fortran author: Shian-Jiann Lin, 2016 + # set up inputs to the "function" + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + q_implicit_fall = qs1 + vt_implicit_fall = vts + + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + hold_data = ze - ze[0, 0, 1] + dd = dts * vt_implicit_fall + q_implicit_fall = q_implicit_fall * dp1 + + # ----------------------------------------------------------------------- + # sedimentation: non - vectorizable loop + # ----------------------------------------------------------------------- + with computation(FORWARD), interval(0, 1): + if precip_fall == 1: + if use_ppm == False: # noqa + qm = q_implicit_fall / (hold_data + dd) + + with computation(FORWARD), interval(1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + qm = (q_implicit_fall + dd[0, 0, -1] * qm[0, 0, -1]) / (hold_data + dd) + + # ----------------------------------------------------------------------- + # qm is density at this stage + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + qm = qm * hold_data + + # ----------------------------------------------------------------------- + # output mass fluxes: non - vectorizable loop + # ----------------------------------------------------------------------- + with computation(FORWARD), interval(0, 1): + if precip_fall == 1: + if use_ppm == False: # noqa + m1 = q_implicit_fall - qm + + with computation(FORWARD), interval(1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + m1 = m1[0, 0, -1] + q_implicit_fall - qm + + with computation(FORWARD), interval(-1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + precip = m1 + + # ----------------------------------------------------------------------- + # update: + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + q_implicit_fall = qm / dp1 + + # update "outputs" after "function" + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + qs1 = q_implicit_fall + m1_sol = ( + m1_sol + m1 + ) # NOTE: setting this to just m1_sol = m1 gives WILD values (1e31) + + with computation(FORWARD), interval(-1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + precip_snow = precip + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine implicit_fall + + with computation(FORWARD), interval(0, 1): + if precip_fall == 1: + if do_sedi_w: + w1 = (dm * w1 + m1 * vts) / (dm - m1) + + with computation(FORWARD), interval(1, None): + if precip_fall == 1: + if do_sedi_w: + w1 = (dm * w1 - m1[0, 0, -1] * vts[0, 0, -1] + m1 * vts) / ( + dm + m1[0, 0, -1] - m1 + ) + + # reset masks and temporaries + with computation(FORWARD), interval(0, 1): + precip_fall = 0 + + with computation(PARALLEL), interval(...): + melting_mask_1 = False + melting_mask_2 = False + # must be reset to zero everywhere in case there is no graupel + # in a column and no calculations are performed + m1 = 0.0 + + # ----------------------------------------------------------------------- + # ----------------------------------------------------------------------- + # melting of falling graupel into rain + # ----------------------------------------------------------------------- + # ----------------------------------------------------------------------- + + # reference Fortran: gfdl_cloud_microphys.F90: subroutine check_column + # determine if any precip falls in the column + # if it falls anywhere in the column, the entire column becomes true + # initalized to 0 (false), potentially changed to 1 (true) + with computation(FORWARD), interval(...): + if qg1 > driver_constants.QPMIN: + precip_fall = 1 + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine check_column + + with computation(FORWARD), interval(0, 1): + if precip_fall == 0: + precip_graupel = 0 + + with computation(FORWARD), interval(1, None): + if precip_fall == 1: + zt = ze - dts * (vtg[0, 0, -1] + vtg) / 2.0 + + with computation(FORWARD), interval(-1, None): + if precip_fall == 1: + zt[0, 0, 1] = driver_constants.ZS - dts * vtg + + with computation(FORWARD), interval(...): + if precip_fall == 1: + if zt[0, 0, 1] >= zt: + zt[0, 0, 1] = zt - driver_constants.DZ_MIN + + with computation(PARALLEL), interval(...): + if precip_fall == 1 and disable_melt == False: # noqa + # copy frozen mask to make modifyable version + melting_mask_1 = is_frozen + # flip logic for clarity + if melting_mask_1 == True: # noqa + melting_mask_1 = False + else: + melting_mask_1 = True + + with computation(BACKWARD), interval(-1, None): + if precip_fall == 1 and disable_melt == False: # noqa + # ensure no operations are performed on the surface + melting_mask_1 = False + + with computation(BACKWARD), interval(...): + # THIS HAS NEVER BEEN TESTED B/C DTS WAS LESS THAN 300 IN THE TEST CASE + if precip_fall == 1 and disable_melt == False: # noqa + # only operate on melted layers + if melting_mask_1 == True and qg1 > driver_constants.QPMIN: # noqa + # initalize exit trigger + stop_melting = False + m: i32 = 0 + while m < k_end and stop_melting == False: # noqa + mplus1: i32 = ( + m + 1 + ) # TODO remove this line only, replace with better solution + # only opterate on previously iterated k-levels + # if melting_mask_2 == True: #noqa + # if zt[0, 0, 1] >= ze.at(K=m): + # stop_melting = ( + # True # if true exit early for ONLY this k level + # ) + # if stop_melting == False: #noqa + # dtime = min(dts, (ze.at(K=m) - ze.at(K=mplus1)) / vtg) + # if ( + # zt < ze.at(K=mplus1) + # and t1.at(K=m) > driver_constants.tice + # ): + # dtime = min(1.0, dtime / tau_g2r) + # sink = min( + # qg1 * dp1 / dp1.at(K=m), + # dtime + # * (t1.at(K=m) - driver_constants.tice) + # / icpk.at(K=m), + # ) + # offset = i32(m - current_k_level) + # hold_t1 = t1.at(K=m) + # t1[0, 0, offset] = hold_t1 - sink * icpk.at(K=m) + # qg1 = qg1 - sink * dp1.at(K=m) / dp1 + # if zt < 0: + # precip_rain = precip_rain + sink * dp1.at( + # K=m + # ) # precip as rain + # else: + # # qr source here will fall next time step + # # (therefore, can evap) + # hold_qr1 = qr1.at(K=m) + # qr1[0, 0, offset] = hold_qr1 + sink + # if stop_melting == False: #noqa + # if qg1 < driver_constants.qpmin: + # stop_melting = True + m = m + 1 + # set current layer as iterated layer + melting_mask_2 = True + + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if do_sedi_w == True: # noqa + dm = dp1 * (1.0 + qv1 + ql1 + qr1 + qi1 + qs1 + qg1) + + # begin reference Fortran: gfdl_cloud_microphys.F90: subroutine implicit_fall + # this code computes the time-implicit monotonic scheme + # Fortran author: Shian-Jiann Lin, 2016 + # set up inputs to the "function" + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + q_implicit_fall = qg1 + vt_implicit_fall = vtg + + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + hold_data = ze - ze[0, 0, 1] + dd = dts * vt_implicit_fall + q_implicit_fall = q_implicit_fall * dp1 + + # ----------------------------------------------------------------------- + # sedimentation: non - vectorizable loop + # ----------------------------------------------------------------------- + with computation(FORWARD), interval(0, 1): + if precip_fall == 1: + if use_ppm == False: # noqa + qm = q_implicit_fall / (hold_data + dd) + + with computation(FORWARD), interval(1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + qm = (q_implicit_fall + dd[0, 0, -1] * qm[0, 0, -1]) / (hold_data + dd) + + # ----------------------------------------------------------------------- + # qm is density at this stage + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + qm = qm * hold_data + + # ----------------------------------------------------------------------- + # output mass fluxes: non - vectorizable loop + # ----------------------------------------------------------------------- + with computation(FORWARD), interval(0, 1): + if precip_fall == 1: + if use_ppm == False: # noqa + m1 = q_implicit_fall - qm + + with computation(FORWARD), interval(1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + m1 = m1[0, 0, -1] + q_implicit_fall - qm + + with computation(FORWARD), interval(-1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + precip = m1 + + # ----------------------------------------------------------------------- + # update: + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + q_implicit_fall = qm / dp1 + + # update "outputs" after "function" + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + qg1 = q_implicit_fall + m1_sol = ( + m1_sol + m1 + ) # NOTE: setting this to just m1_sol = m1 gives WILD values (1e31) + + with computation(FORWARD), interval(-1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + precip_graupel = precip + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine implicit_fall + + with computation(FORWARD), interval(0, 1): + if precip_fall == 1: + if do_sedi_w: + w1 = (dm * w1 + m1 * vtg) / (dm - m1) + + with computation(FORWARD), interval(1, None): + if precip_fall == 1: + if do_sedi_w: + w1 = (dm * w1 - m1[0, 0, -1] * vtg[0, 0, -1] + m1 * vtg) / ( + dm + m1[0, 0, -1] - m1 + ) diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/warm_rain.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/warm_rain.py new file mode 100644 index 000000000..8bb7c8171 --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/GFDL_1M_driver/warm_rain.py @@ -0,0 +1,608 @@ +import gt4py.cartesian.gtscript as gtscript +from gt4py.cartesian.gtscript import ( + BACKWARD, + FORWARD, + PARALLEL, + computation, + exp, + i32, + interval, + log, + max, + sqrt, + trunc, +) + +import pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_constants as driver_constants +from ndsl.dsl.typing import Float, FloatField, FloatFieldIJ + + +GlobalTable_driver_qsat = gtscript.GlobalTable[(Float, (int(driver_constants.LENGTH)))] + + +@gtscript.function +def wqs2( + ta: Float, + den: Float, + table2: GlobalTable_driver_qsat, + des2: GlobalTable_driver_qsat, +): + """ + compute the saturated specific humidity for table2 + with additional calculation of gradient (dq/dt) + + pure water phase; universal dry / moist formular using air density + input "den" can be either dry or moist air density + + reference Fortran: gfdl_cloud_microphys.F90: function wqs2 + """ + tmin = driver_constants.TABLE_ICE - 160.0 + + if ta - tmin > 0: + ans = ta - tmin + else: + ans = 0 + ap1 = 10.0 * ans + 1.0 + ap1 = min(2621.0, ap1) + it = i32(trunc(ap1)) + es = table2.A[it - 1] + (ap1 - it) * des2.A[it - 1] + qsat = es / (driver_constants.RVGAS * ta * den) + it = i32( + trunc(ap1 - 0.5) + ) # check if this rounds or truncates. need truncation here + # finite diff, del_t = 0.1: + dqdt = ( + 10.0 + * (des2.A[it - 1] + (ap1 - it) * (des2.A[it] - des2.A[it - 1])) + / (driver_constants.RVGAS * ta * den) + ) + + return qsat, dqdt + + +@gtscript.function +def revap_racc( + half_dt: Float, + t1: Float, + qv1: Float, + ql1: Float, + qr1: Float, + qi1: Float, + qs1: Float, + qg1: Float, + qa1: Float, + den1: Float, + denfac: Float, + rh_limited: Float, + table1: GlobalTable_driver_qsat, + table2: GlobalTable_driver_qsat, + table3: GlobalTable_driver_qsat, + table4: GlobalTable_driver_qsat, + des1: GlobalTable_driver_qsat, + des2: GlobalTable_driver_qsat, + des3: GlobalTable_driver_qsat, + des4: GlobalTable_driver_qsat, +): + """ + evaporate rain + + reference Fortran: gfdl_cloud_microphys.F90: subroutine revap_racc + """ + from __externals__ import ( + c_air, + c_vap, + cracw, + crevp_0, + crevp_1, + crevp_2, + crevp_3, + crevp_4, + d0_vap, + lv00, + tau_revp, + ) + + revap = 0.0 + + if t1 > driver_constants.T_WFR and qr1 > driver_constants.QPMIN: + # area and timescale efficiency on revap + fac_revp = 1.0 - exp(-half_dt / tau_revp) + + # ----------------------------------------------------------------------- + # define heat capacity and latent heat coefficient + # ----------------------------------------------------------------------- + + lhl = lv00 + d0_vap * t1 + q_liq = ql1 + qr1 + q_sol = qi1 + qs1 + qg1 + cvm = ( + c_air + + qv1 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + lcpk = lhl / cvm + + tin = t1 - lcpk * ql1 # presence of clouds suppresses the rain evap + qpz = qv1 + ql1 + qsat, dqsdt = wqs2(tin, den1, table2, des2) + dqh = max(ql1, rh_limited * max(qpz, driver_constants.QCMIN)) + dqh = min(dqh, 0.2 * qpz) # new limiter + dqv = qsat - qv1 # use this to prevent super - sat the gird box + q_minus = qpz - dqh + q_plus = qpz + dqh + + # ----------------------------------------------------------------------- + # qsat must be > q_minus to activate evaporation + # qsat must be < q_plus to activate accretion + # ----------------------------------------------------------------------- + + # ----------------------------------------------------------------------- + # rain evaporation + # ----------------------------------------------------------------------- + + if dqv > driver_constants.QVMIN and qsat > q_minus: + if qsat > q_plus: + dq = qsat - qpz + else: + # ----------------------------------------------------------------------- + # q_minus < qsat < q_plus + # dq == dqh if qsat == q_minus + # ----------------------------------------------------------------------- + dq = 0.25 * (q_minus - qsat) ** 2 / dqh + qden = qr1 * den1 + t2 = tin * tin + evap = ( + crevp_0 + * t2 + * dq + * (crevp_1 * sqrt(qden) + crevp_2 * exp(0.725 * log(qden))) + / (crevp_3 * t2 + crevp_4 * qsat * den1) + ) + evap = min(qr1, min(half_dt * fac_revp * evap, dqv / (1.0 + lcpk * dqsdt))) + qr1 = qr1 - evap + qv1 = qv1 + evap + q_liq = q_liq - evap + cvm = ( + c_air + + qv1 * c_vap + + q_liq * driver_constants.C_LIQ + + q_sol * driver_constants.C_ICE + ) + t1 = t1 - evap * lhl / cvm + revap = evap / half_dt + + # ----------------------------------------------------------------------- + # accretion: pracc + # ----------------------------------------------------------------------- + + if ( + qr1 > driver_constants.QPMIN + and ql1 > driver_constants.QCMIN + and qsat < q_minus + ): + sink = half_dt * denfac * cracw * exp(0.95 * log(qr1 * den1)) + sink = sink / (1.0 + sink) * ql1 + ql1 = ql1 - sink + qr1 = qr1 + sink + + return ( + t1, + qv1, + qr1, + ql1, + qi1, + qs1, + qg1, + qa1, + revap, + ) + + +def warm_rain( + dp1: FloatField, + dz1: FloatField, + t1: FloatField, + qv1: FloatField, + ql1: FloatField, + qr1: FloatField, + qi1: FloatField, + qs1: FloatField, + qg1: FloatField, + qa1: FloatField, + ccn: FloatField, + den1: FloatField, + denfac: FloatField, + c_praut: FloatField, + vtr: FloatField, + evap1: FloatField, + m1_rain: FloatField, + w1: FloatField, + rh_limited: FloatField, + eis: FloatFieldIJ, + onemsig: FloatFieldIJ, + precip_rain: FloatFieldIJ, + ze: FloatField, + zt: FloatField, + precip_fall: FloatFieldIJ, + table1: GlobalTable_driver_qsat, + table2: GlobalTable_driver_qsat, + table3: GlobalTable_driver_qsat, + table4: GlobalTable_driver_qsat, + des1: GlobalTable_driver_qsat, + des2: GlobalTable_driver_qsat, + des3: GlobalTable_driver_qsat, + des4: GlobalTable_driver_qsat, +): + """ + warm rain cloud microphysics: evaporation, accretion + + reference Fortran: gfdl_cloud_microphys.F90: subroutine warm_rain + """ + from __externals__ import ( + const_vr, + do_qa, + do_sedi_w, + dts, + irain_f, + k_end, + ql0_max, + rthreshs, + rthreshu, + use_ppm, + vr_fac, + vr_max, + z_slope_liq, + ) + + # warm rain cloud microphysics + with computation(PARALLEL), interval(...): + half_dt = 0.5 * dts + + # ----------------------------------------------------------------------- + # terminal speed of rain + # ----------------------------------------------------------------------- + m1_rain = 0.0 + + # reference Fortran: gfdl_cloud_microphys.F90: subroutine check_column + # determine if any precip falls in the column + # if it falls anywhere in the column, the entire column becomes true + # initalized to 0 (false), potentially changed to 1 (true) + with computation(FORWARD), interval(...): + if qr1 > driver_constants.QPMIN: + precip_fall = 1 + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine check_column + + # ----------------------------------------------------------------------- + # auto - conversion + # assuming linear subgrid vertical distribution of cloud water + # following lin et al. 1994, mwr + # ----------------------------------------------------------------------- + + with computation(PARALLEL), interval(...): + # Use In-Cloud condensates + if do_qa == False: # noqa + qadum = max(qa1, driver_constants.QCMIN) + else: + qadum = 1.0 + ql1 = ql1 / qadum + qi1 = qi1 / qadum + + fac_rc = ( + min(1.0, eis / 15.0) ** 2 + ) # Estimated inversion strength determine stable regime + fac_rc = ( + driver_constants.RC * (rthreshs * fac_rc + rthreshu * (1.0 - fac_rc)) ** 3 + ) + + with computation(PARALLEL), interval(...): + if irain_f != 0: + # ----------------------------------------------------------------------- + # no subgrid varaibility + # ----------------------------------------------------------------------- + if qadum > onemsig: + if t1 > driver_constants.T_WFR: + qc = fac_rc * ccn / den1 + dq = ql1 - qc + if dq > 0.0: + sink = min( + dq, + dts * c_praut * den1 * exp(driver_constants.SO3 * log(ql1)), + ) + sink = min(ql0_max, min(ql1, max(0.0, sink))) + ql1 = ql1 - sink + qr1 = qr1 + sink * qadum + + with computation(FORWARD), interval(1, None): + if irain_f == 0: + # ----------------------------------------------------------------------- + # with subgrid variability + # ----------------------------------------------------------------------- + + # begin reference Fortran: gfdl_cloud_microphys.F90: subroutine linear_prof + # definition of vertical subgrid variability + # used for cloud ice and cloud water autoconversion + # qi -- > ql & ql -- > qr + # edges: qe == qbar + / - dm + if z_slope_liq == True: # noqa + dql = 0.5 * (ql1 - ql1[0, 0, -1]) + + # ----------------------------------------------------------------------- + # use twice the strength of the positive definiteness limiter (lin et al 1994) + # ----------------------------------------------------------------------- + + with computation(FORWARD), interval(1, -1): + if irain_f == 0: + if z_slope_liq == True: # noqa + dl = 0.5 * min(abs(dql + dql[0, 0, 1]), 0.5 * ql1) + if dql * dql[0, 0, 1] <= 0.0: + if dql > 0.0: # local max + dl = min(dl, min(dql, -dql[0, 0, 1])) + else: + dl = 0.0 + + with computation(FORWARD), interval(0, 1): + if irain_f == 0: + if z_slope_liq == True: # noqa + dl = 0 + + with computation(FORWARD), interval(-1, None): + if irain_f == 0: + if z_slope_liq == True: # noqa + dl = 0 + + # ----------------------------------------------------------------------- + # impose a presumed background horizontal variability + # that is proportional to the value itself + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + if irain_f == 0: + if z_slope_liq == True: # noqa + dl = max(dl, max(driver_constants.QVMIN, rh_limited * ql1)) + if z_slope_liq == False: # noqa + dl = max(driver_constants.QVMIN, rh_limited * ql1) + + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine linear_prof + + if qadum > onemsig: + if t1 > driver_constants.T_WFR + driver_constants.DT_FR: + dl = min(max(driver_constants.QCMIN, dl), 0.5 * ql1) + # -------------------------------------------------------------------- + # as in klein's gfdl am2 stratiform scheme (with subgrid variations) + # -------------------------------------------------------------------- + qc = fac_rc * ccn / den1 + dq = 0.5 * (ql1 + dl - qc) + # -------------------------------------------------------------------- + # dq = dl if qc == q_minus = ql - dl + # dq = 0 if qc == q_plus = ql + dl + # -------------------------------------------------------------------- + if dq > 0.0: # q_plus > qc + # -------------------------------------------------------------------- + # revised continuous form: linearly decays + # (with subgrid dl) to zero at qc == ql + dl + # -------------------------------------------------------------------- + sink = ( + min(1.0, dq / dl) + * dts + * c_praut + * den1 + * exp(driver_constants.SO3 * log(ql1)) + ) + sink = min(ql0_max, min(ql1, max(0.0, sink))) + ql1 = ql1 - sink + qr1 = qr1 + sink * qadum + + # Revert In-Cloud condensate + ql1 = ql1 * qadum + qi1 = qi1 * qadum + + # ----------------------------------------------------------------------- + # fall speed of rain + # ----------------------------------------------------------------------- + + if precip_fall == 0: + vtr = driver_constants.VF_MIN + elif const_vr == True: # noqa + vtr = vr_fac # ifs_2016: 4.0 + else: + qden = qr1 * den1 + if qr1 < driver_constants.THR: + vtr = driver_constants.VR_MIN + else: + vtr = ( + vr_fac + * driver_constants.VCONR + * sqrt(min(10.0, driver_constants.SFCRHO / den1)) + * exp(0.2 * log(qden / driver_constants.NORMR)) + ) + vtr = min(vr_max, max(driver_constants.VR_MIN, vtr)) + + with computation(FORWARD), interval(-1, None): + ze[0, 0, 1] = driver_constants.ZS + + with computation(BACKWARD), interval(...): + ze = ze[0, 0, 1] - dz1 # dz < 0 + + # ----------------------------------------------------------------------- + # evaporation and accretion of rain for the first 1 / 2 time step + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + ( + t1, + qv1, + qr1, + ql1, + qi1, + qs1, + qg1, + qa1, + revap, + ) = revap_racc( + half_dt, + t1, + qv1, + ql1, + qr1, + qi1, + qs1, + qg1, + qa1, + den1, + denfac, + rh_limited, + table1, + table2, + table3, + table4, + des1, + des2, + des3, + des4, + ) + + evap1 = revap + + with computation(PARALLEL), interval(...): + if do_sedi_w == True: # noqa + dm = dp1 * (1.0 + qv1 + ql1 + qr1 + qi1 + qs1 + qg1) + + # ----------------------------------------------------------------------- + # mass flux induced by falling rain + # ----------------------------------------------------------------------- + + with computation(FORWARD), interval(0, 1): + if precip_fall == 0: + precip_rain = 0.0 + + # begin reference Fortran: gfdl_cloud_microphys.F90: subroutine implicit_fall + # this code computes the time-implicit monotonic scheme + # Fortran author: Shian-Jiann Lin, 2016 + # set up inputs to the "function" + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + q_implicit_fall = qr1 + vt_implicit_fall = vtr + + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + dz_implicit_fall = ze - ze[0, 0, 1] + dd = dts * vt_implicit_fall + q_implicit_fall = q_implicit_fall * dp1 + + # ----------------------------------------------------------------------- + # sedimentation: non - vectorizable loop + # ----------------------------------------------------------------------- + with computation(FORWARD), interval(0, 1): + if precip_fall == 1: + if use_ppm == False: # noqa + qm = q_implicit_fall / (dz_implicit_fall + dd) + + with computation(FORWARD), interval(1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + qm = (q_implicit_fall + dd[0, 0, -1] * qm[0, 0, -1]) / ( + dz_implicit_fall + dd + ) + + # ----------------------------------------------------------------------- + # qm is density at this stage + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + qm = qm * dz_implicit_fall + + # ----------------------------------------------------------------------- + # output mass fluxes: non - vectorizable loop + # ----------------------------------------------------------------------- + with computation(FORWARD), interval(0, 1): + if precip_fall == 1: + if use_ppm == False: # noqa + m1 = q_implicit_fall - qm + + with computation(FORWARD), interval(1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + m1 = m1[0, 0, -1] + q_implicit_fall - qm + + with computation(FORWARD), interval(-1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + precip = m1 + + # ----------------------------------------------------------------------- + # update: + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + q_implicit_fall = qm / dp1 + + # update "outputs" after "function" + with computation(PARALLEL), interval(...): + if precip_fall == 1: + if use_ppm == False: # noqa + qr1 = q_implicit_fall + m1_rain = ( + m1_rain + m1 + ) # NOTE: setting this to just m1_rain = m1 gives WILD values (1e31) + + with computation(FORWARD), interval(-1, None): + if precip_fall == 1: + if use_ppm == False: # noqa + precip_rain = precip + # end reference Fortran: gfdl_cloud_microphys.F90: subroutine implicit_fall + + # ----------------------------------------------------------------------- + # vertical velocity transportation during sedimentation + # ----------------------------------------------------------------------- + with computation(FORWARD), interval(0, 1): + if do_sedi_w == True: # noqa + w1 = (dm * w1 + m1_rain * vtr) / (dm - m1_rain) + + with computation(FORWARD), interval(1, None): + if do_sedi_w == True: # noqa + w1 = (dm * w1 - m1_rain[0, 0, -1] * vtr[0, 0, -1] + m1_rain * vtr) / ( + dm + m1_rain[0, 0, -1] - m1_rain + ) + + # ----------------------------------------------------------------------- + # evaporation and accretion of rain for the remaing 1 / 2 time step + # ----------------------------------------------------------------------- + with computation(PARALLEL), interval(...): + ( + t1, + qv1, + qr1, + ql1, + qi1, + qs1, + qg1, + qa1, + revap, + ) = revap_racc( + half_dt, + t1, + qv1, + ql1, + qr1, + qi1, + qs1, + qg1, + qa1, + den1, + denfac, + rh_limited, + table1, + table2, + table3, + table4, + des1, + des2, + des3, + des4, + ) + + evap1 = evap1 + revap diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/evap_subl_pdf_core.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/evap_subl_pdf_core.py index de13c3e73..0bd5b5711 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/evap_subl_pdf_core.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/GFDL_1M/evap_subl_pdf_core.py @@ -8,13 +8,14 @@ atan, computation, exp, + i32, interval, sqrt, tan, ) import pyMoist.constants as constants -from ndsl.dsl.typing import Float, FloatField, FloatFieldIJ, Int +from ndsl.dsl.typing import Float, FloatField, FloatFieldIJ from pyMoist.field_types import FloatField_VaporSaturationTable from pyMoist.saturation.qsat import QSat_Float, QSat_Float_Ice, QSat_Float_Liquid from pyMoist.shared_incloud_processes import ( @@ -26,7 +27,7 @@ @gtscript.function def pdffrac( - pdfshape: Int, + pdfshape: i32, qtmean: Float, sigmaqt1: Float, sigmaqt2: Float, @@ -51,7 +52,7 @@ def pdffrac( @gtscript.function def pdfcondensate( - pdfshape: Int, + pdfshape: i32, qtmean: Float, sigmaqt1: Float, sigmaqt2: Float, diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.c b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.c index 26c4b90d2..c28be004b 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.c +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.c @@ -19,6 +19,23 @@ extern int pymoist_interface_c_init(moist_flags_t *flags) } } +extern int gfdl_1m_interface_c_init(gfdl_1m_flags_t *flags) +{ + // Check magic number + if (flags->mn_123456789 != 123456789) + { + printf("Magic number failed, gfdl_1m interface is broken on the C side\n"); + exit(-1); + } + + int return_code = gfdl_1m_interface_py_init(flags); + + if (return_code < 0) + { + exit(return_code); + } +} + void pymoist_interface_c_run_GFDL1M( float dw_land, float dw_ocean, int PDFSHAPE, float TURNRHCRIT_PARAM, float DT_MOIST, float CCW_EVAP_EFF, float CCI_EVAP_EFF, @@ -45,6 +62,31 @@ void pymoist_interface_c_run_GFDL1M( } } +void pymoist_interface_c_run_GFDL_1M_driver( + float *RAD_QV, float *RAD_QL, float *RAD_QR, float *RAD_QI, float *RAD_QS, float *RAD_QG, float *RAD_CF, float *NACTAll, + float *DQVDTmic, float *DQLDTmic, float *DQRDTmic, float *DQIDTmic, + float *DQSDTmic, float *DQGDTmic, float *DQADTmic, float *DTDTmic, + float *T, float *W, float *U, float *V, float *DUDTmic, float *DVDTmic, float *DZ, float *DP, + float *AREA, float *FRLAND, float *CNV_FRC, float *SRF_TYPE, float *EIS, float *RHCRIT3D, + float DT_MOIST, float ANV_ICEFALL, float LS_ICEFALL, + float *REV_LS, float *RSU_LS, + float *PRCP_RAIN, float *PRCP_SNOW, float *PRCP_ICE, float *PRCP_GRAUPEL, + float *PFL_LS, float *PFI_LS, + int LHYDROSTATIC, int LPHYS_HYDROSTATIC) +{ + int return_code = pymoist_interface_py_run_GFDL_1M_driver( + RAD_QV, RAD_QL, RAD_QR, RAD_QI, RAD_QS, RAD_QG, RAD_CF, NACTAll, + DQVDTmic, DQLDTmic, DQRDTmic, DQIDTmic, DQSDTmic, DQGDTmic, DQADTmic, DTDTmic, + T, W, U, V, DUDTmic, DVDTmic, DZ, DP, AREA, FRLAND, CNV_FRC, SRF_TYPE, EIS, RHCRIT3D, + DT_MOIST, ANV_ICEFALL, LS_ICEFALL, + REV_LS, RSU_LS, PRCP_RAIN, PRCP_SNOW, PRCP_ICE, PRCP_GRAUPEL, PFL_LS, PFI_LS, + LHYDROSTATIC, LPHYS_HYDROSTATIC); + if (return_code < 0) + { + exit(return_code); + } +} + void pymoist_interface_c_run_AerActivation( // input float *aero_dgn, float *aero_num, float *aero_hygroscopicity, float *aero_sigma, diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.f90 b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.f90 index f62c7d2cf..f6112f110 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.f90 +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.f90 @@ -6,11 +6,15 @@ module pymoist_interface_mod private public :: pymoist_interface_f_init + public :: gfdl_1m_interface_f_init public :: pymoist_interface_f_run_AerActivation public :: pymoist_interface_f_run_GFDL1M + public :: pymoist_interface_f_run_gfdl_1m_driver public :: pymoist_interface_f_finalize public :: make_moist_flags_C_interop + public :: make_gfdl_1m_flags_C_interop public :: moist_flags_interface_type + public :: gfdl_1m_flags_interface_type !----------------------------------------------------------------------- ! Shadow C interoperable config struct for FV. See `fv_arrays.f90` for @@ -30,18 +34,115 @@ module pymoist_interface_mod integer(kind=c_int) :: make_flags_C_interop = 123456789 end type + type, bind(c) :: gfdl_1m_flags_interface_type + ! GFDL_1M driver + logical(kind=c_bool) :: phys_hydrostatic + logical(kind=c_bool) :: hydrostatic + logical(kind=c_bool) :: do_qa + logical(kind=c_bool) :: fix_negative + logical(kind=c_bool) :: fast_sat_adj + logical(kind=c_bool) :: const_vi + logical(kind=c_bool) :: const_vs + logical(kind=c_bool) :: const_vg + logical(kind=c_bool) :: const_vr + logical(kind=c_bool) :: use_ccn + logical(kind=c_bool) :: do_bigg + logical(kind=c_bool) :: do_evap + logical(kind=c_bool) :: do_subl + logical(kind=c_bool) :: z_slope_liq + logical(kind=c_bool) :: z_slope_ice + logical(kind=c_bool) :: prog_ccn + logical(kind=c_bool) :: preciprad + logical(kind=c_bool) :: use_ppm + logical(kind=c_bool) :: mono_prof + logical(kind=c_bool) :: do_sedi_heat + logical(kind=c_bool) :: sedi_transport + logical(kind=c_bool) :: do_sedi_w + logical(kind=c_bool) :: de_ice + logical(kind=c_bool) :: mp_print + real(kind=c_float) :: dt_moist + real(kind=c_float) :: mp_time + real(kind=c_float) :: t_min + real(kind=c_float) :: t_sub + real(kind=c_float) :: tau_r2g + real(kind=c_float) :: tau_smlt + real(kind=c_float) :: tau_g2r + real(kind=c_float) :: dw_land + real(kind=c_float) :: dw_ocean + real(kind=c_float) :: vi_fac + real(kind=c_float) :: vr_fac + real(kind=c_float) :: vs_fac + real(kind=c_float) :: vg_fac + real(kind=c_float) :: ql_mlt + real(kind=c_float) :: vi_max + real(kind=c_float) :: vs_max + real(kind=c_float) :: vg_max + real(kind=c_float) :: vr_max + real(kind=c_float) :: qs_mlt + real(kind=c_float) :: qs0_crt + real(kind=c_float) :: qi_gen + real(kind=c_float) :: ql0_max + real(kind=c_float) :: qi0_max + real(kind=c_float) :: qi0_crt + real(kind=c_float) :: qr0_crt + real(kind=c_float) :: rh_inc + real(kind=c_float) :: rh_ins + real(kind=c_float) :: rh_inr + real(kind=c_float) :: rthreshu + real(kind=c_float) :: rthreshs + real(kind=c_float) :: ccn_l + real(kind=c_float) :: ccn_o + real(kind=c_float) :: qc_crt + real(kind=c_float) :: tau_g2v + real(kind=c_float) :: tau_v2g + real(kind=c_float) :: tau_s2v + real(kind=c_float) :: tau_v2s + real(kind=c_float) :: tau_revp + real(kind=c_float) :: tau_frz + real(kind=c_float) :: sat_adj0 + real(kind=c_float) :: c_piacr + real(kind=c_float) :: tau_imlt + real(kind=c_float) :: tau_v2l + real(kind=c_float) :: tau_l2v + real(kind=c_float) :: tau_i2v + real(kind=c_float) :: tau_i2s + real(kind=c_float) :: tau_l2r + real(kind=c_float) :: qi_lim + real(kind=c_float) :: ql_gen + real(kind=c_float) :: c_paut + real(kind=c_float) :: c_psaci + real(kind=c_float) :: c_pgacs + real(kind=c_float) :: c_pgaci + real(kind=c_float) :: c_cracw + real(kind=c_float) :: alin + real(kind=c_float) :: clin + real(kind=c_float) :: cld_min + integer(kind=c_int) :: icloud_f + integer(kind=c_int) :: irain_f + ! Magic number + integer(kind=c_int) :: make_flags_C_interop = 123456789 + end type interface - subroutine pymoist_interface_f_init( moist_flags) bind(c, name='pymoist_interface_c_init') + subroutine pymoist_interface_f_init(moist_flags) bind(c, name='pymoist_interface_c_init') - import c_int, c_float, c_double, moist_flags_interface_type + import c_int, c_float, c_double, c_bool, moist_flags_interface_type implicit none type(moist_flags_interface_type), intent(in) :: moist_flags end subroutine pymoist_interface_f_init + subroutine gfdl_1m_interface_f_init(gfdl_1m_flags) bind(c, name='gfdl_1m_interface_c_init') + + import c_int, c_float, c_double, c_bool, gfdl_1m_flags_interface_type + + implicit none + type(gfdl_1m_flags_interface_type), intent(in) :: gfdl_1m_flags + + end subroutine gfdl_1m_interface_f_init + subroutine pymoist_interface_f_run_AerActivation( & aero_dgn, aero_num, aero_hygroscopicity, aero_sigma, & frland, nn_ocean, nn_land, & @@ -115,6 +216,39 @@ subroutine pymoist_interface_f_run_GFDL1M( & end subroutine pymoist_interface_f_run_GFDL1M + subroutine pymoist_interface_f_run_GFDL_1M_driver( & + RAD_QV, RAD_QL, RAD_QR, RAD_QI, RAD_QS, RAD_QG, RAD_CF, NACTAll, & + DQVDTmic, DQLDTmic, DQRDTmic, DQIDTmic, & + DQSDTmic, DQGDTmic, DQADTmic, DTDTmic, & + T, W, U, V, DUDTmic, DVDTmic, DZ, DP, & + AREA, DT_MOIST, FRLAND, CNV_FRC, SRF_TYPE, EIS, & + RHCRIT3D, ANV_ICEFALL, LS_ICEFALL, & + REV_LS, RSU_LS, & + PRCP_RAIN, PRCP_SNOW, PRCP_ICE, PRCP_GRAUPEL, & + PFL_LS, PFI_LS, & + LHYDROSTATIC, LPHYS_HYDROSTATIC ) bind(c, name='pymoist_interface_c_run_GFDL_1M_driver') + + import c_int, c_float, c_bool + + implicit none + + ! Input + real(kind=c_float), dimension(*), intent(in) :: RAD_QV, RAD_QL, RAD_QR, RAD_QI, RAD_QS, RAD_QG, RAD_CF, NACTAll + real(kind=c_float), dimension(*), intent(in) :: T, W, U, V, DUDTmic, DVDTmic, DZ, DP + + real(kind=c_float), dimension(*), intent(in) :: AREA, FRLAND, CNV_FRC, SRF_TYPE, EIS, RHCRIT3D + real(kind=c_float), value, intent(in) :: DT_MOIST, LS_ICEFALL, ANV_ICEFALL + integer(kind=c_int), value, intent(in) :: LHYDROSTATIC, LPHYS_HYDROSTATIC ! Actually bool but LOGICAL(4) and (1) are fighting + + ! Output + real(kind=c_float), dimension(*), intent(inout) :: DQVDTmic, DQLDTmic, DQRDTmic, DQIDTmic, DQSDTmic, DQGDTmic, DQADTmic, DTDTmic + real(kind=c_float), dimension(*), intent(inout) :: REV_LS, RSU_LS + real(kind=c_float), dimension(*), intent(inout) :: PRCP_RAIN, PRCP_SNOW, PRCP_ICE, PRCP_GRAUPEL + real(kind=c_float), dimension(*), intent(inout) :: PFL_LS, PFI_LS + + end subroutine pymoist_interface_f_run_GFDL_1M_driver + + subroutine pymoist_interface_f_finalize() bind(c, name='pymoist_interface_c_finalize') end subroutine pymoist_interface_f_finalize @@ -123,8 +257,12 @@ end subroutine pymoist_interface_f_finalize contains subroutine make_moist_flags_C_interop(npx, npy, npz , nx, ny, n_tiles, n_modes, moist_flags) + integer, intent(in) :: nx, ny, npx, npy, npz, n_tiles - integer, intent(in) :: n_modes ! Aer Activation + ! Aer Activation + integer, intent(in) :: n_modes + + type(moist_flags_interface_type), intent(out) :: moist_flags moist_flags%npx = npx @@ -134,6 +272,123 @@ subroutine make_moist_flags_C_interop(npx, npy, npz , nx, ny, n_tiles, n_modes, moist_flags%layout_y = ny moist_flags%n_tiles = n_tiles moist_flags%n_modes = n_modes + end subroutine make_moist_flags_C_interop + subroutine make_gfdl_1m_flags_C_interop(phys_hydrostatic, hydrostatic, do_qa, fix_negative, fast_sat_adj, & + const_vi, const_vs, const_vg, const_vr, use_ccn, do_bigg, do_evap, & + do_subl, z_slope_liq, z_slope_ice, prog_ccn, preciprad, use_ppm, & + mono_prof, do_sedi_heat, sedi_transport, do_sedi_w, de_ice, mp_print, & + dt_moist, mp_time, t_min, t_sub, tau_r2g, tau_smlt, tau_g2r, & + dw_land, dw_ocean, vi_fac, vr_fac, vs_fac, vg_fac, ql_mlt, vi_max, & + vs_max, vg_max, vr_max, qs_mlt, qs0_crt, qi_gen, ql0_max, qi0_max, & + qi0_crt, qr0_crt, rh_inc, rh_ins, rh_inr, rthreshu, rthreshs, ccn_l, & + ccn_o, qc_crt, tau_g2v, tau_v2g, tau_s2v, tau_v2s, tau_revp, tau_frz, & + sat_adj0, c_piacr, tau_imlt, tau_v2l, tau_l2v, tau_i2v, tau_i2s, & + tau_l2r, qi_lim, ql_gen, c_paut, c_psaci, c_pgacs, c_pgaci, c_cracw, & + alin, clin, cld_min, icloud_f, irain_f, gfdl_1m_flags) + + ! GFDL_1M driver + logical, intent(in) :: phys_hydrostatic, hydrostatic, do_qa, fix_negative, fast_sat_adj + logical, intent(in) :: const_vi, const_vs, const_vg, const_vr, use_ccn, do_bigg, do_evap + logical, intent(in) :: do_subl, z_slope_liq, z_slope_ice, prog_ccn, preciprad, use_ppm + logical, intent(in) :: mono_prof, do_sedi_heat, sedi_transport, do_sedi_w, de_ice, mp_print + real, intent(in) :: dt_moist, mp_time, t_min, t_sub, tau_r2g, tau_smlt, tau_g2r + real, intent(in) :: dw_land, dw_ocean, vi_fac, vr_fac, vs_fac, vg_fac, ql_mlt, vi_max + real, intent(in) :: vs_max, vg_max, vr_max, qs_mlt, qs0_crt, qi_gen, ql0_max, qi0_max + real, intent(in) :: qi0_crt, qr0_crt, rh_inc, rh_ins, rh_inr, rthreshu, rthreshs, ccn_l + real, intent(in) :: ccn_o, qc_crt, tau_g2v, tau_v2g, tau_s2v, tau_v2s, tau_revp, tau_frz + real, intent(in) :: sat_adj0, c_piacr, tau_imlt, tau_v2l, tau_l2v, tau_i2v, tau_i2s + real, intent(in) :: tau_l2r, qi_lim, ql_gen, c_paut, c_psaci, c_pgacs, c_pgaci, c_cracw + real, intent(in) :: alin, clin, cld_min + integer, intent(in) :: icloud_f, irain_f + + type(gfdl_1m_flags_interface_type), intent(out) :: gfdl_1m_flags + + gfdl_1m_flags%phys_hydrostatic = phys_hydrostatic + gfdl_1m_flags%hydrostatic = hydrostatic + gfdl_1m_flags%do_qa = do_qa + gfdl_1m_flags%fix_negative = fix_negative + gfdl_1m_flags%fast_sat_adj = fast_sat_adj + gfdl_1m_flags%const_vi = const_vi + gfdl_1m_flags%const_vs = const_vs + gfdl_1m_flags%const_vg = const_vg + gfdl_1m_flags%const_vr = const_vr + gfdl_1m_flags%use_ccn = use_ccn + gfdl_1m_flags%do_bigg = do_bigg + gfdl_1m_flags%do_evap = do_evap + gfdl_1m_flags%do_subl = do_subl + gfdl_1m_flags%z_slope_liq = z_slope_liq + gfdl_1m_flags%z_slope_ice = z_slope_ice + gfdl_1m_flags%prog_ccn = prog_ccn + gfdl_1m_flags%preciprad = preciprad + gfdl_1m_flags%use_ppm = use_ppm + gfdl_1m_flags%mono_prof = mono_prof + gfdl_1m_flags%do_sedi_heat = do_sedi_heat + gfdl_1m_flags%sedi_transport = sedi_transport + gfdl_1m_flags%do_sedi_w = do_sedi_w + gfdl_1m_flags%de_ice = de_ice + gfdl_1m_flags%mp_print = mp_print + gfdl_1m_flags%dt_moist = dt_moist + gfdl_1m_flags%mp_time = mp_time + gfdl_1m_flags%t_min = t_min + gfdl_1m_flags%t_sub = t_sub + gfdl_1m_flags%tau_r2g = tau_r2g + gfdl_1m_flags%tau_smlt = tau_smlt + gfdl_1m_flags%tau_g2r = tau_g2r + gfdl_1m_flags%dw_land = dw_land + gfdl_1m_flags%dw_ocean = dw_ocean + gfdl_1m_flags%vi_fac = vi_fac + gfdl_1m_flags%vr_fac = vr_fac + gfdl_1m_flags%vs_fac = vs_fac + gfdl_1m_flags%vg_fac = vg_fac + gfdl_1m_flags%ql_mlt = ql_mlt + gfdl_1m_flags%vi_max = vi_max + gfdl_1m_flags%vs_max = vs_max + gfdl_1m_flags%vg_max = vg_max + gfdl_1m_flags%vr_max = vr_max + gfdl_1m_flags%qs_mlt = qs_mlt + gfdl_1m_flags%qs0_crt = qs0_crt + gfdl_1m_flags%qi_gen = qi_gen + gfdl_1m_flags%ql0_max = ql0_max + gfdl_1m_flags%qi0_max = qi0_max + gfdl_1m_flags%qi0_crt = qi0_crt + gfdl_1m_flags%qr0_crt = qr0_crt + gfdl_1m_flags%rh_inc = rh_inc + gfdl_1m_flags%rh_ins = rh_ins + gfdl_1m_flags%rh_inr = rh_inr + gfdl_1m_flags%rthreshu = rthreshu + gfdl_1m_flags%rthreshs = rthreshs + gfdl_1m_flags%ccn_l = ccn_l + gfdl_1m_flags%ccn_o = ccn_o + gfdl_1m_flags%qc_crt = qc_crt + gfdl_1m_flags%tau_g2v = tau_g2v + gfdl_1m_flags%tau_v2g = tau_v2g + gfdl_1m_flags%tau_s2v = tau_s2v + gfdl_1m_flags%tau_v2s = tau_v2s + gfdl_1m_flags%tau_revp = tau_revp + gfdl_1m_flags%tau_frz = tau_frz + gfdl_1m_flags%sat_adj0 = sat_adj0 + gfdl_1m_flags%c_piacr = c_piacr + gfdl_1m_flags%tau_imlt = tau_imlt + gfdl_1m_flags%tau_v2l = tau_v2l + gfdl_1m_flags%tau_l2v = tau_l2v + gfdl_1m_flags%tau_i2v = tau_i2v + gfdl_1m_flags%tau_i2s = tau_i2s + gfdl_1m_flags%tau_l2r = tau_l2r + gfdl_1m_flags%qi_lim = qi_lim + gfdl_1m_flags%ql_gen = ql_gen + gfdl_1m_flags%c_paut = c_paut + gfdl_1m_flags%c_psaci = c_psaci + gfdl_1m_flags%c_pgacs = c_pgacs + gfdl_1m_flags%c_pgaci = c_pgaci + gfdl_1m_flags%c_cracw = c_cracw + gfdl_1m_flags%alin = alin + gfdl_1m_flags%clin = clin + gfdl_1m_flags%cld_min = cld_min + gfdl_1m_flags%icloud_f = icloud_f + gfdl_1m_flags%irain_f = irain_f + + end subroutine make_gfdl_1m_flags_C_interop + end module pymoist_interface_mod diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.py index 2b390fd10..24bc438e4 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/interface.py @@ -19,8 +19,10 @@ from pyMoist.interface.python_bridge import ( pyMoist_init, pyMoist_run_AerActivation, - pyMoist_run_GFDL1M, - pyMoist_finalize + pyMoist_run_GFDL_1M_evap_subl_hystpdf, + pymoist_run_GFDL_1M_driver, + pyMoist_finalize, + gfdl_1m_init ) import traceback @@ -35,6 +37,17 @@ def pymoist_interface_py_init(flags) -> int: return -1 return 0 +@ffi.def_extern() +def gfdl_1m_interface_py_init(flags) -> int: + + try: + gfdl_1m_init(flags) + except Exception as err: + print("Error in Python:") + print(traceback.format_exc()) + return -1 + return 0 + @ffi.def_extern() def pymoist_interface_py_run_AerActivation( aero_dgn, aero_num, aero_hygroscopicity, aero_sigma, @@ -70,7 +83,7 @@ def pymoist_interface_py_run_GFDL1M( SUBLC, EVAPC, RHX): try: - pyMoist_run_GFDL1M( + pyMoist_run_GFDL_1M_evap_subl_hystpdf( dw_land, dw_ocean, PDFSHAPE, TURNRHCRIT_PARAM, DT_MOIST, CCW_EVAP_EFF, CCI_EVAP_EFF, LMELTFRZ, @@ -86,6 +99,38 @@ def pymoist_interface_py_run_GFDL1M( return -1 return 0 +@ffi.def_extern() +def pymoist_interface_py_run_GFDL_1M_driver( + RAD_QV, RAD_QL, RAD_QR, RAD_QI, RAD_QS, RAD_QG, RAD_CF, NACTAll, + DQVDTmic, DQLDTmic, DQRDTmic, DQIDTmic, + DQSDTmic, DQGDTmic, DQADTmic, DTDTmic, + T, W, U, V, DUDTmic, DVDTmic, DZ, DP, + AREA, FRLAND, CNV_FRC, SRF_TYPE, EIS, RHCRIT3D, + DT_MOIST, ANV_ICEFALL, LS_ICEFALL, + REV_LS, RSU_LS, + PRCP_RAIN, PRCP_SNOW, PRCP_ICE, PRCP_GRAUPEL, PFL_LS, PFI_LS, + LHYDROSTATIC, LPHYS_HYDROSTATIC + ): + + try: + pymoist_run_GFDL_1M_driver( + RAD_QV, RAD_QL, RAD_QR, RAD_QI, RAD_QS, RAD_QG, RAD_CF, + NACTAll, + DQVDTmic, DQLDTmic, DQRDTmic, DQIDTmic, + DQSDTmic, DQGDTmic, DQADTmic, DTDTmic, + T, W, U, V, DUDTmic, DVDTmic, DZ, DP, + AREA, FRLAND, CNV_FRC, SRF_TYPE, EIS, RHCRIT3D, + DT_MOIST, ANV_ICEFALL, LS_ICEFALL, + REV_LS, RSU_LS, + PRCP_RAIN, PRCP_SNOW, PRCP_ICE, PRCP_GRAUPEL, PFL_LS, PFI_LS, + LHYDROSTATIC, LPHYS_HYDROSTATIC + ) + except Exception as err: + print("Error in Python:") + print(traceback.format_exc()) + return -1 + return 0 + @ffi.def_extern() def pymoist_interface_py_finalize() -> int: try: @@ -96,16 +141,18 @@ def pymoist_interface_py_finalize() -> int: return -1 return 0 -""".format( - TMPFILEBASE -) +""".format(TMPFILEBASE) with open("moist.h") as f: data = "".join([line for line in f if not line.startswith("#")]) data = data.replace("CFFI_DLLEXPORT", "") ffi.embedding_api(data) -ffi.set_source(TMPFILEBASE, '#include "moist.h"') +ffi.set_source( + TMPFILEBASE, + '#include "moist.h"', + library_dirs=["/Library/Frameworks/Python.framework/Versions/3.11/lib"], +) ffi.embedding_init_code(source) -ffi.compile(target="lib" + TMPFILEBASE + ".so", verbose=True) +ffi.compile(target="lib" + TMPFILEBASE + ".*", verbose=True) diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/moist.h b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/moist.h index eb1d84c82..a162f641a 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/moist.h +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/cffi_lib/moist.h @@ -23,6 +23,96 @@ typedef struct int mn_123456789; } moist_flags_t; +typedef struct +{ + // GFDL_1M driver + bool phys_hydrostatic; + bool hydrostatic; + bool do_qa; + bool fix_negative; + bool fast_sat_adj; + bool const_vi; + bool const_vs; + bool const_vg; + bool const_vr; + bool use_ccn; + bool do_bigg; + bool do_evap; + bool do_subl; + bool z_slope_liq; + bool z_slope_ice; + bool prog_ccn; + bool preciprad; + bool use_ppm; + bool mono_prof; + bool do_sedi_heat; + bool sedi_transport; + bool do_sedi_w; + bool de_ice; + bool mp_print; + float dt_moist; + float mp_time; + float t_min; + float t_sub; + float tau_r2g; + float tau_smlt; + float tau_g2r; + float dw_land; + float dw_ocean; + float vi_fac; + float vr_fac; + float vs_fac; + float vg_fac; + float ql_mlt; + float vi_max; + float vs_max; + float vg_max; + float vr_max; + float qs_mlt; + float qs0_crt; + float qi_gen; + float ql0_max; + float qi0_max; + float qi0_crt; + float qr0_crt; + float rh_inc; + float rh_ins; + float rh_inr; + float rthreshu; + float rthreshs; + float ccn_l; + float ccn_o; + float qc_crt; + float tau_g2v; + float tau_v2g; + float tau_s2v; + float tau_v2s; + float tau_revp; + float tau_frz; + float sat_adj0; + float c_piacr; + float tau_imlt; + float tau_v2l; + float tau_l2v; + float tau_i2v; + float tau_i2s; + float tau_l2r; + float qi_lim; + float ql_gen; + float c_paut; + float c_psaci; + float c_pgacs; + float c_pgaci; + float c_cracw; + float alin; + float clin; + float cld_min; + int icloud_f; + int irain_f; + // Magic number needs to be last item + int mn_123456789; +} gfdl_1m_flags_t; + // Carry wrapper for MPI typedef union { @@ -32,6 +122,8 @@ typedef union extern int pymoist_interface_py_init(moist_flags_t *flags); +extern int gfdl_1m_interface_py_init(gfdl_1m_flags_t *flags); + extern int pymoist_interface_py_run_AerActivation( // input float *aero_dgn, float *aero_num, float *aero_hygroscopicity, float *aero_sigma, @@ -52,4 +144,16 @@ extern int pymoist_interface_py_run_GFDL1M( float *T, float *Q, float *QLCN, float *QICN, float *QLLS, float *QILS, float *CLLS, float *CLCN, float *SUBLC, float *EVAPC, float *RHX); +extern int pymoist_interface_py_run_GFDL_1M_driver( + float *RAD_QV, float *RAD_QL, float *RAD_QR, float *RAD_QI, float *RAD_QS, float *RAD_QG, float *RAD_CF, float *NACTAll, + float *DQVDTmic, float *DQLDTmic, float *DQRDTmic, float *DQIDTmic, + float *DQSDTmic, float *DQGDTmic, float *DQADTmic, float *DTDTmic, + float *T, float *W, float *U, float *V, float *DUDTmic, float *DVDTmic, float *DZ, float *DP, + float *AREA, float *FRLAND, float *CNV_FRC, float *SRF_TYPE, float *EIS, float *RHCRIT3D, + float DT_MOIST, float ANV_ICEFALL, float LS_ICEFALL, + float *REV_LS, float *RSU_LS, + float *PRCP_RAIN, float *PRCP_SNOW, float *PRCP_ICE, float *PRCP_GRAUPEL, + float *PFL_LS, float *PFI_LS, + bool LHYDROSTATIC, bool LPHYS_HYDROSTATIC); + extern int pymoist_interface_py_finalize(); diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/f_py_conversion.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/f_py_conversion.py index 0b4ffb56d..a2f596caf 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/f_py_conversion.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/f_py_conversion.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from math import prod from types import ModuleType from typing import List, Optional, Tuple, TypeAlias @@ -76,7 +78,7 @@ def device_sync(self): def _fortran_to_numpy( self, - fptr: "cffi.FFI.CData", + fptr: cffi.FFI.CData, dim: Optional[List[int]] = None, ) -> np.ndarray: """ @@ -133,7 +135,7 @@ def _transform_from_fortran_layout( def fortran_to_python( self, - fptr: "cffi.FFI.CData", + fptr: cffi.FFI.CData, dim: Optional[List[int]] = None, swap_axes: Optional[Tuple[int, int]] = None, ) -> PythonArray: @@ -194,7 +196,7 @@ def _transform_from_python_layout( def python_to_fortran( self, array: PythonArray, - fptr: "cffi.FFI.CData", + fptr: cffi.FFI.CData, ptr_offset: int = 0, swap_axes: Optional[Tuple[int, int]] = None, ) -> np.ndarray: diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/flags.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/flags.py index 642d729bb..a6e759f0d 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/flags.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/flags.py @@ -1,13 +1,15 @@ -from dataclasses import dataclass -from typing import TYPE_CHECKING +from __future__ import annotations +from dataclasses import dataclass +from typing import Any -if TYPE_CHECKING: - import cffi +import cffi +import numpy as np @dataclass -class MoistFlags: +class moist_flags: + # Grid layout npx: int = 0 npy: int = 0 npz: int = 0 @@ -20,24 +22,127 @@ class MoistFlags: mn_123456789: int = 0 +@dataclass +class gfdl_1m_flags: + # GFDL_1M driver (for now initalized to junk values, these values dont matter, right?) + phys_hydrostatic: bool = False + hydrostatic: bool = False + dt_moist: np.float32 = 0 + mp_time: np.float32 = 0 + t_min: np.float32 = 0 + t_sub: np.float32 = 0 + tau_r2g: np.float32 = 0 + tau_smlt: np.float32 = 0 + tau_g2r: np.float32 = 0 + dw_land: np.float32 = 0 + dw_ocean: np.float32 = 0 + vi_fac: np.float32 = 0 + vr_fac: np.float32 = 0 + vs_fac: np.float32 = 0 + vg_fac: np.float32 = 0 + ql_mlt: np.float32 = 0 + do_qa: bool = False + fix_negative: bool = False + vi_max: np.float32 = 0 + vs_max: np.float32 = 0 + vg_max: np.float32 = 0 + vr_max: np.float32 = 0 + qs_mlt: np.float32 = 0 + qs0_crt: np.float32 = 0 + qi_gen: np.float32 = 0 + ql0_max: np.float32 = 0 + qi0_max: np.float32 = 0 + qi0_crt: np.float32 = 0 + qr0_crt: np.float32 = 0 + fast_sat_adj: bool = False + rh_inc: np.float32 = 0 + rh_ins: np.float32 = 0 + rh_inr: np.float32 = 0 + const_vi: bool = False + const_vs: bool = False + const_vg: bool = False + const_vr: bool = False + use_ccn: bool = False + rthreshu: np.float32 = 0 + rthreshs: np.float32 = 0 + ccn_l: np.float32 = 0 + ccn_o: np.float32 = 0 + qc_crt: np.float32 = 0 + tau_g2v: np.float32 = 0 + tau_v2g: np.float32 = 0 + tau_s2v: np.float32 = 0 + tau_v2s: np.float32 = 0 + tau_revp: np.float32 = 0 + tau_frz: np.float32 = 0 + do_bigg: bool = False + do_evap: bool = False + do_subl: bool = False + sat_adj0: np.float32 = 0 + c_piacr: np.float32 = 0 + tau_imlt: np.float32 = 0 + tau_v2l: np.float32 = 0 + tau_l2v: np.float32 = 0 + tau_i2v: np.float32 = 0 + tau_i2s: np.float32 = 0 + tau_l2r: np.float32 = 0 + qi_lim: np.float32 = 0 + ql_gen: np.float32 = 0 + c_paut: np.float32 = 0 + c_psaci: np.float32 = 0 + c_pgacs: np.float32 = 0 + c_pgaci: np.float32 = 0 + z_slope_liq: bool = False + z_slope_ice: bool = False + prog_ccn: bool = False + c_cracw: np.float32 = 0 + alin: np.float32 = 0 + clin: np.float32 = 0 + preciprad: bool = False + cld_min: np.float32 = 0 + use_ppm: bool = False + mono_prof: bool = False + do_sedi_heat: bool = False + sedi_transport: bool = False + do_sedi_w: bool = False + de_ice: bool = False + icloud_f: np.int32 = 0 + irain_f: np.int32 = 0 + mp_print: bool = False + # Magic number + mn_123456789: int = 0 + + def _generic_config_bridge( - py_flags: MoistFlags, - fv_flags: "cffi.FFI.CData", + py_flags: Any, + f_flags: cffi.FFI.CData, ): keys = list(filter(lambda k: not k.startswith("__"), dir(type(py_flags)))) for k in keys: - if hasattr(fv_flags, k): - setattr(py_flags, k, getattr(fv_flags, k)) + if hasattr(f_flags, k): + setattr(py_flags, k, getattr(f_flags, k)) + + +def moist_flags_f_to_python( + f_flags: cffi.FFI.CData, +) -> moist_flags: + if f_flags.mn_123456789 != 123456789: + raise RuntimeError( + "Magic number failed, pyMoist interface is broken on the python side" + ) + + py_flags = moist_flags() + _generic_config_bridge(py_flags, f_flags) + return py_flags -def flags_fv_to_python( - fv_flags: "cffi.FFI.CData", -) -> MoistFlags: - if fv_flags.mn_123456789 != 123456789: +def gfdl_1m_flags_f_to_python( + f_flags: cffi.FFI.CData, +) -> gfdl_1m_flags: + if f_flags.mn_123456789 != 123456789: raise RuntimeError( "Magic number failed, pyMoist interface is broken on the python side" ) - py_flags = MoistFlags() - _generic_config_bridge(py_flags, fv_flags) + py_flags = gfdl_1m_flags() + _generic_config_bridge(py_flags, f_flags) return py_flags diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/python_bridge.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/python_bridge.py index 3dc3b0e01..f73509f0b 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/python_bridge.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/python_bridge.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import os -from typing import TYPE_CHECKING, Dict, List +from typing import Dict, List +import cffi import numpy as np from mpi4py import MPI @@ -9,12 +12,11 @@ from ndsl.optional_imports import cupy as cp from pyMoist.interface.cuda_profiler import CUDAProfiler, TimedCUDAProfiler from pyMoist.interface.f_py_conversion import FortranPythonConversion -from pyMoist.interface.flags import flags_fv_to_python -from pyMoist.interface.wrapper import GEOSPyMoistWrapper, MemorySpace - - -if TYPE_CHECKING: - import cffi +from pyMoist.interface.flags import gfdl_1m_flags_f_to_python, moist_flags_f_to_python +from pyMoist.interface.wrapper import ( + GEOSPyMoistWrapper, + MemorySpace, +) class PYMOIST_WRAPPER: @@ -23,12 +25,12 @@ def __init__(self) -> None: def init( self, - fv_flags: "cffi.FFI.CData", + pyMoist_flags: cffi.FFI.CData, backend: str = "dace:cpu", ) -> None: self.rank = MPI.COMM_WORLD.Get_rank() self.backend = backend - self.flags = flags_fv_to_python(fv_flags) + self.flags = moist_flags_f_to_python(pyMoist_flags) print(f"Moist Flags:\n{self.flags}") # For Fortran<->NumPy conversion if is_gpu_backend(self.backend): @@ -44,7 +46,7 @@ def init( numpy_module, ) - # Setup pyFV3's dynamical core + # Initalize pyMoist self.pymoist = GEOSPyMoistWrapper(self.flags, backend) self._timings: Dict[str, List[float]] = {} @@ -58,24 +60,24 @@ def finalize(self): def aer_activation( self, - f_aero_dgn: "cffi.FFI.CData", - f_aero_num: "cffi.FFI.CData", - f_aero_hygroscopicity: "cffi.FFI.CData", - f_aero_sigma: "cffi.FFI.CData", - f_frland: "cffi.FFI.CData", + f_aero_dgn: cffi.FFI.CData, + f_aero_num: cffi.FFI.CData, + f_aero_hygroscopicity: cffi.FFI.CData, + f_aero_sigma: cffi.FFI.CData, + f_frland: cffi.FFI.CData, f_nn_ocean: np.float32, f_nn_land: np.float32, - f_t: "cffi.FFI.CData", - f_plo: "cffi.FFI.CData", - f_qicn: "cffi.FFI.CData", - f_qils: "cffi.FFI.CData", - f_qlcn: "cffi.FFI.CData", - f_qlls: "cffi.FFI.CData", - f_vvel: "cffi.FFI.CData", - f_tke: "cffi.FFI.CData", - f_nacti: "cffi.FFI.CData", - f_nwfa: "cffi.FFI.CData", - f_nactl: "cffi.FFI.CData", + f_t: cffi.FFI.CData, + f_plo: cffi.FFI.CData, + f_qicn: cffi.FFI.CData, + f_qils: cffi.FFI.CData, + f_qlcn: cffi.FFI.CData, + f_qlls: cffi.FFI.CData, + f_vvel: cffi.FFI.CData, + f_tke: cffi.FFI.CData, + f_nacti: cffi.FFI.CData, + f_nwfa: cffi.FFI.CData, + f_nactl: cffi.FFI.CData, ): CUDAProfiler.start_cuda_profiler() with TimedCUDAProfiler("[AER] Fortran -> Python", self._timings): @@ -175,36 +177,36 @@ def aer_activation( self.f_py.python_to_fortran(nwfa, f_nwfa) self.f_py.python_to_fortran(nactl, f_nactl) - def GFDL_1M__EVAP_SUBL_HYSTPDF( + def GFDL_1M_evap_subl_hystpdf( self, - f_EIS: "cffi.FFI.CData", + f_EIS: cffi.FFI.CData, f_dw_land: np.float32, f_dw_ocean: np.float32, f_PDF_shape: np.int32, - f_TurnRHCrit_Param: "cffi.FFI.CData", - f_PLmb: "cffi.FFI.CData", - f_KLCL: "cffi.FFI.CData", - f_PLEmb: "cffi.FFI.CData", - f_Area: "cffi.FFI.CData", + f_TurnRHCrit_Param: cffi.FFI.CData, + f_PLmb: cffi.FFI.CData, + f_KLCL: cffi.FFI.CData, + f_PLEmb: cffi.FFI.CData, + f_Area: cffi.FFI.CData, f_dt_moist: np.float32, - f_CNV_FRC: "cffi.FFI.CData", - f_SRF_TYPE: "cffi.FFI.CData", - f_T: "cffi.FFI.CData", - f_QLCN: "cffi.FFI.CData", - f_QICN: "cffi.FFI.CData", - f_QLLS: "cffi.FFI.CData", - f_QILS: "cffi.FFI.CData", + f_CNV_FRC: cffi.FFI.CData, + f_SRF_TYPE: cffi.FFI.CData, + f_T: cffi.FFI.CData, + f_QLCN: cffi.FFI.CData, + f_QICN: cffi.FFI.CData, + f_QLLS: cffi.FFI.CData, + f_QILS: cffi.FFI.CData, f_CCW_EVAP_EFF: np.float32, f_CCI_EVAP_EFF: np.float32, - f_Q: "cffi.FFI.CData", - f_CLLS: "cffi.FFI.CData", - f_CLCN: "cffi.FFI.CData", - f_NACTL: "cffi.FFI.CData", - f_NACTI: "cffi.FFI.CData", - f_QST: "cffi.FFI.CData", - f_SUBLC: "cffi.FFI.CData", - f_EVAPC: "cffi.FFI.CData", - f_RHX: "cffi.FFI.CData", + f_Q: cffi.FFI.CData, + f_CLLS: cffi.FFI.CData, + f_CLCN: cffi.FFI.CData, + f_NACTL: cffi.FFI.CData, + f_NACTI: cffi.FFI.CData, + f_QST: cffi.FFI.CData, + f_SUBLC: cffi.FFI.CData, + f_EVAPC: cffi.FFI.CData, + f_RHX: cffi.FFI.CData, f_LMELTFRZ: bool = True, ): CUDAProfiler.start_cuda_profiler() @@ -263,7 +265,7 @@ def GFDL_1M__EVAP_SUBL_HYSTPDF( self.f_py.device_sync() with TimedCUDAProfiler("[GFDL_1M] Run", self._timings): - self.pymoist.gfdl_1M( + self.pymoist.GFDL_1M_evap( EIS=eis, dw_land=Float(f_dw_land), dw_ocean=Float(f_dw_ocean), @@ -316,11 +318,213 @@ def GFDL_1M__EVAP_SUBL_HYSTPDF( self.f_py.python_to_fortran(self.pymoist.gfdl_1M.evapc.view[:], f_EVAPC) self.f_py.python_to_fortran(self.pymoist.gfdl_1M.rhx.view[:], f_RHX) + def GFDL_1M_driver( + self, + f_qv: cffi.FFI.CData, + f_ql: cffi.FFI.CData, + f_qr: cffi.FFI.CData, + f_qi: cffi.FFI.CData, + f_qs: cffi.FFI.CData, + f_qg: cffi.FFI.CData, + f_qa: cffi.FFI.CData, + f_qn: cffi.FFI.CData, + f_qv_dt: cffi.FFI.CData, + f_ql_dt: cffi.FFI.CData, + f_qr_dt: cffi.FFI.CData, + f_qi_dt: cffi.FFI.CData, + f_qs_dt: cffi.FFI.CData, + f_qg_dt: cffi.FFI.CData, + f_qa_dt: cffi.FFI.CData, + f_t_dt: cffi.FFI.CData, + f_t: cffi.FFI.CData, + f_w: cffi.FFI.CData, + f_uin: cffi.FFI.CData, + f_vin: cffi.FFI.CData, + f_udt: cffi.FFI.CData, + f_vdt: cffi.FFI.CData, + f_dz: cffi.FFI.CData, + f_dp: cffi.FFI.CData, + f_area: cffi.FFI.CData, + f_fr_land: cffi.FFI.CData, + f_cnv_frc: cffi.FFI.CData, + f_srf_type: cffi.FFI.CData, + f_eis: cffi.FFI.CData, + f_rhcrit3d: cffi.FFI.CData, + f_anv_icefall: np.float32, + f_ls_icefall: np.float32, + f_hydrostatic: bool, + f_phys_hydrostatic: bool, + f_rain: cffi.FFI.CData, + f_snow: cffi.FFI.CData, + f_ice: cffi.FFI.CData, + f_graupel: cffi.FFI.CData, + f_m2_rain: cffi.FFI.CData, + f_m2_sol: cffi.FFI.CData, + f_revap: cffi.FFI.CData, + f_isubl: cffi.FFI.CData, + ): + CUDAProfiler.start_cuda_profiler() + + with TimedCUDAProfiler("[GFDL_1M] Fortran -> Python", self._timings): + qv = self.f_py.fortran_to_python(f_qv) + ql = self.f_py.fortran_to_python(f_ql) + qr = self.f_py.fortran_to_python(f_qr) + qi = self.f_py.fortran_to_python(f_qi) + qs = self.f_py.fortran_to_python(f_qs) + qg = self.f_py.fortran_to_python(f_qg) + qa = self.f_py.fortran_to_python(f_qa) + qn = self.f_py.fortran_to_python(f_qn) + qv_dt = self.f_py.fortran_to_python(f_qv_dt) + ql_dt = self.f_py.fortran_to_python(f_ql_dt) + qr_dt = self.f_py.fortran_to_python(f_qr_dt) + qi_dt = self.f_py.fortran_to_python(f_qi_dt) + qs_dt = self.f_py.fortran_to_python(f_qs_dt) + qg_dt = self.f_py.fortran_to_python(f_qg_dt) + qa_dt = self.f_py.fortran_to_python(f_qa_dt) + t_dt = self.f_py.fortran_to_python(f_t_dt) + t = self.f_py.fortran_to_python(f_t) + w = self.f_py.fortran_to_python(f_w) + uin = self.f_py.fortran_to_python(f_uin) + vin = self.f_py.fortran_to_python(f_vin) + udt = self.f_py.fortran_to_python(f_udt) + vdt = self.f_py.fortran_to_python(f_vdt) + dz = self.f_py.fortran_to_python(f_dz) + dp = self.f_py.fortran_to_python(f_dp) + area = self.f_py.fortran_to_python( + f_area, + [ + self.flags.npx, + self.flags.npy, + ], + ) + fr_land = self.f_py.fortran_to_python( + f_fr_land, + [ + self.flags.npx, + self.flags.npy, + ], + ) + cnv_frc = self.f_py.fortran_to_python( + f_cnv_frc, + [ + self.flags.npx, + self.flags.npy, + ], + ) + srf_type = self.f_py.fortran_to_python( + f_srf_type, + [ + self.flags.npx, + self.flags.npy, + ], + ) + eis = self.f_py.fortran_to_python( + f_eis, + [ + self.flags.npx, + self.flags.npy, + ], + ) + rhcrit3d = self.f_py.fortran_to_python(f_rhcrit3d) + + self.f_py.device_sync() + + with TimedCUDAProfiler("[GFDL_1M] Run", self._timings): + self.pymoist.GFDL_1M_driver( + qv=qv, + ql=ql, + qr=qr, + qi=qi, + qs=qs, + qg=qg, + qa=qa, + qn=qn, # NACTL + NACTI + qv_dt=qv_dt, + ql_dt=ql_dt, + qr_dt=qr_dt, + qi_dt=qi_dt, + qs_dt=qs_dt, + qg_dt=qg_dt, + qa_dt=qa_dt, + t_dt=t_dt, + t=t, + w=w, + uin=uin, + vin=vin, + udt=udt, + vdt=vdt, + dz=dz, + dp=dp, + area=area, + fr_land=fr_land, + cnv_frc=cnv_frc, + srf_type=srf_type, + eis=eis, + rhcrit3d=rhcrit3d, + anv_icefall=Float(f_anv_icefall), + ls_icefall=Float(f_ls_icefall), + ) + + # Convert NumPy arrays back to Fortran + with TimedCUDAProfiler("[GFDL_1M] Python -> Fortran", self._timings): + self.f_py.python_to_fortran(qv, f_qv) + self.f_py.python_to_fortran(ql, f_ql) + self.f_py.python_to_fortran(qr, f_qr) + self.f_py.python_to_fortran(qi, f_qi) + self.f_py.python_to_fortran(qs, f_qs) + self.f_py.python_to_fortran(qg, f_qg) + self.f_py.python_to_fortran(qa, f_qa) + self.f_py.python_to_fortran(qn, f_qn) + self.f_py.python_to_fortran(qv_dt, f_qv_dt) + self.f_py.python_to_fortran(ql_dt, f_ql_dt) + self.f_py.python_to_fortran(qr_dt, f_qr_dt) + self.f_py.python_to_fortran(qi_dt, f_qi_dt) + self.f_py.python_to_fortran(qs_dt, f_qs_dt) + self.f_py.python_to_fortran(qg_dt, f_qg_dt) + self.f_py.python_to_fortran(qa_dt, f_qa_dt) + self.f_py.python_to_fortran(t_dt, f_t_dt) + self.f_py.python_to_fortran(t, f_t) + self.f_py.python_to_fortran(w, f_w) + self.f_py.python_to_fortran(uin, f_uin) + self.f_py.python_to_fortran(vin, f_vin) + self.f_py.python_to_fortran(udt, f_udt) + self.f_py.python_to_fortran(vdt, f_vdt) + self.f_py.python_to_fortran(dz, f_dz) + self.f_py.python_to_fortran(dp, f_dp) + self.f_py.python_to_fortran(area, f_area) + self.f_py.python_to_fortran(fr_land, f_fr_land) + self.f_py.python_to_fortran(cnv_frc, f_cnv_frc) + self.f_py.python_to_fortran(srf_type, f_srf_type) + self.f_py.python_to_fortran(eis, f_eis) + self.f_py.python_to_fortran(rhcrit3d, f_rhcrit3d) + self.f_py.python_to_fortran( + self.pymoist.GFDL_1M_driver.rain.view[:], f_rain + ) + self.f_py.python_to_fortran( + self.pymoist.GFDL_1M_driver.snow.view[:], f_snow + ) + self.f_py.python_to_fortran(self.pymoist.GFDL_1M_driver.ice.view[:], f_ice) + self.f_py.python_to_fortran( + self.pymoist.GFDL_1M_driver.graupel.view[:], f_graupel + ) + self.f_py.python_to_fortran( + self.pymoist.GFDL_1M_driver.m2_rain.view[:], f_m2_rain + ) + self.f_py.python_to_fortran( + self.pymoist.GFDL_1M_driver.m2_sol.view[:], f_m2_sol + ) + self.f_py.python_to_fortran( + self.pymoist.GFDL_1M_driver.revap.view[:], f_revap + ) + self.f_py.python_to_fortran( + self.pymoist.GFDL_1M_driver.isubl.view[:], f_isubl + ) + WRAPPER = PYMOIST_WRAPPER() -def pyMoist_run_GFDL1M( +def pyMoist_run_GFDL_1M_evap_subl_hystpdf( dw_land: np.float32, dw_ocean: np.float32, PDFSHAPE: np.int32, @@ -329,31 +533,31 @@ def pyMoist_run_GFDL1M( CCW_EVAP_EFF: np.float32, CCI_EVAP_EFF: np.float32, LMELTFRZ: bool, - AREA: "cffi.FFI.CData", - CNV_FRC: "cffi.FFI.CData", - SRF_TYPE: "cffi.FFI.CData", - KLCL: "cffi.FFI.CData", - EIS: "cffi.FFI.CData", - PLmb: "cffi.FFI.CData", - PLEmb: "cffi.FFI.CData", - NACTL: "cffi.FFI.CData", - NACTI: "cffi.FFI.CData", - QST: "cffi.FFI.CData", - T: "cffi.FFI.CData", - Q: "cffi.FFI.CData", - QLCN: "cffi.FFI.CData", - QICN: "cffi.FFI.CData", - QLLS: "cffi.FFI.CData", - QILS: "cffi.FFI.CData", - CLLS: "cffi.FFI.CData", - CLCN: "cffi.FFI.CData", - SUBLC: "cffi.FFI.CData", - EVAPC: "cffi.FFI.CData", - RHX: "cffi.FFI.CData", + AREA: cffi.FFI.CData, + CNV_FRC: cffi.FFI.CData, + SRF_TYPE: cffi.FFI.CData, + KLCL: cffi.FFI.CData, + EIS: cffi.FFI.CData, + PLmb: cffi.FFI.CData, + PLEmb: cffi.FFI.CData, + NACTL: cffi.FFI.CData, + NACTI: cffi.FFI.CData, + QST: cffi.FFI.CData, + T: cffi.FFI.CData, + Q: cffi.FFI.CData, + QLCN: cffi.FFI.CData, + QICN: cffi.FFI.CData, + QLLS: cffi.FFI.CData, + QILS: cffi.FFI.CData, + CLLS: cffi.FFI.CData, + CLCN: cffi.FFI.CData, + SUBLC: cffi.FFI.CData, + EVAPC: cffi.FFI.CData, + RHX: cffi.FFI.CData, ): if not WRAPPER.ready: raise RuntimeError("[pyMoist] Bad init, did you call init?") - WRAPPER.GFDL_1M__EVAP_SUBL_HYSTPDF( + WRAPPER.GFDL_1M_evap_subl_hystpdf( f_EIS=EIS, f_dw_land=dw_land, f_dw_ocean=dw_ocean, @@ -386,25 +590,119 @@ def pyMoist_run_GFDL1M( ) +def pymoist_run_GFDL_1M_driver( + RAD_QV: cffi.FFI.CData, + RAD_QL: cffi.FFI.CData, + RAD_QR: cffi.FFI.CData, + RAD_QI: cffi.FFI.CData, + RAD_QS: cffi.FFI.CData, + RAD_QG: cffi.FFI.CData, + RAD_CF: cffi.FFI.CData, + NACTAll: cffi.FFI.CData, + DQVDTmic: cffi.FFI.CData, + DQLDTmic: cffi.FFI.CData, + DQRDTmic: cffi.FFI.CData, + DQIDTmic: cffi.FFI.CData, + DQSDTmic: cffi.FFI.CData, + DQGDTmic: cffi.FFI.CData, + DQADTmic: cffi.FFI.CData, + DTDTmic: cffi.FFI.CData, + T: cffi.FFI.CData, + W: cffi.FFI.CData, + U: cffi.FFI.CData, + V: cffi.FFI.CData, + DUDTmic: cffi.FFI.CData, + DVDTmic: cffi.FFI.CData, + DZ: cffi.FFI.CData, + DP: cffi.FFI.CData, + AREA: cffi.FFI.CData, + FRLAND: cffi.FFI.CData, + CNV_FRC: cffi.FFI.CData, + SRF_TYPE: cffi.FFI.CData, + EIS: cffi.FFI.CData, + RHCRIT3D: cffi.FFI.CData, + DT_MOIST: np.float32, + ANV_ICEFALL: np.float32, + LS_ICEFALL: np.float32, + REV_LS: cffi.FFI.CData, + RSU_LS: cffi.FFI.CData, + PRCP_RAIN: cffi.FFI.CData, + PRCP_SNOW: cffi.FFI.CData, + PRCP_ICE: cffi.FFI.CData, + PRCP_GRAUPEL: cffi.FFI.CData, + PFL_LS: cffi.FFI.CData, + PFI_LS: cffi.FFI.CData, + LHYDROSTATIC: bool, + LPHYS_HYDROSTATIC: bool, +): + if not WRAPPER.ready: + raise RuntimeError("[pyMoist] Bad init, did you call init?") + + WRAPPER.GFDL_1M_driver( + f_qv=RAD_QV, + f_ql=RAD_QL, + f_qr=RAD_QR, + f_qi=RAD_QI, + f_qs=RAD_QS, + f_qg=RAD_QG, + f_qa=RAD_CF, + f_qn=NACTAll, + f_qv_dt=DQVDTmic, + f_ql_dt=DQLDTmic, + f_qr_dt=DQRDTmic, + f_qi_dt=DQIDTmic, + f_qs_dt=DQSDTmic, + f_qg_dt=DQGDTmic, + f_qa_dt=DQADTmic, + f_t_dt=DTDTmic, + f_t=T, + f_w=W, + f_uin=U, + f_vin=V, + f_udt=DUDTmic, + f_vdt=DVDTmic, + f_dz=DZ, + f_dp=DP, + f_area=AREA, + f_fr_land=FRLAND, + f_cnv_frc=CNV_FRC, + f_srf_type=SRF_TYPE, + f_eis=EIS, + f_rhcrit3d=RHCRIT3D, + f_anv_icefall=ANV_ICEFALL, + f_ls_icefall=LS_ICEFALL, + f_hydrostatic=LHYDROSTATIC, + f_phys_hydrostatic=LPHYS_HYDROSTATIC, + f_rain=PRCP_RAIN, + f_snow=PRCP_SNOW, + f_ice=PRCP_ICE, + f_graupel=PRCP_GRAUPEL, + f_m2_rain=PFL_LS, + f_m2_sol=PFI_LS, + f_revap=REV_LS, + f_isubl=RSU_LS, + ) + + def pyMoist_run_AerActivation( - aero_dgn: "cffi.FFI.CData", - aero_num: "cffi.FFI.CData", - aero_hygroscopicity: "cffi.FFI.CData", - aero_sigma: "cffi.FFI.CData", - frland: "cffi.FFI.CData", + aero_dgn: cffi.FFI.CData, + aero_num: cffi.FFI.CData, + aero_hygroscopicity: cffi.FFI.CData, + aero_sigma: cffi.FFI.CData, + frland: cffi.FFI.CData, nn_ocean: np.float32, nn_land: np.float32, - t: "cffi.FFI.CData", - plo: "cffi.FFI.CData", - qicn: "cffi.FFI.CData", - qils: "cffi.FFI.CData", - qlcn: "cffi.FFI.CData", - qlls: "cffi.FFI.CData", - vvel: "cffi.FFI.CData", - tke: "cffi.FFI.CData", - nacti: "cffi.FFI.CData", - nwfa: "cffi.FFI.CData", - nactl: "cffi.FFI.CData", + t: cffi.FFI.CData, + plo: cffi.FFI.CData, + qicn: cffi.FFI.CData, + qils: cffi.FFI.CData, + qlcn: cffi.FFI.CData, + qlls: cffi.FFI.CData, + vvel: cffi.FFI.CData, + tke: cffi.FFI.CData, + nacti: cffi.FFI.CData, + nwfa: cffi.FFI.CData, + nactl: cffi.FFI.CData, ): if not WRAPPER.ready: raise RuntimeError("[GEOS WRAPPER] Bad init, did you call init?") @@ -435,12 +733,20 @@ def pyMoist_finalize(): WRAPPER.finalize() -def pyMoist_init(fv_flags: "cffi.FFI.CData"): +def pyMoist_init(pyMoist_flags: cffi.FFI.CData): # Read in the backend BACKEND = os.environ.get("GEOS_PYFV3_BACKEND", "dace:cpu") if WRAPPER.ready: raise RuntimeError("[PYMOIST WRAPPER] Double init") WRAPPER.init( - fv_flags=fv_flags, + pyMoist_flags=pyMoist_flags, backend=BACKEND, ) + + +def gfdl_1m_init(gfdl_1m_flags: cffi.FFI.CData): + if not WRAPPER.ready: + raise RuntimeError("[GFDL_1M WRAPPER] pyMoist_init needs to be called first") + WRAPPER.pymoist.init_gfdl_1m_flags( + flags=gfdl_1m_flags_f_to_python(gfdl_1m_flags), + ) diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/wrapper.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/wrapper.py index 44ffc9bdb..b9763e1b0 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/wrapper.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/interface/wrapper.py @@ -5,6 +5,7 @@ import enum import logging import os +from typing import Callable, Optional from gt4py.cartesian.config import build_settings as gt_build_settings from mpi4py import MPI @@ -16,6 +17,7 @@ DaceConfig, DaCeOrchestration, GridIndexing, + MPIComm, NullComm, PerformanceCollector, QuantityFactory, @@ -32,7 +34,9 @@ from ndsl.optional_imports import cupy as cp from pyMoist.aer_activation import AerActivation from pyMoist.GFDL_1M.GFDL_1M import GFDL_1M -from pyMoist.interface.flags import MoistFlags +from pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver import GFDL_1M_driver +from pyMoist.interface.flags import gfdl_1m_flags, moist_flags +import numpy as np class MemorySpace(enum.Enum): @@ -79,6 +83,7 @@ def __enter__(self): else: ndsl_log.info(f"Stencil backend waits on {self.comm.Get_rank()}") self.comm.Barrier() + ndsl_log.info(f"Stencil backend released on {self.comm.Get_rank()}") def __exit__(self, type, value, traceback): if self.no_op: @@ -86,20 +91,23 @@ def __exit__(self, type, value, traceback): if not self.config.do_compile: ndsl_log.info(f"Stencil backend read cache on {self.comm.Get_rank()}") else: - ndsl_log.info(f"Stencil backend compiled on {self.comm.Get_rank()}") + ndsl_log.info( + f"Stencil backend was compiled on {self.comm.Get_rank()} now waiting for other ranks" + ) self.comm.Barrier() + ndsl_log.info(f"Rank {self.comm.Get_rank()} ready for execution") class GEOSPyMoistWrapper: def __init__( self, - flags: MoistFlags, + flags: moist_flags, backend="numpy", fortran_mem_space: MemorySpace = MemorySpace.HOST, ) -> None: # Look for an override to run on a single node single_rank_override = int(os.getenv("GEOS_PYFV3_SINGLE_RANK_OVERRIDE", -1)) - comm = MPI.COMM_WORLD + comm = MPIComm() if single_rank_override >= 0: comm = NullComm(single_rank_override, 6, 42) @@ -125,12 +133,14 @@ def __init__( tile_partitioner=partitioner.tile, tile_rank=self.communicator.tile.rank, ) - quantity_factory = QuantityFactory.from_backend(sizer=sizer, backend=backend) + self.quantity_factory = QuantityFactory.from_backend( + sizer=sizer, backend=backend + ) self.nmodes_quantity_factory = AerActivation.make_nmodes_quantity_factory( - quantity_factory + self.quantity_factory ) - stencil_config = StencilConfig( + self.stencil_config = StencilConfig( compilation_config=CompilationConfig( backend=backend, rebuild=False, validate_args=True ), @@ -139,42 +149,23 @@ def __init__( # Build a DaCeConfig for orchestration. # This and all orchestration code are transparent when outside # configuration deactivate orchestration - stencil_config.dace_config = DaceConfig( + self.stencil_config.dace_config = DaceConfig( communicator=self.communicator, - backend=stencil_config.backend, + backend=self.stencil_config.backend, tile_nx=self.flags.npx * self.flags.layout_x, tile_nz=self.flags.npz, ) - self._is_orchestrated = stencil_config.dace_config.is_dace_orchestrated() + self._is_orchestrated = self.stencil_config.dace_config.is_dace_orchestrated() # TODO: Orchestrate all code called from this function self._grid_indexing = GridIndexing.from_sizer_and_communicator( sizer=sizer, comm=self.communicator ) - stencil_factory = StencilFactory( - config=stencil_config, grid_indexing=self._grid_indexing + self.stencil_factory = StencilFactory( + config=self.stencil_config, grid_indexing=self._grid_indexing ) - with StencilBackendCompilerOverride( - MPI.COMM_WORLD, - stencil_config.dace_config, - ): - self.aer_activation = AerActivation( - stencil_factory=stencil_factory, - quantity_factory=quantity_factory, - n_modes=flags.n_modes, - USE_AERSOL_NN=True, - ) - print( - "[PYMOIST] Defaulted to SaturationFormulation.Staars" - "for QSat in GFDL_1M" - ) - self.gfdl_1M = GFDL_1M( - stencil_factory=stencil_factory, - quantity_factory=quantity_factory, - ) - self._fortran_mem_space = fortran_mem_space self._pace_mem_space = ( MemorySpace.DEVICE if is_gpu_backend(backend) else MemorySpace.HOST @@ -205,6 +196,147 @@ def __init__( f" Nvidia MPS : {MPS_is_on}" ) + # JIT system for the component of Moist + self._aer_activation: Optional[AerActivation] = None + self._GFDL_1M_evap: Optional[GFDL_1M] = None + self._GFDL_1M_driver: Optional[GFDL_1M_driver] = None + + # Initalize flags later + self.gfdl_1m_flags: Optional[gfdl_1m_flags] = None + + @property + def GFDL_1M_driver(self) -> Callable: + if not self._GFDL_1M_driver: + if self.gfdl_1m_flags is None: + raise RuntimeError("GFDL_1M flags not initalized") + with StencilBackendCompilerOverride( + MPI.COMM_WORLD, + self.stencil_config.dace_config, + ): + self._GFDL_1M_driver = GFDL_1M_driver( + self.stencil_factory, + self.quantity_factory, + self.gfdl_1m_flags.phys_hydrostatic, + self.gfdl_1m_flags.hydrostatic, + self.gfdl_1m_flags.dt_moist, + # Namelist options + self.gfdl_1m_flags.mp_time, + self.gfdl_1m_flags.t_min, + self.gfdl_1m_flags.t_sub, + self.gfdl_1m_flags.tau_r2g, + self.gfdl_1m_flags.tau_smlt, + self.gfdl_1m_flags.tau_g2r, + self.gfdl_1m_flags.dw_land, + self.gfdl_1m_flags.dw_ocean, + self.gfdl_1m_flags.vi_fac, + self.gfdl_1m_flags.vr_fac, + self.gfdl_1m_flags.vs_fac, + self.gfdl_1m_flags.vg_fac, + self.gfdl_1m_flags.ql_mlt, + self.gfdl_1m_flags.do_qa, + self.gfdl_1m_flags.fix_negative, + self.gfdl_1m_flags.vi_max, + self.gfdl_1m_flags.vs_max, + self.gfdl_1m_flags.vg_max, + self.gfdl_1m_flags.vr_max, + self.gfdl_1m_flags.qs_mlt, + self.gfdl_1m_flags.qs0_crt, + self.gfdl_1m_flags.qi_gen, + self.gfdl_1m_flags.ql0_max, + self.gfdl_1m_flags.qi0_max, + self.gfdl_1m_flags.qi0_crt, + self.gfdl_1m_flags.qr0_crt, + self.gfdl_1m_flags.fast_sat_adj, + self.gfdl_1m_flags.rh_inc, + self.gfdl_1m_flags.rh_ins, + self.gfdl_1m_flags.rh_inr, + self.gfdl_1m_flags.const_vi, + self.gfdl_1m_flags.const_vs, + self.gfdl_1m_flags.const_vg, + self.gfdl_1m_flags.const_vr, + self.gfdl_1m_flags.use_ccn, + self.gfdl_1m_flags.rthreshu, + self.gfdl_1m_flags.rthreshs, + self.gfdl_1m_flags.ccn_l, + self.gfdl_1m_flags.ccn_o, + self.gfdl_1m_flags.qc_crt, + self.gfdl_1m_flags.tau_g2v, + self.gfdl_1m_flags.tau_v2g, + self.gfdl_1m_flags.tau_s2v, + self.gfdl_1m_flags.tau_v2s, + self.gfdl_1m_flags.tau_revp, + self.gfdl_1m_flags.tau_frz, + self.gfdl_1m_flags.do_bigg, + self.gfdl_1m_flags.do_evap, + self.gfdl_1m_flags.do_subl, + self.gfdl_1m_flags.sat_adj0, + self.gfdl_1m_flags.c_piacr, + self.gfdl_1m_flags.tau_imlt, + self.gfdl_1m_flags.tau_v2l, + self.gfdl_1m_flags.tau_l2v, + self.gfdl_1m_flags.tau_i2v, + self.gfdl_1m_flags.tau_i2s, + self.gfdl_1m_flags.tau_l2r, + self.gfdl_1m_flags.qi_lim, + self.gfdl_1m_flags.ql_gen, + self.gfdl_1m_flags.c_paut, + self.gfdl_1m_flags.c_psaci, + self.gfdl_1m_flags.c_pgacs, + self.gfdl_1m_flags.c_pgaci, + self.gfdl_1m_flags.z_slope_liq, + self.gfdl_1m_flags.z_slope_ice, + self.gfdl_1m_flags.prog_ccn, + self.gfdl_1m_flags.c_cracw, + self.gfdl_1m_flags.alin, + self.gfdl_1m_flags.clin, + self.gfdl_1m_flags.preciprad, + self.gfdl_1m_flags.cld_min, + self.gfdl_1m_flags.use_ppm, + self.gfdl_1m_flags.mono_prof, + self.gfdl_1m_flags.do_sedi_heat, + self.gfdl_1m_flags.sedi_transport, + self.gfdl_1m_flags.do_sedi_w, + self.gfdl_1m_flags.de_ice, + np.int32(self.gfdl_1m_flags.icloud_f), + np.int32(self.gfdl_1m_flags.irain_f), + self.gfdl_1m_flags.mp_print, + ) + return self._GFDL_1M_driver + + def init_gfdl_1m_flags( + self, + flags, + ): + self.gfdl_1m_flags = flags + + @property + def aer_activation(self) -> Callable: + if not self._aer_activation: + with StencilBackendCompilerOverride( + MPI.COMM_WORLD, + self.stencil_config.dace_config, + ): + self._aer_activation = AerActivation( + stencil_factory=self.stencil_factory, + quantity_factory=self.quantity_factory, + n_modes=self.flags.n_modes, + USE_AERSOL_NN=True, + ) + return self._aer_activation + + @property + def GFDL_1M_evap(self) -> Callable: + if not self._GFDL_1M_evap: + with StencilBackendCompilerOverride( + MPI.COMM_WORLD, + self.stencil_config.dace_config, + ): + self._GFDL_1M_evap = GFDL_1M( + stencil_factory=self.stencil_factory, + quantity_factory=self.quantity_factory, + ) + return self._GFDL_1M_evap + def make_nmmodes_quantity(self, data): qty = self.nmodes_quantity_factory.empty( [X_DIM, Y_DIM, Z_DIM, "n_modes"], diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/saturation/qsat.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/saturation/qsat.py index 88032b9b8..35610d7fc 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/saturation/qsat.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/saturation/qsat.py @@ -47,6 +47,7 @@ def QSat_Float_Liquid( PL: Float = -999.0, DQ_trigger: bool = False, ): + DQ = 0.0 # qsatlqu.code with UTBL = True if TL <= TMINLQU: QS = estlqu @@ -90,6 +91,7 @@ def QSat_Float_Ice( PL: Float = -999.0, DQ_trigger: bool = False, ): + DQ = 0.0 # qsatice.code with UTBL = True if TL <= TMINTBL: QS = ese[0][0] # type: ignore @@ -137,6 +139,7 @@ def QSat_Float( RAMP_trigger: bool = False, DQSAT_trigger: bool = False, ): + DQ = 0.0 if RAMP_trigger: URAMP = -abs(RAMP) else: diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/shared_fundamental_math.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/shared_generic_math.py similarity index 76% rename from GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/shared_fundamental_math.py rename to GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/shared_generic_math.py index 311cd94b0..b35f40d27 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/shared_fundamental_math.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/shared_generic_math.py @@ -3,6 +3,7 @@ meteorological quantities""" import gt4py.cartesian.gtscript as gtscript +from gt4py.cartesian.gtscript import exp import pyMoist.constants as constants from ndsl.dsl.typing import Float @@ -22,3 +23,9 @@ def air_density(PL: Float, TE: Float) -> Float: """ air_density = (100.0 * PL) / (constants.MAPL_RDRY * TE) return air_density + + +@gtscript.function +def sigma(dx) -> Float: + sigma = 1.0 - 0.9839 * exp(-0.09835 * (dx / 1000.0)) # Arakawa 2011 sigma + return sigma diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/shared_incloud_processes.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/shared_incloud_processes.py index 19d13d8de..5e8b51df6 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/shared_incloud_processes.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/pyMoist/shared_incloud_processes.py @@ -7,6 +7,7 @@ import pyMoist.constants as constants from ndsl.dsl.typing import Float, FloatField +from pyMoist.shared_generic_math import air_density @gtscript.function @@ -124,7 +125,7 @@ def cloud_effective_radius_liquid( """ # Calculate liquid water content WC = ( - 1.0e3 * (100.0 * PL) / (constants.MAPL_RDRY * TE) * QC + 1.0e3 * air_density(PL, TE) * QC ) # air density [g/m3] * liquid cloud mixing ratio [kg/kg] # Calculate cloud drop number concentration from the aerosol model + .... NNX = max(NNL * 1.0e-6, 10.0) @@ -177,7 +178,7 @@ def cloud_effective_radius_ice( """ # Calculate ice water content WC = ( - 1.0e3 * (100.0 * PL) / (constants.MAPL_RDRY * TE) * QC + 1.0e3 * air_density(PL, TE) * QC ) # air density [g/m3] * ice cloud mixing ratio [kg/kg] # Calculate radius in meters [m] if constants.ICE_RADII_PARAM == 1: diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_GFDL_1M_driver.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_GFDL_1M_driver.py new file mode 100644 index 000000000..2c1696d78 --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_GFDL_1M_driver.py @@ -0,0 +1,463 @@ +from ndsl import Namelist, Quantity, StencilFactory +from ndsl.constants import X_DIM, Y_DIM, Z_DIM +from ndsl.dsl.typing import Float, Int +from ndsl.stencils.testing.translate import TranslateFortranData2Py +from pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver import GFDL_1M_driver + + +class TranslateGFDL_1M_driver(TranslateFortranData2Py): + def __init__(self, grid, namelist: Namelist, stencil_factory: StencilFactory): + super().__init__(grid, stencil_factory) + self.stencil_factory = stencil_factory + self.quantity_factory = grid.quantity_factory + self._grid = grid + + # FloatField Inputs + self.in_vars["data_vars"] = { + "RAD_QV": {}, + "RAD_QL": {}, + "RAD_QR": {}, + "RAD_QI": {}, + "RAD_QS": {}, + "RAD_QG": {}, + "RAD_CF": {}, + "NACTLI": {}, + "DQVDTmic": {}, + "DQLDTmic": {}, + "DQRDTmic": {}, + "DQIDTmic": {}, + "DQSDTmic": {}, + "DQGDTmic": {}, + "DQADTmic": {}, + "DTDTmic": {}, + "T": {}, + "W": {}, + "U": {}, + "V": {}, + "DUDTmic": {}, + "DVDTmic": {}, + "DZ": {}, + "DP": {}, + "AREA": {}, + "FRLAND": {}, + "CNV_FRC": {}, + "SRF_TYPE": {}, + "EIS": {}, + "RHCRIT3D": {}, + "REV_LS": {}, + "RSU_LS": {}, + "PRCP_RAIN": {}, + "PRCP_SNOW": {}, + "PRCP_ICE": {}, + "PRCP_GRAUPEL": {}, + "PFL_LS": {}, + "PFI_LS": {}, + "KBOT": {}, + "KTOP": {}, + } + + # Float Inputs + self.in_vars["parameters"] = [ + "DT_MOIST", + "ANV_ICEFALL", + "LS_ICEFALL", + "LHYDROSTATIC", + "LPHYS_HYDROSTATIC", + # Namelist options + "mp_time", + "t_min", + "t_sub", + "tau_r2g", + "tau_smlt", + "tau_g2r", + "dw_land", + "dw_ocean", + "vi_fac", + "vr_fac", + "vs_fac", + "vg_fac", + "ql_mlt", + "do_qa", + "fix_negative", + "vi_max", + "vs_max", + "vg_max", + "vr_max", + "qs_mlt", + "qs0_crt", + "qi_gen", + "ql0_max", + "qi0_max", + "qi0_crt", + "qr0_crt", + "fast_sat_adj", + "rh_inc", + "rh_ins", + "rh_inr", + "const_vi", + "const_vs", + "const_vg", + "const_vr", + "use_ccn", + "rthreshu", + "rthreshs", + "ccn_l", + "ccn_o", + "qc_crt", + "tau_g2v", + "tau_v2g", + "tau_s2v", + "tau_v2s", + "tau_revp", + "tau_frz", + "do_bigg", + "do_evap", + "do_subl", + "sat_adj0", + "c_piacr", + "tau_imlt", + "tau_v2l", + "tau_l2v", + "tau_i2v", + "tau_i2s", + "tau_l2r", + "qi_lim", + "ql_gen", + "c_paut", + "c_psaci", + "c_pgacs", + "c_pgaci", + "z_slope_liq", + "z_slope_ice", + "prog_ccn", + "c_cracw", + "alin", + "clin", + "preciprad", + "cld_min", + "use_ppm", + "mono_prof", + "do_sedi_heat", + "sedi_transport", + "do_sedi_w", + "de_ice", + "icloud_f", + "irain_f", + "mp_print", + ] + + # FloatField Outputs + self.out_vars = { + "DQADTmic": self.grid.compute_dict(), + "DTDTmic": self.grid.compute_dict(), + "DUDTmic": self.grid.compute_dict(), + "DVDTmic": self.grid.compute_dict(), + "W": self.grid.compute_dict(), + "DQVDTmic": self.grid.compute_dict(), + "DQLDTmic": self.grid.compute_dict(), + "DQRDTmic": self.grid.compute_dict(), + "DQIDTmic": self.grid.compute_dict(), + "DQSDTmic": self.grid.compute_dict(), + "DQGDTmic": self.grid.compute_dict(), + "PRCP_RAIN": self.grid.compute_dict(), + "PRCP_SNOW": self.grid.compute_dict(), + "PRCP_ICE": self.grid.compute_dict(), + "PRCP_GRAUPEL": self.grid.compute_dict(), + "PFL_LS": self.grid.compute_dict(), + "PFI_LS": self.grid.compute_dict(), + "REV_LS": self.grid.compute_dict(), + "RSU_LS": self.grid.compute_dict(), + } + + def make_ij_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM], + "n/a", + ) + qty.view[:, :] = qty.np.asarray(data[:, :]) + return qty + + def make_ijk_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM, Z_DIM], + "n/a", + ) + qty.view[:, :, :] = qty.np.asarray(data[:, :, :]) + return qty + + def compute(self, inputs): + # FloatField Variables + RAD_QV = self.make_ijk_field(inputs["RAD_QV"]) + RAD_QL = self.make_ijk_field(inputs["RAD_QL"]) + RAD_QR = self.make_ijk_field(inputs["RAD_QR"]) + RAD_QI = self.make_ijk_field(inputs["RAD_QI"]) + RAD_QS = self.make_ijk_field(inputs["RAD_QS"]) + RAD_QG = self.make_ijk_field(inputs["RAD_QG"]) + RAD_CF = self.make_ijk_field(inputs["RAD_CF"]) + NACTLI = self.make_ijk_field(inputs["NACTLI"]) + DQVDTmic = self.make_ijk_field(inputs["DQVDTmic"]) + DQLDTmic = self.make_ijk_field(inputs["DQLDTmic"]) + DQRDTmic = self.make_ijk_field(inputs["DQRDTmic"]) + DQIDTmic = self.make_ijk_field(inputs["DQIDTmic"]) + DQSDTmic = self.make_ijk_field(inputs["DQSDTmic"]) + DQGDTmic = self.make_ijk_field(inputs["DQGDTmic"]) + DQADTmic = self.make_ijk_field(inputs["DQADTmic"]) + DTDTmic = self.make_ijk_field(inputs["DTDTmic"]) + T = self.make_ijk_field(inputs["T"]) + W = self.make_ijk_field(inputs["W"]) + U = self.make_ijk_field(inputs["U"]) + V = self.make_ijk_field(inputs["V"]) + DUDTmic = self.make_ijk_field(inputs["DUDTmic"]) + DVDTmic = self.make_ijk_field(inputs["DVDTmic"]) + DZ = self.make_ijk_field(inputs["DZ"]) + DP = self.make_ijk_field(inputs["DP"]) + AREA = self.make_ij_field(inputs["AREA"]) + FRLAND = self.make_ij_field(inputs["FRLAND"]) + CNV_FRC = self.make_ij_field(inputs["CNV_FRC"]) + SRF_TYPE = self.make_ij_field(inputs["SRF_TYPE"]) + EIS = self.make_ij_field(inputs["EIS"]) + RHCRIT3D = self.make_ijk_field(inputs["RHCRIT3D"]) + REV_LS = self.make_ijk_field(inputs["REV_LS"]) + RSU_LS = self.make_ijk_field(inputs["RSU_LS"]) + PRCP_RAIN = self.make_ij_field(inputs["PRCP_RAIN"]) + PRCP_SNOW = self.make_ij_field(inputs["PRCP_SNOW"]) + PRCP_ICE = self.make_ij_field(inputs["PRCP_ICE"]) + PRCP_GRAUPEL = self.make_ij_field(inputs["PRCP_GRAUPEL"]) + PFL_LS = self.make_ijk_field(inputs["PFL_LS"]) + PFI_LS = self.make_ijk_field(inputs["PFI_LS"]) + + # Point Variables + DT_MOIST = Float(inputs["DT_MOIST"]) + ANV_ICEFALL = Float(inputs["ANV_ICEFALL"]) + LS_ICEFALL = Float(inputs["LS_ICEFALL"]) + LHYDROSTATIC = bool(inputs["LHYDROSTATIC"]) + LPHYS_HYDROSTATIC = bool(inputs["LPHYS_HYDROSTATIC"]) + KBOT = Int(inputs["KBOT"]) + KTOP = Int(inputs["KTOP"]) + # Namelist options + mp_time = Float(inputs["mp_time"]) + t_min = Float(inputs["t_min"]) + t_sub = Float(inputs["t_sub"]) + tau_r2g = Float(inputs["tau_r2g"]) + tau_smlt = Float(inputs["tau_smlt"]) + tau_g2r = Float(inputs["tau_g2r"]) + dw_land = Float(inputs["dw_land"]) + dw_ocean = Float(inputs["dw_ocean"]) + vi_fac = Float(inputs["vi_fac"]) + vr_fac = Float(inputs["vr_fac"]) + vs_fac = Float(inputs["vs_fac"]) + vg_fac = Float(inputs["vg_fac"]) + ql_mlt = Float(inputs["ql_mlt"]) + do_qa = bool(inputs["do_qa"]) + fix_negative = bool(inputs["fix_negative"]) + vi_max = Float(inputs["vi_max"]) + vs_max = Float(inputs["vs_max"]) + vg_max = Float(inputs["vg_max"]) + vr_max = Float(inputs["vr_max"]) + qs_mlt = Float(inputs["qs_mlt"]) + qs0_crt = Float(inputs["qs0_crt"]) + qi_gen = Float(inputs["qi_gen"]) + ql0_max = Float(inputs["ql0_max"]) + qi0_max = Float(inputs["qi0_max"]) + qi0_crt = Float(inputs["qi0_crt"]) + qr0_crt = Float(inputs["qr0_crt"]) + fast_sat_adj = bool(inputs["fast_sat_adj"]) + rh_inc = Float(inputs["rh_inc"]) + rh_ins = Float(inputs["rh_ins"]) + rh_inr = Float(inputs["rh_inr"]) + const_vi = bool(inputs["const_vi"]) + const_vs = bool(inputs["const_vs"]) + const_vg = bool(inputs["const_vg"]) + const_vr = bool(inputs["const_vr"]) + use_ccn = Float(inputs["use_ccn"]) + rthreshu = Float(inputs["rthreshu"]) + rthreshs = Float(inputs["rthreshs"]) + ccn_l = Float(inputs["ccn_l"]) + ccn_o = Float(inputs["ccn_o"]) + qc_crt = Float(inputs["qc_crt"]) + tau_g2v = Float(inputs["tau_g2v"]) + tau_v2g = Float(inputs["tau_v2g"]) + tau_s2v = Float(inputs["tau_s2v"]) + tau_v2s = Float(inputs["tau_v2s"]) + tau_revp = Float(inputs["tau_revp"]) + tau_frz = Float(inputs["tau_frz"]) + do_bigg = Float(inputs["do_bigg"]) + do_evap = Float(inputs["do_evap"]) + do_subl = Float(inputs["do_subl"]) + sat_adj0 = Float(inputs["sat_adj0"]) + c_piacr = Float(inputs["c_piacr"]) + tau_imlt = Float(inputs["tau_imlt"]) + tau_v2l = Float(inputs["tau_v2l"]) + tau_l2v = Float(inputs["tau_l2v"]) + tau_i2v = Float(inputs["tau_i2v"]) + tau_i2s = Float(inputs["tau_i2s"]) + tau_l2r = Float(inputs["tau_l2r"]) + qi_lim = Float(inputs["qi_lim"]) + ql_gen = Float(inputs["ql_gen"]) + c_paut = Float(inputs["c_paut"]) + c_psaci = Float(inputs["c_psaci"]) + c_pgacs = Float(inputs["c_pgacs"]) + c_pgaci = Float(inputs["c_pgaci"]) + z_slope_liq = Float(inputs["z_slope_liq"]) + z_slope_ice = Float(inputs["z_slope_ice"]) + prog_ccn = Float(inputs["prog_ccn"]) + c_cracw = Float(inputs["c_cracw"]) + alin = Float(inputs["alin"]) + clin = Float(inputs["clin"]) + preciprad = Float(inputs["preciprad"]) + cld_min = Float(inputs["cld_min"]) + use_ppm = bool(inputs["use_ppm"]) + mono_prof = Float(inputs["mono_prof"]) + do_sedi_heat = Float(inputs["do_sedi_heat"]) + sedi_transport = bool(inputs["sedi_transport"]) + do_sedi_w = bool(inputs["do_sedi_w"]) + de_ice = Float(inputs["de_ice"]) + icloud_f = Float(inputs["icloud_f"]) + irain_f = Float(inputs["irain_f"]) + mp_print = Float(inputs["mp_print"]) + + stencil = GFDL_1M_driver( + self.stencil_factory, + self.quantity_factory, + LPHYS_HYDROSTATIC, + LHYDROSTATIC, + DT_MOIST, + # Namelist options + mp_time, + t_min, + t_sub, + tau_r2g, + tau_smlt, + tau_g2r, + dw_land, + dw_ocean, + vi_fac, + vr_fac, + vs_fac, + vg_fac, + ql_mlt, + do_qa, + fix_negative, + vi_max, + vs_max, + vg_max, + vr_max, + qs_mlt, + qs0_crt, + qi_gen, + ql0_max, + qi0_max, + qi0_crt, + qr0_crt, + fast_sat_adj, + rh_inc, + rh_ins, + rh_inr, + const_vi, + const_vs, + const_vg, + const_vr, + use_ccn, + rthreshu, + rthreshs, + ccn_l, + ccn_o, + qc_crt, + tau_g2v, + tau_v2g, + tau_s2v, + tau_v2s, + tau_revp, + tau_frz, + do_bigg, + do_evap, + do_subl, + sat_adj0, + c_piacr, + tau_imlt, + tau_v2l, + tau_l2v, + tau_i2v, + tau_i2s, + tau_l2r, + qi_lim, + ql_gen, + c_paut, + c_psaci, + c_pgacs, + c_pgaci, + z_slope_liq, + z_slope_ice, + prog_ccn, + c_cracw, + alin, + clin, + preciprad, + cld_min, + use_ppm, + mono_prof, + do_sedi_heat, + sedi_transport, + do_sedi_w, + de_ice, + icloud_f, + irain_f, + mp_print, + ) + + stencil( + RAD_QV, + RAD_QL, + RAD_QR, + RAD_QI, + RAD_QS, + RAD_QG, + RAD_CF, + NACTLI, + DQVDTmic, + DQLDTmic, + DQRDTmic, + DQIDTmic, + DQSDTmic, + DQGDTmic, + DQADTmic, + DTDTmic, + T, + W, + U, + V, + DUDTmic, + DVDTmic, + DZ, + DP, + AREA, + FRLAND, + CNV_FRC, + SRF_TYPE, + EIS, + RHCRIT3D, + ANV_ICEFALL, + LS_ICEFALL, + ) + + return { + "DQADTmic": DQADTmic.view[:], + "DTDTmic": DTDTmic.view[:], + "DUDTmic": DUDTmic.view[:], + "DVDTmic": DVDTmic.view[:], + "W": W.view[:], + "DQVDTmic": DQVDTmic.view[:], + "DQLDTmic": DQLDTmic.view[:], + "DQRDTmic": DQRDTmic.view[:], + "DQIDTmic": DQIDTmic.view[:], + "DQSDTmic": DQSDTmic.view[:], + "DQGDTmic": DQGDTmic.view[:], + "PRCP_RAIN": stencil.rain.view[:], + "PRCP_SNOW": stencil.snow.view[:], + "PRCP_ICE": stencil.ice.view[:], + "PRCP_GRAUPEL": stencil.graupel.view[:], + "PFL_LS": stencil.m2_rain.view[:], + "PFI_LS": stencil.m2_sol.view[:], + "REV_LS": stencil.revap.view[:], + "RSU_LS": stencil.isubl.view[:], + } diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_GFDL_1M_driver_preloop.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_GFDL_1M_driver_preloop.py new file mode 100644 index 000000000..95f75c3fa --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_GFDL_1M_driver_preloop.py @@ -0,0 +1,216 @@ +import pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_constants as driver_constants +from ndsl import Namelist, Quantity, StencilFactory, orchestrate +from ndsl.constants import X_DIM, Y_DIM, Z_DIM, Z_INTERFACE_DIM +from ndsl.stencils.testing.translate import TranslateFortranData2Py +from pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_core import ( + fix_negative_values, + init_temporaries, +) + + +class TranslateGFDL_1M_driver_preloop(TranslateFortranData2Py): + def __init__(self, grid, namelist: Namelist, stencil_factory: StencilFactory): + super().__init__(grid, stencil_factory) + self.stencil_factory = stencil_factory + self.quantity_factory = grid.quantity_factory + self._grid = grid + + # FloatField Inputs + self.in_vars["data_vars"] = { + "u_GFDL_1M_driver_preloop": {}, + "v_GFDL_1M_driver_preloop": {}, + "w_GFDL_1M_driver_preloop": {}, + "area_GFDL_1M_driver_preloop": {}, + "qs_GFDL_1M_driver_preloop": {}, + "qi_GFDL_1M_driver_preloop": {}, + "qg_GFDL_1M_driver_preloop": {}, + "ql_GFDL_1M_driver_preloop": {}, + "qr_GFDL_1M_driver_preloop": {}, + "qa_GFDL_1M_driver_preloop": {}, + "qn_GFDL_1M_driver_preloop": {}, + "qv_GFDL_1M_driver_preloop": {}, + "t_GFDL_1M_driver_preloop": {}, + "dp_GFDL_1M_driver_preloop": {}, + "dz_GFDL_1M_driver_preloop": {}, + "rhcrit_GFDL_1M_driver_preloop": {}, + } + + # FloatField Outputs + self.out_vars = { + "t_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "p_dry_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "ql_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "qs_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "qg_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "qi_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "qr_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "qv_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "dp_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "den_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "c_praut_GFDL_1M_driver_preloop": self.grid.compute_dict(), + "omq_GFDL_1M_driver_preloop": self.grid.compute_dict(), + } + + # initialize temporaries + self.t1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.dp1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.omq = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qv1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.ql1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qr1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qi1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qs1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qg1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.qa1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.den = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.p_dry = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.m1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.u1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.v1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.w1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.ccn = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.c_praut = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.rh_limited = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.ze = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_INTERFACE_DIM], "n/a") + self.zt = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_INTERFACE_DIM], "n/a") + self.cvm = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.lhi = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.icpk = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.is_frozen = self.quantity_factory.ones([X_DIM, Y_DIM, Z_DIM], "n/a") + self.precip_fall = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.hold_data = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + + # set externals manually to the need for avoid another workaround + c_paut = 1 + cpaut = c_paut * 0.104 * driver_constants.GRAV / 1.717e-5 + c_air = driver_constants.CP_AIR + c_vap = driver_constants.CP_VAP + d0_vap = c_vap - driver_constants.C_LIQ + lv00 = driver_constants.HLV0 - d0_vap * driver_constants.T_ICE + + # initalize stencils + orchestrate(obj=self, config=stencil_factory.config.dace_config) + self._create_temporaries = stencil_factory.from_dims_halo( + func=init_temporaries, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "cpaut": cpaut, + }, + ) + + self._gfdl_1m_driver_preloop = stencil_factory.from_dims_halo( + func=fix_negative_values, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "c_air": c_air, + "c_vap": c_vap, + "d0_vap": d0_vap, + "lv00": lv00, + }, + ) + + def make_ij_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM], + "n/a", + ) + qty.view[:, :] = qty.np.asarray(data[:, :]) + return qty + + def make_ijk_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM, Z_DIM], + "n/a", + ) + qty.view[:, :, :] = qty.np.asarray(data[:, :, :]) + return qty + + def compute(self, inputs): + # FloatField Variables + u = self.make_ijk_field(inputs["u_GFDL_1M_driver_preloop"]) + v = self.make_ijk_field(inputs["v_GFDL_1M_driver_preloop"]) + w = self.make_ijk_field(inputs["w_GFDL_1M_driver_preloop"]) + area = self.make_ij_field(inputs["area_GFDL_1M_driver_preloop"]) + qs = self.make_ijk_field(inputs["qs_GFDL_1M_driver_preloop"]) + qi = self.make_ijk_field(inputs["qi_GFDL_1M_driver_preloop"]) + qg = self.make_ijk_field(inputs["qg_GFDL_1M_driver_preloop"]) + ql = self.make_ijk_field(inputs["ql_GFDL_1M_driver_preloop"]) + qr = self.make_ijk_field(inputs["qr_GFDL_1M_driver_preloop"]) + qa = self.make_ijk_field(inputs["qa_GFDL_1M_driver_preloop"]) + qn = self.make_ijk_field(inputs["qn_GFDL_1M_driver_preloop"]) + qv = self.make_ijk_field(inputs["qv_GFDL_1M_driver_preloop"]) + t = self.make_ijk_field(inputs["t_GFDL_1M_driver_preloop"]) + dp = self.make_ijk_field(inputs["dp_GFDL_1M_driver_preloop"]) + dz = self.make_ijk_field(inputs["dz_GFDL_1M_driver_preloop"]) + rhcrit = self.make_ijk_field(inputs["rhcrit_GFDL_1M_driver_preloop"]) + + # make outputs + self.vti = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.vts = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.vtg = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.onemsig = self.quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + + self._create_temporaries( + t, + dp, + rhcrit, + qv, + ql, + qi, + qr, + qs, + qg, + qa, + qn, + dz, + u, + v, + w, + area, + self.t1, + self.dp1, + self.omq, + self.qv1, + self.ql1, + self.qr1, + self.qi1, + self.qs1, + self.qg1, + self.qa1, + self.den, + self.p_dry, + self.m1, + self.u1, + self.v1, + self.w1, + self.onemsig, + self.ccn, + self.c_praut, + self.rh_limited, + ) + + self._gfdl_1m_driver_preloop( + self.t1, + self.qv1, + self.ql1, + self.qr1, + self.qi1, + self.qs1, + self.qg1, + self.dp1, + ) + + return { + "t_GFDL_1M_driver_preloop": self.t1.view[:], + "p_dry_GFDL_1M_driver_preloop": self.p_dry.view[:], + "ql_GFDL_1M_driver_preloop": self.ql1.view[:], + "qs_GFDL_1M_driver_preloop": self.qs1.view[:], + "qg_GFDL_1M_driver_preloop": self.qg1.view[:], + "qi_GFDL_1M_driver_preloop": self.qi1.view[:], + "qr_GFDL_1M_driver_preloop": self.qr1.view[:], + "qv_GFDL_1M_driver_preloop": self.qv1.view[:], + "dp_GFDL_1M_driver_preloop": self.dp1.view[:], + "den_GFDL_1M_driver_preloop": self.den.view[:], + "c_praut_GFDL_1M_driver_preloop": self.c_praut.view[:], + "omq_GFDL_1M_driver_preloop": self.omq.view[:], + } diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_GFDL_driver_tables.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_GFDL_driver_tables.py new file mode 100644 index 000000000..95fc4d52b --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_GFDL_driver_tables.py @@ -0,0 +1,43 @@ +from ndsl import Namelist, StencilFactory +from ndsl.stencils.testing.translate import TranslateFortranData2Py +from pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_tables import get_tables + + +class TranslateGFDL_driver_tables(TranslateFortranData2Py): + def __init__(self, grid, namelist: Namelist, stencil_factory: StencilFactory): + super().__init__(grid, stencil_factory) + self.stencil_factory = stencil_factory + self.quantity_factory = grid.quantity_factory + self._grid = grid + + # FloatField Inputs + self.in_vars["data_vars"] = {} + + # FloatField Outputs + self.out_vars = { + "table1_driver": self.grid.compute_dict(), + "table2_driver": self.grid.compute_dict(), + "table3_driver": self.grid.compute_dict(), + "table4_driver": self.grid.compute_dict(), + "des1_driver": self.grid.compute_dict(), + "des2_driver": self.grid.compute_dict(), + "des3_driver": self.grid.compute_dict(), + "des4_driver": self.grid.compute_dict(), + } + + def compute(self, inputs): + + self.sat_tables = get_tables(self.stencil_factory.backend) + + print(len(self.sat_tables.table1)) + + return { + "table1_driver": self.sat_tables.table1, + "table2_driver": self.sat_tables.table2, + "table3_driver": self.sat_tables.table3, + "table4_driver": self.sat_tables.table4, + "des1_driver": self.sat_tables.des1, + "des2_driver": self.sat_tables.des2, + "des3_driver": self.sat_tables.des3, + "des4_driver": self.sat_tables.des4, + } diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_fall_speed.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_fall_speed.py new file mode 100644 index 000000000..fd4cfcfd7 --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_fall_speed.py @@ -0,0 +1,164 @@ +from gt4py.cartesian.gtscript import PARALLEL, computation, interval + +from ndsl import Namelist, Quantity, StencilFactory, orchestrate +from ndsl.constants import X_DIM, Y_DIM, Z_DIM +from ndsl.dsl.typing import Float, FloatField, FloatFieldIJ +from ndsl.stencils.testing.translate import TranslateFortranData2Py +from pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_core import fall_speed_core + + +class Translatefall_speed(TranslateFortranData2Py): + def __init__(self, grid, namelist: Namelist, stencil_factory: StencilFactory): + super().__init__(grid, stencil_factory) + self.stencil_factory = stencil_factory + self.quantity_factory = grid.quantity_factory + self._grid = grid + + # FloatField Inputs + self.in_vars["data_vars"] = { + "p1_fall_speed": {}, + "cnv_frc_fall_speed": {}, + "anv_icefall_fall_speed": {}, + "lsc_icefall_fall_speed": {}, + "den_fall_speed": {}, + "qs_fall_speed": {}, + "qi_fall_speed": {}, + "qg_fall_speed": {}, + "ql_fall_speed": {}, + "t_fall_speed": {}, + "const_vi_fall_speed": {}, + "const_vs_fall_speed": {}, + "const_vg_fall_speed": {}, + "vi_fac_fall_speed": {}, + "vi_max_fall_speed": {}, + "vs_fac_fall_speed": {}, + "vs_max_fall_speed": {}, + "vg_fac_fall_speed": {}, + "vg_max_fall_speed": {}, + } + + # FloatField Outputs + self.out_vars = { + "vti_fall_speed": self.grid.compute_dict(), + "vts_fall_speed": self.grid.compute_dict(), + "vtg_fall_speed": self.grid.compute_dict(), + } + + def make_ij_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM], + "n/a", + ) + qty.view[:, :] = qty.np.asarray(data[:, :]) + return qty + + def make_ijk_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM, Z_DIM], + "n/a", + ) + qty.view[:, :, :] = qty.np.asarray(data[:, :, :]) + return qty + + def compute(self, inputs): + # FloatField Variables + p1 = self.make_ijk_field(inputs["p1_fall_speed"]) + qs = self.make_ijk_field(inputs["qs_fall_speed"]) + qi = self.make_ijk_field(inputs["qi_fall_speed"]) + qg = self.make_ijk_field(inputs["qg_fall_speed"]) + ql = self.make_ijk_field(inputs["ql_fall_speed"]) + den = self.make_ijk_field(inputs["den_fall_speed"]) + t = self.make_ijk_field(inputs["t_fall_speed"]) + cnv_frc = self.make_ij_field(inputs["cnv_frc_fall_speed"]) + + # Float Variables + anv_icefall = Float(inputs["anv_icefall_fall_speed"][0]) + lsc_icefall = Float(inputs["lsc_icefall_fall_speed"][0]) + const_vi = Float(inputs["const_vi_fall_speed"][0]) + const_vs = Float(inputs["const_vs_fall_speed"][0]) + const_vg = Float(inputs["const_vg_fall_speed"][0]) + vi_fac = Float(inputs["vi_fac_fall_speed"][0]) + vi_max = Float(inputs["vi_max_fall_speed"][0]) + vs_fac = Float(inputs["vs_fac_fall_speed"][0]) + vs_max = Float(inputs["vs_max_fall_speed"][0]) + vg_fac = Float(inputs["vg_fac_fall_speed"][0]) + vg_max = Float(inputs["vg_max_fall_speed"][0]) + + # Revert to boolean + if const_vi == 1: + const_vi = True + else: + const_vi = False + if const_vs == 1: + const_vs = True + else: + const_vs = False + if const_vg == 1: + const_vg = True + else: + const_vg = False + + # make outputs + self.vti = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.vts = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.vtg = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + + orchestrate(obj=self, config=self.stencil_factory.config.dace_config) + self._stencil = self.stencil_factory.from_dims_halo( + func=stencil, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "const_vi": const_vi, + "const_vs": const_vs, + "const_vg": const_vg, + "vi_fac": vi_fac, + "vi_max": vi_max, + "vs_fac": vs_fac, + "vs_max": vs_max, + "vg_fac": vg_fac, + "vg_max": vg_max, + }, + ) + + self._stencil( + p1, + cnv_frc, + anv_icefall, + lsc_icefall, + den, + qs, + qi, + qg, + ql, + t, + self.vti, + self.vts, + self.vtg, + ) + + return { + "vti_fall_speed": self.vti.view[:], + "vts_fall_speed": self.vts.view[:], + "vtg_fall_speed": self.vtg.view[:], + } + + +def stencil( + p1: FloatField, + cnv_frc: FloatFieldIJ, + anv_icefall: Float, + lsc_icefall: Float, + den: FloatField, + qs: FloatField, + qi: FloatField, + qg: FloatField, + ql: FloatField, + t: FloatField, + vti: FloatField, + vts: FloatField, + vtg: FloatField, +): + with computation(PARALLEL), interval(...): + vti, vts, vtg = fall_speed_core( + p1, cnv_frc, anv_icefall, lsc_icefall, den, qs, qi, qg, ql, t + ) diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_icloud.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_icloud.py new file mode 100644 index 000000000..92737b528 --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_icloud.py @@ -0,0 +1,661 @@ +import numpy as np + +import pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_constants as driver_constants +from ndsl import Namelist, Quantity, StencilFactory, orchestrate +from ndsl.constants import X_DIM, Y_DIM, Z_DIM +from ndsl.dsl.typing import Float +from ndsl.stencils.testing.translate import TranslateFortranData2Py +from pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_tables import get_tables +from pyMoist.GFDL_1M.GFDL_1M_driver.icloud import icloud + + +class Translateicloud(TranslateFortranData2Py): + def __init__(self, grid, namelist: Namelist, stencil_factory: StencilFactory): + super().__init__(grid, stencil_factory) + self.stencil_factory = stencil_factory + self.quantity_factory = grid.quantity_factory + self._grid = grid + + # FloatField Inputs + self.in_vars["data_vars"] = { + "t1_icloud": {}, + "p1_icloud": {}, + "dp1_icloud": {}, + "qv_icloud": {}, + "ql_icloud": {}, + "qr_icloud": {}, + "qg_icloud": {}, + "qs_icloud": {}, + "qi_icloud": {}, + "qa_icloud": {}, + "den1_icloud": {}, + "denfac_icloud": {}, + "vtg_icloud": {}, + "vts_icloud": {}, + "vtr_icloud": {}, + "ccn_icloud": {}, + "rh_limited_icloud": {}, + "cnv_frc_icloud": {}, + "srf_type_icloud": {}, + "mp_time_icloud": {}, + "t_min_icloud": {}, + "t_sub_icloud": {}, + "tau_r2g_icloud": {}, + "tau_smlt_icloud": {}, + "tau_g2r_icloud": {}, + "dw_land_icloud": {}, + "dw_ocean_icloud": {}, + "vi_fac_icloud": {}, + "vr_fac_icloud": {}, + "vs_fac_icloud": {}, + "vg_fac_icloud": {}, + "ql_mlt_icloud": {}, + "do_qa_icloud": {}, + "fix_negative_icloud": {}, + "vi_max_icloud": {}, + "vs_max_icloud": {}, + "vg_max_icloud": {}, + "vr_max_icloud": {}, + "qs_mlt_icloud": {}, + "qs0_crt_icloud": {}, + "qi_gen_icloud": {}, + "ql0_max_icloud": {}, + "qi0_max_icloud": {}, + "qi0_crt_icloud": {}, + "qr0_crt_icloud": {}, + "fast_sat_adj_icloud": {}, + "rh_inc_icloud": {}, + "rh_ins_icloud": {}, + "rh_inr_icloud": {}, + "const_vi_icloud": {}, + "const_vs_icloud": {}, + "const_vg_icloud": {}, + "const_vr_icloud": {}, + "use_ccn_icloud": {}, + "rthreshu_icloud": {}, + "rthreshs_icloud": {}, + "ccn_l_icloud": {}, + "ccn_o_icloud": {}, + "qc_crt_icloud": {}, + "tau_g2v_icloud": {}, + "tau_v2g_icloud": {}, + "tau_s2v_icloud": {}, + "tau_v2s_icloud": {}, + "tau_revp_icloud": {}, + "tau_frz_icloud": {}, + "do_bigg_icloud": {}, + "do_evap_icloud": {}, + "do_subl_icloud": {}, + "sat_adj0_icloud": {}, + "c_piacr_icloud": {}, + "tau_imlt_icloud": {}, + "tau_v2l_icloud": {}, + "tau_l2v_icloud": {}, + "tau_i2v_icloud": {}, + "tau_i2s_icloud": {}, + "tau_l2r_icloud": {}, + "qi_lim_icloud": {}, + "ql_gen_icloud": {}, + "c_paut_icloud": {}, + "c_psaci_icloud": {}, + "c_pgacs_icloud": {}, + "c_pgaci_icloud": {}, + "z_slope_liq_icloud": {}, + "z_slope_ice_icloud": {}, + "prog_ccn_icloud": {}, + "c_cracw_icloud": {}, + "alin_icloud": {}, + "clin_icloud": {}, + "preciprad_icloud": {}, + "cld_min_icloud": {}, + "use_ppm_icloud": {}, + "mono_prof_icloud": {}, + "do_sedi_heat_icloud": {}, + "sedi_transport_icloud": {}, + "do_sedi_w_icloud": {}, + "de_ice_icloud": {}, + "icloud_f_icloud": {}, + "irain_f_icloud": {}, + "mp_print_icloud": {}, + "hydrostatic_icloud": {}, + "dts_icloud": {}, + } + + # FloatField Outputs + self.out_vars = { + "t1_icloud": self.grid.compute_dict(), + "qv_icloud": self.grid.compute_dict(), + "ql_icloud": self.grid.compute_dict(), + "qr_icloud": self.grid.compute_dict(), + "qg_icloud": self.grid.compute_dict(), + "qs_icloud": self.grid.compute_dict(), + "qi_icloud": self.grid.compute_dict(), + "qa_icloud": self.grid.compute_dict(), + "subl1_icloud": self.grid.compute_dict(), + } + + def make_ij_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM], + "n/a", + ) + qty.view[:, :] = qty.np.asarray(data[:, :]) + return qty + + def make_ijk_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM, Z_DIM], + "n/a", + ) + qty.view[:, :, :] = qty.np.asarray(data[:, :, :]) + return qty + + def compute(self, inputs): + # FloatField Variables + t1_icloud = self.make_ijk_field(inputs["t1_icloud"]) + p1_icloud = self.make_ijk_field(inputs["p1_icloud"]) + dp1_icloud = self.make_ijk_field(inputs["dp1_icloud"]) + qv_icloud = self.make_ijk_field(inputs["qv_icloud"]) + ql_icloud = self.make_ijk_field(inputs["ql_icloud"]) + qr_icloud = self.make_ijk_field(inputs["qr_icloud"]) + qg_icloud = self.make_ijk_field(inputs["qg_icloud"]) + qs_icloud = self.make_ijk_field(inputs["qs_icloud"]) + qi_icloud = self.make_ijk_field(inputs["qi_icloud"]) + qa_icloud = self.make_ijk_field(inputs["qa_icloud"]) + den1_icloud = self.make_ijk_field(inputs["den1_icloud"]) + denfac_icloud = self.make_ijk_field(inputs["denfac_icloud"]) + vtg_icloud = self.make_ijk_field(inputs["vtg_icloud"]) + vts_icloud = self.make_ijk_field(inputs["vts_icloud"]) + vtr_icloud = self.make_ijk_field(inputs["vtr_icloud"]) + ccn_icloud = self.make_ijk_field(inputs["ccn_icloud"]) + rh_limited_icloud = self.make_ijk_field(inputs["rh_limited_icloud"]) + cnv_frc_icloud = self.make_ij_field(inputs["cnv_frc_icloud"]) + srf_type_icloud = self.make_ij_field(inputs["srf_type_icloud"]) + + # Float Variables + # Namelist options + mp_time = Float(inputs["mp_time_icloud"][0]) + t_min = Float(inputs["t_min_icloud"][0]) + t_sub = Float(inputs["t_sub_icloud"][0]) + tau_r2g = Float(inputs["tau_r2g_icloud"][0]) + tau_smlt = Float(inputs["tau_smlt_icloud"][0]) + tau_g2r = Float(inputs["tau_g2r_icloud"][0]) + dw_land = Float(inputs["dw_land_icloud"][0]) + dw_ocean = Float(inputs["dw_ocean_icloud"][0]) + vi_fac = Float(inputs["vi_fac_icloud"][0]) + vr_fac = Float(inputs["vr_fac_icloud"][0]) + vs_fac = Float(inputs["vs_fac_icloud"][0]) + vg_fac = Float(inputs["vg_fac_icloud"][0]) + ql_mlt = Float(inputs["ql_mlt_icloud"][0]) + do_qa = Float(inputs["do_qa_icloud"][0]) + fix_negative = Float(inputs["fix_negative_icloud"][0]) + vi_max = Float(inputs["vi_max_icloud"][0]) + vs_max = Float(inputs["vs_max_icloud"][0]) + vg_max = Float(inputs["vg_max_icloud"][0]) + vr_max = Float(inputs["vr_max_icloud"][0]) + qs_mlt = Float(inputs["qs_mlt_icloud"][0]) + qs0_crt = Float(inputs["qs0_crt_icloud"][0]) + qi_gen = Float(inputs["qi_gen_icloud"][0]) + ql0_max = Float(inputs["ql0_max_icloud"][0]) + qi0_max = Float(inputs["qi0_max_icloud"][0]) + qi0_crt = Float(inputs["qi0_crt_icloud"][0]) + qr0_crt = Float(inputs["qr0_crt_icloud"][0]) + fast_sat_adj = Float(inputs["fast_sat_adj_icloud"][0]) + rh_inc = Float(inputs["rh_inc_icloud"][0]) + rh_ins = Float(inputs["rh_ins_icloud"][0]) + rh_inr = Float(inputs["rh_inr_icloud"][0]) + const_vi = Float(inputs["const_vi_icloud"][0]) + const_vs = Float(inputs["const_vs_icloud"][0]) + const_vg = Float(inputs["const_vg_icloud"][0]) + const_vr = Float(inputs["const_vr_icloud"][0]) + use_ccn = Float(inputs["use_ccn_icloud"][0]) + rthreshu = Float(inputs["rthreshu_icloud"][0]) + rthreshs = Float(inputs["rthreshs_icloud"][0]) + ccn_l = Float(inputs["ccn_l_icloud"][0]) + ccn_o = Float(inputs["ccn_o_icloud"][0]) + qc_crt = Float(inputs["qc_crt_icloud"][0]) + tau_g2v = Float(inputs["tau_g2v_icloud"][0]) + tau_v2g = Float(inputs["tau_v2g_icloud"][0]) + tau_s2v = Float(inputs["tau_s2v_icloud"][0]) + tau_v2s = Float(inputs["tau_v2s_icloud"][0]) + tau_revp = Float(inputs["tau_revp_icloud"][0]) + tau_frz = Float(inputs["tau_frz_icloud"][0]) + do_bigg = Float(inputs["do_bigg_icloud"][0]) + do_evap = Float(inputs["do_evap_icloud"][0]) + do_subl = Float(inputs["do_subl_icloud"][0]) + sat_adj0 = Float(inputs["sat_adj0_icloud"][0]) + c_piacr = Float(inputs["c_piacr_icloud"][0]) + tau_imlt = Float(inputs["tau_imlt_icloud"][0]) + tau_v2l = Float(inputs["tau_v2l_icloud"][0]) + tau_l2v = Float(inputs["tau_l2v_icloud"][0]) + tau_i2v = Float(inputs["tau_i2v_icloud"][0]) + tau_i2s = Float(inputs["tau_i2s_icloud"][0]) + tau_l2r = Float(inputs["tau_l2r_icloud"][0]) + qi_lim = Float(inputs["qi_lim_icloud"][0]) + ql_gen = Float(inputs["ql_gen_icloud"][0]) + c_paut = Float(inputs["c_paut_icloud"][0]) + c_psaci = Float(inputs["c_psaci_icloud"][0]) + c_pgacs = Float(inputs["c_pgacs_icloud"][0]) + c_pgaci = Float(inputs["c_pgaci_icloud"][0]) + z_slope_liq = Float(inputs["z_slope_liq_icloud"][0]) + z_slope_ice = Float(inputs["z_slope_ice_icloud"][0]) + prog_ccn = Float(inputs["prog_ccn_icloud"][0]) + c_cracw = Float(inputs["c_cracw_icloud"][0]) + alin = Float(inputs["alin_icloud"][0]) + clin = Float(inputs["clin_icloud"][0]) + preciprad = Float(inputs["preciprad_icloud"][0]) + cld_min = Float(inputs["cld_min_icloud"][0]) + use_ppm = Float(inputs["use_ppm_icloud"][0]) + mono_prof = Float(inputs["mono_prof_icloud"][0]) + do_sedi_heat = Float(inputs["do_sedi_heat_icloud"][0]) + sedi_transport = Float(inputs["sedi_transport_icloud"][0]) + do_sedi_w = Float(inputs["do_sedi_w_icloud"][0]) + de_ice = Float(inputs["de_ice_icloud"][0]) + icloud_f = Float(inputs["icloud_f_icloud"][0]) + irain_f = Float(inputs["irain_f_icloud"][0]) + mp_print = Float(inputs["mp_print_icloud"][0]) + hydrostatic = Float(inputs["hydrostatic_icloud"][0]) + dts = Float(inputs["dts_icloud"][0]) + + # Revert to boolean + if hydrostatic == 1: + hydrostatic = True + else: + hydrostatic = False + if fix_negative == 1: + fix_negative = True + else: + fix_negative = False + if sedi_transport == 1: + sedi_transport = True + else: + sedi_transport = False + if const_vi == 1: + const_vi = True + else: + const_vi = False + if const_vs == 1: + const_vs = True + else: + const_vs = False + if const_vg == 1: + const_vg = True + else: + const_vg = False + if use_ppm == 1: + use_ppm = True + else: + use_ppm = False + if do_qa == 1: + do_qa = True + else: + do_qa = False + if fast_sat_adj == 1: + fast_sat_adj = True + else: + fast_sat_adj = False + + # Calculate additional constants + # ----------------------------------------------------------------------- + # define heat capacity of dry air and water vap based on hydrostatical property + # ----------------------------------------------------------------------- + + phys_hydrostatic = ( + True # not about to try to serialize this, it should always be true + ) + if phys_hydrostatic or hydrostatic: + c_air = driver_constants.CP_AIR + c_vap = driver_constants.CP_VAP + p_nonhydro = False + else: + c_air = driver_constants.CV_AIR + c_vap = driver_constants.CV_VAP + p_nonhydro = True + d0_vap = c_vap - driver_constants.C_LIQ + lv00 = driver_constants.HLV0 - d0_vap * driver_constants.T_ICE + + if hydrostatic: + do_sedi_w = False + + # ----------------------------------------------------------------------- + # define latent heat coefficient used in wet bulb and bigg mechanism + # ----------------------------------------------------------------------- + + latv = driver_constants.HLV + lati = driver_constants.HLF + lats = latv + lati + lat2 = lats * lats + + lcp = latv / driver_constants.CP_AIR + icp = lati / driver_constants.CP_AIR + tcp = (latv + lati) / driver_constants.CP_AIR + + # ----------------------------------------------------------------------- + # calculate cloud condensation nuclei (ccn) + # the following is based on klein eq. 15 + # ----------------------------------------------------------------------- + + cpaut = c_paut * 0.104 * driver_constants.GRAV / 1.717e-5 + + # ----------------------------------------------------------------------- + # define conversion scalar / factor for icloud + # ----------------------------------------------------------------------- + rdts = 1.0 / dts + fac_imlt = 1.0 - np.exp(-dts / tau_imlt) + fac_i2s = 1.0 - np.exp(-dts / tau_i2s) + fac_v2l = 1.0 - np.exp(-dts / tau_v2l) + fac_l2v = 1.0 - np.exp(-dts / tau_l2v) + fac_i2v = 1.0 - np.exp(-dts / tau_i2v) + fac_s2v = 1.0 - np.exp(-dts / tau_s2v) + fac_v2s = 1.0 - np.exp(-dts / tau_v2s) + fac_g2v = 1.0 - np.exp(-dts / tau_g2v) + fac_v2g = 1.0 - np.exp(-dts / tau_v2g) + fac_frz = 1.0 - np.exp(-dts / tau_frz) + + # ----------------------------------------------------------------------- + # constatns from setupm + # ----------------------------------------------------------------------- + + cgacs = ( + driver_constants.PISQ + * driver_constants.RNZG + * driver_constants.RNZS + * driver_constants.RHOS + ) + cgacs = cgacs * c_pgacs + + csacw = ( + driver_constants.PIE + * driver_constants.RNZS + * clin + * driver_constants.GAM325 + / (4.0 * driver_constants.ACT[0] ** 0.8125) + ) + # decreasing csacw to reduce cloud water --- > snow + + craci = ( + driver_constants.PIE + * driver_constants.RNZR + * alin + * driver_constants.GAM380 + / (4.0 * driver_constants.ACT[1] ** 0.95) + ) + csaci = csacw * c_psaci + + cgacw = ( + driver_constants.PIE + * driver_constants.RNZG + * driver_constants.GAM350 + * driver_constants.GCON + / (4.0 * driver_constants.ACT[5] ** 0.875) + ) + + cgaci = cgacw * c_pgaci + + cracw = craci # cracw = 3.27206196043822 + cracw = c_cracw * cracw + + cssub = np.zeros(5) + cgsub = np.zeros(5) + crevp = np.zeros(5) + + cssub[0] = ( + 2.0 + * driver_constants.PIE + * driver_constants.VDIFU + * driver_constants.TCOND + * driver_constants.RVGAS + * driver_constants.RNZS + ) + cgsub[0] = ( + 2.0 + * driver_constants.PIE + * driver_constants.VDIFU + * driver_constants.TCOND + * driver_constants.RVGAS + * driver_constants.RNZG + ) + crevp[0] = ( + 2.0 + * driver_constants.PIE + * driver_constants.VDIFU + * driver_constants.TCOND + * driver_constants.RVGAS + * driver_constants.RNZR + ) + cssub[1] = 0.78 / np.sqrt(driver_constants.ACT[0]) + cgsub[1] = 0.78 / np.sqrt(driver_constants.ACT[5]) + crevp[1] = 0.78 / np.sqrt(driver_constants.ACT[1]) + cssub[2] = ( + 0.31 + * driver_constants.SCM3 + * driver_constants.GAM263 + * np.sqrt(clin / driver_constants.VISK) + / driver_constants.ACT[0] ** 0.65625 + ) + cgsub[2] = ( + 0.31 + * driver_constants.SCM3 + * driver_constants.GAM275 + * np.sqrt(driver_constants.GCON / driver_constants.VISK) + / driver_constants.ACT[5] ** 0.6875 + ) + crevp[2] = ( + 0.31 + * driver_constants.SCM3 + * driver_constants.GAM209 + * np.sqrt(alin / driver_constants.VISK) + / driver_constants.ACT[1] ** 0.725 + ) + cssub[3] = driver_constants.TCOND * driver_constants.RVGAS + cssub[4] = driver_constants.HLTS**2 * driver_constants.VDIFU + cgsub[3] = cssub[3] + crevp[3] = cssub[3] + cgsub[4] = cssub[4] + crevp[4] = driver_constants.HLTC**2 * driver_constants.VDIFU + + cgfr_0 = ( + 20.0e2 + * driver_constants.PISQ + * driver_constants.RNZR + * driver_constants.RHOR + / driver_constants.ACT[1] ** 1.75 + ) + cgfr_1 = 0.66 + + cssub_0 = cssub[0] + cssub_1 = cssub[1] + cssub_2 = cssub[2] + cssub_3 = cssub[3] + cssub_4 = cssub[4] + + cgsub_0 = cgsub[0] + cgsub_1 = cgsub[1] + cgsub_2 = cgsub[2] + cgsub_3 = cgsub[3] + cgsub_4 = cgsub[4] + + crevp_0 = crevp[0] + crevp_1 = crevp[1] + crevp_2 = crevp[2] + crevp_3 = crevp[3] + crevp_4 = crevp[4] + + # smlt: five constants (lin et al. 1983) + + csmlt = np.zeros(5) + csmlt[0] = ( + 2.0 + * driver_constants.PIE + * driver_constants.TCOND + * driver_constants.RNZS + / driver_constants.HLTF + ) + csmlt[1] = ( + 2.0 + * driver_constants.PIE + * driver_constants.VDIFU + * driver_constants.RNZS + * driver_constants.HLTC + / driver_constants.HLTF + ) + csmlt[2] = cssub[1] + csmlt[3] = cssub[2] + csmlt[4] = driver_constants.CH2O / driver_constants.HLTF + + csmlt_0 = csmlt[0] + csmlt_1 = csmlt[1] + csmlt_2 = csmlt[2] + csmlt_3 = csmlt[3] + csmlt_4 = csmlt[4] + + # gmlt: five constants + + cgmlt = np.zeros(5) + cgmlt[0] = ( + 2.0 + * driver_constants.PIE + * driver_constants.TCOND + * driver_constants.RNZG + / driver_constants.HLTF + ) + cgmlt[1] = ( + 2.0 + * driver_constants.PIE + * driver_constants.VDIFU + * driver_constants.RNZG + * driver_constants.HLTC + / driver_constants.HLTF + ) + cgmlt[2] = cgsub[1] + cgmlt[3] = cgsub[2] + cgmlt[4] = driver_constants.CH2O / driver_constants.HLTF + + cgmlt_0 = cgmlt[0] + cgmlt_1 = cgmlt[1] + cgmlt_2 = cgmlt[2] + cgmlt_3 = cgmlt[3] + cgmlt_4 = cgmlt[4] + + es0 = 6.107799961e2 # ~6.1 mb + ces0 = driver_constants.EPS * es0 + + # make temporaries + self.TESTVAR_1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.TESTVAR_2 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.csaci = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.csaci.view[:] = csaci + self.csacw = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.csacw.view[:] = csacw + self.c_psaci = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.c_psaci.view[:] = c_psaci + + # make outputs + self.subl1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + + orchestrate(obj=self, config=self.stencil_factory.config.dace_config) + self._stencil = self.stencil_factory.from_dims_halo( + func=icloud, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "c_air": c_air, + "c_vap": c_vap, + "dts": dts, + "rdts": rdts, + "const_vi": const_vi, + "fac_g2v": fac_g2v, + "fac_i2s": fac_i2s, + "fac_imlt": fac_imlt, + "fac_frz": fac_frz, + "fac_l2v": fac_l2v, + "fac_s2v": fac_s2v, + "fac_v2s": fac_v2s, + "fac_v2g": fac_v2g, + "cgacs": cgacs, + "csacw": csacw, + "csaci": csaci, + "cgacw": cgacw, + "cgaci": cgaci, + "cgfr_0": cgfr_0, + "cgfr_1": cgfr_1, + "csmlt_0": csmlt_0, + "csmlt_1": csmlt_1, + "csmlt_2": csmlt_2, + "csmlt_3": csmlt_3, + "csmlt_4": csmlt_4, + "cgmlt_0": cgmlt_0, + "cgmlt_1": cgmlt_1, + "cgmlt_2": cgmlt_2, + "cgmlt_3": cgmlt_3, + "cgmlt_4": cgmlt_4, + "cssub_0": cssub_0, + "cssub_1": cssub_1, + "cssub_2": cssub_2, + "cssub_3": cssub_3, + "cssub_4": cssub_4, + "qi0_crt": qi0_crt, + "qs0_crt": qs0_crt, + "qs_mlt": qs_mlt, + "ql_mlt": ql_mlt, + "z_slope_ice": z_slope_ice, + "lv00": lv00, + "d0_vap": d0_vap, + "lat2": lat2, + "do_qa": do_qa, + "do_evap": do_evap, + "do_bigg": do_bigg, + "qc_crt": qc_crt, + "qi_lim": qi_lim, + "rh_inc": rh_inc, + "rh_inr": rh_inr, + "t_min": t_min, + "t_sub": t_sub, + "preciprad": preciprad, + "icloud_f": icloud_f, + }, + ) + + self.sat_tables = get_tables(self.stencil_factory.backend) + + self._stencil( + t1_icloud, + p1_icloud, + dp1_icloud, + qv_icloud, + ql_icloud, + qr_icloud, + qi_icloud, + qs_icloud, + qg_icloud, + qa_icloud, + den1_icloud, + denfac_icloud, + vts_icloud, + vtg_icloud, + vtr_icloud, + self.subl1, + rh_limited_icloud, + ccn_icloud, + cnv_frc_icloud, + srf_type_icloud, + self.sat_tables.table1, + self.sat_tables.table2, + self.sat_tables.table3, + self.sat_tables.table4, + self.sat_tables.des1, + self.sat_tables.des2, + self.sat_tables.des3, + self.sat_tables.des4, + ) + + return { + "t1_icloud": t1_icloud.view[:], + "qv_icloud": qv_icloud.view[:], + "ql_icloud": ql_icloud.view[:], + "qr_icloud": qr_icloud.view[:], + "qi_icloud": qi_icloud.view[:], + "qs_icloud": qs_icloud.view[:], + "qg_icloud": qg_icloud.view[:], + "qa_icloud": qa_icloud.view[:], + "subl1_icloud": self.subl1.view[:], + } diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_terminal_fall.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_terminal_fall.py new file mode 100644 index 000000000..7d35007a0 --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_terminal_fall.py @@ -0,0 +1,231 @@ +from ndsl import Namelist, Quantity, StencilFactory, orchestrate +from ndsl.constants import X_DIM, Y_DIM, Z_DIM, Z_INTERFACE_DIM +from ndsl.dsl.typing import Float, Int +from ndsl.stencils.testing.translate import TranslateFortranData2Py +from pyMoist.GFDL_1M.GFDL_1M_driver.terminal_fall import terminal_fall + + +class Translateterminal_fall(TranslateFortranData2Py): + def __init__(self, grid, namelist: Namelist, stencil_factory: StencilFactory): + super().__init__(grid, stencil_factory) + self.stencil_factory = stencil_factory + self.quantity_factory = grid.quantity_factory + self._grid = grid + + # FloatField Inputs + self.in_vars["data_vars"] = { + "t_terminal_fall": {}, + "qv_terminal_fall": {}, + "ql_terminal_fall": {}, + "qr_terminal_fall": {}, + "qg_terminal_fall": {}, + "qs_terminal_fall": {}, + "qi_terminal_fall": {}, + "dz1_terminal_fall": {}, + "dp1_terminal_fall": {}, + "den1_terminal_fall": {}, + "vtg_terminal_fall": {}, + "vts_terminal_fall": {}, + "vti_terminal_fall": {}, + "m1_sol_terminal_fall": {}, + "w1_terminal_fall": {}, + "dts_terminal_fall": {}, + "tau_imlt_terminal_fall": {}, + "ql_mlt_terminal_fall": {}, + "c_air_terminal_fall": {}, + "c_vap_terminal_fall": {}, + "d0_vap_terminal_fall": {}, + "lv00_terminal_fall": {}, + "vi_fac_terminal_fall": {}, + "do_sedi_w_terminal_fall": {}, + "use_ppm_terminal_fall": {}, + "tau_smlt_terminal_fall": {}, + "tau_g2r_terminal_fall": {}, + } + + # FloatField Outputs + self.out_vars = { + "t_terminal_fall": self.grid.compute_dict(), + "qv_terminal_fall": self.grid.compute_dict(), + "ql_terminal_fall": self.grid.compute_dict(), + "qr_terminal_fall": self.grid.compute_dict(), + "qg_terminal_fall": self.grid.compute_dict(), + "qs_terminal_fall": self.grid.compute_dict(), + "qi_terminal_fall": self.grid.compute_dict(), + "dz1_terminal_fall": self.grid.compute_dict(), + "dp1_terminal_fall": self.grid.compute_dict(), + "den1_terminal_fall": self.grid.compute_dict(), + "m1_sol_terminal_fall": self.grid.compute_dict(), + "r1_terminal_fall": self.grid.compute_dict(), + "g1_terminal_fall": self.grid.compute_dict(), + "s1_terminal_fall": self.grid.compute_dict(), + "i1_terminal_fall": self.grid.compute_dict(), + } + + def make_ij_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM], + "n/a", + ) + qty.view[:, :] = qty.np.asarray(data[:, :]) + return qty + + def make_ijk_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM, Z_DIM], + "n/a", + ) + qty.view[:, :, :] = qty.np.asarray(data[:, :, :]) + return qty + + def compute(self, inputs): + # FloatField Variables + t_terminal_fall = self.make_ijk_field(inputs["t_terminal_fall"]) + t_original = t_terminal_fall + qv_terminal_fall = self.make_ijk_field(inputs["qv_terminal_fall"]) + qv_original = qv_terminal_fall + ql_terminal_fall = self.make_ijk_field(inputs["ql_terminal_fall"]) + ql_original = ql_terminal_fall + qr_terminal_fall = self.make_ijk_field(inputs["qr_terminal_fall"]) + qr_original = qr_terminal_fall + qg_terminal_fall = self.make_ijk_field(inputs["qg_terminal_fall"]) + qg_original = qg_terminal_fall + qs_terminal_fall = self.make_ijk_field(inputs["qs_terminal_fall"]) + qs_original = qs_terminal_fall + qi_terminal_fall = self.make_ijk_field(inputs["qi_terminal_fall"]) + qi_original = qi_terminal_fall + dz1_terminal_fall = self.make_ijk_field(inputs["dz1_terminal_fall"]) + dz1_original = dz1_terminal_fall + dp1_terminal_fall = self.make_ijk_field(inputs["dp1_terminal_fall"]) + dp1_original = dp1_terminal_fall + den1_terminal_fall = self.make_ijk_field(inputs["den1_terminal_fall"]) + den1_original = den1_terminal_fall + vtg_terminal_fall = self.make_ijk_field(inputs["vtg_terminal_fall"]) + vtg_original = vtg_terminal_fall + vts_terminal_fall = self.make_ijk_field(inputs["vts_terminal_fall"]) + vts_original = vts_terminal_fall + vti_terminal_fall = self.make_ijk_field(inputs["vti_terminal_fall"]) + vti_original = vti_terminal_fall + m1_sol_terminal_fall = self.make_ijk_field(inputs["m1_sol_terminal_fall"]) + m1_sol_original = m1_sol_terminal_fall + w1_terminal_fall = self.make_ijk_field(inputs["w1_terminal_fall"]) + w1_original = w1_terminal_fall + + # Float Variables + dts = Float(inputs["dts_terminal_fall"][0]) + tau_imlt = Float(inputs["tau_imlt_terminal_fall"][0]) + ql_mlt = Float(inputs["ql_mlt_terminal_fall"][0]) + c_air = Float(inputs["c_air_terminal_fall"][0]) + c_vap = Float(inputs["c_vap_terminal_fall"][0]) + d0_vap = Float(inputs["d0_vap_terminal_fall"][0]) + lv00 = Float(inputs["lv00_terminal_fall"][0]) + vi_fac = Float(inputs["vi_fac_terminal_fall"][0]) + do_sedi_w = Float(inputs["do_sedi_w_terminal_fall"][0]) + use_ppm = Float(inputs["use_ppm_terminal_fall"][0]) + tau_smlt = Float(inputs["tau_smlt_terminal_fall"][0]) + tau_g2r = Float(inputs["tau_g2r_terminal_fall"][0]) + + # Revert to boolean + if do_sedi_w == 1: + do_sedi_w = True + else: + do_sedi_w = False + if use_ppm == 1: + use_ppm = True + else: + use_ppm = False + + # make masks + self.is_frozen = self.quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=bool + ) + self.precip_fall = self.quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.melting_mask_1 = self.quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=bool + ) + self.melting_mask_2 = self.quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=bool + ) + self.current_k_level = self.quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=Int + ) + for k in range(self.current_k_level.view[:].shape[2]): + self.current_k_level.view[:, :, k] = k + + # make temporaries + self.m1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.ze = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_INTERFACE_DIM], "n/a") + self.zt = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_INTERFACE_DIM], "n/a") + + # make outputs + self.rain = self.quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.snow = self.quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.ice = self.quantity_factory.ones([X_DIM, Y_DIM], "n/a") + self.graupel = self.quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + + orchestrate(obj=self, config=self.stencil_factory.config.dace_config) + self._stencil = self.stencil_factory.from_dims_halo( + func=terminal_fall, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "dts": dts, + "tau_imlt": tau_imlt, + "ql_mlt": ql_mlt, + "c_air": c_air, + "c_vap": c_vap, + "d0_vap": d0_vap, + "lv00": lv00, + "vi_fac": vi_fac, + "do_sedi_w": do_sedi_w, + "use_ppm": use_ppm, + "tau_smlt": tau_smlt, + "tau_g2r": tau_g2r, + }, + ) + + self._stencil( + t_terminal_fall, + qv_terminal_fall, + ql_terminal_fall, + qr_terminal_fall, + qg_terminal_fall, + qs_terminal_fall, + qi_terminal_fall, + dz1_terminal_fall, + dp1_terminal_fall, + den1_terminal_fall, + vtg_terminal_fall, + vts_terminal_fall, + vti_terminal_fall, + self.rain, + self.graupel, + self.snow, + self.ice, + m1_sol_terminal_fall, + w1_terminal_fall, + self.ze, + self.zt, + self.is_frozen, + self.precip_fall, + self.melting_mask_1, + self.melting_mask_2, + self.current_k_level, + ) + + return { + "t_terminal_fall": t_terminal_fall.view[:], + "qv_terminal_fall": qv_terminal_fall.view[:], + "ql_terminal_fall": ql_terminal_fall.view[:], + "qr_terminal_fall": qr_terminal_fall.view[:], + "qg_terminal_fall": qg_terminal_fall.view[:], + "qs_terminal_fall": qs_terminal_fall.view[:], + "qi_terminal_fall": qi_terminal_fall.view[:], + "dz1_terminal_fall": dz1_terminal_fall.view[:], + "dp1_terminal_fall": dp1_terminal_fall.view[:], + "den1_terminal_fall": den1_terminal_fall.view[:], + "m1_sol_terminal_fall": m1_sol_terminal_fall.view[:], + "r1_terminal_fall": self.rain.view[:], + "g1_terminal_fall": self.graupel.view[:], + "s1_terminal_fall": self.snow.view[:], + "i1_terminal_fall": self.ice.view[:], + } diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_warm_rain.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_warm_rain.py new file mode 100644 index 000000000..5e29ea331 --- /dev/null +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/GFDL_1M_driver/translate_warm_rain.py @@ -0,0 +1,294 @@ +from ndsl import Namelist, Quantity, StencilFactory, orchestrate +from ndsl.constants import X_DIM, Y_DIM, Z_DIM, Z_INTERFACE_DIM +from ndsl.dsl.typing import Float, Int +from ndsl.stencils.testing.translate import TranslateFortranData2Py +from pyMoist.GFDL_1M.GFDL_1M_driver.GFDL_1M_driver_tables import get_tables +from pyMoist.GFDL_1M.GFDL_1M_driver.warm_rain import warm_rain + + +class Translatewarm_rain(TranslateFortranData2Py): + def __init__(self, grid, namelist: Namelist, stencil_factory: StencilFactory): + super().__init__(grid, stencil_factory) + self.stencil_factory = stencil_factory + self.quantity_factory = grid.quantity_factory + self._grid = grid + + # FloatField Inputs + self.in_vars["data_vars"] = { + "dp1_warm_rain": {}, + "dz1_warm_rain": {}, + "t1_warm_rain": {}, + "qv_warm_rain": {}, + "ql_warm_rain": {}, + "qr_warm_rain": {}, + "qi_warm_rain": {}, + "qs_warm_rain": {}, + "qg_warm_rain": {}, + "qa_warm_rain": {}, + "ccn_warm_rain": {}, + "den_warm_rain": {}, + "denfac_warm_rain": {}, + "c_praut_warm_rain": {}, + "vtr_warm_rain": {}, + "evap1_warm_rain": {}, + "m1_rain_warm_rain": {}, + "w1_warm_rain": {}, + "rh_limited_warm_rain": {}, + "eis_warm_rain": {}, + "onemsig_warm_rain": {}, + "dts_warm_rain": {}, + "do_qa_warm_rain": {}, + "rthreshs_warm_rain": {}, + "rthreshu_warm_rain": {}, + "irain_f_warm_rain": {}, + "ql0_max_warm_rain": {}, + "z_slope_liq_warm_rain": {}, + "vr_fac_warm_rain": {}, + "const_vr_warm_rain": {}, + "vr_max_warm_rain": {}, + "vr_min_warm_rain": {}, + "tau_revp_warm_rain": {}, + "lv00_warm_rain": {}, + "d0_vap_warm_rain": {}, + "c_air_warm_rain": {}, + "c_vap_warm_rain": {}, + "crevp_0_warm_rain": {}, + "crevp_1_warm_rain": {}, + "crevp_2_warm_rain": {}, + "crevp_3_warm_rain": {}, + "crevp_4_warm_rain": {}, + "cracw_warm_rain": {}, + "do_sedi_w_warm_rain": {}, + "use_ppm_warm_rain": {}, + } + + # FloatField Outputs + self.out_vars = { + "t1_warm_rain": self.grid.compute_dict(), + "qv_warm_rain": self.grid.compute_dict(), + "ql_warm_rain": self.grid.compute_dict(), + "qr_warm_rain": self.grid.compute_dict(), + "qi_warm_rain": self.grid.compute_dict(), + "qs_warm_rain": self.grid.compute_dict(), + "qg_warm_rain": self.grid.compute_dict(), + "qa_warm_rain": self.grid.compute_dict(), + "vtr_warm_rain": self.grid.compute_dict(), + "evap1_warm_rain": self.grid.compute_dict(), + "m1_rain_warm_rain": self.grid.compute_dict(), + "r1_warm_rain": self.grid.compute_dict(), + } + + self.sat_tables = get_tables(self.stencil_factory.backend) + + def make_ij_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM], + "n/a", + ) + qty.view[:, :] = qty.np.asarray(data[:, :]) + return qty + + def make_ijk_field(self, data) -> Quantity: + qty = self.quantity_factory.empty( + [X_DIM, Y_DIM, Z_DIM], + "n/a", + ) + qty.view[:, :, :] = qty.np.asarray(data[:, :, :]) + return qty + + def compute(self, inputs): + # FloatField Variables + dp1_warm_rain = self.make_ijk_field(inputs["dp1_warm_rain"]) + dp1_original = dp1_warm_rain + dz1_warm_rain = self.make_ijk_field(inputs["dz1_warm_rain"]) + dz1_original = dz1_warm_rain + t1_warm_rain = self.make_ijk_field(inputs["t1_warm_rain"]) + t1_original = t1_warm_rain + qv_warm_rain = self.make_ijk_field(inputs["qv_warm_rain"]) + qv_original = qv_warm_rain + ql_warm_rain = self.make_ijk_field(inputs["ql_warm_rain"]) + ql_original = ql_warm_rain + qr_warm_rain = self.make_ijk_field(inputs["qr_warm_rain"]) + qr_original = qr_warm_rain + qi_warm_rain = self.make_ijk_field(inputs["qi_warm_rain"]) + qi_original = qi_warm_rain + qs_warm_rain = self.make_ijk_field(inputs["qs_warm_rain"]) + qs_original = qs_warm_rain + qg_warm_rain = self.make_ijk_field(inputs["qg_warm_rain"]) + qg_original = qg_warm_rain + qa_warm_rain = self.make_ijk_field(inputs["qa_warm_rain"]) + qa_original = qa_warm_rain + ccn_warm_rain = self.make_ijk_field(inputs["ccn_warm_rain"]) + ccn_original = ccn_warm_rain + den_warm_rain = self.make_ijk_field(inputs["den_warm_rain"]) + den_original = den_warm_rain + denfac_warm_rain = self.make_ijk_field(inputs["denfac_warm_rain"]) + denfac_original = denfac_warm_rain + c_praut_warm_rain = self.make_ijk_field(inputs["c_praut_warm_rain"]) + c_praut_original = c_praut_warm_rain + vtr_warm_rain = self.make_ijk_field(inputs["vtr_warm_rain"]) + vtr_original = vtr_warm_rain + evap1_warm_rain = self.make_ijk_field(inputs["evap1_warm_rain"]) + evap1_original = evap1_warm_rain + m1_rain_warm_rain = self.make_ijk_field(inputs["m1_rain_warm_rain"]) + m1_rain_original = m1_rain_warm_rain + w1_warm_rain = self.make_ijk_field(inputs["w1_warm_rain"]) + w1_original = w1_warm_rain + rh_limited_warm_rain = self.make_ijk_field(inputs["rh_limited_warm_rain"]) + rh_limited_original = rh_limited_warm_rain + eis_warm_rain = self.make_ij_field(inputs["eis_warm_rain"]) + eis_original = eis_warm_rain + onemsig_warm_rain = self.make_ij_field(inputs["onemsig_warm_rain"]) + onemsig_original = onemsig_warm_rain + + # Float Variables + dts = Float(inputs["dts_warm_rain"][0]) + do_qa = Float(inputs["do_qa_warm_rain"][0]) + rthreshs = Float(inputs["rthreshs_warm_rain"][0]) + rthreshu = Float(inputs["rthreshu_warm_rain"][0]) + irain_f = Float(inputs["irain_f_warm_rain"][0]) + ql0_max = Float(inputs["ql0_max_warm_rain"][0]) + z_slope_liq = Float(inputs["z_slope_liq_warm_rain"][0]) + vr_fac = Float(inputs["vr_fac_warm_rain"][0]) + const_vr = Float(inputs["const_vr_warm_rain"][0]) + vr_max = Float(inputs["vr_max_warm_rain"][0]) + tau_revp = Float(inputs["tau_revp_warm_rain"][0]) + lv00 = Float(inputs["lv00_warm_rain"][0]) + d0_vap = Float(inputs["d0_vap_warm_rain"][0]) + c_air = Float(inputs["c_air_warm_rain"][0]) + c_vap = Float(inputs["c_vap_warm_rain"][0]) + crevp_0 = Float(inputs["crevp_0_warm_rain"][0]) + crevp_1 = Float(inputs["crevp_1_warm_rain"][0]) + crevp_2 = Float(inputs["crevp_2_warm_rain"][0]) + crevp_3 = Float(inputs["crevp_3_warm_rain"][0]) + crevp_4 = Float(inputs["crevp_4_warm_rain"][0]) + cracw = Float(inputs["cracw_warm_rain"][0]) + do_sedi_w = Float(inputs["do_sedi_w_warm_rain"][0]) + use_ppm = Float(inputs["use_ppm_warm_rain"][0]) + + # Revert to boolean + if do_qa == 1: + do_qa = True + else: + do_qa = False + if z_slope_liq == 1: + z_slope_liq = True + else: + z_slope_liq = False + if const_vr == 1: + const_vr = True + else: + const_vr = False + if do_sedi_w == 1: + do_sedi_w = True + else: + do_sedi_w = False + + # make masks + self.is_frozen = self.quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=bool + ) + self.precip_fall = self.quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.melting_mask_1 = self.quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=bool + ) + self.melting_mask_2 = self.quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=bool + ) + self.current_k_level = self.quantity_factory.zeros( + [X_DIM, Y_DIM, Z_DIM], "n/a", dtype=Int + ) + for k in range(self.current_k_level.view[:].shape[2]): + self.current_k_level.view[:, :, k] = k + + # make temporaries + self.TESTVAR_1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.TESTVAR_2 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + self.ze = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_INTERFACE_DIM], "n/a") + self.zt = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_INTERFACE_DIM], "n/a") + + # make outputs + self.rain = self.quantity_factory.zeros([X_DIM, Y_DIM], "n/a") + self.evap1 = self.quantity_factory.zeros([X_DIM, Y_DIM, Z_DIM], "n/a") + + orchestrate(obj=self, config=self.stencil_factory.config.dace_config) + self._stencil = self.stencil_factory.from_dims_halo( + func=warm_rain, + compute_dims=[X_DIM, Y_DIM, Z_DIM], + externals={ + "dts": dts, + "do_qa": do_qa, + "rthreshs": rthreshs, + "rthreshu": rthreshu, + "irain_f": irain_f, + "ql0_max": ql0_max, + "z_slope_liq": z_slope_liq, + "vr_fac": vr_fac, + "const_vr": const_vr, + "vr_max": vr_max, + "tau_revp": tau_revp, + "lv00": lv00, + "d0_vap": d0_vap, + "c_air": c_air, + "c_vap": c_vap, + "crevp_0": crevp_0, + "crevp_1": crevp_1, + "crevp_2": crevp_2, + "crevp_3": crevp_3, + "crevp_4": crevp_4, + "cracw": cracw, + "do_sedi_w": do_sedi_w, + "use_ppm": use_ppm, + }, + ) + + self._stencil( + dp1_warm_rain, + dz1_warm_rain, + t1_warm_rain, + qv_warm_rain, + ql_warm_rain, + qr_warm_rain, + qi_warm_rain, + qs_warm_rain, + qg_warm_rain, + qa_warm_rain, + ccn_warm_rain, + den_warm_rain, + denfac_warm_rain, + c_praut_warm_rain, + vtr_warm_rain, + self.evap1, + m1_rain_warm_rain, + w1_warm_rain, + rh_limited_warm_rain, + eis_warm_rain, + onemsig_warm_rain, + self.rain, + self.ze, + self.zt, + self.precip_fall, + self.sat_tables.table1, + self.sat_tables.table2, + self.sat_tables.table3, + self.sat_tables.table4, + self.sat_tables.des1, + self.sat_tables.des2, + self.sat_tables.des3, + self.sat_tables.des4, + ) + + return { + "t1_warm_rain": t1_warm_rain.view[:], + "qv_warm_rain": qv_warm_rain.view[:], + "ql_warm_rain": ql_warm_rain.view[:], + "qr_warm_rain": qr_warm_rain.view[:], + "qi_warm_rain": qi_warm_rain.view[:], + "qs_warm_rain": qs_warm_rain.view[:], + "qg_warm_rain": qg_warm_rain.view[:], + "qa_warm_rain": qa_warm_rain.view[:], + "vtr_warm_rain": vtr_warm_rain.view[:], + "evap1_warm_rain": self.evap1.view[:], + "m1_rain_warm_rain": m1_rain_warm_rain.view[:], + "r1_warm_rain": self.rain.view[:], + } diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/translate_GFDL_1M.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/translate_GFDL_1M.py similarity index 98% rename from GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/translate_GFDL_1M.py rename to GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/translate_GFDL_1M.py index 4cfc2f75c..ce1088f67 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/translate_GFDL_1M.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/GFDL_1M/translate_GFDL_1M.py @@ -40,7 +40,7 @@ def __init__(self, grid, namelist: Namelist, stencil_factory: StencilFactory): "dw_land", "dw_ocean", "TURNRHCRIT_PARAM", - "DT_MOIST_Float", + "DT_MOIST", "CCW_EVAP_EFF", "CCI_EVAP_EFF", "PDFSHAPE", @@ -102,7 +102,7 @@ def compute(self, inputs): dw_land = Float(inputs["dw_land"]) dw_ocean = Float(inputs["dw_ocean"]) TURNRHCRIT_PARAM = Float(inputs["TURNRHCRIT_PARAM"]) - DT_MOIST = Float(inputs["DT_MOIST_Float"]) + DT_MOIST = Float(inputs["DT_MOIST"]) CCW_EVAP_EFF = Float(inputs["CCW_EVAP_EFF"]) CCI_EVAP_EFF = Float(inputs["CCI_EVAP_EFF"]) PDFSHAPE = Float(inputs["PDFSHAPE"]) diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/__init__.py b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/__init__.py index 49588e5fe..eee481c92 100644 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/__init__.py +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/savepoint/__init__.py @@ -1,5 +1,16 @@ +from .GFDL_1M.GFDL_1M_driver.translate_fall_speed import Translatefall_speed +from .GFDL_1M.GFDL_1M_driver.translate_GFDL_1M_driver import TranslateGFDL_1M_driver +from .GFDL_1M.GFDL_1M_driver.translate_GFDL_1M_driver_preloop import ( + TranslateGFDL_1M_driver_preloop, +) +from .GFDL_1M.GFDL_1M_driver.translate_GFDL_driver_tables import ( + TranslateGFDL_driver_tables, +) +from .GFDL_1M.GFDL_1M_driver.translate_icloud import Translateicloud +from .GFDL_1M.GFDL_1M_driver.translate_terminal_fall import Translateterminal_fall +from .GFDL_1M.GFDL_1M_driver.translate_warm_rain import Translatewarm_rain +from .GFDL_1M.translate_GFDL_1M import TranslateGFDL_1M from .translate_aer_activation import TranslateAerActivation -from .translate_GFDL_1M import TranslateGFDL_1M from .translate_qsat import TranslateQSat from .translate_radiation_coupling import TranslateRadCouple from .translate_redistribute_clouds import TranslateRedistributeClouds diff --git a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/scripts/run_tests.sh b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/scripts/run_tests.sh index 94e777860..a9ef7e953 100755 --- a/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/scripts/run_tests.sh +++ b/GEOSagcm_GridComp/GEOSphysics_GridComp/GEOSmoist_GridComp/pyMoist/tests/scripts/run_tests.sh @@ -1,10 +1,20 @@ #!/bin/bash -rm -rf ./.gt_cache_* -export PACE_FLOAT_PRECISION=32 +clear +# rm -rf ./.gt_cache_* +rm -rf ./.translate-* +export GT4PY_LITERAL_PRECISION=32 export FV3_DACEMODE=Python -python -m pytest -v -s -x\ - --data_path=../../test_data/11.5.2/Moist/TBC_C24_L72_Debug \ - --backend=dace:cpu \ +export PACE_FLOAT_PRECISION=32 +export PACE_TEST_N_THRESHOLD_SAMPLES=0 +export PACE_DACE_DEBUG=True +export GT4PY_COMPILE_OPT_LEVEL=0 +# for debugging only +export OMP_NUM_THREADS=1 +python -m pytest -s \ + --data_path=/Users/ckropiew/netcdfs \ + --backend=gt:cpu_kfirst \ --grid=default \ --multimodal_metric \ + --which_modules=icloud \ + --which_rank=0 \ ..