├── .gitignore ├── test ├── unit-test │ ├── tests │ │ ├── CMakeLists.txt │ │ ├── utilities │ │ │ ├── CMakeLists.txt │ │ │ └── test_state_converters.pf │ │ ├── phys_utils │ │ │ ├── CMakeLists.txt │ │ │ ├── test_atmos_pbl_utils.pf │ │ │ └── test_atmos_rad_utils.pf │ │ └── mmm │ │ │ └── CMakeLists.txt │ ├── include │ │ └── ccpp_kinds.F90 │ ├── README.md │ └── CMakeLists.txt ├── musica │ ├── configuration │ │ ├── micm_util │ │ │ ├── config.json │ │ │ ├── species.json │ │ │ └── reactions.json │ │ └── analytical │ │ │ ├── config.json │ │ │ ├── species.json │ │ │ └── reactions.json │ ├── README.md │ ├── micm │ │ ├── test_micm_mock_mods.F90 │ │ └── CMakeLists.txt │ ├── musica_ccpp_namelist.F90 │ ├── util │ │ └── CMakeLists.txt │ ├── aerosol_stub │ │ └── CMakeLists.txt │ ├── aerosol │ │ └── CMakeLists.txt │ └── tuvx │ │ ├── test_tuvx_wavelength_grid.F90 │ │ ├── test_tuvx_surface_albedo.F90 │ │ └── test_tuvx_temperature.F90 ├── cmake │ ├── SetDefaults.cmake │ └── TestUtils.cmake ├── .dockerignore ├── include │ └── ccpp_kinds.F90 ├── test_suites │ ├── suite_file_io_test.xml │ ├── suite_dme_adjust.xml │ ├── suite_tj2016_precip.xml │ ├── suite_dry_adiabatic_adjust.xml │ ├── suite_tropopause_find.xml │ ├── suite_tj2016_sfc_pbl_hs.xml │ ├── suite_rayleigh_friction.xml │ ├── suite_kessler_test.xml │ ├── suite_convection_permitting.xml │ ├── suite_zhang_mcfarlane.xml │ ├── suite_gw_cam4.xml │ ├── suite_convect_shallow_hack.xml │ └── suite_gw_cam7_se.xml ├── test_schemes │ ├── initialize_constituents.meta │ └── file_io_test.meta ├── CMakeLists.txt ├── valgrind.supp └── docker │ └── Dockerfile.musica.no_install ├── to_be_ccppized ├── coords_1d.meta ├── namelist_utils.F90 ├── ccpp_const_utils.F90 └── ccpp_tuvx_utils.F90 ├── .github ├── pull_request_template.md ├── PULL_REQUEST_TEMPLATE │ ├── main-template.md │ └── develop-template.md └── workflows │ ├── no-direct-pr-to-main.yaml │ ├── test.yaml │ └── unit-tests.yaml ├── schemes ├── rrtmgp │ ├── objects │ │ ├── ccpp_fluxes.meta │ │ ├── ccpp_fluxes_byband.meta │ │ ├── ccpp_gas_concentrations.meta │ │ ├── ccpp_source_functions.meta │ │ ├── ccpp_gas_optics_rrtmgp.meta │ │ ├── ccpp_fluxes.F90 │ │ ├── ccpp_fluxes_byband.F90 │ │ ├── ccpp_gas_concentrations.F90 │ │ ├── ccpp_optical_props.meta │ │ ├── ccpp_source_functions.F90 │ │ ├── ccpp_gas_optics_rrtmgp.F90 │ │ └── ccpp_optical_props.F90 │ └── utils │ │ └── rrtmgp_dry_static_energy_tendency.F90 ├── musica │ ├── aerosol_stub │ │ └── README.md │ ├── aerosol │ │ └── musica_ccpp_aerosol_state.F90 │ ├── util │ │ └── musica_ccpp_util.F90 │ └── tuvx │ │ ├── musica_ccpp_tuvx_wavelength_grid.F90 │ │ └── musica_ccpp_tuvx_temperature.F90 ├── mmm │ ├── ccpp_kind_types.F90 │ └── CMakeLists.txt ├── conservation_adjust │ └── check_energy │ │ ├── check_energy_chng_namelist.xml │ │ ├── check_energy_save_teout.meta │ │ ├── check_energy_scaling.meta │ │ ├── check_energy_save_teout.F90 │ │ ├── check_energy_zero_fluxes.F90 │ │ ├── check_energy_zero_fluxes.meta │ │ ├── dycore_energy_consistency_adjust.meta │ │ ├── check_energy_scaling.F90 │ │ ├── check_energy_fix.meta │ │ ├── check_energy_fix.F90 │ │ └── dycore_energy_consistency_adjust.F90 ├── sima_diagnostics │ ├── check_energy_gmean_diagnostics_namelist.xml │ ├── kessler_diagnostics.meta │ ├── compute_cloud_fraction_diagnostics.meta │ ├── gravity_wave_drag_common_diagnostics.meta │ ├── rayleigh_friction_diagnostics.meta │ ├── sima_tend_diagnostics.meta │ ├── convective_cloud_cover_diagnostics.meta │ ├── check_energy_gmean_diagnostics.meta │ ├── check_energy_fix_diagnostics.meta │ ├── compute_cloud_fraction_diagnostics.F90 │ ├── kessler_diagnostics.F90 │ ├── zm_tendency_diagnostics.meta │ ├── gravity_wave_drag_common_diagnostics.F90 │ ├── zm_convr_tendency_diagnostics.meta │ ├── sima_tend_diagnostics.F90 │ ├── check_energy_diagnostics.meta │ ├── zm_momtran_tendency_diagnostics.meta │ ├── zm_convr_tendency_diagnostics.F90 │ ├── cloud_particle_sedimentation_diagnostics.meta │ ├── convective_cloud_cover_diagnostics.F90 │ ├── check_energy_gmean_diagnostics.F90 │ ├── rayleigh_friction_diagnostics.F90 │ ├── zm_momtran_tendency_diagnostics.F90 │ └── zm_evap_tendency_diagnostics.meta ├── utilities │ ├── to_be_ccppized_temporary.meta │ ├── to_be_ccppized_temporary.F90 │ ├── static_energy.F90 │ ├── convert_dry_constituent_tendencies_to_dry_air_basis.meta │ ├── static_energy.meta │ └── convert_dry_constituent_tendencies_to_dry_air_basis.F90 ├── hack_shallow │ ├── set_shallow_conv_fluxes_to_general.F90 │ ├── hack_convect_shallow_namelist.xml │ ├── set_shallow_conv_fluxes_to_general.meta │ └── set_general_conv_fluxes_to_shallow.F90 ├── cloud_fraction │ ├── set_cloud_fraction_top.meta │ ├── set_cloud_fraction_top.F90 │ └── cloud_fraction_fice.meta ├── zhang_mcfarlane │ ├── set_deep_conv_fluxes_to_general.F90 │ ├── set_deep_conv_fluxes_to_general.meta │ ├── set_general_conv_fluxes_to_deep.F90 │ ├── save_ttend_from_convect_deep.meta │ └── save_ttend_from_convect_deep.F90 ├── holtslag_boville │ ├── holtslag_boville_diff_options.meta │ └── holtslag_boville_diff_options.F90 ├── vertical_diffusion │ ├── vertical_diffusion_options.meta │ ├── vertical_diffusion_options.F90 │ └── vertical_diffusion_sponge_layer.meta ├── thermo_water_update │ ├── thermo_water_update.meta │ └── thermo_water_update.F90 ├── rayleigh_friction │ └── rayleigh_friction_namelist.xml └── gravity_wave_drag │ ├── gravity_wave_drag_top_taper.meta │ ├── gw_common.meta │ ├── gravity_wave_drag_top_taper.F90 │ └── gw_utils.F90 ├── suites ├── suite_musica.xml ├── suite_held_suarez_1994.xml ├── suite_adiabatic.xml ├── suite_tj2016.xml └── suite_kessler.xml ├── doc └── ChangeLog_template ├── .gitmodules ├── phys_utils ├── atmos_phys_rad_utils.F90 └── atmos_phys_string_utils.F90 └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.DS_Store 2 | **/*.pyc 3 | **/build/ 4 | **/CMakeCache.txt 5 | **/CMakeFiles/ 6 | .vscode 7 | xcode/ -------------------------------------------------------------------------------- /test/unit-test/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(utilities) 2 | add_subdirectory(phys_utils) 3 | add_subdirectory(mmm) 4 | -------------------------------------------------------------------------------- /test/musica/configuration/micm_util/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "camp-files": [ 3 | "species.json", 4 | "reactions.json" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /test/musica/configuration/analytical/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "camp-files": [ 3 | "species.json", 4 | "reactions.json" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /to_be_ccppized/coords_1d.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = coords1d 3 | type = ddt 4 | 5 | [ccpp-arg-table] 6 | name = coords1d 7 | type = ddt 8 | -------------------------------------------------------------------------------- /test/unit-test/tests/utilities/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_pfunit_ctest(utilities_tests 2 | TEST_SOURCES test_state_converters.pf 3 | LINK_LIBRARIES utilities 4 | ) 5 | 6 | -------------------------------------------------------------------------------- /to_be_ccppized/namelist_utils.F90: -------------------------------------------------------------------------------- 1 | module namelist_utils 2 | 3 | use shr_nl_mod, only: & 4 | find_group_name => shr_nl_find_group_name 5 | 6 | end module namelist_utils 7 | -------------------------------------------------------------------------------- /test/cmake/SetDefaults.cmake: -------------------------------------------------------------------------------- 1 | # Overwrite the init values choosen by CMake 2 | if (CMAKE_Fortran_COMPILER_ID MATCHES "GNU") 3 | set(CMAKE_Fortran_FLAGS_DEBUG_INIT "-g") 4 | endif() 5 | -------------------------------------------------------------------------------- /test/.dockerignore: -------------------------------------------------------------------------------- 1 | # ignore all 2 | * 3 | 4 | # add things to copy 5 | !cmake/ 6 | !docker/ 7 | !held_suarez 8 | !kessler 9 | !musica/ 10 | !test/ 11 | !utilities 12 | !zm 13 | !CMakeLists.txt -------------------------------------------------------------------------------- /test/include/ccpp_kinds.F90: -------------------------------------------------------------------------------- 1 | module ccpp_kinds 2 | 3 | use ISO_FORTRAN_ENV, only: kind_phys => REAL64 4 | 5 | implicit none 6 | private 7 | 8 | public kind_phys 9 | 10 | end module ccpp_kinds -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Please go the the `Preview` tab and select the appropriate PR template: 2 | 3 | * [development branch](?expand=1&template=develop-template.md) 4 | * [main branch](?expand=1&template=main-template.md) 5 | -------------------------------------------------------------------------------- /test/unit-test/include/ccpp_kinds.F90: -------------------------------------------------------------------------------- 1 | module ccpp_kinds 2 | 3 | use ISO_FORTRAN_ENV, only: kind_phys => REAL64 4 | 5 | implicit none 6 | private 7 | 8 | public :: kind_phys 9 | 10 | end module ccpp_kinds 11 | 12 | -------------------------------------------------------------------------------- /test/unit-test/tests/phys_utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_pfunit_ctest(phys_utils_tests 2 | TEST_SOURCES test_atmos_pbl_utils.pf 3 | TEST_SOURCES test_atmos_string_utils.pf 4 | TEST_SOURCES test_atmos_rad_utils.pf 5 | LINK_LIBRARIES phys_utils 6 | ) 7 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_fluxes.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = ty_fluxes_broadband_ccpp 3 | type = ddt 4 | # dependencies = /path/to/ext/rte-frontend/mo_fluxes.F90 5 | 6 | [ccpp-arg-table] 7 | name = ty_fluxes_broadband_ccpp 8 | type = ddt 9 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_fluxes_byband.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = ty_fluxes_byband_ccpp 3 | type = ddt 4 | # dependencies = /path/to/ext/extensions/mo_fluxes_byband.F90 5 | 6 | [ccpp-arg-table] 7 | name = ty_fluxes_byband_ccpp 8 | type = ddt 9 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_gas_concentrations.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = ty_gas_concs_ccpp 3 | type = ddt 4 | # dependencies = /path/to/ext/gas-optics/mo_gas_concentrations.F90 5 | 6 | [ccpp-arg-table] 7 | name = ty_gas_concs_ccpp 8 | type = ddt 9 | -------------------------------------------------------------------------------- /test/unit-test/tests/mmm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_pfunit_ctest(mmm_physics_compat_tests 2 | TEST_SOURCES 3 | mmm_physics_compat_tests.pf 4 | OTHER_SOURCES 5 | ../../include/ccpp_kinds.F90 6 | LINK_LIBRARIES 7 | mmm_physics_compat 8 | ) 9 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_source_functions.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = ty_source_func_lw_ccpp 3 | type = ddt 4 | # dependencies = /path/to/ext/rte-frontend/mo_source_functions.F90 5 | 6 | [ccpp-arg-table] 7 | name = ty_source_func_lw_ccpp 8 | type = ddt 9 | -------------------------------------------------------------------------------- /schemes/musica/aerosol_stub/README.md: -------------------------------------------------------------------------------- 1 | The stub aerosol model 2 | ====================== 3 | 4 | The files in this folder define a stub aerosol model, primarily for use during 5 | development. Functions of the stub aerosol classes return values corresponding 6 | to the absence of aerosols. -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_gas_optics_rrtmgp.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = ty_gas_optics_rrtmgp_ccpp 3 | type = ddt 4 | # dependencies = /path/to/ext/rrtmgp-frontend/mo_gas_optics_rrtmgp.F90 5 | 6 | [ccpp-arg-table] 7 | name = ty_gas_optics_rrtmgp_ccpp 8 | type = ddt 9 | -------------------------------------------------------------------------------- /test/test_suites/suite_file_io_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | file_io_test 7 | 8 | 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/main-template.md: -------------------------------------------------------------------------------- 1 | Tag name (The PR title should also include the tag name): 2 | Originator(s): 3 | 4 | List all `development` PR numbers included in this PR and the title of each: 5 | 6 | List all automated tests that failed, as well as an explanation for why they weren't fixed: 7 | -------------------------------------------------------------------------------- /test/musica/README.md: -------------------------------------------------------------------------------- 1 | MUSICA tests for CAM-SIMA Physics 2 | ================================= 3 | 4 | To build and run the MUSICA tests for CAM-SIMA in a Docker container, from the 5 | top-level folder run: 6 | 7 | ``` 8 | docker build -t atmos-phys . -f test/docker/Docker.musica 9 | docker run -it atmos-phys bash 10 | make test 11 | ``` -------------------------------------------------------------------------------- /test/test_suites/suite_dme_adjust.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | initialize_constituents 6 | dme_adjust 7 | sima_state_diagnostics 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /suites/suite_musica.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | calc_dry_air_ideal_gas_density 6 | musica_ccpp 7 | 8 | 9 | sima_state_diagnostics 10 | 11 | 12 | -------------------------------------------------------------------------------- /schemes/mmm/ccpp_kind_types.F90: -------------------------------------------------------------------------------- 1 | !> The mere existence of this module is to satisfy the misdirected dependency of MMM physics, 2 | !> which inexplicably depends on `ccpp_kind_types` instead of `ccpp_kinds`. 3 | module ccpp_kind_types 4 | use ccpp_kinds, only: kind_phys 5 | 6 | implicit none 7 | 8 | private 9 | public :: kind_phys 10 | contains 11 | end module ccpp_kind_types 12 | -------------------------------------------------------------------------------- /test/test_suites/suite_tj2016_precip.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tj2016_precip 6 | apply_heating_rate 7 | qneg 8 | sima_state_diagnostics 9 | sima_tend_diagnostics 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_fluxes.F90: -------------------------------------------------------------------------------- 1 | module ccpp_fluxes 2 | ! CCPP wrapper for ty_fluxes_broadband DDT from RRTMGP 3 | use mo_fluxes, only: ty_fluxes_broadband 4 | 5 | !> \section arg_table_ty_fluxes_broadband_ccpp Argument Table 6 | !! \htmlinclude ty_fluxes_broadband_ccpp.html 7 | type, public :: ty_fluxes_broadband_ccpp 8 | type(ty_fluxes_broadband) :: fluxes 9 | end type 10 | 11 | end module ccpp_fluxes 12 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_fluxes_byband.F90: -------------------------------------------------------------------------------- 1 | module ccpp_fluxes_byband 2 | ! CCPP wrapper for ty_fluxes_byband DDT from RRTMGP 3 | use mo_fluxes_byband, only: ty_fluxes_byband 4 | 5 | !> \section arg_table_ty_fluxes_byband_ccpp Argument Table 6 | !! \htmlinclude ty_fluxes_byband_ccpp.html 7 | type, public :: ty_fluxes_byband_ccpp 8 | type(ty_fluxes_byband) :: fluxes 9 | end type 10 | 11 | end module ccpp_fluxes_byband 12 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_gas_concentrations.F90: -------------------------------------------------------------------------------- 1 | module ccpp_gas_concentrations 2 | ! CCPP wrapper for ty_gas_concs DDT from RRTMGP 3 | use mo_gas_concentrations, only: ty_gas_concs 4 | 5 | !> \section arg_table_ty_gas_concs_ccpp Argument Table 6 | !! \htmlinclude ty_gas_concs_ccpp.html 7 | type, public :: ty_gas_concs_ccpp 8 | type(ty_gas_concs) :: gas_concs 9 | end type 10 | 11 | end module ccpp_gas_concentrations 12 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_optical_props.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = ty_optical_props_1scl_ccpp 3 | type = ddt 4 | # dependencies = /path/to/ext/rte-frontend/mo_optical_props.F90 5 | 6 | [ccpp-arg-table] 7 | name = ty_optical_props_1scl_ccpp 8 | type = ddt 9 | 10 | [ccpp-table-properties] 11 | name = ty_optical_props_2str_ccpp 12 | type = ddt 13 | 14 | [ccpp-arg-table] 15 | name = ty_optical_props_2str_ccpp 16 | type = ddt 17 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_source_functions.F90: -------------------------------------------------------------------------------- 1 | module ccpp_source_functions 2 | ! CCPP wrapper for ty_source_func_lw DDT from RRTMGP 3 | use mo_source_functions, only: ty_source_func_lw 4 | 5 | !> \section arg_table_ty_source_func_lw_ccpp Argument Table 6 | !! \htmlinclude ty_source_func_lw_ccpp.html 7 | type, public :: ty_source_func_lw_ccpp 8 | type(ty_source_func_lw) :: sources 9 | end type 10 | 11 | end module ccpp_source_functions 12 | -------------------------------------------------------------------------------- /test/test_suites/suite_dry_adiabatic_adjust.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | dadadj 7 | apply_constituent_tendencies 8 | apply_heating_rate 9 | qneg 10 | geopotential_temp 11 | 12 | 13 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_gas_optics_rrtmgp.F90: -------------------------------------------------------------------------------- 1 | module ccpp_gas_optics_rrtmgp 2 | ! CCPP wrapper for ty_gas_optics_rrtmgp DDT from RRTMGP 3 | use mo_gas_optics_rrtmgp, only: ty_gas_optics_rrtmgp 4 | 5 | !> \section arg_table_ty_gas_optics_rrtmgp_ccpp Argument Table 6 | !! \htmlinclude ty_gas_optics_rrtmgp_ccpp.html 7 | type, public :: ty_gas_optics_rrtmgp_ccpp 8 | type(ty_gas_optics_rrtmgp) :: gas_props 9 | end type 10 | 11 | end module ccpp_gas_optics_rrtmgp 12 | -------------------------------------------------------------------------------- /schemes/musica/aerosol/musica_ccpp_aerosol_state.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | module musica_ccpp_aerosol_state 4 | 5 | implicit none 6 | private 7 | 8 | public :: aerosol_state_t 9 | 10 | !> Defines the state of an aerosol system according to 11 | !! the aerosol representation of a specific aerosol package. 12 | type, abstract :: aerosol_state_t 13 | end type aerosol_state_t 14 | 15 | end module musica_ccpp_aerosol_state -------------------------------------------------------------------------------- /test/musica/configuration/micm_util/species.json: -------------------------------------------------------------------------------- 1 | { 2 | "camp-data": [ 3 | { 4 | "name": "A", 5 | "type": "CHEM_SPEC", 6 | "__is advected": true 7 | }, 8 | { 9 | "name": "B", 10 | "type": "CHEM_SPEC", 11 | "__is advected": true 12 | }, 13 | { 14 | "name": "C", 15 | "type": "CHEM_SPEC", 16 | "__is advected": true 17 | }, 18 | { 19 | "name": "D", 20 | "type": "CHEM_SPEC", 21 | "__is advected": true 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /test/test_suites/suite_tropopause_find.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | tropopause_find 9 | tropopause_diagnostics 10 | qneg 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/test_suites/suite_tj2016_sfc_pbl_hs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tj2016_sfc_pbl_hs 6 | apply_heating_rate 7 | apply_tendency_of_eastward_wind 8 | apply_tendency_of_northward_wind 9 | qneg 10 | sima_state_diagnostics 11 | sima_tend_diagnostics 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/test_suites/suite_rayleigh_friction.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | rayleigh_friction 7 | rayleigh_friction_diagnostics 8 | apply_heating_rate 9 | apply_tendency_of_eastward_wind 10 | apply_tendency_of_northward_wind 11 | geopotential_temp 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /doc/ChangeLog_template: -------------------------------------------------------------------------------- 1 | =============================================================== 2 | 3 | Tag name: 4 | Originator(s): 5 | Date: 6 | One-line Summary: 7 | Github PR URL: 8 | 9 | This PR fixes the following NCAR/atmospheric_physics Github issues: 10 | 11 | Code reviewed by: 12 | 13 | List all existing files that have been added (A), modified (M), or deleted (D), 14 | and describe the changes: 15 | 16 | List and Describe any test failures: 17 | 18 | Summarize any changes to answers: 19 | 20 | =============================================================== 21 | -------------------------------------------------------------------------------- /suites/suite_held_suarez_1994.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | held_suarez_1994 6 | apply_tendency_of_eastward_wind 7 | apply_tendency_of_northward_wind 8 | apply_heating_rate 9 | geopotential_temp 10 | sima_state_diagnostics 11 | 12 | 13 | sima_tend_diagnostics 14 | 15 | 16 | -------------------------------------------------------------------------------- /.github/workflows/no-direct-pr-to-main.yaml: -------------------------------------------------------------------------------- 1 | name: PRs to main must be from development branch 2 | on: 3 | pull_request_target: 4 | types: 5 | - opened 6 | - reopened 7 | - synchronize 8 | - edited 9 | branches: 10 | - main 11 | jobs: 12 | check-branches: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Check branches 16 | run: | 17 | if [ ${{ github.head_ref }} != "development" ]; then 18 | echo "Merge requests to main branch are only allowed from the development branch." 19 | exit 1 20 | fi 21 | -------------------------------------------------------------------------------- /test/musica/micm/test_micm_mock_mods.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2024-2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | module musica_ccpp_species 4 | ! Mock module for testing 5 | use ccpp_kinds, only: kind_phys 6 | 7 | implicit none 8 | private 9 | public :: micm_indices_constituent_props, micm_molar_mass_array 10 | 11 | integer, parameter :: micm_indices_constituent_props(4) = (/ 1, 2, 3, 4 /) 12 | real(kind_phys), parameter :: micm_molar_mass_array(4) = & 13 | (/ 200._kind_phys, 100._kind_phys, 150._kind_phys, 250._kind_phys /) 14 | end module musica_ccpp_species 15 | -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/check_energy_chng_namelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | logical 8 | diagnostics 9 | check_energy_nl 10 | flag_for_energy_conservation_warning 11 | flag 12 | 13 | Turn on verbose output identifying columns that fail energy/water conservation checks. Default: FALSE 14 | 15 | 16 | false 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/check_energy_gmean_diagnostics_namelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | logical 8 | diagnostics 9 | check_energy_gmean_nl 10 | flag_for_energy_global_means_output 11 | flag 12 | 13 | Turn on output of global means of total energy and heating rate for energy conservation. Default: TRUE 14 | 15 | 16 | true 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /schemes/utilities/to_be_ccppized_temporary.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = to_be_ccppized_temporary 3 | type = scheme 4 | dependencies = ../../to_be_ccppized/wv_saturation.F90 5 | [ccpp-arg-table] 6 | name = to_be_ccppized_temporary_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | long_name = Error message for error handling in CCPP 11 | units = none 12 | type = character | kind = len=512 13 | dimensions = () 14 | intent = out 15 | [ errflg ] 16 | standard_name = ccpp_error_code 17 | long_name = Error flag for error handling in CCPP 18 | units = 1 19 | type = integer 20 | dimensions = () 21 | intent = out 22 | 23 | -------------------------------------------------------------------------------- /test/musica/micm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(test_micm_util test_micm_util.F90 test_micm_mock_mods.F90) 2 | 3 | target_sources(test_micm_util 4 | PUBLIC 5 | ${MUSICA_SRC_PATH}/micm/musica_ccpp_micm_util.F90 6 | ${MUSICA_SRC_PATH}/util/musica_ccpp_util.F90 7 | ${CCPP_TEST_SRC_PATH}/ccpp_kinds.F90 8 | ) 9 | 10 | target_link_libraries(test_micm_util 11 | PRIVATE 12 | musica-fortran musica mechanism_configuration yaml-cpp stdc++ netcdff 13 | ) 14 | 15 | add_test( 16 | NAME test_micm_util 17 | COMMAND $ 18 | WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} 19 | ) 20 | 21 | add_memory_check_test(test_micm_util $ "" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "mmm-physics"] 2 | path = schemes/mmm/mmm_physics 3 | url = https://github.com/NCAR/MMM-physics.git 4 | fxtag = 20250616-MPASv8.3 5 | fxrequired = AlwaysRequired 6 | fxDONOTUSEurl = https://github.com/NCAR/MMM-physics.git 7 | [submodule "pumas"] 8 | path = schemes/pumas/pumas 9 | url = https://github.com/ESCOMP/PUMAS 10 | fxrequired = AlwaysRequired 11 | fxtag = pumas_cam-release_v1.39 12 | fxDONOTUSEurl = https://github.com/ESCOMP/PUMAS 13 | [submodule "rte-rrtmgp"] 14 | path = schemes/rrtmgp/ext 15 | url = https://github.com/earth-system-radiation/rte-rrtmgp.git 16 | fxrequired = AlwaysRequired 17 | fxtag = v1.9.2 18 | fxDONOTUSEurl = https://github.com/earth-system-radiation/rte-rrtmgp.git 19 | -------------------------------------------------------------------------------- /test/musica/musica_ccpp_namelist.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2024-2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | 4 | ! Stub for auto-generated MUSICA namelist module 5 | module musica_ccpp_namelist 6 | 7 | implicit none 8 | 9 | private 10 | 11 | character(len=250), public :: micm_solver_type = 'Rosenbrock' 12 | character(len=250), public :: filename_of_micm_configuration = 'musica_configurations/chapman/micm/config.json' 13 | character(len=250), public :: filename_of_tuvx_configuration = 'musica_configurations/chapman/tuvx/config.json' 14 | character(len=250), public :: filename_of_tuvx_micm_mapping_configuration = 'musica_configurations/chapman/tuvx_micm_mapping.json' 15 | 16 | end module musica_ccpp_namelist 17 | -------------------------------------------------------------------------------- /schemes/rrtmgp/objects/ccpp_optical_props.F90: -------------------------------------------------------------------------------- 1 | module ccpp_optical_props 2 | ! CCPP wrapper for ty_optical_props_* DDTs from RRTMGP 3 | use mo_optical_props, only: ty_optical_props_1scl 4 | use mo_optical_props, only: ty_optical_props_2str 5 | 6 | !> \section arg_table_ty_optical_props_1scl_ccpp Argument Table 7 | !! \htmlinclude ty_optical_props_1scl_ccpp.html 8 | type, public :: ty_optical_props_1scl_ccpp 9 | type(ty_optical_props_1scl) :: optical_props 10 | end type 11 | 12 | !> \section arg_table_ty_optical_props_2str_ccpp Argument Table 13 | !! \htmlinclude ty_optical_props_2str_ccpp.html 14 | type, public :: ty_optical_props_2str_ccpp 15 | type(ty_optical_props_2str) :: optical_props 16 | end type 17 | 18 | end module ccpp_optical_props 19 | -------------------------------------------------------------------------------- /test/unit-test/tests/utilities/test_state_converters.pf: -------------------------------------------------------------------------------- 1 | @test 2 | subroutine test_temp_to_potential_temp() 3 | use funit 4 | use state_converters, only : temp_to_potential_temp_run 5 | use ccpp_kinds, only: kind_phys 6 | 7 | integer, parameter :: ncol = 5 8 | integer, parameter :: nz = 5 9 | 10 | real(kind_phys) :: temp(ncol, nz) 11 | real(kind_phys) :: exner(ncol, nz) 12 | real(kind_phys) :: theta(ncol, nz) 13 | character(len=512) :: errmsg 14 | integer :: errflg 15 | 16 | temp = 1 17 | exner = 1 18 | theta = 1 19 | 20 | errmsg = "" 21 | errflg = 0 22 | 23 | call temp_to_potential_temp_run(ncol, nz, temp, exner, theta, errmsg, errflg) 24 | 25 | @assertEqual(0, errflg) 26 | 27 | end subroutine test_temp_to_potential_temp 28 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/develop-template.md: -------------------------------------------------------------------------------- 1 | Originator(s): 2 | 3 | Description (include issue title and the keyword ['closes', 'fixes', 'resolves'] and issue number): 4 | 5 | List all namelist files that were added or changed: 6 | 7 | List all files eliminated and why: 8 | 9 | List all files added and what they do: 10 | 11 | List all existing files that have been modified, and describe the changes: 12 | (Helpful git command: `git diff --name-status development...`) 13 | 14 | List all automated tests that failed, as well as an explanation for why they weren't fixed: 15 | 16 | Is this an answer-changing PR? If so, is it a new physics package, algorithm change, tuning change, etc? 17 | 18 | If yes to the above question, describe how this code was validated with the new/modified features: 19 | -------------------------------------------------------------------------------- /schemes/hack_shallow/set_shallow_conv_fluxes_to_general.F90: -------------------------------------------------------------------------------- 1 | module set_shallow_conv_fluxes_to_general 2 | 3 | use ccpp_kinds, only: kind_phys 4 | 5 | implicit none 6 | 7 | contains 8 | 9 | !> \section arg_table_set_shallow_conv_fluxes_to_general_run Argument Table 10 | !! \htmlinclude set_shallow_conv_fluxes_to_general_run.html 11 | subroutine set_shallow_conv_fluxes_to_general_run(prec_gen, prec_sh, prdprec_gen, prdprec_sh) 12 | 13 | real(kind_phys), intent(out) :: prec_gen(:) 14 | real(kind_phys), intent(in) :: prec_sh(:) 15 | real(kind_phys), intent(out) :: prdprec_gen(:,:) 16 | real(kind_phys), intent(in) :: prdprec_sh(:,:) 17 | 18 | prec_gen = prec_sh 19 | prdprec_gen = prdprec_sh 20 | 21 | end subroutine set_shallow_conv_fluxes_to_general_run 22 | 23 | end module set_shallow_conv_fluxes_to_general 24 | -------------------------------------------------------------------------------- /schemes/cloud_fraction/set_cloud_fraction_top.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = set_cloud_fraction_top 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = set_cloud_fraction_top_init 7 | type = scheme 8 | [ trop_cloud_top_lev ] 9 | standard_name = vertical_layer_index_of_troposphere_cloud_physics_top 10 | units = index 11 | type = integer 12 | dimensions = () 13 | intent = in 14 | [ top_lev ] 15 | standard_name = vertical_layer_index_of_cloud_fraction_top 16 | units = index 17 | type = integer 18 | dimensions = () 19 | intent = out 20 | [ errmsg ] 21 | standard_name = ccpp_error_message 22 | units = none 23 | type = character | kind = len=512 24 | dimensions = () 25 | intent = out 26 | [ errflg ] 27 | standard_name = ccpp_error_code 28 | units = 1 29 | type = integer 30 | dimensions = () 31 | intent = out 32 | -------------------------------------------------------------------------------- /schemes/zhang_mcfarlane/set_deep_conv_fluxes_to_general.F90: -------------------------------------------------------------------------------- 1 | module set_deep_conv_fluxes_to_general 2 | 3 | use ccpp_kinds, only: kind_phys 4 | 5 | implicit none 6 | 7 | contains 8 | 9 | !=============================================================================== 10 | !> \section arg_table_set_deep_conv_fluxes_to_general_run Argument Table 11 | !! \htmlinclude set_deep_conv_fluxes_to_general_run.html 12 | !! 13 | 14 | subroutine set_deep_conv_fluxes_to_general_run(prec_gen, prec_dp, prdprec_gen, prdprec_dp) 15 | 16 | real(kind_phys), intent(out) :: prec_gen(:) 17 | real(kind_phys), intent(in) :: prec_dp(:) 18 | real(kind_phys), intent(out) :: prdprec_gen(:,:) 19 | real(kind_phys), intent(in) :: prdprec_dp(:,:) 20 | 21 | prec_gen = prec_dp 22 | prdprec_gen = prdprec_dp 23 | 24 | end subroutine set_deep_conv_fluxes_to_general_run 25 | 26 | end module set_deep_conv_fluxes_to_general 27 | -------------------------------------------------------------------------------- /schemes/utilities/to_be_ccppized_temporary.F90: -------------------------------------------------------------------------------- 1 | module to_be_ccppized_temporary 2 | ! This module is a TEMPORARY place to put calls to initialization routines which have not yet 3 | ! been CCPP'ized, and the run methods are being called directly in CCPP'ized routines. 4 | 5 | ! Once a module has been CCPP'ized, then the call in this routine needs to be removed 6 | 7 | implicit none 8 | 9 | contains 10 | 11 | !> \section arg_table_to_be_ccppized_temporary_init Argument Table 12 | !! \htmlinclude to_be_ccppized_temporary_init.html 13 | !! 14 | subroutine to_be_ccppized_temporary_init(errmsg, errflg) 15 | 16 | use wv_saturation, only: wv_sat_init 17 | 18 | character(len=512), intent(out) :: errmsg 19 | integer, intent(out) :: errflg 20 | 21 | errmsg = ' ' 22 | errflg = 0 23 | 24 | call wv_sat_init() 25 | 26 | end subroutine to_be_ccppized_temporary_init 27 | 28 | end module to_be_ccppized_temporary 29 | 30 | -------------------------------------------------------------------------------- /test/test_suites/suite_kessler_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | calc_exner 6 | temp_to_potential_temp 7 | calc_dry_air_ideal_gas_density 8 | wet_to_dry_water_vapor 9 | wet_to_dry_cloud_liquid_water 10 | wet_to_dry_rain 11 | kessler 12 | potential_temp_to_temp 13 | dry_to_wet_water_vapor 14 | dry_to_wet_cloud_liquid_water 15 | dry_to_wet_rain 16 | kessler_update 17 | qneg 18 | geopotential_temp 19 | 20 | 21 | sima_state_diagnostics 22 | kessler_diagnostics 23 | 24 | 25 | -------------------------------------------------------------------------------- /schemes/holtslag_boville/holtslag_boville_diff_options.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = holtslag_boville_diff_options 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = holtslag_boville_diff_options_init 7 | type = scheme 8 | [ amIRoot ] 9 | standard_name = flag_for_mpi_root 10 | units = flag 11 | type = logical 12 | dimensions = () 13 | intent = in 14 | [ iulog ] 15 | standard_name = log_output_unit 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = in 20 | [ is_hbr_pbl_scheme ] 21 | standard_name = flag_for_hbr_configuration_of_holtslag_boville_mixing_scheme 22 | units = flag 23 | type = logical 24 | dimensions = () 25 | intent = in 26 | [ errmsg ] 27 | standard_name = ccpp_error_message 28 | units = none 29 | type = character | kind = len=512 30 | dimensions = () 31 | intent = out 32 | [ errflg ] 33 | standard_name = ccpp_error_code 34 | units = 1 35 | type = integer 36 | dimensions = () 37 | intent = out 38 | -------------------------------------------------------------------------------- /test/unit-test/tests/phys_utils/test_atmos_pbl_utils.pf: -------------------------------------------------------------------------------- 1 | @test 2 | subroutine test_free_eddy_coef_is_zero_when_ri_equals_zero() 3 | use funit 4 | use atmos_phys_pbl_utils, only : calc_free_atm_eddy_flux_coefficient 5 | use ccpp_kinds, only: kind_phys 6 | 7 | real(kind_phys) :: kvf 8 | 9 | kvf = calc_free_atm_eddy_flux_coefficient(30.0_kind_phys, 0.0_kind_phys, 0.01_kind_phys) 10 | 11 | @assertEqual(0.0_kind_phys, kvf) 12 | end subroutine test_free_eddy_coef_is_zero_when_ri_equals_zero 13 | 14 | @test 15 | subroutine test_free_eddy_atm_coef_is_zero_when_ri_stable_near_zero() 16 | use funit 17 | use atmos_phys_pbl_utils, only : calc_free_atm_eddy_flux_coefficient 18 | use ccpp_kinds, only: kind_phys 19 | 20 | real(kind_phys) :: kvf 21 | 22 | kvf = calc_free_atm_eddy_flux_coefficient(30.0_kind_phys, nearest(0.0_kind_phys, 1.0_kind_phys), 0.01_kind_phys) 23 | 24 | @assertEqual(0.0_kind_phys, kvf) 25 | end subroutine test_free_eddy_atm_coef_is_zero_when_ri_stable_near_zero 26 | -------------------------------------------------------------------------------- /test/musica/configuration/analytical/species.json: -------------------------------------------------------------------------------- 1 | { 2 | "camp-data": [ 3 | { 4 | "name": "A", 5 | "type": "CHEM_SPEC", 6 | "molecular weight [kg mol-1]": 0.01802, 7 | "__is advected": true 8 | }, 9 | { 10 | "name": "B", 11 | "type": "CHEM_SPEC", 12 | "molecular weight [kg mol-1]": 0.02897, 13 | "__is advected": true 14 | }, 15 | { 16 | "name": "C", 17 | "type": "CHEM_SPEC", 18 | "molecular weight [kg mol-1]": 0.0319988, 19 | "__is advected": true 20 | }, 21 | { 22 | "name": "D", 23 | "type": "CHEM_SPEC", 24 | "molecular weight [kg mol-1]": 0.0479982, 25 | "__is advected": true 26 | }, 27 | { 28 | "name": "E", 29 | "type": "CHEM_SPEC", 30 | "molecular weight [kg mol-1]": 0.07254, 31 | "__is advected": true 32 | }, 33 | { 34 | "name": "F", 35 | "type": "CHEM_SPEC", 36 | "molecular weight [kg mol-1]": 0.082356, 37 | "__is advected": true 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /test/cmake/TestUtils.cmake: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Utility functions for creating tests 3 | 4 | if(CCPP_ENABLE_MEMCHECK) 5 | find_program(MEMORYCHECK_COMMAND "valgrind") 6 | 7 | # Set the Valgrind suppressions file for tests 8 | set(MEMCHECK_SUPPRESS "--suppressions=${CMAKE_SOURCE_DIR}/valgrind.supp") 9 | endif() 10 | 11 | ################################################################################ 12 | # Runs a test with memory checking if enabled 13 | 14 | function(add_memory_check_test test_name test_binary test_args working_dir) 15 | if(CCPP_ENABLE_MEMCHECK) 16 | add_test(NAME memcheck_${test_name} 17 | COMMAND mpirun -v -np 1 ${MEMORYCHECK_COMMAND} --leak-check=full --error-exitcode=1 --trace-children=yes --gen-suppressions=all ${MEMCHECK_SUPPRESS} 18 | ${test_binary} ${test_args} 19 | WORKING_DIRECTORY ${working_dir}) 20 | endif() 21 | endfunction(add_memory_check_test) 22 | 23 | ################################################################################ -------------------------------------------------------------------------------- /test/musica/util/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # MUSICA grid test 2 | add_executable(test_musica_grid test_musica_grid.F90) 3 | 4 | target_sources(test_musica_grid 5 | PUBLIC 6 | ${MUSICA_CCPP_SOURCES} 7 | ${TO_BE_CCPPIZED_SRC_PATH}/ccpp_const_utils.F90 8 | ${TO_BE_CCPPIZED_SRC_PATH}/ccpp_tuvx_utils.F90 9 | ${CCPP_SRC_PATH}/ccpp_constituent_prop_mod.F90 10 | ${CCPP_SRC_PATH}/ccpp_hash_table.F90 11 | ${CCPP_SRC_PATH}/ccpp_hashable.F90 12 | ${CCPP_TEST_SRC_PATH}/ccpp_kinds.F90 13 | ../musica_ccpp_namelist.F90 14 | ) 15 | 16 | target_link_libraries(test_musica_grid 17 | PRIVATE 18 | musica-fortran musica mechanism_configuration yaml-cpp stdc++ netcdff 19 | ) 20 | 21 | set_target_properties(test_musica_grid 22 | PROPERTIES 23 | LINKER_LANGUAGE Fortran 24 | ) 25 | 26 | add_test( 27 | NAME test_musica_grid 28 | COMMAND $ 29 | WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} 30 | ) 31 | 32 | add_memory_check_test(test_musica_grid $ "" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) 33 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/kessler_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = kessler_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = kessler_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | units = none 11 | type = character | kind = len=512 12 | dimensions = () 13 | intent = out 14 | [ errflg ] 15 | standard_name = ccpp_error_code 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = out 20 | 21 | [ccpp-arg-table] 22 | name = kessler_diagnostics_run 23 | type = scheme 24 | [ precl ] 25 | standard_name = total_precipitation_rate_at_surface 26 | units = m s-1 27 | type = real | kind = kind_phys 28 | dimensions = (horizontal_loop_extent) 29 | intent = in 30 | [ errmsg ] 31 | standard_name = ccpp_error_message 32 | units = none 33 | type = character | kind = len=512 34 | dimensions = () 35 | intent = out 36 | [ errflg ] 37 | standard_name = ccpp_error_code 38 | units = 1 39 | type = integer 40 | dimensions = () 41 | intent = out 42 | -------------------------------------------------------------------------------- /schemes/mmm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | # `mmm_physics_compat` has not been integrated into the CMake build of any top level projects yet, 4 | # and this CMakeLists.txt file is currently for unit testing purposes only. 5 | # Making a change to this CMakeLists.txt file will not impact the build of a parent project at this time. 6 | project(mmm_physics_compat 7 | VERSION 8 | 0.1.0 9 | DESCRIPTION 10 | "MMM physics compatibility layer for CCPP" 11 | LANGUAGES 12 | Fortran 13 | ) 14 | 15 | add_library(mmm_physics_compat) 16 | target_sources(mmm_physics_compat 17 | PRIVATE 18 | ../../test/unit-test/include/ccpp_kinds.F90 19 | ccpp_kind_types.F90 20 | mmm_physics_compat.F90 21 | ) 22 | target_compile_options(mmm_physics_compat 23 | PRIVATE 24 | $<$,$>:-fbacktrace -fcheck=all -std=f2018 -Wall -Wextra -Wpedantic> 25 | ) 26 | target_include_directories(mmm_physics_compat 27 | INTERFACE 28 | ${CMAKE_CURRENT_BINARY_DIR} 29 | ) 30 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - development 8 | workflow_dispatch: 9 | pull_request: 10 | 11 | jobs: 12 | test_musica_api: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | submodules: recursive 18 | - name: build Docker image 19 | run: docker build -t musica -f test/docker/Dockerfile.musica . 20 | - name: run tests in container 21 | run: docker run --name test-container -t musica bash -c 'make test ARGS="--rerun-failed --output-on-failure -j8"' 22 | test_musica_api_no_install: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | with: 27 | submodules: recursive 28 | - name: build Docker image 29 | run: docker build -t musica-no-install -f test/docker/Dockerfile.musica.no_install . 30 | - name: run tests in container 31 | run: docker run --name test-container -t musica-no-install bash -c 'make test ARGS="--rerun-failed --output-on-failure -j8"' 32 | -------------------------------------------------------------------------------- /schemes/hack_shallow/hack_convect_shallow_namelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | real 8 | conv 9 | hkconv_nl 10 | characteristic_adjustment_time_for_shallow_convection 11 | s 12 | 13 | Characteristic adjustment time scale for Hack shallow scheme. Default: 1800.0 14 | 15 | 16 | 1800.0 17 | 18 | 19 | 20 | real 21 | conv 22 | hkconv_nl 23 | rain_water_autoconversion_coefficient_for_shallow_convection 24 | m-1 25 | 26 | Rain water autoconversion coefficient for Hack shallow scheme. Resolution dependent. 27 | 28 | 29 | 2.0e-4 30 | 1.0e-4 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /phys_utils/atmos_phys_rad_utils.F90: -------------------------------------------------------------------------------- 1 | module atmos_phys_rad_utils 2 | ! Radiation utility functions 3 | 4 | implicit none 5 | private 6 | 7 | public :: is_visible 8 | 9 | contains 10 | 11 | pure logical function is_visible(wavenumber) 12 | ! Returns true if the provided wavenumber is above the visible threshold 13 | use ccpp_kinds, only: kind_phys 14 | 15 | ! Wavenumber is in the visible if it is above the visible threshold 16 | ! wavenumber, and in the infrared if it is below the threshold 17 | ! This function doesn't distinquish between visible and UV. 18 | 19 | ! wavenumber in inverse cm (cm^-1) 20 | real(kind_phys), intent(in) :: wavenumber 21 | 22 | ! Set threshold between visible and infrared to 0.7 micron, or 14286 cm^-1 23 | real(kind_phys), parameter :: visible_wavenumber_threshold = 14286._kind_phys ! cm^-1 24 | 25 | if (wavenumber > visible_wavenumber_threshold) then 26 | is_visible = .true. 27 | else 28 | is_visible = .false. 29 | end if 30 | 31 | end function is_visible 32 | 33 | end module atmos_phys_rad_utils 34 | -------------------------------------------------------------------------------- /test/musica/aerosol_stub/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # MUSICA stub aerosol model tests 2 | add_executable(test_stub_aerosol_model test_stub_aerosol_model.F90) 3 | 4 | target_sources(test_stub_aerosol_model 5 | PUBLIC 6 | ${MUSICA_CCPP_SOURCES} 7 | ${TO_BE_CCPPIZED_SRC_PATH}/ccpp_const_utils.F90 8 | ${TO_BE_CCPPIZED_SRC_PATH}/ccpp_tuvx_utils.F90 9 | ${CCPP_SRC_PATH}/ccpp_constituent_prop_mod.F90 10 | ${CCPP_SRC_PATH}/ccpp_hash_table.F90 11 | ${CCPP_SRC_PATH}/ccpp_hashable.F90 12 | ${CCPP_TEST_SRC_PATH}/ccpp_kinds.F90 13 | ../musica_ccpp_namelist.F90 14 | ) 15 | 16 | target_link_libraries(test_stub_aerosol_model 17 | PRIVATE 18 | musica-fortran musica mechanism_configuration yaml-cpp stdc++ netcdff 19 | ) 20 | 21 | set_target_properties(test_stub_aerosol_model 22 | PROPERTIES 23 | LINKER_LANGUAGE Fortran 24 | ) 25 | 26 | add_test( 27 | NAME test_stub_aerosol_model 28 | COMMAND $ 29 | WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} 30 | ) 31 | 32 | add_memory_check_test(test_stub_aerosol_model $ "" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/check_energy_save_teout.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = check_energy_save_teout 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = check_energy_save_teout_run 7 | type = scheme 8 | [ ncol ] 9 | standard_name = horizontal_loop_extent 10 | units = count 11 | type = integer 12 | dimensions = () 13 | intent = in 14 | [ te_cur_dyn ] 15 | standard_name = vertically_integrated_total_energy_using_dycore_energy_formula 16 | units = J m-2 17 | type = real | kind = kind_phys 18 | dimensions = (horizontal_loop_extent) 19 | intent = in 20 | [ teout ] 21 | standard_name = vertically_integrated_total_energy_using_dycore_energy_formula_at_end_of_physics_timestep 22 | units = J m-2 23 | type = real | kind = kind_phys 24 | dimensions = (horizontal_loop_extent) 25 | intent = out 26 | [ errmsg ] 27 | standard_name = ccpp_error_message 28 | units = none 29 | type = character | kind = len=512 30 | dimensions = () 31 | intent = out 32 | [ errflg ] 33 | standard_name = ccpp_error_code 34 | units = 1 35 | type = integer 36 | dimensions = () 37 | intent = out 38 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/compute_cloud_fraction_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = compute_cloud_fraction_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = compute_cloud_fraction_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | units = none 11 | type = character | kind = len=512 12 | dimensions = () 13 | intent = out 14 | [ errflg ] 15 | standard_name = ccpp_error_code 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = out 20 | 21 | [ccpp-arg-table] 22 | name = compute_cloud_fraction_diagnostics_run 23 | type = scheme 24 | [ cldst ] 25 | standard_name = stratiform_cloud_area_fraction 26 | units = fraction 27 | type = real | kind = kind_phys 28 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 29 | intent = in 30 | [ errmsg ] 31 | standard_name = ccpp_error_message 32 | units = none 33 | type = character | kind = len=512 34 | dimensions = () 35 | intent = out 36 | [ errflg ] 37 | standard_name = ccpp_error_code 38 | units = 1 39 | type = integer 40 | dimensions = () 41 | intent = out 42 | -------------------------------------------------------------------------------- /schemes/vertical_diffusion/vertical_diffusion_options.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = vertical_diffusion_options 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = vertical_diffusion_options_init 7 | type = scheme 8 | [ amIRoot ] 9 | standard_name = flag_for_mpi_root 10 | units = flag 11 | type = logical 12 | dimensions = () 13 | intent = in 14 | [ iulog ] 15 | standard_name = log_output_unit 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = in 20 | [ do_iss_in ] 21 | standard_name = do_implicit_total_surface_stress_in_vertical_diffusion 22 | units = flag 23 | type = logical 24 | dimensions = () 25 | intent = in 26 | [ am_correction_in ] 27 | standard_name = do_angular_momentum_correction_in_vertical_diffusion 28 | units = flag 29 | type = logical 30 | dimensions = () 31 | intent = in 32 | [ errmsg ] 33 | standard_name = ccpp_error_message 34 | units = none 35 | type = character | kind = len=512 36 | dimensions = () 37 | intent = out 38 | [ errflg ] 39 | standard_name = ccpp_error_code 40 | units = 1 41 | type = integer 42 | dimensions = () 43 | intent = out 44 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/gravity_wave_drag_common_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = gravity_wave_drag_common_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = gravity_wave_drag_common_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | units = none 11 | type = character | kind = len=512 12 | dimensions = () 13 | intent = out 14 | [ errflg ] 15 | standard_name = ccpp_error_code 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = out 20 | 21 | [ccpp-arg-table] 22 | name = gravity_wave_drag_common_diagnostics_run 23 | type = scheme 24 | [ egwdffi_tot ] 25 | standard_name = effective_diffusivity_coefficient_at_interfaces_due_to_gravity_wave_drag 26 | units = m2 s-1 27 | type = real | kind = kind_phys 28 | dimensions = (horizontal_loop_extent, vertical_interface_dimension) 29 | intent = in 30 | [ errmsg ] 31 | standard_name = ccpp_error_message 32 | units = none 33 | type = character | kind = len=512 34 | dimensions = () 35 | intent = out 36 | [ errflg ] 37 | standard_name = ccpp_error_code 38 | units = 1 39 | type = integer 40 | dimensions = () 41 | intent = out 42 | -------------------------------------------------------------------------------- /test/musica/aerosol/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # MUSICA integration test for the abstract aerosol model 2 | add_executable(test_musica_aerosol_model_mock_host mock_host.F90) 3 | 4 | target_sources(test_musica_aerosol_model_mock_host 5 | PUBLIC 6 | ${MUSICA_CCPP_SOURCES} 7 | ${TO_BE_CCPPIZED_SRC_PATH}/ccpp_const_utils.F90 8 | ${TO_BE_CCPPIZED_SRC_PATH}/ccpp_tuvx_utils.F90 9 | ${CCPP_SRC_PATH}/ccpp_constituent_prop_mod.F90 10 | ${CCPP_SRC_PATH}/ccpp_hash_table.F90 11 | ${CCPP_SRC_PATH}/ccpp_hashable.F90 12 | ${CCPP_TEST_SRC_PATH}/ccpp_kinds.F90 13 | ../musica_ccpp_namelist.F90 14 | ) 15 | 16 | target_link_libraries(test_musica_aerosol_model_mock_host 17 | PRIVATE 18 | musica-fortran musica mechanism_configuration yaml-cpp stdc++ netcdff 19 | ) 20 | 21 | set_target_properties(test_musica_aerosol_model_mock_host 22 | PROPERTIES 23 | LINKER_LANGUAGE Fortran 24 | ) 25 | 26 | add_test( 27 | NAME test_musica_aerosol_model_mock_host 28 | COMMAND $ 29 | WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} 30 | ) 31 | 32 | add_memory_check_test(test_musica_aerosol_model_mock_host $ "" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) -------------------------------------------------------------------------------- /schemes/cloud_fraction/set_cloud_fraction_top.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2024-2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | ! 4 | ! Stub scheme to set top of cloud physics to below top cloud level. 5 | ! Used for all macrophysical schemes except RK. 6 | module set_cloud_fraction_top 7 | implicit none 8 | private 9 | 10 | public :: set_cloud_fraction_top_init 11 | 12 | contains 13 | 14 | !> \section arg_table_set_cloud_fraction_top_init Argument Table 15 | !! \htmlinclude set_cloud_fraction_top_init.html 16 | subroutine set_cloud_fraction_top_init(trop_cloud_top_lev, top_lev, errmsg, errflg) 17 | integer, intent(in) :: trop_cloud_top_lev ! Troposphere cloud physics top level [index] 18 | integer, intent(out) :: top_lev ! Cloud fraction top level [index] 19 | character(len=512), intent(out) :: errmsg ! Error message 20 | integer, intent(out) :: errflg ! Error flag 21 | 22 | ! Initialize error handling 23 | errmsg = '' 24 | errflg = 0 25 | 26 | ! Limit CAM5+ cloud physics to below top cloud level. 27 | top_lev = trop_cloud_top_lev 28 | 29 | end subroutine set_cloud_fraction_top_init 30 | 31 | end module set_cloud_fraction_top 32 | -------------------------------------------------------------------------------- /schemes/zhang_mcfarlane/set_deep_conv_fluxes_to_general.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = set_deep_conv_fluxes_to_general 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = set_deep_conv_fluxes_to_general_run 7 | type = scheme 8 | [ prec_gen ] 9 | standard_name = lwe_precipitation_rate_at_surface_due_to_convection 10 | units = m s-1 11 | type = real | kind = kind_phys 12 | dimensions = (horizontal_loop_extent) 13 | intent = out 14 | [ prec_dp ] 15 | standard_name = lwe_precipitation_rate_at_surface_due_to_deep_convection 16 | units = m s-1 17 | type = real | kind = kind_phys 18 | dimensions = (horizontal_loop_extent) 19 | intent = in 20 | [ prdprec_gen ] 21 | standard_name = tendency_of_precipitation_wrt_moist_air_and_condensed_water_due_to_convection_excluding_subcloud_evaporation 22 | units = kg kg-1 s-1 23 | type = real | kind = kind_phys 24 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 25 | intent = out 26 | [ prdprec_dp ] 27 | standard_name = tendency_of_precipitation_wrt_moist_air_and_condensed_water_due_to_deep_convection_excluding_subcloud_evaporation 28 | units = kg kg-1 s-1 29 | type = real | kind = kind_phys 30 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 31 | intent = in 32 | -------------------------------------------------------------------------------- /schemes/hack_shallow/set_shallow_conv_fluxes_to_general.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = set_shallow_conv_fluxes_to_general 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = set_shallow_conv_fluxes_to_general_run 7 | type = scheme 8 | [ prec_gen ] 9 | standard_name = lwe_precipitation_rate_at_surface_due_to_convection 10 | units = m s-1 11 | type = real | kind = kind_phys 12 | dimensions = (horizontal_loop_extent) 13 | intent = out 14 | [ prec_sh ] 15 | standard_name = lwe_precipitation_rate_at_surface_due_to_shallow_convection 16 | units = m s-1 17 | type = real | kind = kind_phys 18 | dimensions = (horizontal_loop_extent) 19 | intent = in 20 | [ prdprec_gen ] 21 | standard_name = tendency_of_precipitation_wrt_moist_air_and_condensed_water_due_to_convection_excluding_subcloud_evaporation 22 | units = kg kg-1 s-1 23 | type = real | kind = kind_phys 24 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 25 | intent = out 26 | [ prdprec_sh ] 27 | standard_name = tendency_of_precipitation_wrt_moist_air_and_condensed_water_due_to_shallow_convection_excluding_subcloud_evaporation 28 | units = kg kg-1 s-1 29 | type = real | kind = kind_phys 30 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 31 | intent = in 32 | -------------------------------------------------------------------------------- /test/test_schemes/initialize_constituents.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = initialize_constituents 3 | type = scheme 4 | [ccpp-arg-table] 5 | name = initialize_constituents_register 6 | type = scheme 7 | [ constituents ] 8 | standard_name = dynamic_constituents_for_initialize_constituents 9 | units = none 10 | dimensions = (:) 11 | allocatable = True 12 | type = ccpp_constituent_properties_t 13 | intent = out 14 | [ errmsg ] 15 | standard_name = ccpp_error_message 16 | long_name = Error message for error handling in CCPP 17 | units = none 18 | type = character | kind = len=512 19 | dimensions = () 20 | intent = out 21 | [ errcode ] 22 | standard_name = ccpp_error_code 23 | long_name = Error flag for error handling in CCPP 24 | units = 1 25 | type = integer 26 | dimensions = () 27 | intent = out 28 | [ccpp-arg-table] 29 | name = initialize_constituents_run 30 | type = scheme 31 | [ errmsg ] 32 | standard_name = ccpp_error_message 33 | long_name = Error message for error handling in CCPP 34 | units = none 35 | type = character | kind = len=512 36 | dimensions = () 37 | intent = out 38 | [ errcode ] 39 | standard_name = ccpp_error_code 40 | long_name = Error flag for error handling in CCPP 41 | units = 1 42 | type = integer 43 | dimensions = () 44 | intent = out 45 | -------------------------------------------------------------------------------- /test/test_schemes/file_io_test.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = file_io_test 3 | type = scheme 4 | dependencies=../../phys_utils/ccpp_io_reader.F90 5 | [ccpp-arg-table] 6 | name = file_io_test_init 7 | type = scheme 8 | [ file_path ] 9 | standard_name = filename_of_rrtmgp_shortwave_coefficients 10 | long_name = file name and path to RRTMGP shortwave coefficients file 11 | units = none 12 | type = character | kind = len=* 13 | dimensions = () 14 | intent = in 15 | [ errmsg ] 16 | standard_name = ccpp_error_message 17 | long_name = Error message for error handling in CCPP 18 | units = none 19 | type = character | kind = len=512 20 | dimensions = () 21 | intent = out 22 | [ errcode ] 23 | standard_name = ccpp_error_code 24 | long_name = Error flag for error handling in CCPP 25 | units = 1 26 | type = integer 27 | dimensions = () 28 | intent = out 29 | [ccpp-arg-table] 30 | name = file_io_test_run 31 | type = scheme 32 | [ errmsg ] 33 | standard_name = ccpp_error_message 34 | long_name = Error message for error handling in CCPP 35 | units = none 36 | type = character | kind = len=512 37 | dimensions = () 38 | intent = out 39 | [ errcode ] 40 | standard_name = ccpp_error_code 41 | long_name = Error flag for error handling in CCPP 42 | units = 1 43 | type = integer 44 | dimensions = () 45 | intent = out 46 | -------------------------------------------------------------------------------- /test/unit-test/README.md: -------------------------------------------------------------------------------- 1 | # Unit Tests 2 | 3 | To add or update unit tests, follow the instructions from the [development guide](https://escomp.github.io/CAM-SIMA-docs/atmospheric_physics/development_workflow/#5-unit-testing). Also, make sure [pFUnit](https://github.com/Goddard-Fortran-Ecosystem/pFUnit) is built and installed following the [build directions](https://github.com/Goddard-Fortran-Ecosystem/pFUnit?tab=readme-ov-file#building-and-installing-pfunit) (see the atmospheric_physics [github workflow file](../../.github/workflows/unit-tests.yaml) for a more detailed example of how to build pFUnit): 4 | 5 | ```bash 6 | $ git clone --depth 1 --branch v4.10.0 https://github.com/Goddard-Fortran-Ecosystem/pFUnit.git 7 | $ cd pFUnit 8 | $ cmake -B./build -S. 9 | $ cd build 10 | $ make install 11 | ``` 12 | 13 | To run the tests, from the root directory of your clone, run: 14 | 15 | ```bash 16 | $ cmake \ 17 | -DCMAKE_PREFIX_PATH=/build/installed \ 18 | -DATMOSPHERIC_PHYSICS_ENABLE_CODE_COVERAGE=ON \ 19 | -B./build \ 20 | -S./test/unit-test 21 | $ cd build 22 | $ make 23 | $ ctest -V --output-on-failure 24 | ``` 25 | 26 | Where `` is the path to your pfunit repository. The install path of pFUnit may be different depending on how you've built your local verison (see the example in the [workflow file](../../.github/workflows/unit-tests.yaml)). 27 | -------------------------------------------------------------------------------- /test/unit-test/tests/phys_utils/test_atmos_rad_utils.pf: -------------------------------------------------------------------------------- 1 | @test 2 | subroutine wavenumber_is_visible() 3 | use funit 4 | use atmos_phys_rad_utils, only : is_visible 5 | use ccpp_kinds, only : kind_phys 6 | 7 | real(kind_phys), parameter :: test_wavenumber = 15555._kind_phys 8 | logical :: output_logical 9 | 10 | output_logical = is_visible(test_wavenumber) 11 | 12 | @assertEqual(.true., output_logical) 13 | end subroutine wavenumber_is_visible 14 | 15 | @test 16 | subroutine wavenumber_is_not_visible() 17 | use funit 18 | use atmos_phys_rad_utils, only : is_visible 19 | use ccpp_kinds, only : kind_phys 20 | 21 | real(kind_phys), parameter :: test_wavenumber = 823._kind_phys 22 | logical :: output_logical 23 | 24 | output_logical = is_visible(test_wavenumber) 25 | 26 | @assertEqual(.false., output_logical) 27 | end subroutine wavenumber_is_not_visible 28 | 29 | @test 30 | subroutine wavenumber_is_on_the_cusp() 31 | use funit 32 | use atmos_phys_rad_utils, only : is_visible 33 | use ccpp_kinds, only : kind_phys 34 | 35 | real(kind_phys), parameter :: test_wavenumber = 14286._kind_phys 36 | logical :: output_logical 37 | 38 | output_logical = is_visible(test_wavenumber) 39 | 40 | @assertEqual(.false., output_logical) 41 | end subroutine wavenumber_is_on_the_cusp 42 | -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/check_energy_scaling.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = check_energy_scaling 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = check_energy_scaling_run 7 | type = scheme 8 | [ ncol ] 9 | standard_name = horizontal_loop_extent 10 | units = count 11 | type = integer 12 | dimensions = () 13 | intent = in 14 | [ cp_or_cv_dycore ] 15 | standard_name = specific_heat_of_air_used_in_dycore 16 | units = J kg-1 K-1 17 | type = real | kind = kind_phys 18 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 19 | intent = in 20 | [ cpairv ] 21 | standard_name = composition_dependent_specific_heat_of_dry_air_at_constant_pressure 22 | units = J kg-1 K-1 23 | type = real | kind = kind_phys 24 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 25 | intent = in 26 | [ scaling_dycore ] 27 | standard_name = ratio_of_specific_heat_of_air_used_in_physics_energy_formula_to_specific_heat_of_air_used_in_dycore_energy_formula 28 | units = 1 29 | type = real | kind = kind_phys 30 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 31 | intent = out 32 | [ errmsg ] 33 | standard_name = ccpp_error_message 34 | units = none 35 | type = character | kind = len=512 36 | dimensions = () 37 | intent = out 38 | [ errflg ] 39 | standard_name = ccpp_error_code 40 | units = 1 41 | type = integer 42 | dimensions = () 43 | intent = out 44 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/rayleigh_friction_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = rayleigh_friction_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = rayleigh_friction_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | units = none 11 | type = character | kind = len=512 12 | dimensions = () 13 | intent = out 14 | [ errflg ] 15 | standard_name = ccpp_error_code 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = out 20 | 21 | [ccpp-arg-table] 22 | name = rayleigh_friction_diagnostics_run 23 | type = scheme 24 | [ dudt ] 25 | standard_name = tendency_of_eastward_wind 26 | units = m s-2 27 | type = real | kind = kind_phys 28 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 29 | intent = in 30 | [ dvdt ] 31 | standard_name = tendency_of_northward_wind 32 | units = m s-2 33 | type = real | kind = kind_phys 34 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 35 | intent = in 36 | [ dsdt ] 37 | standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure 38 | units = J kg-1 s-1 39 | type = real | kind = kind_phys 40 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 41 | intent = in 42 | [ errmsg ] 43 | standard_name = ccpp_error_message 44 | units = none 45 | type = character | kind = len=512 46 | dimensions = () 47 | intent = out 48 | [ errflg ] 49 | standard_name = ccpp_error_code 50 | units = 1 51 | type = integer 52 | dimensions = () 53 | intent = out 54 | -------------------------------------------------------------------------------- /schemes/thermo_water_update/thermo_water_update.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = thermo_water_update 3 | type = scheme 4 | dependencies = ../../../../data/cam_thermo.F90 5 | 6 | [ccpp-arg-table] 7 | name = thermo_water_update_run 8 | type = scheme 9 | [ mmr ] 10 | standard_name = ccpp_constituents 11 | units = none 12 | type = real | kind = kind_phys 13 | dimensions = (horizontal_loop_extent, vertical_layer_dimension, number_of_ccpp_constituents) 14 | intent = in 15 | [ ncol ] 16 | standard_name = horizontal_loop_extent 17 | units = count 18 | type = integer 19 | dimensions = () 20 | intent = in 21 | [ pver ] 22 | standard_name = vertical_layer_dimension 23 | units = count 24 | type = integer 25 | dimensions = () 26 | intent = in 27 | [ energy_formula_dycore ] 28 | standard_name = total_energy_formula_for_dycore 29 | units = 1 30 | type = integer 31 | dimensions = () 32 | intent = in 33 | [ pdel ] 34 | standard_name = air_pressure_thickness 35 | units = Pa 36 | type = real | kind = kind_phys 37 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 38 | intent = in 39 | [ pdeldry ] 40 | standard_name = air_pressure_thickness_of_dry_air 41 | units = Pa 42 | type = real | kind = kind_phys 43 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 44 | intent = in 45 | [ cp_or_cv_dycore ] 46 | standard_name = specific_heat_of_air_used_in_dycore 47 | units = J kg-1 K-1 48 | type = real | kind = kind_phys 49 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 50 | intent = out 51 | -------------------------------------------------------------------------------- /schemes/vertical_diffusion/vertical_diffusion_options.F90: -------------------------------------------------------------------------------- 1 | ! Module to load namelist options for vertical diffusion solver scheme. 2 | module vertical_diffusion_options 3 | 4 | use ccpp_kinds, only: kind_phys 5 | 6 | implicit none 7 | private 8 | save 9 | 10 | ! CCPP-compliant public interfaces 11 | public :: vertical_diffusion_options_init 12 | 13 | contains 14 | 15 | !> \section arg_table_vertical_diffusion_options_init Argument Table 16 | !! \htmlinclude arg_table_vertical_diffusion_options_init.html 17 | subroutine vertical_diffusion_options_init( & 18 | amIRoot, iulog, & 19 | do_iss_in, & 20 | am_correction_in, & 21 | errmsg, errflg) 22 | 23 | ! Input arguments 24 | logical, intent(in) :: amIRoot ! are we on the MPI root task? 25 | integer, intent(in) :: iulog ! log output unit 26 | logical, intent(in) :: do_iss_in ! Use implicit turbulent surface stress computation 27 | logical, intent(in) :: am_correction_in ! Do angular momentum conservation correction 28 | 29 | character(len=512), intent(out) :: errmsg ! error message 30 | integer, intent(out) :: errflg ! error flag 31 | 32 | errmsg = '' 33 | errflg = 0 34 | 35 | if(amIRoot) then 36 | write(iulog,*) "vertical diffusion solver: do_iss ", do_iss_in 37 | write(iulog,*) "vertical diffusion solver: am_correction ", am_correction_in 38 | endif 39 | 40 | end subroutine vertical_diffusion_options_init 41 | 42 | end module vertical_diffusion_options 43 | -------------------------------------------------------------------------------- /schemes/holtslag_boville/holtslag_boville_diff_options.F90: -------------------------------------------------------------------------------- 1 | ! Module to load namelist options for the Holstlag-Boville boundary layer scheme 2 | module holtslag_boville_diff_options 3 | use ccpp_kinds, only: kind_phys 4 | 5 | implicit none 6 | private 7 | save 8 | 9 | ! public CCPP-compliant subroutines 10 | public :: holtslag_boville_diff_options_init 11 | 12 | contains 13 | 14 | !> \section arg_table_holtslag_boville_diff_options_init Argument Table 15 | !! \htmlinclude arg_table_holtslag_boville_diff_options_init.html 16 | subroutine holtslag_boville_diff_options_init( & 17 | amIRoot, iulog, & 18 | is_hbr_pbl_scheme, & 19 | errmsg, errflg) 20 | 21 | ! Input arguments 22 | logical, intent(in) :: amIRoot ! are we on the MPI root task? 23 | integer, intent(in) :: iulog ! log output unit 24 | logical, intent(in) :: is_hbr_pbl_scheme ! is HBR = true; is HB = false [flag] 25 | 26 | ! Output arguments 27 | character(len=512), intent(out) :: errmsg ! error message 28 | integer, intent(out) :: errflg ! error flag 29 | 30 | errmsg = '' 31 | errflg = 0 32 | 33 | if(amIRoot) then 34 | if(is_hbr_pbl_scheme) then 35 | write(iulog,*) 'Holtslag-Boville PBL: initializing as HBR PBL scheme.' 36 | else 37 | write(iulog,*) 'Holtslag-Boville PBL: initializing as HB PBL scheme.' 38 | endif 39 | endif 40 | 41 | end subroutine holtslag_boville_diff_options_init 42 | 43 | end module holtslag_boville_diff_options 44 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/sima_tend_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = sima_tend_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = sima_tend_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | units = none 11 | type = character | kind = len=512 12 | dimensions = () 13 | intent = out 14 | [ errflg ] 15 | standard_name = ccpp_error_code 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = out 20 | 21 | [ccpp-arg-table] 22 | name = sima_tend_diagnostics_run 23 | type = scheme 24 | [ dTdt_total ] 25 | standard_name = tendency_of_air_temperature_due_to_model_physics 26 | units = K s-1 27 | type = real | kind = kind_phys 28 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 29 | intent = in 30 | [ dudt_total ] 31 | standard_name = tendency_of_eastward_wind_due_to_model_physics 32 | units = m s-2 33 | type = real | kind = kind_phys 34 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 35 | intent = in 36 | [ dvdt_total ] 37 | standard_name = tendency_of_northward_wind_due_to_model_physics 38 | units = m s-2 39 | type = real | kind = kind_phys 40 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 41 | intent = in 42 | [ errmsg ] 43 | standard_name = ccpp_error_message 44 | units = none 45 | type = character | kind = len=512 46 | dimensions = () 47 | intent = out 48 | [ errflg ] 49 | standard_name = ccpp_error_code 50 | units = 1 51 | type = integer 52 | dimensions = () 53 | intent = out 54 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/convective_cloud_cover_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = convective_cloud_cover_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = convective_cloud_cover_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | units = none 11 | type = character | kind = len=512 12 | dimensions = () 13 | intent = out 14 | [ errflg ] 15 | standard_name = ccpp_error_code 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = out 20 | 21 | [ccpp-arg-table] 22 | name = convective_cloud_cover_diagnostics_run 23 | type = scheme 24 | [ shallowcu ] 25 | standard_name = shallow_convective_cloud_area_fraction 26 | units = fraction 27 | type = real | kind = kind_phys 28 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 29 | intent = in 30 | [ deepcu ] 31 | standard_name = deep_convective_cloud_area_fraction 32 | units = fraction 33 | type = real | kind = kind_phys 34 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 35 | intent = in 36 | [ concld ] 37 | standard_name = convective_cloud_area_fraction 38 | units = fraction 39 | type = real | kind = kind_phys 40 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 41 | intent = in 42 | [ errmsg ] 43 | standard_name = ccpp_error_message 44 | units = none 45 | type = character | kind = len=512 46 | dimensions = () 47 | intent = out 48 | [ errflg ] 49 | standard_name = ccpp_error_code 50 | units = 1 51 | type = integer 52 | dimensions = () 53 | intent = out 54 | -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/check_energy_save_teout.F90: -------------------------------------------------------------------------------- 1 | ! save total energy for global fixer in next timestep 2 | ! this must be called after the last parameterization and physics_update, 3 | ! and after a final check_energy_chng to compute te_cur. 4 | module check_energy_save_teout 5 | use ccpp_kinds, only: kind_phys 6 | 7 | implicit none 8 | private 9 | 10 | public :: check_energy_save_teout_run 11 | 12 | contains 13 | 14 | !> \section arg_table_check_energy_save_teout_run Argument Table 15 | !! \htmlinclude arg_table_check_energy_save_teout_run.html 16 | subroutine check_energy_save_teout_run(ncol, te_cur_dyn, teout, errmsg, errflg) 17 | 18 | ! Input arguments 19 | integer, intent(in) :: ncol ! number of atmospheric columns 20 | real(kind_phys), intent(in) :: te_cur_dyn (:) ! dycore formula: current total energy [J m-2] 21 | 22 | ! Output arguments 23 | real(kind_phys), intent(out) :: teout(:) ! total energy for global fixer in next timestep [J m-2] 24 | character(len=512), intent(out) :: errmsg ! error message 25 | integer, intent(out) :: errflg ! error flag 26 | 27 | errmsg = '' 28 | errflg = 0 29 | 30 | ! nb hplin: note that in physpkg.F90, the pbuf is updated to the previous dyn timestep 31 | ! through itim_old. Need to check if we need to replicate such pbuf functionality 32 | ! in the CAM-SIMA/CCPP infrastructure. 33 | teout(:ncol) = te_cur_dyn(:ncol) 34 | 35 | end subroutine check_energy_save_teout_run 36 | 37 | end module check_energy_save_teout 38 | -------------------------------------------------------------------------------- /test/musica/configuration/analytical/reactions.json: -------------------------------------------------------------------------------- 1 | { 2 | "camp-data": [ 3 | { 4 | "type": "MECHANISM", 5 | "name": "analytical test", 6 | "reactions": [ 7 | { 8 | "type": "ARRHENIUS", 9 | "A": 0.004, 10 | "C": 50, 11 | "reactants": { 12 | "A": { 13 | "qty": 1 14 | } 15 | }, 16 | "products": { 17 | "B": { 18 | "yield": 1 19 | } 20 | } 21 | }, 22 | { 23 | "type": "ARRHENIUS", 24 | "A": 0.012, 25 | "B": -2, 26 | "C": 75, 27 | "D": 50, 28 | "E": 1.0e-6, 29 | "reactants": { 30 | "B": { 31 | "qty": 1 32 | } 33 | }, 34 | "products": { 35 | "C": { 36 | "yield": 1 37 | } 38 | } 39 | }, 40 | { 41 | "type": "ARRHENIUS", 42 | "A": 0.001, 43 | "reactants": { 44 | "D": { 45 | "qty": 1 46 | } 47 | }, 48 | "products": { 49 | "E": { 50 | "yield": 1 51 | } 52 | } 53 | }, 54 | { 55 | "type": "ARRHENIUS", 56 | "A": 0.002, 57 | "reactants": { 58 | "E": { 59 | "qty": 1 60 | } 61 | }, 62 | "products": { 63 | "F": { 64 | "yield": 1 65 | } 66 | } 67 | } 68 | ] 69 | } 70 | ] 71 | } 72 | -------------------------------------------------------------------------------- /suites/suite_adiabatic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | check_energy_gmean 7 | 8 | check_energy_gmean_diagnostics 9 | 10 | 14 | check_energy_zero_fluxes 15 | check_energy_fix 16 | apply_heating_rate 17 | geopotential_temp 18 | 19 | check_energy_scaling 20 | check_energy_chng 21 | 22 | check_energy_fix_diagnostics 23 | 24 | 25 | check_energy_save_teout 26 | 27 | 28 | sima_state_diagnostics 29 | 30 | 31 | 32 | sima_tend_diagnostics 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/musica/configuration/micm_util/reactions.json: -------------------------------------------------------------------------------- 1 | { 2 | "camp-data": [ 3 | { 4 | "type": "MECHANISM", 5 | "name": "analytical test", 6 | "reactions": [ 7 | { 8 | "type": "ARRHENIUS", 9 | "A": 0.001, 10 | "reactants": { 11 | "A": { 12 | "qty": 1 13 | }, 14 | "B": { 15 | "qty": 1 16 | } 17 | }, 18 | "products": { 19 | "C": { 20 | "yield": 1 21 | }, 22 | "D": { 23 | "yield": 1 24 | } 25 | } 26 | }, 27 | { 28 | "type": "USER_DEFINED", 29 | "MUSICA name": "user1", 30 | "reactants": { 31 | "A": { 32 | "qty": 1 33 | }, 34 | "B": { 35 | "qty": 1 36 | } 37 | }, 38 | "products": { 39 | "C": { 40 | "yield": 1 41 | }, 42 | "D": { 43 | "yield": 1 44 | } 45 | } 46 | }, 47 | { 48 | "type": "USER_DEFINED", 49 | "MUSICA name": "user2", 50 | "reactants": { 51 | "A": { 52 | "qty": 1 53 | }, 54 | "B": { 55 | "qty": 1 56 | } 57 | }, 58 | "products": { 59 | "C": { 60 | "yield": 1 61 | }, 62 | "D": { 63 | "yield": 1 64 | } 65 | } 66 | } 67 | ] 68 | } 69 | ] 70 | } 71 | -------------------------------------------------------------------------------- /test/test_suites/suite_convection_permitting.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | calc_exner 6 | compute_characteristic_grid_length_scale 7 | geopotential_height_wrt_sfc_at_if_to_msl 8 | geopotential_height_wrt_sfc_to_msl 9 | temp_to_potential_temp 10 | wet_to_dry_water_vapor 11 | wet_to_dry_cloud_liquid_water 12 | wet_to_dry_cloud_ice 13 | 14 | mmm_physics_compat 15 | 16 | bl_gwdo_compat_pre 17 | bl_gwdo_compat 18 | bl_gwdo_diagnostics 19 | 20 | cu_ntiedtke_compat_pre 21 | cu_ntiedtke_compat 22 | cu_ntiedtke_diagnostics 23 | 24 | mmm_physics_accumulate_tendencies 25 | apply_tendency_of_eastward_wind 26 | apply_tendency_of_northward_wind 27 | apply_tendency_of_air_temperature 28 | dry_to_wet_water_vapor 29 | dry_to_wet_cloud_liquid_water 30 | dry_to_wet_cloud_ice 31 | qneg 32 | geopotential_temp 33 | 34 | mmm_physics_persist_states 35 | 36 | sima_state_diagnostics 37 | 38 | 39 | sima_tend_diagnostics 40 | 41 | 42 | -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/check_energy_zero_fluxes.F90: -------------------------------------------------------------------------------- 1 | ! zeros input fluxes to check_energy 2 | ! before running other schemes 3 | module check_energy_zero_fluxes 4 | use ccpp_kinds, only: kind_phys 5 | 6 | implicit none 7 | private 8 | 9 | public :: check_energy_zero_fluxes_run 10 | 11 | contains 12 | 13 | !> \section arg_table_check_energy_zero_fluxes_run Argument Table 14 | !! \htmlinclude arg_table_check_energy_zero_fluxes_run.html 15 | subroutine check_energy_zero_fluxes_run(ncol, name, flx_vap, flx_cnd, flx_ice, flx_sen, errmsg, errflg) 16 | ! Input arguments 17 | integer, intent(in) :: ncol ! number of atmospheric columns 18 | 19 | ! Output arguments 20 | character(len=64), intent(out) :: name ! parameterization name for fluxes 21 | real(kind_phys), intent(out) :: flx_vap(:) ! boundary flux of vapor [kg m-2 s-1] 22 | real(kind_phys), intent(out) :: flx_cnd(:) ! boundary flux of liquid+ice (precip?) [m s-1] 23 | real(kind_phys), intent(out) :: flx_ice(:) ! boundary flux of ice (snow?) [m s-1] 24 | real(kind_phys), intent(out) :: flx_sen(:) ! boundary flux of sensible heat [W m-2] 25 | character(len=512), intent(out) :: errmsg ! error message 26 | integer, intent(out) :: errflg ! error flag 27 | 28 | errmsg = '' 29 | errflg = 0 30 | 31 | ! reset values to zero 32 | name = '' 33 | flx_vap(:) = 0._kind_phys 34 | flx_cnd(:) = 0._kind_phys 35 | flx_ice(:) = 0._kind_phys 36 | flx_sen(:) = 0._kind_phys 37 | end subroutine check_energy_zero_fluxes_run 38 | 39 | end module check_energy_zero_fluxes 40 | -------------------------------------------------------------------------------- /schemes/utilities/static_energy.F90: -------------------------------------------------------------------------------- 1 | ! Updates dry static energy from updated temperature and geopotential height. 2 | ! If ran, must be after geopotential_temp scheme. 3 | module static_energy 4 | 5 | use ccpp_kinds, only: kind_phys 6 | 7 | implicit none 8 | private 9 | 10 | public :: update_dry_static_energy_run 11 | 12 | CONTAINS 13 | 14 | !> \section arg_table_update_dry_static_energy_run Argument Table 15 | !! \htmlinclude update_dry_static_energy_run.html 16 | subroutine update_dry_static_energy_run(nz, gravit, temp, zm, phis, & 17 | st_energy, cpair, errcode, errmsg) 18 | 19 | ! Dummy arguments 20 | integer, intent(in) :: nz ! Num vertical layers 21 | real(kind_phys), intent(in) :: gravit ! gravitational acceleration 22 | real(kind_phys), intent(in) :: temp(:,:) ! air temperature 23 | real(kind_phys), intent(in) :: zm(:,:) ! geopotential height 24 | real(kind_phys), intent(in) :: phis(:) ! surface geopotential 25 | real(kind_phys), intent(out) :: st_energy(:,:) ! dry static energy 26 | real(kind_phys), intent(in) :: cpair(:,:) ! specific heat, dry air 27 | integer, intent(out) :: errcode 28 | character(len=512), intent(out) :: errmsg 29 | 30 | ! Local variable 31 | integer :: klev 32 | 33 | errcode = 0 34 | errmsg = '' 35 | 36 | do klev = 1, nz 37 | st_energy(:, klev) = (temp(:, klev) * cpair(:,klev)) + & 38 | (gravit * zm(:, klev)) + phis(:) 39 | end do 40 | 41 | end subroutine update_dry_static_energy_run 42 | 43 | end module static_energy 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IMPORTANT NOTE - This repository is currently under development and items contained within it should be used with caution. 2 | 3 | # NCAR CCPP-enabled Atmospheric Physics 4 | 5 | Physics packages which are CCPP_enabled (along with supporting routines) are stored in this repository. 6 | 7 | # Requirements for ccpp physics schemes 8 | 9 | * Physics schemes contain two files, a .F90 file which contains the routines and a .meta file which contains the CCPP metadata. 10 | 11 | * Standard names for metadata can be found [here](https://github.com/gold2718/ccpp-framework/wiki/Metadata-standard-names) 12 | 13 | * Physics modules may contain one or more of the following routines (where XXX is the name of the module containing the physics) 14 | * XXX_init - contains the startup/restart initialization required for the package. This is unthreaded and may contain I/O of undistibuted data (e.g. parameter tables) 15 | * XXX_timestep_init - contains the initialization required for each timestep. This is unthreaded and may contain I/O of undistibuted data (e.g. parameter tables) 16 | * XXX_run - the code which is run every timestep. Threading is controlled via the host model and the number of available threads will be passed into the routine. No I/O is permitted in this routine 17 | * XXX_timestep_final - contains any post timestep handling. This is unthreaded 18 | * XXX_final - contains any code logic which needs to be performed at the end of the run prior to the program exiting. This is unthreaded. 19 | 20 | # Steps to adding a physics package to the repository 21 | * Currently under discussion 22 | 23 | # CCPP resources 24 | 25 | * [ccpp framework repository](https://github.com/NCAR/ccpp-framework) 26 | 27 | -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/check_energy_zero_fluxes.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = check_energy_zero_fluxes 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = check_energy_zero_fluxes_run 7 | type = scheme 8 | [ ncol ] 9 | standard_name = horizontal_loop_extent 10 | units = count 11 | type = integer 12 | dimensions = () 13 | intent = in 14 | [ name ] 15 | standard_name = scheme_name 16 | units = none 17 | type = character | kind = len=64 18 | dimensions = () 19 | intent = out 20 | [ flx_vap ] 21 | standard_name = net_water_vapor_fluxes_through_top_and_bottom_of_atmosphere_column 22 | units = kg m-2 s-1 23 | type = real | kind = kind_phys 24 | dimensions = (horizontal_loop_extent) 25 | intent = out 26 | [ flx_cnd ] 27 | standard_name = net_liquid_and_lwe_ice_fluxes_through_top_and_bottom_of_atmosphere_column 28 | units = m s-1 29 | type = real | kind = kind_phys 30 | dimensions = (horizontal_loop_extent) 31 | intent = out 32 | [ flx_ice ] 33 | standard_name = net_lwe_ice_fluxes_through_top_and_bottom_of_atmosphere_column 34 | units = m s-1 35 | type = real | kind = kind_phys 36 | dimensions = (horizontal_loop_extent) 37 | intent = out 38 | [ flx_sen ] 39 | standard_name = net_sensible_heat_flux_through_top_and_bottom_of_atmosphere_column 40 | units = W m-2 41 | type = real | kind = kind_phys 42 | dimensions = (horizontal_loop_extent) 43 | intent = out 44 | [ errmsg ] 45 | standard_name = ccpp_error_message 46 | units = none 47 | type = character | kind = len=512 48 | dimensions = () 49 | intent = out 50 | [ errflg ] 51 | standard_name = ccpp_error_code 52 | units = 1 53 | type = integer 54 | dimensions = () 55 | intent = out 56 | -------------------------------------------------------------------------------- /schemes/rayleigh_friction/rayleigh_friction_namelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | integer 12 | rayleigh_friction 13 | rayleigh_friction_nl 14 | center_vertical_layer_for_rayleigh_friction 15 | index 16 | 17 | Variable to specify the vertical index at which the 18 | Rayleigh friction term is centered (the peak value). 19 | 20 | 21 | 2 22 | 23 | 24 | 25 | 26 | real 27 | kind_phys 28 | rayleigh_friction 29 | rayleigh_friction_nl 30 | number_of_vertical_layers_for_rayleigh_friction 31 | count 32 | 33 | Range (number of layers) of the Rayleigh Friction profile. If 0, range is set to satisfy center=2. 34 | 35 | 36 | 0 37 | 38 | 39 | 40 | 41 | real 42 | kind_phys 43 | rayleigh_friction 44 | rayleigh_friction_nl 45 | model_top_decay_time_for_rayleigh_friction 46 | days 47 | 48 | Approximate value of max decay time (in units of days) at model top. If 0, no Rayleigh Friction is computed or applied. 49 | 50 | 51 | 0 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/check_energy_gmean_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = check_energy_gmean_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = check_energy_gmean_diagnostics_init 7 | type = scheme 8 | [ print_global_means_in ] 9 | standard_name = flag_for_energy_global_means_output 10 | units = flag 11 | type = logical 12 | dimensions = () 13 | intent = in 14 | 15 | [ccpp-arg-table] 16 | name = check_energy_gmean_diagnostics_run 17 | type = scheme 18 | [ amIRoot ] 19 | standard_name = flag_for_mpi_root 20 | units = flag 21 | type = logical 22 | dimensions = () 23 | intent = in 24 | [ iulog ] 25 | standard_name = log_output_unit 26 | units = 1 27 | type = integer 28 | dimensions = () 29 | intent = in 30 | [ teinp_glob ] 31 | standard_name = global_mean_vertically_integrated_total_energy_using_dycore_energy_formula_at_start_of_physics_timestep 32 | units = J m-2 33 | type = real | kind = kind_phys 34 | dimensions = () 35 | intent = in 36 | [ teout_glob ] 37 | standard_name = global_mean_vertically_integrated_total_energy_using_dycore_energy_formula_at_end_of_physics_timestep 38 | units = J m-2 39 | type = real | kind = kind_phys 40 | dimensions = () 41 | intent = in 42 | [ heat_glob ] 43 | standard_name = global_mean_heating_rate_correction_for_energy_conservation 44 | units = J kg-1 s-1 45 | type = real | kind = kind_phys 46 | dimensions = () 47 | intent = in 48 | [ errmsg ] 49 | standard_name = ccpp_error_message 50 | units = none 51 | type = character | kind = len=512 52 | dimensions = () 53 | intent = out 54 | [ errflg ] 55 | standard_name = ccpp_error_code 56 | units = 1 57 | type = integer 58 | dimensions = () 59 | intent = out 60 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.21) 2 | 3 | project( 4 | atmosphericphysics 5 | VERSION 0.1.0 6 | LANGUAGES Fortran C CXX 7 | ) 8 | 9 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH};${CMAKE_CURRENT_LIST_DIR}/cmake) 10 | set(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_MODULE_PATH}/SetDefaults.cmake) 11 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) 12 | 13 | set(CMAKE_CXX_STANDARD 20) 14 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 15 | 16 | # --------------------------------------------------------------------------------------------- 17 | # NOTE: If 'CCPP_ENABLE_MUSICA_TESTS' is enabled, this is no longer a stand-alone CMake project. 18 | # The MUSICA CCPP wrapper requires both the MUSICA library and ccpp-framework/src. 19 | # To enable 'CCPP_ENABLE_MUSICA_TESTS', you can either build a CMake project using 20 | # 'docker/Dockerfile.musica' or follow the build instructions outlined in that file. 21 | # The following '$ENV' variables are configured by the Dockerfile. 22 | # --------------------------------------------------------------------------------------------- 23 | option(CCPP_ENABLE_MUSICA_TESTS "Build the MUSICA tests" OFF) 24 | option(CCPP_ENABLE_MEMCHECK "Enable memory checks in tests" OFF) 25 | 26 | set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) 27 | set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) 28 | 29 | if (CCPP_ENABLE_MUSICA_TESTS) 30 | set(MUSICA_SRC_PATH ${CMAKE_SOURCE_DIR}/../schemes/musica) 31 | set(TO_BE_CCPPIZED_SRC_PATH ${CMAKE_SOURCE_DIR}/../to_be_ccppized) 32 | set(CCPP_SRC_PATH ${CMAKE_SOURCE_DIR}/$ENV{CCPP_SRC_PATH}) 33 | set(CCPP_TEST_SRC_PATH ${CMAKE_SOURCE_DIR}/include) 34 | 35 | include(TestUtils) 36 | include(CTest) 37 | enable_testing() 38 | 39 | add_subdirectory(musica) 40 | endif() 41 | -------------------------------------------------------------------------------- /schemes/cloud_fraction/cloud_fraction_fice.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = cloud_fraction_fice 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = cloud_fraction_fice_run 7 | type = scheme 8 | [ ncol ] 9 | standard_name = horizontal_loop_extent 10 | units = count 11 | type = integer 12 | dimensions = () 13 | intent = in 14 | [ t ] 15 | standard_name = air_temperature 16 | units = K 17 | type = real | kind = kind_phys 18 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 19 | intent = in 20 | [ tmelt ] 21 | standard_name = freezing_point_of_water 22 | units = K 23 | type = real | kind = kind_phys 24 | dimensions = () 25 | intent = in 26 | [ top_lev ] 27 | standard_name = vertical_layer_index_of_cloud_fraction_top 28 | units = index 29 | type = integer 30 | dimensions = () 31 | intent = in 32 | [ pver ] 33 | standard_name = vertical_layer_dimension 34 | units = count 35 | type = integer 36 | dimensions = () 37 | intent = in 38 | [ fice ] 39 | standard_name = mass_fraction_of_ice_content_within_stratiform_cloud 40 | units = fraction 41 | type = real | kind = kind_phys 42 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 43 | intent = out 44 | [ fsnow ] 45 | standard_name = mass_fraction_of_snow_content_within_stratiform_cloud 46 | units = fraction 47 | type = real | kind = kind_phys 48 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 49 | intent = out 50 | [ errmsg ] 51 | standard_name = ccpp_error_message 52 | units = none 53 | type = character | kind = len=512 54 | dimensions = () 55 | intent = out 56 | [ errflg ] 57 | standard_name = ccpp_error_code 58 | units = 1 59 | type = integer 60 | dimensions = () 61 | intent = out 62 | -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/dycore_energy_consistency_adjust.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = dycore_energy_consistency_adjust 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = dycore_energy_consistency_adjust_run 7 | type = scheme 8 | [ ncol ] 9 | standard_name = horizontal_loop_extent 10 | units = count 11 | type = integer 12 | dimensions = () 13 | intent = in 14 | [ pver ] 15 | standard_name = vertical_layer_dimension 16 | units = count 17 | type = integer 18 | dimensions = () 19 | intent = in 20 | [ do_consistency_adjust ] 21 | standard_name = flag_for_dycore_energy_consistency_adjustment 22 | units = flag 23 | type = logical 24 | dimensions = () 25 | intent = in 26 | [ scaling_dycore ] 27 | standard_name = ratio_of_specific_heat_of_air_used_in_physics_energy_formula_to_specific_heat_of_air_used_in_dycore_energy_formula 28 | units = 1 29 | type = real | kind = kind_phys 30 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 31 | intent = in 32 | [ tend_dTdt ] 33 | standard_name = tendency_of_air_temperature_due_to_model_physics 34 | units = K s-1 35 | type = real | kind = kind_phys 36 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 37 | intent = in 38 | [ tend_dTdt_local ] 39 | standard_name = tendency_of_air_temperature 40 | units = K s-1 41 | type = real | kind = kind_phys 42 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 43 | intent = out 44 | [ errmsg ] 45 | standard_name = ccpp_error_message 46 | units = none 47 | type = character | kind = len=512 48 | dimensions = () 49 | intent = out 50 | [ errflg ] 51 | standard_name = ccpp_error_code 52 | units = 1 53 | type = integer 54 | dimensions = () 55 | intent = out 56 | -------------------------------------------------------------------------------- /test/test_suites/suite_zhang_mcfarlane.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | initialize_constituents 6 | to_be_ccppized_temporary 7 | set_cloud_fraction_top 8 | zm_conv_options 9 | zm_convr 10 | zm_convr_tendency_diagnostics 11 | apply_heating_rate 12 | apply_constituent_tendencies 13 | qneg 14 | geopotential_temp 15 | cloud_fraction_fice 16 | set_deep_conv_fluxes_to_general 17 | zm_conv_evap 18 | set_general_conv_fluxes_to_deep 19 | zm_evap_tendency_diagnostics 20 | apply_heating_rate 21 | apply_constituent_tendencies 22 | qneg 23 | geopotential_temp 24 | cloud_fraction_fice 25 | zm_conv_momtran 26 | zm_momtran_tendency_diagnostics 27 | apply_heating_rate 28 | apply_tendency_of_eastward_wind 29 | apply_tendency_of_northward_wind 30 | geopotential_temp 31 | zm_conv_convtran 32 | zm_tendency_diagnostics 33 | apply_constituent_tendencies 34 | qneg 35 | geopotential_temp 36 | zm_diagnostics 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/check_energy_scaling.F90: -------------------------------------------------------------------------------- 1 | module check_energy_scaling 2 | use ccpp_kinds, only: kind_phys 3 | 4 | implicit none 5 | private 6 | 7 | public :: check_energy_scaling_run 8 | 9 | contains 10 | 11 | ! CCPP routine to get scaling factor for conversion of temperature increment. 12 | ! This is extracted to a separate subroutine so that scaling_dycore can be passed 13 | ! directly to the CCPP-ized check_energy_chng_run subroutine from CAM with subcolumns. 14 | ! 15 | ! When subcolumns are removed from CAM, this dummy scheme can be removed, and 16 | ! scaling_dycore can just be calculated in check_energy_chng. (hplin, 9/5/24) 17 | !> \section arg_table_check_energy_scaling_run Argument Table 18 | !! \htmlinclude arg_table_check_energy_scaling_run.html 19 | subroutine check_energy_scaling_run( & 20 | ncol, & 21 | cp_or_cv_dycore, cpairv, & 22 | scaling_dycore, & 23 | errmsg, errflg) 24 | 25 | ! Input arguments 26 | integer, intent(in) :: ncol ! number of atmospheric columns 27 | real(kind_phys), intent(in) :: cp_or_cv_dycore(:,:) ! cp or cv from dycore [J kg-1 K-1] 28 | real(kind_phys), intent(in) :: cpairv(:,:) ! specific heat of dry air at constant pressure [J kg-1 K-1] 29 | 30 | ! Output arguments 31 | real(kind_phys), intent(out) :: scaling_dycore(:,:) ! scaling for conversion of temperature increment [1] 32 | character(len=512), intent(out) :: errmsg 33 | integer, intent(out) :: errflg 34 | 35 | errmsg = '' 36 | errflg = 0 37 | 38 | scaling_dycore(:ncol,:) = cpairv(:ncol,:) / cp_or_cv_dycore(:ncol,:) 39 | 40 | end subroutine check_energy_scaling_run 41 | 42 | end module check_energy_scaling 43 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/check_energy_fix_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = check_energy_fix_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = check_energy_fix_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | units = none 11 | type = character | kind = len=512 12 | dimensions = () 13 | intent = out 14 | [ errflg ] 15 | standard_name = ccpp_error_code 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = out 20 | 21 | [ccpp-arg-table] 22 | name = check_energy_fix_diagnostics_run 23 | type = scheme 24 | [ te_ini_dyn ] 25 | standard_name = vertically_integrated_total_energy_using_dycore_energy_formula_at_start_of_physics_timestep 26 | units = J m-2 27 | type = real | kind = kind_phys 28 | dimensions = (horizontal_loop_extent) 29 | intent = in 30 | [ te_cur_dyn ] 31 | standard_name = vertically_integrated_total_energy_using_dycore_energy_formula 32 | units = J m-2 33 | type = real | kind = kind_phys 34 | dimensions = (horizontal_loop_extent) 35 | intent = in 36 | [ teout ] 37 | standard_name = vertically_integrated_total_energy_using_dycore_energy_formula_at_end_of_physics_timestep 38 | units = J m-2 39 | type = real | kind = kind_phys 40 | dimensions = (horizontal_loop_extent) 41 | intent = in 42 | [ eshflx ] 43 | standard_name = net_sensible_heat_flux_through_top_and_bottom_of_atmosphere_column 44 | units = W m-2 45 | type = real | kind = kind_phys 46 | dimensions = (horizontal_loop_extent) 47 | intent = in 48 | [ errmsg ] 49 | standard_name = ccpp_error_message 50 | units = none 51 | type = character | kind = len=512 52 | dimensions = () 53 | intent = out 54 | [ errflg ] 55 | standard_name = ccpp_error_code 56 | units = 1 57 | type = integer 58 | dimensions = () 59 | intent = out 60 | -------------------------------------------------------------------------------- /to_be_ccppized/ccpp_const_utils.F90: -------------------------------------------------------------------------------- 1 | ! ccpp_const_utils contains utility functions that use 2 | ! the ccpp constituent properties pointer. 3 | ! this code was separated out to remove circular dependencies. 4 | module ccpp_const_utils 5 | implicit none 6 | private 7 | 8 | public :: ccpp_const_get_idx 9 | 10 | contains 11 | 12 | subroutine ccpp_const_get_idx(constituent_props, name, cindex, errmsg, errflg) 13 | use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 14 | 15 | ! Input arguments 16 | type(ccpp_constituent_prop_ptr_t), intent(in) :: constituent_props(:) 17 | character(len=*), intent(in) :: name ! constituent name 18 | 19 | ! Output arguments 20 | integer, intent(out) :: cindex ! global constituent index 21 | character(len=512), intent(out) :: errmsg ! error message 22 | integer, intent(out) :: errflg ! error flag 23 | 24 | ! Local variables 25 | integer :: t_cindex 26 | character(len=256) :: t_const_name 27 | 28 | errmsg = '' 29 | errflg = 0 30 | 31 | cindex = -1 32 | 33 | ! This convoluted loop is brought to you in exchange for avoiding a 34 | ! circular dependency on cam_ccpp_cap::cam_const_get_index. 35 | const_props_loop: do t_cindex = lbound(constituent_props, 1), ubound(constituent_props, 1) 36 | call constituent_props(t_cindex)%standard_name(t_const_name, errflg, errmsg) 37 | if (errflg /= 0) then 38 | ! Abort subroutine and return with error. 39 | return 40 | end if 41 | 42 | if (trim(t_const_name) == trim(name)) then 43 | cindex = t_cindex 44 | exit const_props_loop 45 | end if 46 | enddo const_props_loop 47 | 48 | end subroutine ccpp_const_get_idx 49 | 50 | end module ccpp_const_utils 51 | -------------------------------------------------------------------------------- /schemes/utilities/convert_dry_constituent_tendencies_to_dry_air_basis.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = convert_dry_constituent_tendencies_to_dry_air_basis 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = convert_dry_constituent_tendencies_to_dry_air_basis_run 7 | type = scheme 8 | [ ncol ] 9 | standard_name = horizontal_loop_extent 10 | units = count 11 | type = integer 12 | dimensions = () 13 | intent = in 14 | [ pver ] 15 | standard_name = vertical_layer_dimension 16 | units = count 17 | type = integer 18 | dimensions = () 19 | intent = in 20 | [ pcnst ] 21 | standard_name = number_of_ccpp_constituents 22 | units = count 23 | type = integer 24 | dimensions = () 25 | intent = in 26 | [ pdel ] 27 | standard_name = air_pressure_thickness 28 | units = Pa 29 | type = real | kind = kind_phys 30 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 31 | intent = in 32 | [ pdeldry ] 33 | standard_name = air_pressure_thickness_of_dry_air 34 | units = Pa 35 | type = real | kind = kind_phys 36 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 37 | intent = in 38 | [ const_props ] 39 | standard_name = ccpp_constituent_properties 40 | units = none 41 | type = ccpp_constituent_prop_ptr_t 42 | dimensions = (number_of_ccpp_constituents) 43 | intent = in 44 | [ tend_q ] 45 | standard_name = ccpp_constituent_tendencies 46 | units = none 47 | type = real | kind = kind_phys 48 | dimensions = (horizontal_loop_extent, vertical_layer_dimension, number_of_ccpp_constituents) 49 | intent = inout 50 | [ errmsg ] 51 | standard_name = ccpp_error_message 52 | units = none 53 | type = character | kind = len=512 54 | dimensions = () 55 | intent = out 56 | [ errflg ] 57 | standard_name = ccpp_error_code 58 | units = 1 59 | type = integer 60 | dimensions = () 61 | intent = out 62 | -------------------------------------------------------------------------------- /schemes/gravity_wave_drag/gravity_wave_drag_top_taper.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = gravity_wave_drag_top_taper 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = gravity_wave_drag_top_taper_init 7 | type = scheme 8 | [ pver ] 9 | standard_name = vertical_layer_dimension 10 | units = count 11 | type = integer 12 | dimensions = () 13 | intent = in 14 | [ amIRoot ] 15 | standard_name = flag_for_mpi_root 16 | units = flag 17 | type = logical 18 | dimensions = () 19 | intent = in 20 | [ iulog ] 21 | standard_name = log_output_unit 22 | units = 1 23 | type = integer 24 | dimensions = () 25 | intent = in 26 | [ gw_top_taper ] 27 | standard_name = taper_gravity_wave_drag_at_model_top 28 | units = flag 29 | type = logical 30 | dimensions = () 31 | intent = in 32 | [ nbot_gravity_wave_top_taper ] 33 | standard_name = vertical_index_of_bottom_limit_for_tapering_gravity_wave_drag_at_model_top 34 | units = index 35 | type = integer 36 | dimensions = () 37 | intent = in 38 | [ pref_edge ] 39 | standard_name = reference_pressure_at_interface 40 | units = Pa 41 | type = real | kind = kind_phys 42 | dimensions = (vertical_interface_dimension) 43 | intent = in 44 | [ pref_mid ] 45 | standard_name = reference_pressure_in_atmosphere_layer 46 | units = Pa 47 | type = real | kind = kind_phys 48 | dimensions = (vertical_layer_dimension) 49 | intent = in 50 | [ vramp ] 51 | standard_name = gravity_wave_drag_tapering_coefficients 52 | units = 1 53 | type = real | kind = kind_phys 54 | dimensions = (vertical_layer_dimension) 55 | intent = out 56 | [ errmsg ] 57 | standard_name = ccpp_error_message 58 | units = none 59 | type = character | kind = len=512 60 | dimensions = () 61 | intent = out 62 | [ errflg ] 63 | standard_name = ccpp_error_code 64 | units = 1 65 | type = integer 66 | dimensions = () 67 | intent = out 68 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/compute_cloud_fraction_diagnostics.F90: -------------------------------------------------------------------------------- 1 | ! Diagnostics for cloud fraction 2 | module compute_cloud_fraction_diagnostics 3 | use ccpp_kinds, only: kind_phys 4 | 5 | implicit none 6 | private 7 | save 8 | 9 | public :: compute_cloud_fraction_diagnostics_init 10 | public :: compute_cloud_fraction_diagnostics_run 11 | 12 | contains 13 | 14 | !> \section arg_table_compute_cloud_fraction_diagnostics_init Argument Table 15 | !! \htmlinclude compute_cloud_fraction_diagnostics_init.html 16 | subroutine compute_cloud_fraction_diagnostics_init(errmsg, errflg) 17 | use cam_history, only: history_add_field 18 | use cam_history_support, only: horiz_only 19 | 20 | character(len=512), intent(out) :: errmsg 21 | integer, intent(out) :: errflg 22 | 23 | ! Local variables: 24 | 25 | errmsg = '' 26 | errflg = 0 27 | 28 | ! History add field calls 29 | call history_add_field('CLDST', 'stratiform_cloud_area_fraction', 'lev', 'avg', 'fraction') 30 | 31 | end subroutine compute_cloud_fraction_diagnostics_init 32 | 33 | !> \section arg_table_compute_cloud_fraction_diagnostics_run Argument Table 34 | !! \htmlinclude compute_cloud_fraction_diagnostics_run.html 35 | subroutine compute_cloud_fraction_diagnostics_run( & 36 | cldst, & 37 | errmsg, errflg) 38 | 39 | use cam_history, only: history_out_field 40 | 41 | ! Input parameters 42 | real(kind_phys), intent(in) :: cldst(:,:) 43 | 44 | 45 | ! CCPP error handling variables 46 | character(len=512), intent(out) :: errmsg 47 | integer, intent(out) :: errflg 48 | 49 | errmsg = '' 50 | errflg = 0 51 | 52 | ! History out field calls 53 | call history_out_field('CLDST', cldst) 54 | 55 | end subroutine compute_cloud_fraction_diagnostics_run 56 | 57 | end module compute_cloud_fraction_diagnostics 58 | -------------------------------------------------------------------------------- /test/unit-test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | 3 | project(atmospheric_physics VERSION 0.0.1 LANGUAGES Fortran) 4 | 5 | find_package(PFUNIT REQUIRED) 6 | 7 | if(NOT ATMOSPHERIC_PHYSICS_IS_TOP_LEVEL) 8 | message(WARNING "atmospheric-physics is not integrated into the CMake build of any top level " 9 | "project yet and this CMake is for testing purposes only. " 10 | "Making a change to this project's CMake will not impact the build of " 11 | "a parent project at this time.") 12 | endif() 13 | 14 | option(ATMOSPHERIC_PHYSICS_ENABLE_TESTS "Run pFUnit unit tests" OFF) 15 | option(ATMOSPHERIC_PHYSICS_ENABLE_CODE_COVERAGE "Run code coverage tool" OFF) 16 | 17 | if(ATMOSPHERIC_PHYSICS_ENABLE_CODE_COVERAGE) 18 | add_compile_options(-O0 --coverage) 19 | add_link_options(--coverage) 20 | endif() 21 | 22 | set(CMAKE_BUILD_TYPE Debug) 23 | 24 | set(UTILITIES_SRC 25 | ../../schemes/utilities/state_converters.F90 26 | ../../schemes/utilities/static_energy.F90 27 | ../../schemes/utilities/physics_tendency_updaters.F90 28 | include/ccpp_kinds.F90 29 | ) 30 | 31 | add_library(utilities ${UTILITIES_SRC}) 32 | target_compile_options(utilities PRIVATE -ffree-line-length-none) 33 | target_include_directories(utilities PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) 34 | 35 | set(PHYS_UTILS_SRC 36 | ../../phys_utils/atmos_phys_pbl_utils.F90 37 | ../../phys_utils/atmos_phys_string_utils.F90 38 | ../../phys_utils/atmos_phys_rad_utils.F90 39 | include/ccpp_kinds.F90 40 | ) 41 | 42 | add_library(phys_utils ${PHYS_UTILS_SRC}) 43 | target_compile_options(phys_utils PRIVATE -ffree-line-length-none) 44 | target_include_directories(phys_utils PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) 45 | 46 | add_subdirectory(../../schemes/mmm mmm) 47 | 48 | if(ATMOSPHERIC_PHYSICS_ENABLE_TESTS OR ATMOSPHERIC_PHYSICS_ENABLE_CODE_COVERAGE) 49 | enable_testing() 50 | add_subdirectory(tests) 51 | endif() 52 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/kessler_diagnostics.F90: -------------------------------------------------------------------------------- 1 | module kessler_diagnostics 2 | ! 3 | ! Diagnostics for use by the Kessler physics suite only 4 | ! 5 | 6 | use ccpp_kinds, only: kind_phys 7 | 8 | implicit none 9 | private 10 | save 11 | 12 | public :: kessler_diagnostics_init ! init routine 13 | public :: kessler_diagnostics_run ! main routine 14 | 15 | CONTAINS 16 | 17 | !> \section arg_table_kessler_diagnostics_init Argument Table 18 | !! \htmlinclude kessler_diagnostics_init.html 19 | subroutine kessler_diagnostics_init(errmsg, errflg) 20 | use cam_history, only: history_add_field 21 | use cam_history_support, only: horiz_only 22 | 23 | character(len=512), intent(out) :: errmsg 24 | integer, intent(out) :: errflg 25 | 26 | ! Local variables: 27 | 28 | errmsg = '' 29 | errflg = 0 30 | 31 | call history_add_field('PRECT', 'total_precipitation_rate_at_surface', horiz_only, 'avg', 'm s-1') 32 | 33 | end subroutine kessler_diagnostics_init 34 | 35 | !> \section arg_table_kessler_diagnostics_run Argument Table 36 | !! \htmlinclude kessler_diagnostics_run.html 37 | subroutine kessler_diagnostics_run(precl, errmsg, errflg) 38 | 39 | use cam_history, only: history_out_field 40 | !------------------------------------------------ 41 | ! Input / output parameters 42 | !------------------------------------------------ 43 | ! State variables 44 | real(kind_phys), intent(in) :: precl(:) ! Total precipitation 45 | ! CCPP error handling variables 46 | character(len=512), intent(out) :: errmsg 47 | integer, intent(out) :: errflg 48 | 49 | errmsg = '' 50 | errflg = 0 51 | 52 | call history_out_field('PRECT', precl) 53 | 54 | end subroutine kessler_diagnostics_run 55 | 56 | !======================================================================= 57 | 58 | end module kessler_diagnostics 59 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/zm_tendency_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = zm_tendency_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = zm_tendency_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | long_name = Error message for error handling in CCPP 11 | units = none 12 | type = character | kind = len=512 13 | dimensions = () 14 | intent = out 15 | [ errflg ] 16 | standard_name = ccpp_error_code 17 | long_name = Error flag for error handling in CCPP 18 | units = 1 19 | type = integer 20 | dimensions = () 21 | intent = out 22 | 23 | [ccpp-arg-table] 24 | name = zm_tendency_diagnostics_run 25 | type = scheme 26 | [ ncol ] 27 | standard_name = horizontal_loop_extent 28 | units = count 29 | type = integer 30 | dimensions = () 31 | intent = in 32 | [ pver ] 33 | standard_name = vertical_layer_dimension 34 | units = count 35 | type = integer 36 | dimensions = () 37 | intent = in 38 | [ pverp ] 39 | standard_name = vertical_interface_dimension 40 | units = count 41 | type = integer 42 | dimensions = () 43 | intent = in 44 | [ const_props ] 45 | standard_name = ccpp_constituent_properties 46 | units = none 47 | type = ccpp_constituent_prop_ptr_t 48 | dimensions = (number_of_ccpp_constituents) 49 | intent = in 50 | [ dqdt ] 51 | standard_name = ccpp_constituent_tendencies 52 | units = none 53 | type = real | kind = kind_phys 54 | dimensions = (horizontal_loop_extent,vertical_layer_dimension,number_of_ccpp_constituents) 55 | intent = in 56 | [ errmsg ] 57 | standard_name = ccpp_error_message 58 | long_name = Error message for error handling in CCPP 59 | units = none 60 | type = character | kind = len=512 61 | dimensions = () 62 | intent = out 63 | [ errflg ] 64 | standard_name = ccpp_error_code 65 | long_name = Error flag for error handling in CCPP 66 | units = 1 67 | type = integer 68 | dimensions = () 69 | intent = out 70 | -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/check_energy_fix.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = check_energy_fix 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = check_energy_fix_run 7 | type = scheme 8 | [ ncol ] 9 | standard_name = horizontal_loop_extent 10 | units = count 11 | type = integer 12 | dimensions = () 13 | intent = in 14 | [ pver ] 15 | standard_name = vertical_layer_dimension 16 | units = count 17 | type = integer 18 | dimensions = () 19 | intent = in 20 | [ pint ] 21 | standard_name = air_pressure_at_interface 22 | units = Pa 23 | type = real | kind = kind_phys 24 | dimensions = (horizontal_loop_extent, vertical_interface_dimension) 25 | intent = in 26 | [ gravit ] 27 | standard_name = standard_gravitational_acceleration 28 | units = m s-2 29 | type = real | kind = kind_phys 30 | dimensions = () 31 | intent = in 32 | [ heat_glob ] 33 | standard_name = global_mean_heating_rate_correction_for_energy_conservation 34 | units = J kg-1 s-1 35 | type = real | kind = kind_phys 36 | dimensions = () 37 | intent = in 38 | [ ptend_s ] 39 | standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure 40 | units = J kg-1 s-1 41 | type = real | kind = kind_phys 42 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 43 | intent = out 44 | [ eshflx ] 45 | standard_name = net_sensible_heat_flux_through_top_and_bottom_of_atmosphere_column 46 | units = W m-2 47 | type = real | kind = kind_phys 48 | dimensions = (horizontal_loop_extent) 49 | intent = out 50 | [ scheme_name ] 51 | standard_name = scheme_name 52 | units = none 53 | type = character | kind = len=64 54 | dimensions = () 55 | intent = out 56 | [ errmsg ] 57 | standard_name = ccpp_error_message 58 | units = none 59 | type = character | kind = len=512 60 | dimensions = () 61 | intent = out 62 | [ errflg ] 63 | standard_name = ccpp_error_code 64 | units = 1 65 | type = integer 66 | dimensions = () 67 | intent = out 68 | -------------------------------------------------------------------------------- /schemes/zhang_mcfarlane/set_general_conv_fluxes_to_deep.F90: -------------------------------------------------------------------------------- 1 | module set_general_conv_fluxes_to_deep 2 | 3 | use ccpp_kinds, only: kind_phys 4 | 5 | implicit none 6 | 7 | contains 8 | 9 | !=============================================================================== 10 | !> \section arg_table_set_general_conv_fluxes_to_deep_run Argument Table 11 | !! \htmlinclude set_general_conv_fluxes_to_deep_run.html 12 | !! 13 | 14 | subroutine set_general_conv_fluxes_to_deep_run(tend_s_snwprd_gen, tend_s_snwprd_dp, tend_s_snwevmlt_gen, tend_s_snwevmlt_dp, & 15 | prec_gen, prec_dp, snow_gen, snow_dp, ntprprd_gen, ntprprd_dp, ntsnprd_gen, ntsnprd_dp, & 16 | flxprec_gen, flxprec_dp, flxsnow_gen, flxsnow_dp) 17 | 18 | real(kind_phys), intent(in) :: tend_s_snwprd_gen(:,:) 19 | real(kind_phys), intent(out) :: tend_s_snwprd_dp(:,:) 20 | real(kind_phys), intent(in) :: tend_s_snwevmlt_gen(:,:) 21 | real(kind_phys), intent(out) :: tend_s_snwevmlt_dp(:,:) 22 | real(kind_phys), intent(in) :: prec_gen(:) 23 | real(kind_phys), intent(out) :: prec_dp(:) 24 | real(kind_phys), intent(in) :: snow_gen(:) 25 | real(kind_phys), intent(out) :: snow_dp(:) 26 | real(kind_phys), intent(in) :: ntprprd_gen(:,:) 27 | real(kind_phys), intent(out) :: ntprprd_dp(:,:) 28 | real(kind_phys), intent(in) :: ntsnprd_gen(:,:) 29 | real(kind_phys), intent(out) :: ntsnprd_dp(:,:) 30 | real(kind_phys), intent(in) :: flxprec_gen(:,:) 31 | real(kind_phys), intent(out) :: flxprec_dp(:,:) 32 | real(kind_phys), intent(in) :: flxsnow_gen(:,:) 33 | real(kind_phys), intent(out) :: flxsnow_dp(:,:) 34 | 35 | tend_s_snwprd_dp = tend_s_snwprd_gen 36 | tend_s_snwevmlt_dp = tend_s_snwevmlt_gen 37 | prec_dp = prec_gen 38 | snow_dp = snow_gen 39 | ntprprd_dp = ntprprd_gen 40 | ntsnprd_dp = ntsnprd_gen 41 | flxprec_dp = flxprec_gen 42 | flxsnow_dp = flxsnow_gen 43 | 44 | end subroutine set_general_conv_fluxes_to_deep_run 45 | 46 | end module set_general_conv_fluxes_to_deep 47 | -------------------------------------------------------------------------------- /suites/suite_tj2016.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tj2016_precip 6 | apply_heating_rate 7 | qneg 8 | 9 | 13 | check_energy_zero_fluxes 14 | check_energy_scaling 15 | check_energy_chng 16 | 17 | 18 | sima_state_diagnostics 19 | 20 | 21 | tj2016_sfc_pbl_hs 22 | apply_heating_rate 23 | apply_tendency_of_eastward_wind 24 | apply_tendency_of_northward_wind 25 | qneg 26 | 27 | 28 | thermo_water_update 29 | 30 | 31 | 32 | 33 | 34 | 38 | check_energy_scaling 39 | dycore_energy_consistency_adjust 40 | apply_tendency_of_air_temperature 41 | 42 | 43 | sima_tend_diagnostics 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /schemes/utilities/static_energy.meta: -------------------------------------------------------------------------------- 1 | ######################################################### 2 | [ccpp-table-properties] 3 | name = update_dry_static_energy 4 | type = scheme 5 | [ccpp-arg-table] 6 | name = update_dry_static_energy_run 7 | type = scheme 8 | [ nz ] 9 | standard_name = vertical_layer_dimension 10 | long_name = number of vertical layers 11 | units = count 12 | dimensions = () 13 | type = integer 14 | intent = in 15 | [ gravit ] 16 | standard_name = standard_gravitational_acceleration 17 | units = m s-2 18 | dimensions = () 19 | type = real | kind = kind_phys 20 | intent = in 21 | [ temp ] 22 | standard_name = air_temperature 23 | type = real | kind = kind_phys 24 | units = K 25 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 26 | intent = in 27 | [ zm ] 28 | standard_name = geopotential_height_wrt_surface 29 | type = real | kind = kind_phys 30 | units = m 31 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 32 | intent = in 33 | [ phis ] 34 | standard_name = surface_geopotential 35 | type = real | kind = kind_phys 36 | units = m2 s-2 37 | dimensions = (horizontal_loop_extent) 38 | intent = in 39 | [ st_energy ] 40 | standard_name = dry_static_energy 41 | long_name = Dry static energy 42 | type = real | kind = kind_phys 43 | units = J kg-1 44 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 45 | intent = out 46 | [ cpair ] 47 | standard_name = composition_dependent_specific_heat_of_dry_air_at_constant_pressure 48 | units = J kg-1 K-1 49 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 50 | type = real | kind = kind_phys 51 | intent = in 52 | [ errcode ] 53 | standard_name = ccpp_error_code 54 | long_name = Error flag for error handling in CCPP 55 | units = 1 56 | type = integer 57 | dimensions = () 58 | intent = out 59 | [ errmsg ] 60 | standard_name = ccpp_error_message 61 | long_name = Error message for error handling in CCPP 62 | units = none 63 | type = character | kind = len=512 64 | dimensions = () 65 | intent = out 66 | -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/check_energy_fix.F90: -------------------------------------------------------------------------------- 1 | module check_energy_fix 2 | use ccpp_kinds, only: kind_phys 3 | 4 | implicit none 5 | private 6 | 7 | public :: check_energy_fix_run 8 | 9 | contains 10 | 11 | ! Add heating rate required for global mean total energy conservation 12 | !> \section arg_table_check_energy_fix_run Argument Table 13 | !! \htmlinclude arg_table_check_energy_fix_run.html 14 | subroutine check_energy_fix_run(ncol, pver, pint, gravit, heat_glob, ptend_s, eshflx, scheme_name, errmsg, errflg) 15 | ! Input arguments 16 | integer, intent(in) :: ncol ! number of atmospheric columns 17 | integer, intent(in) :: pver ! number of vertical layers 18 | real(kind_phys), intent(in) :: pint(:,:) ! interface pressure [Pa] 19 | real(kind_phys), intent(in) :: gravit ! gravitational acceleration [m s-2] 20 | real(kind_phys), intent(in) :: heat_glob ! global mean heating rate [J kg-1 s-1] 21 | real(kind_phys), intent(out) :: ptend_s(:,:) ! physics tendency heating rate [J kg-1 s-1] 22 | real(kind_phys), intent(out) :: eshflx(:) ! effective sensible heat flux [W m-2] 23 | ! for check_energy_chng 24 | 25 | ! Output arguments 26 | character(len=64), intent(out) :: scheme_name ! scheme name 27 | character(len=512), intent(out) :: errmsg ! error message 28 | integer, intent(out) :: errflg ! error flag 29 | 30 | ! Local variables 31 | integer :: i 32 | 33 | errmsg = '' 34 | errflg = 0 35 | 36 | ! Set scheme name for check_energy_chng 37 | scheme_name = "check_energy_fix" 38 | 39 | ! add (-) global mean total energy difference as heating 40 | ptend_s(:ncol, :pver) = heat_glob 41 | 42 | ! compute effective sensible heat flux 43 | do i = 1, ncol 44 | eshflx(i) = heat_glob * (pint(i,pver+1) - pint(i,1)) / gravit 45 | end do 46 | end subroutine check_energy_fix_run 47 | 48 | end module check_energy_fix 49 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/gravity_wave_drag_common_diagnostics.F90: -------------------------------------------------------------------------------- 1 | ! Diagnostics for all gravity wave drag parameterizations 2 | ! (used to output total diagnostics in the end of all gravity wave drag schemes) 3 | module gravity_wave_drag_common_diagnostics 4 | use ccpp_kinds, only: kind_phys 5 | 6 | implicit none 7 | private 8 | 9 | public :: gravity_wave_drag_common_diagnostics_init 10 | public :: gravity_wave_drag_common_diagnostics_run 11 | 12 | contains 13 | 14 | !> \section arg_table_gravity_wave_drag_common_diagnostics_init Argument Table 15 | !! \htmlinclude gravity_wave_drag_common_diagnostics_init.html 16 | subroutine gravity_wave_drag_common_diagnostics_init(errmsg, errflg) 17 | use cam_history, only: history_add_field 18 | use cam_history_support, only: horiz_only 19 | 20 | character(len=512), intent(out) :: errmsg 21 | integer, intent(out) :: errflg 22 | 23 | ! Local variables: 24 | 25 | errmsg = '' 26 | errflg = 0 27 | 28 | ! History add field calls 29 | call history_add_field('EKGW', 'effective_diffusivity_coefficient_at_interfaces_due_to_gravity_wave_drag', 'ilev', 'avg', 'm2 s-1') 30 | 31 | end subroutine gravity_wave_drag_common_diagnostics_init 32 | 33 | !> \section arg_table_gravity_wave_drag_common_diagnostics_run Argument Table 34 | !! \htmlinclude gravity_wave_drag_common_diagnostics_run.html 35 | subroutine gravity_wave_drag_common_diagnostics_run( & 36 | egwdffi_tot, & 37 | errmsg, errflg) 38 | 39 | use cam_history, only: history_out_field 40 | 41 | ! Input parameters 42 | real(kind_phys), intent(in) :: egwdffi_tot(:,:) 43 | 44 | ! CCPP error handling variables 45 | character(len=512), intent(out) :: errmsg 46 | integer, intent(out) :: errflg 47 | 48 | errmsg = '' 49 | errflg = 0 50 | 51 | ! History out field calls 52 | call history_out_field('EKGW', egwdffi_tot) 53 | 54 | end subroutine gravity_wave_drag_common_diagnostics_run 55 | 56 | end module gravity_wave_drag_common_diagnostics 57 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/zm_convr_tendency_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = zm_convr_tendency_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = zm_convr_tendency_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | long_name = Error message for error handling in CCPP 11 | units = none 12 | type = character | kind = len=512 13 | dimensions = () 14 | intent = out 15 | [ errflg ] 16 | standard_name = ccpp_error_code 17 | long_name = Error flag for error handling in CCPP 18 | units = 1 19 | type = integer 20 | dimensions = () 21 | intent = out 22 | 23 | [ccpp-arg-table] 24 | name = zm_convr_tendency_diagnostics_run 25 | type = scheme 26 | [ ncol ] 27 | standard_name = horizontal_loop_extent 28 | units = count 29 | type = integer 30 | dimensions = () 31 | intent = in 32 | [ pver ] 33 | standard_name = vertical_layer_dimension 34 | units = count 35 | type = integer 36 | dimensions = () 37 | intent = in 38 | [ cpair ] 39 | standard_name = specific_heat_of_dry_air_at_constant_pressure 40 | units = J kg-1 K-1 41 | type = real | kind = kind_phys 42 | dimensions = () 43 | intent = in 44 | [ heat ] 45 | standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure 46 | units = J kg-1 s-1 47 | type = real | kind = kind_phys 48 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 49 | intent = in 50 | [ qtnd ] 51 | standard_name = tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water 52 | units = kg kg-1 s-1 53 | type = real | kind = kind_phys 54 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 55 | intent = in 56 | [ errmsg ] 57 | standard_name = ccpp_error_message 58 | long_name = Error message for error handling in CCPP 59 | units = none 60 | type = character | kind = len=512 61 | dimensions = () 62 | intent = out 63 | [ errflg ] 64 | standard_name = ccpp_error_code 65 | long_name = Error flag for error handling in CCPP 66 | units = 1 67 | type = integer 68 | dimensions = () 69 | intent = out 70 | 71 | -------------------------------------------------------------------------------- /.github/workflows/unit-tests.yaml: -------------------------------------------------------------------------------- 1 | name: unit-test-code-coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - development 7 | - main 8 | workflow_dispatch: 9 | pull_request: 10 | 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.ref || github.run_id }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | gcc-toolchain: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout atmospheric_physics 20 | uses: actions/checkout@v4 21 | 22 | - name: Install dependencies 23 | run: | 24 | sudo apt update && sudo apt -y install libopenmpi-dev openmpi-bin 25 | 26 | - name: Build pFUnit 27 | run: | 28 | git clone --depth 1 --branch v4.10.0 https://github.com/Goddard-Fortran-Ecosystem/pFUnit.git 29 | cd pFUnit 30 | pwd 31 | cmake -B./build -S. 32 | cd build 33 | make install 34 | 35 | - name: Build atmospheric_physics 36 | run: | 37 | cmake \ 38 | -DCMAKE_PREFIX_PATH=/home/runner/work/atmospheric_physics/atmospheric_physics/pFUnit/build/installed \ 39 | -DATMOSPHERIC_PHYSICS_ENABLE_CODE_COVERAGE=ON \ 40 | -B./build \ 41 | -S./test/unit-test 42 | cd build 43 | make 44 | 45 | - name: Run tests 46 | run: | 47 | cd build && ctest -V --output-on-failure --output-junit test_results.xml 48 | 49 | - name: Upload unit test results 50 | uses: actions/upload-artifact@v4 51 | with: 52 | name: unit-test-results 53 | path: build/test_results.xml 54 | 55 | - name: Setup GCov 56 | run: | 57 | python3 -m venv venv 58 | source venv/bin/activate 59 | pip3 install gcovr 60 | 61 | - name: Run Gcov 62 | run: | 63 | source venv/bin/activate 64 | cd build 65 | gcovr -r .. --filter '\.\./schemes' --filter '\.\./phys_utils' --html atmospheric_physics_code_coverage.html --txt 66 | 67 | - name: Upload code coverage results 68 | uses: actions/upload-artifact@v4 69 | with: 70 | name: code-coverage-results 71 | path: build/atmospheric_physics_code_coverage.html 72 | 73 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/sima_tend_diagnostics.F90: -------------------------------------------------------------------------------- 1 | module sima_tend_diagnostics 2 | 3 | use ccpp_kinds, only: kind_phys 4 | use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 5 | 6 | implicit none 7 | private 8 | save 9 | 10 | public :: sima_tend_diagnostics_init ! init routine 11 | public :: sima_tend_diagnostics_run ! main routine 12 | 13 | 14 | CONTAINS 15 | 16 | !> \section arg_table_sima_tend_diagnostics_init Argument Table 17 | !! \htmlinclude sima_tend_diagnostics_init.html 18 | subroutine sima_tend_diagnostics_init(errmsg, errflg) 19 | use cam_history, only: history_add_field 20 | character(len=512), intent(out) :: errmsg 21 | integer, intent(out) :: errflg 22 | 23 | ! Add tendency fields 24 | call history_add_field('TTEND', 'tendency_of_air_temperature_due_to_model_physics', 'lev', 'avg', 'K s-1') 25 | call history_add_field('UTEND', 'tendency_of_eastward_wind_due_to_model_physics', 'lev', 'avg', 'm s-2') 26 | call history_add_field('VTEND', 'tendency_of_northward_wind_due_to_model_physics', 'lev', 'avg', 'm s-2') 27 | 28 | end subroutine sima_tend_diagnostics_init 29 | 30 | !> \section arg_table_sima_tend_diagnostics_run Argument Table 31 | !! \htmlinclude sima_tend_diagnostics_run.html 32 | subroutine sima_tend_diagnostics_run(dTdt_total, dudt_total, dvdt_total, errmsg, errflg) 33 | use cam_history, only: history_out_field 34 | ! Tendency variables 35 | real(kind_phys), intent(in) :: dTdt_total(:,:) ! tendency of air temperature due to model physics 36 | real(kind_phys), intent(in) :: dudt_total(:,:) ! tendency of eastward wind due to model physics 37 | real(kind_phys), intent(in) :: dvdt_total(:,:) ! tendency of northward wind due to model physics 38 | character(len=512), intent(out) :: errmsg 39 | integer, intent(out) :: errflg 40 | 41 | ! Capture tendency fields 42 | call history_out_field('TTEND', dTdt_total) 43 | call history_out_field('UTEND', dudt_total) 44 | call history_out_field('VTEND', dvdt_total) 45 | 46 | end subroutine sima_tend_diagnostics_run 47 | !======================================================================= 48 | end module sima_tend_diagnostics 49 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/check_energy_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = check_energy_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = check_energy_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | units = none 11 | type = character | kind = len=512 12 | dimensions = () 13 | intent = out 14 | [ errflg ] 15 | standard_name = ccpp_error_code 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = out 20 | 21 | [ccpp-arg-table] 22 | name = check_energy_diagnostics_run 23 | type = scheme 24 | [ cp_or_cv_dycore ] 25 | standard_name = specific_heat_of_air_used_in_dycore 26 | units = J kg-1 K-1 27 | type = real | kind = kind_phys 28 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 29 | intent = in 30 | [ scaling_dycore ] 31 | standard_name = ratio_of_specific_heat_of_air_used_in_physics_energy_formula_to_specific_heat_of_air_used_in_dycore_energy_formula 32 | units = 1 33 | type = real | kind = kind_phys 34 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 35 | intent = in 36 | [ te_cur_phys ] 37 | standard_name = vertically_integrated_total_energy_using_physics_energy_formula 38 | units = J m-2 39 | type = real | kind = kind_phys 40 | dimensions = (horizontal_loop_extent) 41 | intent = in 42 | [ tw_cur ] 43 | standard_name = vertically_integrated_total_water 44 | units = kg m-2 45 | type = real | kind = kind_phys 46 | dimensions = (horizontal_loop_extent) 47 | intent = in 48 | [ tend_te_tnd ] 49 | standard_name = cumulative_total_energy_boundary_flux_using_physics_energy_formula 50 | units = J m-2 s-1 51 | type = real | kind = kind_phys 52 | dimensions = (horizontal_loop_extent) 53 | intent = in 54 | [ tend_tw_tnd ] 55 | standard_name = cumulative_total_water_boundary_flux 56 | units = kg m-2 s-1 57 | type = real | kind = kind_phys 58 | dimensions = (horizontal_loop_extent) 59 | intent = in 60 | [ errmsg ] 61 | standard_name = ccpp_error_message 62 | units = none 63 | type = character | kind = len=512 64 | dimensions = () 65 | intent = out 66 | [ errflg ] 67 | standard_name = ccpp_error_code 68 | units = 1 69 | type = integer 70 | dimensions = () 71 | intent = out 72 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/zm_momtran_tendency_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = zm_momtran_tendency_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = zm_momtran_tendency_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | long_name = Error message for error handling in CCPP 11 | units = none 12 | type = character | kind = len=512 13 | dimensions = () 14 | intent = out 15 | [ errflg ] 16 | standard_name = ccpp_error_code 17 | long_name = Error flag for error handling in CCPP 18 | units = 1 19 | type = integer 20 | dimensions = () 21 | intent = out 22 | 23 | [ccpp-arg-table] 24 | name = zm_momtran_tendency_diagnostics_run 25 | type = scheme 26 | [ ncol ] 27 | standard_name = horizontal_loop_extent 28 | units = count 29 | type = integer 30 | dimensions = () 31 | intent = in 32 | [ pver ] 33 | standard_name = vertical_layer_dimension 34 | units = count 35 | type = integer 36 | dimensions = () 37 | intent = in 38 | [ cpair ] 39 | standard_name = specific_heat_of_dry_air_at_constant_pressure 40 | units = J kg-1 K-1 41 | type = real | kind = kind_phys 42 | dimensions = () 43 | intent = in 44 | [ windu_tend ] 45 | standard_name = tendency_of_eastward_wind 46 | units = m s-2 47 | type = real | kind = kind_phys 48 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 49 | intent = in 50 | [ windv_tend ] 51 | standard_name = tendency_of_northward_wind 52 | units = m s-2 53 | type = real | kind = kind_phys 54 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 55 | intent = in 56 | [ seten ] 57 | standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure 58 | units = J kg-1 s-1 59 | type = real | kind = kind_phys 60 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 61 | intent = in 62 | [ errmsg ] 63 | standard_name = ccpp_error_message 64 | long_name = Error message for error handling in CCPP 65 | units = none 66 | type = character | kind = len=512 67 | dimensions = () 68 | intent = out 69 | [ errflg ] 70 | standard_name = ccpp_error_code 71 | long_name = Error flag for error handling in CCPP 72 | units = 1 73 | type = integer 74 | dimensions = () 75 | intent = out 76 | -------------------------------------------------------------------------------- /schemes/vertical_diffusion/vertical_diffusion_sponge_layer.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = vertical_diffusion_sponge_layer 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = vertical_diffusion_sponge_layer_init 7 | type = scheme 8 | [ amIRoot ] 9 | standard_name = flag_for_mpi_root 10 | units = flag 11 | dimensions = () 12 | type = logical 13 | intent = in 14 | [ iulog ] 15 | standard_name = log_output_unit 16 | units = 1 17 | dimensions = () 18 | type = integer 19 | intent = in 20 | [ ptop_ref ] 21 | standard_name = air_pressure_at_top_of_atmosphere_model 22 | units = Pa 23 | dimensions = () 24 | type = real | kind = kind_phys 25 | intent = in 26 | [ errmsg ] 27 | standard_name = ccpp_error_message 28 | units = none 29 | dimensions = () 30 | type = character | kind = len=512 31 | intent = out 32 | [ errflg ] 33 | standard_name = ccpp_error_code 34 | units = 1 35 | dimensions = () 36 | type = integer 37 | intent = out 38 | 39 | [ccpp-arg-table] 40 | name = vertical_diffusion_sponge_layer_run 41 | type = scheme 42 | [ ncol ] 43 | standard_name = horizontal_loop_extent 44 | units = count 45 | dimensions = () 46 | type = integer 47 | intent = in 48 | [ pverp ] 49 | standard_name = vertical_interface_dimension 50 | units = count 51 | dimensions = () 52 | type = integer 53 | intent = in 54 | [ kvm ] 55 | standard_name = eddy_momentum_diffusivity_at_interfaces 56 | units = m2 s-1 57 | dimensions = (horizontal_loop_extent, vertical_interface_dimension) 58 | type = real | kind = kind_phys 59 | intent = inout 60 | [ errmsg ] 61 | standard_name = ccpp_error_message 62 | units = none 63 | dimensions = () 64 | type = character | kind = len=512 65 | intent = out 66 | [ errflg ] 67 | standard_name = ccpp_error_code 68 | units = 1 69 | dimensions = () 70 | type = integer 71 | intent = out 72 | 73 | [ccpp-arg-table] 74 | name = vertical_diffusion_sponge_layer_final 75 | type = scheme 76 | [ errmsg ] 77 | standard_name = ccpp_error_message 78 | units = none 79 | dimensions = () 80 | type = character | kind = len=512 81 | intent = out 82 | [ errflg ] 83 | standard_name = ccpp_error_code 84 | units = 1 85 | dimensions = () 86 | type = integer 87 | intent = out 88 | -------------------------------------------------------------------------------- /schemes/hack_shallow/set_general_conv_fluxes_to_shallow.F90: -------------------------------------------------------------------------------- 1 | module set_general_conv_fluxes_to_shallow 2 | 3 | use ccpp_kinds, only: kind_phys 4 | 5 | implicit none 6 | 7 | contains 8 | !> \section arg_table_set_general_conv_fluxes_to_shallow_run Argument Table 9 | !! \htmlinclude set_general_conv_fluxes_to_shallow_run.html 10 | subroutine set_general_conv_fluxes_to_shallow_run(tend_s_snwprd_gen, tend_s_snwprd_sh, tend_s_snwevmlt_gen, tend_s_snwevmlt_sh, & 11 | prec_gen, prec_sh, snow_gen, snow_sh, ntprprd_gen, ntprprd_sh, ntsnprd_gen, ntsnprd_sh, & 12 | flxprec_gen, flxprec_sh, flxsnow_gen, flxsnow_sh, & 13 | flx_ice) 14 | 15 | real(kind_phys), intent(in) :: tend_s_snwprd_gen(:,:) 16 | real(kind_phys), intent(out) :: tend_s_snwprd_sh(:,:) 17 | real(kind_phys), intent(in) :: tend_s_snwevmlt_gen(:,:) 18 | real(kind_phys), intent(out) :: tend_s_snwevmlt_sh(:,:) 19 | real(kind_phys), intent(in) :: prec_gen(:) ! precipitation rate is modified by zm_conv_evap based on computed flux 20 | real(kind_phys), intent(out) :: prec_sh(:) ! and thus needs to be renamed from generic to shallow. 21 | real(kind_phys), intent(in) :: snow_gen(:) 22 | real(kind_phys), intent(out) :: snow_sh(:) 23 | real(kind_phys), intent(in) :: ntprprd_gen(:,:) 24 | real(kind_phys), intent(out) :: ntprprd_sh(:,:) 25 | real(kind_phys), intent(in) :: ntsnprd_gen(:,:) 26 | real(kind_phys), intent(out) :: ntsnprd_sh(:,:) 27 | real(kind_phys), intent(in) :: flxprec_gen(:,:) 28 | real(kind_phys), intent(out) :: flxprec_sh(:,:) 29 | real(kind_phys), intent(in) :: flxsnow_gen(:,:) 30 | real(kind_phys), intent(out) :: flxsnow_sh(:,:) 31 | 32 | real(kind_phys), intent(out) :: flx_ice(:) ! net_lwe_ice_fluxes_through_top_and_bottom_of_atmosphere_column [m s-1] for check_energy_chng 33 | 34 | tend_s_snwprd_sh = tend_s_snwprd_gen 35 | tend_s_snwevmlt_sh = tend_s_snwevmlt_gen 36 | prec_sh = prec_gen 37 | snow_sh = snow_gen 38 | ntprprd_sh = ntprprd_gen 39 | ntsnprd_sh = ntsnprd_gen 40 | flxprec_sh = flxprec_gen 41 | flxsnow_sh = flxsnow_gen 42 | 43 | ! boundary flux for check energy 44 | flx_ice = snow_sh 45 | 46 | end subroutine set_general_conv_fluxes_to_shallow_run 47 | 48 | end module set_general_conv_fluxes_to_shallow 49 | -------------------------------------------------------------------------------- /schemes/thermo_water_update/thermo_water_update.F90: -------------------------------------------------------------------------------- 1 | ! This is a non-portable wrapper subroutine for cam_thermo_water_update 2 | ! in the cam_thermo module. 3 | module thermo_water_update 4 | use ccpp_kinds, only: kind_phys 5 | 6 | implicit none 7 | private 8 | 9 | public :: thermo_water_update_run 10 | 11 | contains 12 | 13 | ! Update water dependent properties 14 | !> \section arg_table_thermo_water_update_run Argument Table 15 | !! \htmlinclude arg_table_thermo_water_update_run.html 16 | subroutine thermo_water_update_run( & 17 | mmr, & 18 | ncol, pver, & 19 | energy_formula_dycore, & 20 | pdel, pdeldry, & 21 | cp_or_cv_dycore) 22 | 23 | ! This scheme is non-portable due to dependencies on cam_thermo 24 | ! for the actual logic of cam_thermo_water_update, which depends on air_composition 25 | ! and a series of other subroutines/module properties 26 | use cam_thermo, only: cam_thermo_water_update 27 | 28 | ! Input arguments 29 | real(kind_phys), intent(in) :: mmr(:,:,:) ! constituent mass mixing ratios [kg kg-1] 30 | integer, intent(in) :: ncol ! number of atmospheric columns 31 | integer, intent(in) :: pver ! number of vertical layers 32 | integer, intent(in) :: energy_formula_dycore ! total energy formulation used by dycore 33 | real(kind_phys), intent(in) :: pdel(:,:) ! layer thickness [Pa] 34 | real(kind_phys), intent(in) :: pdeldry(:,:) ! dry layer thickness [Pa] 35 | 36 | ! Output arguments 37 | real(kind_phys), intent(out) :: cp_or_cv_dycore(:,:) ! enthalpy or heat capacity, dycore dependent [J K-1 kg-1] 38 | 39 | call cam_thermo_water_update( & 40 | mmr = mmr, & ! mmr*factor is a dry mixing ratio 41 | ncol = ncol, & 42 | pver = pver, & 43 | energy_formula = energy_formula_dycore, & 44 | cp_or_cv_dycore = cp_or_cv_dycore(:ncol,:), & 45 | to_dry_factor = pdel(:ncol,:)/pdeldry(:ncol,:) & ! factor to convert to dry 46 | ) 47 | 48 | end subroutine thermo_water_update_run 49 | 50 | end module thermo_water_update 51 | -------------------------------------------------------------------------------- /schemes/musica/util/musica_ccpp_util.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2024-2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | module musica_ccpp_util 4 | 5 | use ccpp_kinds, only: kind_phys 6 | 7 | implicit none 8 | 9 | private 10 | public :: has_error_occurred, set_constants 11 | 12 | real(kind_phys), parameter, public :: PI = 3.14159265358979323846_kind_phys 13 | real(kind_phys), parameter, public :: DEGREE_TO_RADIAN = PI / 180.0_kind_phys 14 | real(kind_phys), public, protected :: MOLAR_MASS_DRY_AIR = -HUGE(1.0_kind_phys) ! kg mol-1 15 | 16 | !> Conversion factor for wavelength interfaces from meters (CAM-SIMA) to nanometers (TUV-x) 17 | real(kind_phys), parameter, public :: m_to_nm = 1.0e9_kind_phys 18 | 19 | contains 20 | 21 | !> @brief Set constants used for MUSICA components 22 | !> @param[in] molar_mass_dry_air_in The molar mass of dry air (kg mol-1). 23 | subroutine set_constants(molar_mass_dry_air_in) 24 | 25 | real(kind_phys), intent(in) :: molar_mass_dry_air_in 26 | 27 | MOLAR_MASS_DRY_AIR = molar_mass_dry_air_in 28 | end subroutine set_constants 29 | 30 | !> @brief Evaluate a MUSICA error for failure and convert to CCPP error data 31 | !> @param[in] error The error code to evaluate and convert. 32 | !> @param[out] error_message The CCPP error message. 33 | !> @param[out] error_code The CCPP error code. 34 | !> @return True for an error, false for success. 35 | logical function has_error_occurred(error, error_message, error_code) 36 | use musica_util, only: error_t 37 | 38 | type(error_t), intent(in) :: error 39 | character(len=512), intent(out) :: error_message 40 | integer, intent(out) :: error_code 41 | 42 | character(len=30) :: error_code_str 43 | 44 | if ( error%is_success( ) ) then 45 | error_code = 0 46 | error_message = '' 47 | has_error_occurred = .false. 48 | return 49 | end if 50 | error_code = error%code( ) 51 | write(error_code_str, '(I30)') error%code( ) 52 | error_message = '[MUSICA Error]: ' // error%category( ) // '[' // & 53 | trim( adjustl( error_code_str ) ) // ']: ' // error%message( ) 54 | has_error_occurred = .true. 55 | 56 | end function has_error_occurred 57 | 58 | end module musica_ccpp_util 59 | -------------------------------------------------------------------------------- /test/test_suites/suite_gw_cam4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 21 | 22 | 23 | initialize_constituents 24 | 25 | 26 | gravity_wave_drag_common 27 | 28 | 29 | check_energy_zero_fluxes 30 | gravity_wave_drag_prepare_profiles 31 | 32 | 33 | gravity_wave_drag_top_taper 34 | 35 | 36 | gravity_wave_drag_orographic 37 | 38 | 39 | convert_dry_constituent_tendencies_to_dry_air_basis 40 | 41 | 42 | gravity_wave_drag_common_diagnostics 43 | 44 | 45 | apply_tendency_of_eastward_wind 46 | apply_tendency_of_northward_wind 47 | apply_constituent_tendencies 48 | apply_heating_rate 49 | qneg 50 | geopotential_temp 51 | update_dry_static_energy 52 | 53 | 54 | check_energy_scaling 55 | check_energy_chng 56 | 57 | 58 | -------------------------------------------------------------------------------- /phys_utils/atmos_phys_string_utils.F90: -------------------------------------------------------------------------------- 1 | module atmos_phys_string_utils 2 | ! String utils 3 | 4 | implicit none 5 | private 6 | 7 | public :: to_lower 8 | public :: to_upper 9 | 10 | contains 11 | 12 | pure function to_lower(input_string) result(lowercase_string) 13 | ! Return 'input_string' in all lower case 14 | character(len=*), intent(in) :: input_string 15 | character(len=len(input_string)) :: lowercase_string 16 | ! Local variables 17 | 18 | integer :: i ! Index 19 | integer :: aseq ! ascii collating sequence 20 | integer :: upper_to_lower ! integer to convert case 21 | character(len=1) :: ctmp ! Character temporary 22 | !----------------------------------------------------------------------- 23 | upper_to_lower = iachar("a") - iachar("A") 24 | 25 | do i = 1, len(input_string) 26 | ctmp = input_string(i:i) 27 | aseq = iachar(ctmp) 28 | if ( aseq >= iachar("A") .and. aseq <= iachar("Z") ) & 29 | ctmp = achar(aseq + upper_to_lower) 30 | lowercase_string(i:i) = ctmp 31 | end do 32 | 33 | end function to_lower 34 | 35 | !--------------------------------------------------------------------------- 36 | !--------------------------------------------------------------------------- 37 | 38 | pure function to_upper(input_string) result(uppercase_string) 39 | ! Return 'input_string' in all upper case 40 | character(len=*), intent(in) :: input_string 41 | character(len=len(input_string)) :: uppercase_string 42 | 43 | integer :: i ! Index 44 | integer :: aseq ! ascii collating sequence 45 | integer :: lower_to_upper ! integer to convert case 46 | character(len=1) :: ctmp ! Character temporary 47 | !----------------------------------------------------------------------- 48 | lower_to_upper = iachar("A") - iachar("a") 49 | 50 | do i = 1, len(input_string) 51 | ctmp = input_string(i:i) 52 | aseq = iachar(ctmp) 53 | if ( aseq >= iachar("a") .and. aseq <= iachar("z") ) & 54 | ctmp = achar(aseq + lower_to_upper) 55 | uppercase_string(i:i) = ctmp 56 | end do 57 | 58 | end function to_upper 59 | 60 | end module atmos_phys_string_utils 61 | -------------------------------------------------------------------------------- /suites/suite_kessler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | calc_exner 6 | temp_to_potential_temp 7 | calc_dry_air_ideal_gas_density 8 | wet_to_dry_water_vapor 9 | wet_to_dry_cloud_liquid_water 10 | wet_to_dry_rain 11 | kessler 12 | potential_temp_to_temp 13 | dry_to_wet_water_vapor 14 | dry_to_wet_cloud_liquid_water 15 | dry_to_wet_rain 16 | kessler_update 17 | qneg 18 | geopotential_temp 19 | 20 | 24 | check_energy_zero_fluxes 25 | check_energy_scaling 26 | check_energy_chng 27 | 28 | 29 | sima_state_diagnostics 30 | kessler_diagnostics 31 | 32 | 33 | 34 | 35 | thermo_water_update 36 | 37 | 38 | 39 | 40 | 41 | 45 | check_energy_scaling 46 | dycore_energy_consistency_adjust 47 | apply_tendency_of_air_temperature 48 | 49 | 50 | sima_tend_diagnostics 51 | 52 | 53 | -------------------------------------------------------------------------------- /schemes/zhang_mcfarlane/save_ttend_from_convect_deep.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = save_ttend_from_convect_deep 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = save_ttend_from_convect_deep_timestep_init 7 | type = scheme 8 | [ ncol ] 9 | standard_name = horizontal_dimension 10 | units = count 11 | type = integer 12 | dimensions = () 13 | intent = in 14 | [ pver ] 15 | standard_name = vertical_layer_dimension 16 | units = count 17 | type = integer 18 | dimensions = () 19 | intent = in 20 | [ ttend_dp ] 21 | standard_name = tendency_of_air_temperature_due_to_deep_convection 22 | units = K s-1 23 | type = real | kind = kind_phys 24 | dimensions = (horizontal_dimension, vertical_layer_dimension) 25 | intent = out 26 | [ errmsg ] 27 | standard_name = ccpp_error_message 28 | units = none 29 | type = character | kind = len=512 30 | dimensions = () 31 | intent = out 32 | [ errflg ] 33 | standard_name = ccpp_error_code 34 | units = 1 35 | type = integer 36 | dimensions = () 37 | intent = out 38 | 39 | [ccpp-arg-table] 40 | name = save_ttend_from_convect_deep_run 41 | type = scheme 42 | [ ncol ] 43 | standard_name = horizontal_loop_extent 44 | units = count 45 | type = integer 46 | dimensions = () 47 | intent = in 48 | [ pver ] 49 | standard_name = vertical_layer_dimension 50 | units = count 51 | type = integer 52 | dimensions = () 53 | intent = in 54 | [ tend_s ] 55 | standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure 56 | units = J kg-1 s-1 57 | type = real | kind = kind_phys 58 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 59 | intent = in 60 | [ cpair ] 61 | standard_name = specific_heat_of_dry_air_at_constant_pressure 62 | units = J kg-1 K-1 63 | type = real | kind = kind_phys 64 | dimensions = () 65 | intent = in 66 | [ ttend_dp ] 67 | standard_name = tendency_of_air_temperature_due_to_deep_convection 68 | units = K s-1 69 | type = real | kind = kind_phys 70 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 71 | intent = inout 72 | [ errmsg ] 73 | standard_name = ccpp_error_message 74 | units = none 75 | type = character | kind = len=512 76 | dimensions = () 77 | intent = out 78 | [ errflg ] 79 | standard_name = ccpp_error_code 80 | units = 1 81 | type = integer 82 | dimensions = () 83 | intent = out 84 | -------------------------------------------------------------------------------- /test/musica/tuvx/test_tuvx_wavelength_grid.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2024-2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | program test_tuvx_wavelength_grid 4 | 5 | use musica_ccpp_tuvx_wavelength_grid 6 | 7 | implicit none 8 | 9 | #define ASSERT(x) if (.not.(x)) then; write(*,*) "Assertion failed[", __FILE__, ":", __LINE__, "]: x"; stop 1; endif 10 | #define ASSERT_NEAR( a, b, abs_error ) if( (abs(a - b) >= abs_error) .and. (abs(a - b) /= 0.0) ) then; write(*,*) "Assertion failed[", __FILE__, ":", __LINE__, "]: a, b"; stop 1; endif 11 | 12 | call test_create_wavelength_grid() 13 | 14 | contains 15 | 16 | subroutine test_create_wavelength_grid() 17 | use musica_util, only: error_t 18 | use musica_tuvx_grid, only: grid_t 19 | use ccpp_kinds, only: kind_phys 20 | 21 | integer, parameter :: NUM_WAVELENGTH_GRID_MIDPOINTS = 2 22 | integer, parameter :: NUM_WAVELENGTH_GRID_INTERFACES = 3 23 | real, parameter :: ABS_ERROR = 1e-5 24 | real(kind_phys) :: host_interfaces(NUM_WAVELENGTH_GRID_INTERFACES) = [180.0_kind_phys, 200.0_kind_phys, 240.0_kind_phys] ! nm 25 | real(kind_phys) :: expected_midpoints(NUM_WAVELENGTH_GRID_MIDPOINTS) = [190.0_kind_phys, 220.0_kind_phys] 26 | real(kind_phys) :: interfaces(NUM_WAVELENGTH_GRID_INTERFACES) 27 | real(kind_phys) :: midpoints(NUM_WAVELENGTH_GRID_MIDPOINTS) 28 | type(grid_t), pointer :: wavelength_grid => null() 29 | character(len=512) :: errmsg 30 | integer :: errcode 31 | type(error_t) :: error 32 | integer :: i 33 | 34 | wavelength_grid => create_wavelength_grid(host_interfaces, errmsg, errcode) 35 | ASSERT(errcode == 0) 36 | ASSERT(associated(wavelength_grid)) 37 | 38 | call wavelength_grid%get_edges(interfaces, error) 39 | ASSERT(error%is_success()) 40 | do i = 1, NUM_WAVELENGTH_GRID_INTERFACES 41 | ASSERT_NEAR(interfaces(i), host_interfaces(i), ABS_ERROR) 42 | end do 43 | 44 | call wavelength_grid%get_midpoints(midpoints, error) 45 | ASSERT(error%is_success()) 46 | do i = 1, NUM_WAVELENGTH_GRID_MIDPOINTS 47 | ASSERT_NEAR(midpoints(i), expected_midpoints(i), ABS_ERROR) 48 | end do 49 | 50 | deallocate(wavelength_grid) 51 | 52 | end subroutine test_create_wavelength_grid 53 | 54 | end program test_tuvx_wavelength_grid -------------------------------------------------------------------------------- /schemes/sima_diagnostics/zm_convr_tendency_diagnostics.F90: -------------------------------------------------------------------------------- 1 | module zm_convr_tendency_diagnostics 2 | use ccpp_kinds, only: kind_phys 3 | 4 | implicit none 5 | private 6 | save 7 | 8 | public :: zm_convr_tendency_diagnostics_init ! init routine 9 | public :: zm_convr_tendency_diagnostics_run ! main routine 10 | 11 | CONTAINS 12 | 13 | !> \section arg_table_zm_convr_tendency_diagnostics_init Argument Table 14 | !! \htmlinclude zm_convr_tendency_diagnostics_init.html 15 | subroutine zm_convr_tendency_diagnostics_init(errmsg, errflg) 16 | use cam_history, only: history_add_field 17 | use cam_history_support, only: horiz_only 18 | 19 | character(len=512), intent(out) :: errmsg 20 | integer, intent(out) :: errflg 21 | 22 | ! Local variables: 23 | 24 | errmsg = '' 25 | errflg = 0 26 | 27 | call history_add_field ('ZMDT', 'T tendency - Zhang-McFarlane moist convection', 'lev', 'avg', 'K s-1') 28 | call history_add_field ('ZMDQ', 'Q tendency - Zhang-McFarlane moist convection', 'lev', 'avg', 'kg kg-1 s-1') 29 | 30 | end subroutine zm_convr_tendency_diagnostics_init 31 | 32 | !> \section arg_table_zm_convr_tendency_diagnostics_run Argument Table 33 | !! \htmlinclude zm_convr_tendency_diagnostics_run.html 34 | subroutine zm_convr_tendency_diagnostics_run(ncol, pver, cpair, heat, qtnd, errmsg, errflg) 35 | 36 | use cam_history, only: history_out_field 37 | 38 | !------------------------------------------------ 39 | ! Input / output parameters 40 | !------------------------------------------------ 41 | integer, intent(in) :: ncol 42 | integer, intent(in) :: pver 43 | 44 | real(kind_phys), intent(in) :: cpair 45 | real(kind_phys), intent(in) :: heat(:,:) 46 | real(kind_phys), intent(in) :: qtnd(:,:) 47 | 48 | ! CCPP error handling variables 49 | character(len=512), intent(out) :: errmsg 50 | integer, intent(out) :: errflg 51 | 52 | 53 | real(kind_phys) :: ftem(ncol,pver) 54 | 55 | errmsg = '' 56 | errflg = 0 57 | 58 | ftem(:,:) = 0._kind_phys 59 | 60 | ftem(:ncol,:pver) = heat(:ncol,:pver)/cpair 61 | call history_out_field('ZMDT ', ftem) 62 | call history_out_field('ZMDQ ', qtnd) 63 | 64 | end subroutine zm_convr_tendency_diagnostics_run 65 | 66 | !======================================================================= 67 | 68 | end module zm_convr_tendency_diagnostics 69 | -------------------------------------------------------------------------------- /schemes/gravity_wave_drag/gw_common.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = gravity_wave_drag_common 3 | type = scheme 4 | dependencies = ../../to_be_ccppized/linear_1d_operators.F90,../../to_be_ccppized/coords_1d.F90,../../to_be_ccppized/vdiff_lu_solver.F90,gw_diffusion.F90 5 | 6 | [ccpp-arg-table] 7 | name = gravity_wave_drag_common_init 8 | type = scheme 9 | [ pver_in ] 10 | standard_name = vertical_layer_dimension 11 | units = count 12 | type = integer 13 | dimensions = () 14 | intent = in 15 | [ pverp_in ] 16 | standard_name = vertical_interface_dimension 17 | units = count 18 | type = integer 19 | dimensions = () 20 | intent = in 21 | [ amIRoot ] 22 | standard_name = flag_for_mpi_root 23 | units = flag 24 | type = logical 25 | dimensions = () 26 | intent = in 27 | [ iulog ] 28 | standard_name = log_output_unit 29 | units = 1 30 | type = integer 31 | dimensions = () 32 | intent = in 33 | [ pref_edge ] 34 | standard_name = reference_pressure_at_interface 35 | units = Pa 36 | type = real | kind = kind_phys 37 | dimensions = (vertical_interface_dimension) 38 | intent = in 39 | [ tau_0_ubc_in ] 40 | standard_name = force_zero_stress_at_top_of_atmosphere_due_to_gravity_wave_drag 41 | units = flag 42 | type = logical 43 | dimensions = () 44 | intent = in 45 | [ pi_in ] 46 | standard_name = pi_constant 47 | units = 1 48 | type = real | kind = kind_phys 49 | dimensions = () 50 | intent = in 51 | [ gravit_in ] 52 | standard_name = standard_gravitational_acceleration 53 | units = m s-2 54 | type = real | kind = kind_phys 55 | dimensions = () 56 | intent = in 57 | [ rair_in ] 58 | standard_name = gas_constant_of_dry_air 59 | units = J kg-1 K-1 60 | type = real | kind = kind_phys 61 | dimensions = () 62 | intent = in 63 | [ prndl_in ] 64 | standard_name = inverse_prandtl_number_for_diffusion_in_gravity_wave_drag 65 | units = 1 66 | type = real | kind = kind_phys 67 | dimensions = () 68 | intent = in 69 | [ qbo_hdepth_scaling_in ] 70 | standard_name = scaling_factor_for_heating_depth_in_gravity_waves_from_convection 71 | units = 1 72 | type = real | kind = kind_phys 73 | dimensions = () 74 | intent = in 75 | [ errmsg ] 76 | standard_name = ccpp_error_message 77 | units = none 78 | type = character | kind = len=512 79 | dimensions = () 80 | intent = out 81 | [ errflg ] 82 | standard_name = ccpp_error_code 83 | units = 1 84 | type = integer 85 | dimensions = () 86 | intent = out 87 | -------------------------------------------------------------------------------- /schemes/utilities/convert_dry_constituent_tendencies_to_dry_air_basis.F90: -------------------------------------------------------------------------------- 1 | ! Convert dry constituent tendencies from moist to dry air basis 2 | module convert_dry_constituent_tendencies_to_dry_air_basis 3 | use ccpp_kinds, only: kind_phys 4 | 5 | implicit none 6 | private 7 | save 8 | 9 | ! public CCPP-compliant subroutines 10 | public :: convert_dry_constituent_tendencies_to_dry_air_basis_run 11 | 12 | contains 13 | 14 | !> \section arg_table_convert_dry_constituent_tendencies_to_dry_air_basis_run Argument Table 15 | !! \htmlinclude convert_dry_constituent_tendencies_to_dry_air_basis_run.html 16 | subroutine convert_dry_constituent_tendencies_to_dry_air_basis_run( & 17 | ncol, pver, pcnst, & 18 | pdel, pdeldry, & 19 | const_props, & 20 | tend_q, & 21 | errmsg, errflg) 22 | 23 | use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 24 | 25 | ! Input arguments 26 | integer, intent(in) :: ncol 27 | integer, intent(in) :: pver 28 | integer, intent(in) :: pcnst 29 | real(kind_phys), intent(in) :: pdel(:, :) ! Layer thickness (moist air) [Pa] 30 | real(kind_phys), intent(in) :: pdeldry(:, :) ! Layer thickness (dry air) [Pa] 31 | 32 | ! Framework dependency for constituent properties 33 | type(ccpp_constituent_prop_ptr_t), & 34 | intent(in) :: const_props(:) ! CCPP constituent properties pointer 35 | 36 | ! Input/Output arguments 37 | real(kind_phys), intent(inout) :: tend_q(:, :, :) ! Constituent tendencies [kg kg-1 s-1] 38 | 39 | ! Output arguments 40 | character(len=512), intent(out) :: errmsg 41 | integer, intent(out) :: errflg 42 | 43 | ! Local variables 44 | integer :: i, k, m 45 | logical :: const_is_dry 46 | 47 | errmsg = '' 48 | errflg = 0 49 | 50 | ! Convert the tendencies for the dry constituents to dry air basis 51 | do m = 1, pcnst 52 | ! Check if this constituent is dry type 53 | call const_props(m)%is_dry(const_is_dry, errflg, errmsg) 54 | if (errflg /= 0) return 55 | 56 | if (const_is_dry) then 57 | do k = 1, pver 58 | do i = 1, ncol 59 | tend_q(i, k, m) = tend_q(i, k, m) * pdel(i, k) / pdeldry(i, k) 60 | end do 61 | end do 62 | end if 63 | end do 64 | 65 | end subroutine convert_dry_constituent_tendencies_to_dry_air_basis_run 66 | 67 | end module convert_dry_constituent_tendencies_to_dry_air_basis 68 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/cloud_particle_sedimentation_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = cloud_particle_sedimentation_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = cloud_particle_sedimentation_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | units = none 11 | type = character | kind = len=512 12 | dimensions = () 13 | intent = out 14 | [ errflg ] 15 | standard_name = ccpp_error_code 16 | units = 1 17 | type = integer 18 | dimensions = () 19 | intent = out 20 | 21 | [ccpp-arg-table] 22 | name = cloud_particle_sedimentation_diagnostics_run 23 | type = scheme 24 | [ ncol ] 25 | standard_name = horizontal_loop_extent 26 | units = count 27 | type = integer 28 | dimensions = () 29 | intent = in 30 | [ wvtend ] 31 | standard_name = tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water 32 | units = kg kg-1 s-1 33 | type = real | kind = kind_phys 34 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 35 | intent = in 36 | [ icetend ] 37 | standard_name = tendency_of_cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water 38 | units = kg kg-1 s-1 39 | type = real | kind = kind_phys 40 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 41 | intent = in 42 | [ liqtend ] 43 | standard_name = tendency_of_cloud_liquid_water_mixing_ratio_wrt_moist_air_and_condensed_water 44 | units = kg kg-1 s-1 45 | type = real | kind = kind_phys 46 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 47 | intent = in 48 | [ htend ] 49 | standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure 50 | units = J kg-1 s-1 51 | type = real | kind = kind_phys 52 | dimensions = (horizontal_loop_extent, vertical_layer_dimension) 53 | intent = in 54 | [ snow_sed ] 55 | standard_name = stratiform_lwe_cloud_ice_surface_flux_due_to_sedimentation 56 | units = m s-1 57 | type = real | kind = kind_phys 58 | dimensions = (horizontal_loop_extent) 59 | intent = in 60 | [ sfliq ] 61 | standard_name = stratiform_rain_flux_at_surface_due_to_sedimentation 62 | units = kg m-2 s-1 63 | type = real | kind = kind_phys 64 | dimensions = (horizontal_loop_extent) 65 | intent = in 66 | [ errmsg ] 67 | standard_name = ccpp_error_message 68 | units = none 69 | type = character | kind = len=512 70 | dimensions = () 71 | intent = out 72 | [ errflg ] 73 | standard_name = ccpp_error_code 74 | units = 1 75 | type = integer 76 | dimensions = () 77 | intent = out 78 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/convective_cloud_cover_diagnostics.F90: -------------------------------------------------------------------------------- 1 | ! Diagnostics for cloud fraction - convective cloud cover 2 | module convective_cloud_cover_diagnostics 3 | use ccpp_kinds, only: kind_phys 4 | 5 | implicit none 6 | private 7 | save 8 | 9 | public :: convective_cloud_cover_diagnostics_init 10 | public :: convective_cloud_cover_diagnostics_run 11 | 12 | contains 13 | 14 | !> \section arg_table_convective_cloud_cover_diagnostics_init Argument Table 15 | !! \htmlinclude convective_cloud_cover_diagnostics_init.html 16 | subroutine convective_cloud_cover_diagnostics_init(errmsg, errflg) 17 | use cam_history, only: history_add_field 18 | use cam_history_support, only: horiz_only 19 | 20 | character(len=512), intent(out) :: errmsg 21 | integer, intent(out) :: errflg 22 | 23 | ! Local variables: 24 | 25 | errmsg = '' 26 | errflg = 0 27 | 28 | ! History add field calls 29 | call history_add_field('SH_CLD', 'shallow_convective_cloud_area_fraction', 'lev', 'avg', 'fraction') 30 | call history_add_field('DP_CLD', 'deep_convective_cloud_area_fraction', 'lev', 'avg', 'fraction') 31 | call history_add_field('CONCLD', 'convective_cloud_area_fraction', 'lev', 'avg', 'fraction') 32 | 33 | end subroutine convective_cloud_cover_diagnostics_init 34 | 35 | !> \section arg_table_convective_cloud_cover_diagnostics_run Argument Table 36 | !! \htmlinclude convective_cloud_cover_diagnostics_run.html 37 | subroutine convective_cloud_cover_diagnostics_run( & 38 | shallowcu, deepcu, concld, & 39 | errmsg, errflg) 40 | 41 | use cam_history, only: history_out_field 42 | 43 | ! Input parameters 44 | real(kind_phys), intent(in) :: shallowcu(:, :) ! Shallow convective cloud fraction [fraction] 45 | real(kind_phys), intent(in) :: deepcu(:, :) ! Deep convective cloud fraction [fraction] 46 | real(kind_phys), intent(in) :: concld(:, :) ! Convective cloud cover [fraction] 47 | 48 | 49 | ! CCPP error handling variables 50 | character(len=512), intent(out) :: errmsg 51 | integer, intent(out) :: errflg 52 | 53 | errmsg = '' 54 | errflg = 0 55 | 56 | ! History out field calls 57 | call history_out_field('SH_CLD', shallowcu) 58 | call history_out_field('DP_CLD', deepcu) 59 | call history_out_field('CONCLD', concld) 60 | 61 | end subroutine convective_cloud_cover_diagnostics_run 62 | 63 | end module convective_cloud_cover_diagnostics 64 | -------------------------------------------------------------------------------- /schemes/conservation_adjust/check_energy/dycore_energy_consistency_adjust.F90: -------------------------------------------------------------------------------- 1 | ! MPAS and SE dynamical core specific 2 | ! 1) scaling of temperature for enforcing energy consistency 3 | ! 2) and to ensure correct computation of temperature dependent diagnostic tendencies, e.g., dtcore 4 | module dycore_energy_consistency_adjust 5 | use ccpp_kinds, only: kind_phys 6 | implicit none 7 | private 8 | 9 | public :: dycore_energy_consistency_adjust_run 10 | 11 | contains 12 | !> \section arg_table_dycore_energy_consistency_adjust_run Argument Table 13 | !! \htmlinclude arg_table_dycore_energy_consistency_adjust_run.html 14 | subroutine dycore_energy_consistency_adjust_run( & 15 | ncol, pver, & 16 | do_consistency_adjust, & 17 | scaling_dycore, & 18 | tend_dTdt, & 19 | tend_dTdt_local, & 20 | errmsg, errflg) 21 | 22 | ! Input arguments 23 | integer, intent(in) :: ncol ! number of atmospheric columns 24 | integer, intent(in) :: pver ! number of vertical layers 25 | logical, intent(in) :: do_consistency_adjust ! do energy consistency adjustment? 26 | real(kind_phys), intent(in) :: scaling_dycore(:,:) ! scaling for conversion of temperature increment [1] 27 | real(kind_phys), intent(in) :: tend_dTdt(:,:) ! model physics temperature tendency [K s-1] 28 | 29 | ! Output arguments 30 | real(kind_phys), intent(out) :: tend_dTdt_local(:,:) ! (scheme) temperature tendency [K s-1] 31 | character(len=512), intent(out) :: errmsg ! error message 32 | integer, intent(out) :: errflg ! error flag 33 | 34 | errmsg = '' 35 | errflg = 0 36 | 37 | if (do_consistency_adjust) then 38 | ! original formula for scaling of temperature: 39 | ! T(:ncol,:) = temp_ini(:ncol,:) + & 40 | ! scaling_dycore(:ncol,:) * (T(:ncol,:) - temp_ini(:ncol,:)) 41 | ! and temperature tendency due to model physics: 42 | ! tend_dTdt(:ncol,:) = scaling_dycore(:ncol,:) * tend_dTdt(:ncol,:) 43 | ! 44 | ! the terms can be arranged for this scaling to be applied through scheme tendencies 45 | ! at the cost of a round-off level difference 46 | tend_dTdt_local(:ncol,:) = (scaling_dycore(:ncol,:) - 1._kind_phys) * tend_dTdt(:ncol,:) 47 | endif 48 | ! do nothing for dynamical cores with energy consistent with CAM physics 49 | 50 | end subroutine dycore_energy_consistency_adjust_run 51 | 52 | end module dycore_energy_consistency_adjust 53 | -------------------------------------------------------------------------------- /schemes/musica/tuvx/musica_ccpp_tuvx_wavelength_grid.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2024-2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | module musica_ccpp_tuvx_wavelength_grid 4 | 5 | implicit none 6 | 7 | private 8 | public :: create_wavelength_grid 9 | 10 | ! TUV-x Wavelegnth grid notes 11 | ! 12 | !----------------------------------------------------------------------- 13 | ! The wavelength grid used with TUV-x is based on the grid used in the 14 | ! CAM-Chem photolysis rate constant lookup tables. Slight modifications 15 | ! were made to the grid in the Shumann-Runge and Lyman-alpha regions to 16 | ! work with the expectations of the TUV-x code. 17 | ! 18 | ! The wavelength grid is defined by the host model. Any wavelength- 19 | ! resolved quantities passed to TUV-x must be on this grid. 20 | 21 | !> Label for wavelength grid in TUV-x 22 | character(len=*), parameter, public :: wavelength_grid_label = "wavelength" 23 | !> Unit for wavelength grid in TUV-x 24 | character(len=*), parameter, public :: wavelength_grid_unit = "nm" 25 | 26 | contains 27 | 28 | !> Creates a TUV-x wavelength grid 29 | function create_wavelength_grid( wavelength_grid_interfaces, & 30 | errmsg, errcode ) result( wavelength_grid ) 31 | 32 | use ccpp_kinds, only: kind_phys 33 | use musica_ccpp_util, only: has_error_occurred 34 | use musica_tuvx_grid, only: grid_t 35 | use musica_util, only: error_t 36 | 37 | real(kind_phys), intent(in) :: wavelength_grid_interfaces(:) ! nm 38 | character(len=*), intent(out) :: errmsg 39 | integer, intent(out) :: errcode 40 | type(grid_t), pointer :: wavelength_grid 41 | 42 | ! local variables 43 | reaL(kind_phys) :: midpoints( size( wavelength_grid_interfaces ) - 1 ) ! nm 44 | type(error_t) :: error 45 | 46 | midpoints(:) = & 47 | 0.5 * ( wavelength_grid_interfaces( 1: size( wavelength_grid_interfaces ) - 1 ) & 48 | + wavelength_grid_interfaces( 2: size( wavelength_grid_interfaces ) ) ) 49 | wavelength_grid => grid_t( wavelength_grid_label, wavelength_grid_unit, & 50 | size( midpoints ), error ) 51 | if ( has_error_occurred( error, errmsg, errcode ) ) return 52 | call wavelength_grid%set_edges( wavelength_grid_interfaces, error ) 53 | if ( has_error_occurred( error, errmsg, errcode ) ) return 54 | call wavelength_grid%set_midpoints( midpoints, error ) 55 | if ( has_error_occurred( error, errmsg, errcode ) ) return 56 | 57 | end function create_wavelength_grid 58 | 59 | end module musica_ccpp_tuvx_wavelength_grid -------------------------------------------------------------------------------- /schemes/sima_diagnostics/check_energy_gmean_diagnostics.F90: -------------------------------------------------------------------------------- 1 | ! Diagnostic scheme for check_energy_gmean 2 | ! This creates a debug printout with: 3 | ! - global mean input energy using dycore energy formula 4 | ! - global mean output energy at end of physics timestep using dycore energy formula 5 | ! - global mean heating rate for energy conservation 6 | ! These numbers are very useful for matching models bit-for-bit because they include "everything" in the model. 7 | module check_energy_gmean_diagnostics 8 | use ccpp_kinds, only: kind_phys 9 | 10 | implicit none 11 | private 12 | save 13 | 14 | public :: check_energy_gmean_diagnostics_init 15 | public :: check_energy_gmean_diagnostics_run ! main routine 16 | 17 | ! Private module options. 18 | logical :: print_global_means = .false. 19 | 20 | contains 21 | 22 | !> \section arg_table_check_energy_gmean_diagnostics_init Argument Table 23 | !! \htmlinclude arg_table_check_energy_gmean_diagnostics_init.html 24 | subroutine check_energy_gmean_diagnostics_init(print_global_means_in) 25 | ! Input arguments 26 | logical, intent(in) :: print_global_means_in 27 | 28 | print_global_means = print_global_means_in 29 | end subroutine check_energy_gmean_diagnostics_init 30 | 31 | !> \section arg_table_check_energy_gmean_diagnostics_run Argument Table 32 | !! \htmlinclude check_energy_gmean_diagnostics_run.html 33 | subroutine check_energy_gmean_diagnostics_run( & 34 | amIRoot, & 35 | iulog, & 36 | teinp_glob, & 37 | teout_glob, & 38 | heat_glob, & 39 | errmsg, errflg) 40 | 41 | logical, intent(in) :: amIRoot ! are we on the MPI root task? 42 | integer, intent(in) :: iulog ! log output unit 43 | 44 | real(kind_phys), intent(in) :: teinp_glob ! global mean energy of input state [J m-2] 45 | real(kind_phys), intent(in) :: teout_glob ! global mean energy of output state [J m-2] 46 | real(kind_phys), intent(in) :: heat_glob ! global mean heating rate [J kg-1 s-1] 47 | 48 | character(len=512), intent(out) :: errmsg 49 | integer, intent(out) :: errflg 50 | 51 | errmsg = '' 52 | errflg = 0 53 | 54 | if (print_global_means .and. amIRoot) then 55 | write(iulog,'(1x,a26,1x,e25.17,1x,a15,1x,e25.17)') 'global mean input energy =', teinp_glob, 'output energy =', teout_glob 56 | write(iulog,'(1x,a38,1x,e25.17)') 'heating rate for energy conservation =', heat_glob 57 | endif 58 | 59 | end subroutine check_energy_gmean_diagnostics_run 60 | 61 | end module check_energy_gmean_diagnostics 62 | -------------------------------------------------------------------------------- /test/test_suites/suite_convect_shallow_hack.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | initialize_constituents 7 | to_be_ccppized_temporary 8 | 9 | 10 | zm_conv_options 11 | 12 | 27 | 28 | 29 | convect_shallow_diagnostics 30 | 31 | 32 | check_energy_zero_fluxes 33 | hack_convect_shallow 34 | convect_shallow_diagnostics_after_shallow_scheme 35 | apply_heating_rate 36 | apply_constituent_tendencies 37 | qneg 38 | geopotential_temp 39 | 40 | 41 | cloud_fraction_fice 42 | 43 | 44 | set_shallow_conv_fluxes_to_general 45 | zm_conv_evap 46 | set_general_conv_fluxes_to_shallow 47 | convect_shallow_diagnostics_after_convective_evaporation 48 | apply_heating_rate 49 | apply_constituent_tendencies 50 | qneg 51 | geopotential_temp 52 | 53 | 54 | check_energy_scaling 55 | check_energy_chng 56 | 57 | 58 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/rayleigh_friction_diagnostics.F90: -------------------------------------------------------------------------------- 1 | module rayleigh_friction_diagnostics 2 | 3 | use ccpp_kinds, only: kind_phys 4 | 5 | implicit none 6 | private 7 | save 8 | 9 | public :: rayleigh_friction_diagnostics_init ! init routine 10 | public :: rayleigh_friction_diagnostics_run ! main routine 11 | 12 | CONTAINS 13 | 14 | !> \section arg_table_rayleigh_friction_diagnostics_init Argument Table 15 | !! \htmlinclude rayleigh_friction_diagnostics_init.html 16 | subroutine rayleigh_friction_diagnostics_init(errmsg, errflg) 17 | use cam_history, only: history_add_field 18 | use cam_history_support, only: horiz_only 19 | 20 | character(len=512), intent(out) :: errmsg 21 | integer, intent(out) :: errflg 22 | 23 | ! Local variables: 24 | 25 | errmsg = '' 26 | errflg = 0 27 | 28 | ! History add field calls 29 | call history_add_field('UTEND_RAYLEIGH', 'Zonal wind tendency due to Rayleigh Friction', 'lev', 'avg', 'm s-2') 30 | call history_add_field('VTEND_RAYLEIGH', 'Meridional wind tendency due to Rayleigh Friction', 'lev', 'avg', 'm s-2') 31 | call history_add_field('STEND_RAYLEIGH', 'Dry air enthalpy tendency due to Rayleigh Friction', 'lev', 'avg', 'J kg-1') 32 | 33 | end subroutine rayleigh_friction_diagnostics_init 34 | 35 | !> \section arg_table_rayleigh_friction_diagnostics_run Argument Table 36 | !! \htmlinclude rayleigh_friction_diagnostics_run.html 37 | subroutine rayleigh_friction_diagnostics_run(dudt, dvdt, dsdt, errmsg, errflg) 38 | 39 | use cam_history, only: history_out_field 40 | !------------------------------------------------ 41 | ! Input / output parameters 42 | !------------------------------------------------ 43 | ! State variables 44 | real(kind_phys), intent(in) :: dudt(:,:) !tendency_of_eastward_wind due to RF 45 | real(kind_phys), intent(in) :: dvdt(:,:) !tendency_of_northward_wind due to RF 46 | real(kind_phys), intent(in) :: dsdt(:,:) !tendency_of_dry_air_enthalpy_at_constant_pressure due to RF 47 | 48 | ! CCPP error handling variables 49 | character(len=512), intent(out) :: errmsg 50 | integer, intent(out) :: errflg 51 | 52 | errmsg = '' 53 | errflg = 0 54 | 55 | ! History out field calls 56 | call history_out_field('UTEND_RAYLEIGH', dudt) 57 | call history_out_field('VTEND_RAYLEIGH', dvdt) 58 | call history_out_field('STEND_RAYLEIGH', dsdt) 59 | 60 | end subroutine rayleigh_friction_diagnostics_run 61 | 62 | !======================================================================= 63 | 64 | end module rayleigh_friction_diagnostics 65 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/zm_momtran_tendency_diagnostics.F90: -------------------------------------------------------------------------------- 1 | module zm_momtran_tendency_diagnostics 2 | use ccpp_kinds, only: kind_phys 3 | 4 | implicit none 5 | private 6 | save 7 | 8 | public :: zm_momtran_tendency_diagnostics_init ! init routine 9 | public :: zm_momtran_tendency_diagnostics_run ! main routine 10 | 11 | CONTAINS 12 | 13 | !> \section arg_table_zm_momtran_tendency_diagnostics_init Argument Table 14 | !! \htmlinclude zm_momtran_tendency_diagnostics_init.html 15 | subroutine zm_momtran_tendency_diagnostics_init(errmsg, errflg) 16 | use cam_history, only: history_add_field 17 | use cam_history_support, only: horiz_only 18 | 19 | character(len=512), intent(out) :: errmsg 20 | integer, intent(out) :: errflg 21 | 22 | ! Local variables: 23 | 24 | errmsg = '' 25 | errflg = 0 26 | 27 | call history_add_field ('ZMMTT', 'T tendency - ZM convective momentum transport', 'lev', 'avg', 'K s-1') 28 | call history_add_field ('ZMMTU', 'U tendency - ZM convective momentum transport', 'lev', 'avg', 'm s-2') 29 | call history_add_field ('ZMMTV', 'V tendency - ZM convective momentum transport', 'lev', 'avg', 'm s-2') 30 | 31 | end subroutine zm_momtran_tendency_diagnostics_init 32 | 33 | !> \section arg_table_zm_momtran_tendency_diagnostics_run Argument Table 34 | !! \htmlinclude zm_momtran_tendency_diagnostics_run.html 35 | subroutine zm_momtran_tendency_diagnostics_run(ncol, pver, cpair, windu_tend, windv_tend, seten, errmsg, errflg) 36 | 37 | use cam_history, only: history_out_field 38 | !------------------------------------------------ 39 | ! Input / output parameters 40 | !------------------------------------------------ 41 | integer, intent(in) :: ncol 42 | integer, intent(in) :: pver 43 | real(kind_phys), intent(in) :: cpair 44 | real(kind_phys), intent(in) :: windu_tend(:,:) 45 | real(kind_phys), intent(in) :: windv_tend(:,:) 46 | real(kind_phys), intent(in) :: seten(:,:) 47 | 48 | ! CCPP error handling variables 49 | character(len=512), intent(out) :: errmsg 50 | integer, intent(out) :: errflg 51 | 52 | real(kind_phys) :: ftem(ncol,pver) 53 | 54 | errmsg = '' 55 | errflg = 0 56 | 57 | call history_out_field('ZMMTU', windu_tend) 58 | call history_out_field('ZMMTV', windv_tend) 59 | 60 | ftem(:ncol,:pver) = seten(:ncol,:pver)/cpair 61 | call history_out_field('ZMMTT', ftem) 62 | 63 | end subroutine zm_momtran_tendency_diagnostics_run 64 | 65 | !======================================================================= 66 | 67 | end module zm_momtran_tendency_diagnostics 68 | -------------------------------------------------------------------------------- /schemes/sima_diagnostics/zm_evap_tendency_diagnostics.meta: -------------------------------------------------------------------------------- 1 | [ccpp-table-properties] 2 | name = zm_evap_tendency_diagnostics 3 | type = scheme 4 | 5 | [ccpp-arg-table] 6 | name = zm_evap_tendency_diagnostics_init 7 | type = scheme 8 | [ errmsg ] 9 | standard_name = ccpp_error_message 10 | long_name = Error message for error handling in CCPP 11 | units = none 12 | type = character | kind = len=512 13 | dimensions = () 14 | intent = out 15 | [ errflg ] 16 | standard_name = ccpp_error_code 17 | long_name = Error flag for error handling in CCPP 18 | units = 1 19 | type = integer 20 | dimensions = () 21 | intent = out 22 | 23 | [ccpp-arg-table] 24 | name = zm_evap_tendency_diagnostics_run 25 | type = scheme 26 | [ ncol ] 27 | standard_name = horizontal_loop_extent 28 | units = count 29 | type = integer 30 | dimensions = () 31 | intent = in 32 | [ pver ] 33 | standard_name = vertical_layer_dimension 34 | units = count 35 | type = integer 36 | dimensions = () 37 | intent = in 38 | [ cpair ] 39 | standard_name = specific_heat_of_dry_air_at_constant_pressure 40 | units = J kg-1 K-1 41 | type = real | kind = kind_phys 42 | dimensions = () 43 | intent = in 44 | [ tend_s_snwprd ] 45 | standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_frozen_precipitation_production_due_to_deep_convection 46 | units = J kg-1 s-1 47 | type = real | kind = kind_phys 48 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 49 | intent = in 50 | [ tend_s_snwevmlt ] 51 | standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_evaporation_and_melting_of_frozen_precipitation_due_to_deep_convection 52 | units = J kg-1 s-1 53 | type = real | kind = kind_phys 54 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 55 | intent = in 56 | [ qtnd ] 57 | standard_name = tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water 58 | units = kg kg-1 s-1 59 | type = real | kind = kind_phys 60 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 61 | intent = in 62 | [ heat ] 63 | standard_name = tendency_of_dry_air_enthalpy_at_constant_pressure 64 | units = J kg-1 s-1 65 | type = real | kind = kind_phys 66 | dimensions = (horizontal_loop_extent,vertical_layer_dimension) 67 | intent = in 68 | [ errmsg ] 69 | standard_name = ccpp_error_message 70 | long_name = Error message for error handling in CCPP 71 | units = none 72 | type = character | kind = len=512 73 | dimensions = () 74 | intent = out 75 | [ errflg ] 76 | standard_name = ccpp_error_code 77 | long_name = Error flag for error handling in CCPP 78 | units = 1 79 | type = integer 80 | dimensions = () 81 | intent = out 82 | -------------------------------------------------------------------------------- /schemes/zhang_mcfarlane/save_ttend_from_convect_deep.F90: -------------------------------------------------------------------------------- 1 | ! Save temperature tendency from deep convection 2 | ! for use by gravity wave parameterization 3 | ! 4 | ! This scheme has to be run after all deep convective schemes, 5 | ! before the final tendencies are applied. 6 | ! Since ZM applies tendencies in each sub-scheme, this scheme has 7 | ! to run repeatedly to archive all tendencies from ZM. 8 | module save_ttend_from_convect_deep 9 | use ccpp_kinds, only: kind_phys 10 | 11 | implicit none 12 | private 13 | 14 | public :: save_ttend_from_convect_deep_timestep_init 15 | public :: save_ttend_from_convect_deep_run 16 | 17 | contains 18 | 19 | !> \section arg_table_save_ttend_from_convect_deep_timestep_init Argument Table 20 | !! \htmlinclude save_ttend_from_convect_deep_timestep_init.html 21 | subroutine save_ttend_from_convect_deep_timestep_init(ncol, pver, ttend_dp, errmsg, errflg) 22 | integer, intent(in) :: ncol 23 | integer, intent(in) :: pver 24 | 25 | real(kind_phys), intent(out) :: ttend_dp(:, :) ! Temperature tendency from deep convection [K s-1] 26 | character(len=512), intent(out) :: errmsg 27 | integer, intent(out) :: errflg 28 | 29 | errmsg = '' 30 | errflg = 0 31 | 32 | ttend_dp(:,:) = 0._kind_phys 33 | 34 | end subroutine save_ttend_from_convect_deep_timestep_init 35 | 36 | !> \section arg_table_save_ttend_from_convect_deep_run Argument Table 37 | !! \htmlinclude save_ttend_from_convect_deep_run.html 38 | subroutine save_ttend_from_convect_deep_run( & 39 | ncol, pver, & 40 | tend_s, cpair, & 41 | ttend_dp, & 42 | errmsg, errflg) 43 | 44 | ! Input arguments 45 | integer, intent(in) :: ncol 46 | integer, intent(in) :: pver 47 | real(kind_phys), intent(in) :: tend_s(:, :) ! Enthalpy tendency from deep convection [J kg-1 s-1] 48 | real(kind_phys), intent(in) :: cpair ! Specific heat of dry air at constant pressure [J kg-1 K-1] 49 | 50 | ! Input/output arguments 51 | real(kind_phys), intent(inout) :: ttend_dp(:, :) ! Temperature tendency from deep convection [K s-1] (accummulated) 52 | 53 | ! Output arguments 54 | character(len=512), intent(out) :: errmsg 55 | integer, intent(out) :: errflg 56 | 57 | ! Local variables 58 | integer :: i, k 59 | 60 | errmsg = '' 61 | errflg = 0 62 | 63 | ! Convert to temperature tendency 64 | do k = 1, pver 65 | do i = 1, ncol 66 | ttend_dp(i, k) = ttend_dp(i, k) + tend_s(i, k) / cpair 67 | end do 68 | end do 69 | 70 | end subroutine save_ttend_from_convect_deep_run 71 | 72 | end module save_ttend_from_convect_deep 73 | -------------------------------------------------------------------------------- /test/musica/tuvx/test_tuvx_surface_albedo.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2024-2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | program test_tuvx_surface_albedo 4 | 5 | use musica_ccpp_tuvx_surface_albedo 6 | 7 | implicit none 8 | 9 | #define ASSERT(x) if (.not.(x)) then; write(*,*) "Assertion failed[", __FILE__, ":", __LINE__, "]: x"; stop 1; endif 10 | #define ASSERT_NEAR( a, b, abs_error ) if( (abs(a - b) >= abs_error) .and. (abs(a - b) /= 0.0) ) then; write(*,*) "Assertion failed[", __FILE__, ":", __LINE__, "]: a, b"; stop 1; endif 11 | 12 | call test_update_surface_albedo() 13 | 14 | contains 15 | 16 | subroutine test_update_surface_albedo() 17 | use musica_ccpp_tuvx_wavelength_grid, only: create_wavelength_grid 18 | use musica_util, only: error_t 19 | use musica_tuvx_grid, only: grid_t 20 | use musica_tuvx_profile, only: profile_t 21 | use ccpp_kinds, only: kind_phys 22 | 23 | integer, parameter :: NUM_WAVELENGTH_BINS = 4 24 | real, parameter :: ABS_ERROR = 1e-6 25 | real(kind_phys) :: wavelength_grid_interfaces(NUM_WAVELENGTH_BINS + 1) = & 26 | [200.0e-9_kind_phys, 210.0e-9_kind_phys, 240.0e-9_kind_phys, 300.0e-9_kind_phys, 400.0e-9_kind_phys] 27 | real(kind_phys) :: host_surface_albedo = 0.3_kind_phys 28 | real(kind_phys) :: expected_surface_albedo_interfaces(NUM_WAVELENGTH_BINS + 1) = 0.3_kind_phys 29 | real(kind_phys) :: surface_albedo_interfaces(NUM_WAVELENGTH_BINS + 1) 30 | type(grid_t), pointer :: wavelength_grid 31 | type(profile_t), pointer :: profile 32 | type(error_t) :: error 33 | character(len=512) :: errmsg 34 | integer :: errcode 35 | integer :: i 36 | 37 | wavelength_grid => create_wavelength_grid(wavelength_grid_interfaces, errmsg, errcode) 38 | ASSERT(errcode == 0) 39 | ASSERT(associated(wavelength_grid)) 40 | 41 | profile => create_surface_albedo_profile( wavelength_grid, errmsg, errcode ) 42 | ASSERT(errcode == 0) 43 | ASSERT(associated(profile)) 44 | 45 | call set_surface_albedo_values( profile, host_surface_albedo, errmsg, errcode ) 46 | ASSERT(errcode == 0) 47 | 48 | call profile%get_edge_values( surface_albedo_interfaces, error) 49 | ASSERT(error%is_success()) 50 | do i = 1, size(surface_albedo_interfaces) 51 | ASSERT_NEAR(surface_albedo_interfaces(i), expected_surface_albedo_interfaces(i), ABS_ERROR) 52 | end do 53 | 54 | deallocate( profile ) 55 | deallocate( wavelength_grid ) 56 | 57 | end subroutine test_update_surface_albedo 58 | 59 | end program test_tuvx_surface_albedo -------------------------------------------------------------------------------- /test/valgrind.supp: -------------------------------------------------------------------------------- 1 | ############################################################## 2 | # 3 | # MUSICA TUV-x suppressions 4 | # 5 | # TODO(jiwon) We are experiencing memory leak issues in certain 6 | # functions of TUV-x. It appears that these leaks occur only 7 | # occasionally during initialization. We believe it’s acceptable 8 | # to add a Valgrind suppression for now, and we will investigate 9 | # further if it becomes a significant concern. 10 | # 11 | ############################################################## 12 | { 13 | Suppress_MUSICA_TUV-x_Leak1 14 | Memcheck:Leak 15 | fun:malloc 16 | fun:__musica_config_MOD_get_string 17 | fun:__tuvx_radiator_aerosol_MOD_constructor 18 | fun:__tuvx_radiator_factory_MOD_radiator_builder 19 | fun:__tuvx_radiator_warehouse_MOD_constructor 20 | fun:__tuvx_radiative_transfer_MOD_constructor 21 | fun:__tuvx_core_MOD_constructor 22 | fun:InternalCreateTuvx 23 | ... 24 | } 25 | { 26 | Suppress_MUSICA_TUV-x_Leak2 27 | Memcheck:Leak 28 | fun:malloc 29 | fun:__musica_config_MOD_get_string 30 | fun:__tuvx_radiator_MOD_base_constructor 31 | fun:__tuvx_radiator_MOD_constructor 32 | fun:__tuvx_radiator_factory_MOD_radiator_builder 33 | fun:__tuvx_radiator_warehouse_MOD_constructor 34 | fun:__tuvx_radiative_transfer_MOD_constructor 35 | fun:__tuvx_core_MOD_constructor 36 | fun:InternalCreateTuvx 37 | ... 38 | } 39 | { 40 | Suppress_MUSICA_TUV-x_CreateRadiator 41 | Memcheck:Leak 42 | match-leak-kinds: definite 43 | fun:malloc 44 | fun:__musica_string_MOD_string_assign_char 45 | fun:__tuvx_radiator_from_host_MOD_constructor_char 46 | fun:__tuvx_radiator_from_host_MOD_constructor_string 47 | fun:InternalCreateRadiator 48 | ... 49 | } 50 | { 51 | Suppress_MUSICA_TUV-x_AddRadiator 52 | Memcheck:Leak 53 | match-leak-kinds: definite 54 | fun:malloc 55 | fun:__tuvx_radiator_from_host_MOD___copy_tuvx_radiator_from_host_Radiator_from_host_t 56 | fun:__tuvx_radiator_warehouse_MOD_add_radiator 57 | fun:InternalAddRadiator 58 | ... 59 | } 60 | { 61 | Suppress_MUSICA_TUV-x_GetRadiator 62 | Memcheck:Leak 63 | match-leak-kinds: definite 64 | fun:malloc 65 | fun:__tuvx_radiator_from_host_MOD___copy_tuvx_radiator_from_host_Radiator_from_host_t 66 | fun:InternalGetRadiator 67 | ... 68 | } 69 | { 70 | Suppress_MUSICA_TUV-x_CreateTuvx-RadiatorFromHost 71 | Memcheck:Leak 72 | match-leak-kinds: definite 73 | fun:malloc 74 | fun:__tuvx_radiator_from_host_MOD___copy_tuvx_radiator_from_host_Radiator_from_host_t 75 | fun:__tuvx_radiator_warehouse_MOD_add_radiator 76 | fun:__tuvx_radiator_warehouse_MOD_add_radiators 77 | fun:__tuvx_radiative_transfer_MOD_constructor 78 | fun:__tuvx_core_MOD_constructor 79 | fun:InternalCreateTuvx 80 | ... 81 | } -------------------------------------------------------------------------------- /test/test_suites/suite_gw_cam7_se.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 24 | 25 | 26 | initialize_constituents 27 | 28 | 29 | gravity_wave_drag_common 30 | 31 | 32 | check_energy_zero_fluxes 33 | gravity_wave_drag_prepare_profiles 34 | 35 | 36 | gravity_wave_drag_top_taper 37 | 38 | 39 | gravity_wave_drag_moving_mountain 40 | 41 | 42 | gravity_wave_drag_convection_deep 43 | 44 | 45 | gravity_wave_drag_frontogenesis 46 | 47 | 48 | gravity_wave_drag_ridge 49 | gravity_wave_drag_ridge_beta 50 | 51 | 52 | convert_dry_constituent_tendencies_to_dry_air_basis 53 | 54 | 55 | gravity_wave_drag_common_diagnostics 56 | 57 | 58 | apply_tendency_of_eastward_wind 59 | apply_tendency_of_northward_wind 60 | apply_constituent_tendencies 61 | apply_heating_rate 62 | qneg 63 | geopotential_temp 64 | update_dry_static_energy 65 | 66 | 67 | -------------------------------------------------------------------------------- /test/docker/Dockerfile.musica.no_install: -------------------------------------------------------------------------------- 1 | # This Dockerfile is designed for testing MUSICA CCPP functionality. 2 | # It includes: 3 | # - Unit tests for MUSICA utility functions 4 | # - Integration tests for MUSICA CCPP APIs 5 | # 6 | # No MUSICA library installation is required, as the CMake FetchContent module 7 | # retrieves the MUSICA library automatically. 8 | 9 | FROM ubuntu:22.04 10 | 11 | ARG MUSICA_GIT_TAG=25fff7ae42d146bf3f83ad5ac18b3caac8701ddd 12 | ARG CAM_SIMA_CHEMISTRY_DATA_TAG=1ea9d1b8b04980738894d30a864f9a000daf2e5c 13 | ARG USE_INSTALLED_MUSICA_LIB=OFF 14 | ARG BUILD_TYPE=Release 15 | 16 | RUN apt update \ 17 | && apt install -y sudo \ 18 | && useradd -m test_user \ 19 | && echo "test_user ALL=(root) NOPASSWD: ALL" >> /etc/sudoers.d/test_user \ 20 | && chmod 0440 /etc/sudoers.d/test_user 21 | 22 | USER test_user 23 | WORKDIR /home/test_user 24 | 25 | RUN sudo apt update \ 26 | && sudo apt -y install \ 27 | cmake \ 28 | cmake-curses-gui \ 29 | curl \ 30 | g++ \ 31 | gcc \ 32 | gfortran \ 33 | git \ 34 | libblas-dev \ 35 | liblapack-dev \ 36 | lcov \ 37 | libcurl4-openssl-dev \ 38 | libhdf5-dev \ 39 | libnetcdff-dev \ 40 | libopenmpi-dev \ 41 | m4 \ 42 | make \ 43 | openmpi-bin \ 44 | python3 \ 45 | tree \ 46 | valgrind \ 47 | vim \ 48 | zlib1g-dev \ 49 | && sudo apt clean 50 | 51 | ENV FC=mpif90 52 | ENV FFLAGS="-I/usr/include/" 53 | 54 | COPY . atmospheric_physics 55 | RUN sudo chown -R test_user:test_user atmospheric_physics 56 | 57 | # Clone the MUSICA chemistry data set repository 58 | RUN git clone https://github.com/NCAR/cam-sima-chemistry-data.git \ 59 | && cd cam-sima-chemistry-data \ 60 | && git checkout ${CAM_SIMA_CHEMISTRY_DATA_TAG} 61 | 62 | # Make ccpp-framework available before building test 63 | RUN cd atmospheric_physics/test \ 64 | && mkdir lib \ 65 | && cd lib \ 66 | && git clone -b develop --depth 1 https://github.com/NCAR/ccpp-framework.git 67 | ENV CCPP_SRC_PATH="lib/ccpp-framework/src" 68 | ENV CCPP_FORTRAN_TOOLS_PATH="lib/ccpp-framework/scripts/fortran_tools" 69 | 70 | # Make the ESMStandardNames available 71 | RUN cd atmospheric_physics/test/lib \ 72 | && git clone --depth 1 https://github.com/ESCOMP/ESMStandardNames.git 73 | ENV CCPP_STD_NAMES_PATH="lib/ESMStandardNames" 74 | 75 | RUN cd atmospheric_physics/test \ 76 | && cmake -S . -B build \ 77 | -D CMAKE_BUILD_TYPE=${BUILD_TYPE} \ 78 | -D CCPP_ENABLE_MUSICA_TESTS=ON \ 79 | -D CCPP_ENABLE_MEMCHECK=ON \ 80 | && cmake --build ./build 81 | 82 | # Move the MUSICA configuration to the build root to make the data available for testing 83 | RUN mv /home/test_user/cam-sima-chemistry-data/mechanisms /home/test_user/atmospheric_physics/test/build/musica_configurations 84 | 85 | WORKDIR /home/test_user/atmospheric_physics/test/build 86 | -------------------------------------------------------------------------------- /test/musica/tuvx/test_tuvx_temperature.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2024-2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | program test_tuvx_temperature 4 | 5 | use musica_ccpp_tuvx_temperature 6 | 7 | implicit none 8 | 9 | #define ASSERT(x) if (.not.(x)) then; write(*,*) "Assertion failed[", __FILE__, ":", __LINE__, "]: x"; stop 1; endif 10 | #define ASSERT_NEAR( a, b, abs_error ) if( (abs(a - b) >= abs_error) .and. (abs(a - b) /= 0.0) ) then; write(*,*) "Assertion failed[", __FILE__, ":", __LINE__, "]: a, b"; stop 1; endif 11 | 12 | call test_update_temperature() 13 | 14 | contains 15 | 16 | subroutine test_update_temperature() 17 | use musica_ccpp_tuvx_height_grid, only: create_height_grid 18 | use musica_util, only: error_t 19 | use musica_tuvx_grid, only: grid_t 20 | use musica_tuvx_profile, only: profile_t 21 | use ccpp_kinds, only: kind_phys 22 | 23 | integer, parameter :: NUM_HOST_MIDPOINTS = 5 24 | integer, parameter :: NUM_HOST_INTERFACES = 6 25 | real, parameter :: ABS_ERROR = 1e-4 26 | real(kind_phys) :: host_midpoint_temperature(NUM_HOST_MIDPOINTS) = & 27 | [800.8_kind_phys, 700.7_kind_phys, 600.6_kind_phys, 500.5_kind_phys, 400.4_kind_phys] 28 | real(kind_phys) :: host_surface_temperature = 300.3_kind_phys 29 | real(kind_phys) :: expected_temperature_interfaces(NUM_HOST_MIDPOINTS+2) = & 30 | [300.3_kind_phys, 400.4_kind_phys, 500.5_kind_phys, 600.6_kind_phys, 700.7_kind_phys, 800.8_kind_phys, 800.8_kind_phys] 31 | real(kind_phys) :: temperature_interfaces(NUM_HOST_MIDPOINTS+2) 32 | type(grid_t), pointer :: height_grid 33 | type(profile_t), pointer :: profile 34 | character(len=512) :: errmsg 35 | integer :: errcode 36 | type(error_t) :: error 37 | integer :: i 38 | 39 | height_grid => create_height_grid(NUM_HOST_MIDPOINTS, NUM_HOST_INTERFACES, errmsg, errcode) 40 | ASSERT(errcode == 0) 41 | ASSERT(associated(height_grid)) 42 | 43 | profile => create_temperature_profile( height_grid, errmsg, errcode ) 44 | ASSERT(errcode == 0) 45 | ASSERT(associated(profile)) 46 | 47 | call set_temperature_values( profile, host_midpoint_temperature, & 48 | host_surface_temperature, errmsg, errcode ) 49 | ASSERT(errcode == 0) 50 | 51 | call profile%get_edge_values( temperature_interfaces, error) 52 | ASSERT(error%is_success()) 53 | do i = 1, size(temperature_interfaces) 54 | ASSERT_NEAR(temperature_interfaces(i), expected_temperature_interfaces(i), ABS_ERROR) 55 | end do 56 | 57 | deallocate( profile ) 58 | deallocate( height_grid ) 59 | 60 | end subroutine test_update_temperature 61 | 62 | end program test_tuvx_temperature -------------------------------------------------------------------------------- /schemes/gravity_wave_drag/gravity_wave_drag_top_taper.F90: -------------------------------------------------------------------------------- 1 | module gravity_wave_drag_top_taper 2 | use ccpp_kinds, only: kind_phys 3 | 4 | implicit none 5 | private 6 | 7 | public :: gravity_wave_drag_top_taper_init 8 | 9 | contains 10 | 11 | ! Creates vertical ramp coefficients to taper gravity wave drag 12 | ! at the top levels of the model 13 | !> \section arg_table_gravity_wave_drag_top_taper_init Argument Table 14 | !! \htmlinclude gravity_wave_drag_top_taper_init.html 15 | subroutine gravity_wave_drag_top_taper_init( & 16 | pver, & 17 | amIRoot, iulog, & 18 | gw_top_taper, & 19 | nbot_gravity_wave_top_taper, & 20 | pref_edge, pref_mid, & 21 | vramp, & 22 | errmsg, errflg) 23 | 24 | ! Input arguments 25 | integer, intent(in) :: pver 26 | logical, intent(in) :: amIRoot 27 | integer, intent(in) :: iulog 28 | 29 | logical, intent(in) :: gw_top_taper ! Apply gravity wave top tapering [flag] 30 | integer, intent(in) :: nbot_gravity_wave_top_taper ! Bottom level to taper gravity waves at top of model [index] 31 | real(kind_phys), intent(in) :: pref_edge(:) ! Reference pressure at layer interfaces [Pa] 32 | real(kind_phys), intent(in) :: pref_mid(:) ! Reference pressure at layer midpoints [Pa] 33 | 34 | ! Output arguments 35 | real(kind_phys), intent(out) :: vramp(:) ! Gravity wave drag tapering coefficients [1] 36 | 37 | character(len=512), intent(out) :: errmsg 38 | integer, intent(out) :: errflg 39 | 40 | integer :: k ! Vertical level index 41 | integer :: topndx ! Top level index for tapering [index] 42 | integer :: botndx ! Bottom level index for tapering [index] 43 | 44 | errmsg = '' 45 | errflg = 0 46 | 47 | ! Initialize vramp to unity (no tapering by default) 48 | vramp(:pver) = 1._kind_phys 49 | 50 | if (gw_top_taper) then 51 | topndx = 1 52 | botndx = nbot_gravity_wave_top_taper 53 | 54 | if (botndx > 1) then 55 | ! Compute tapering coefficients from bottom index to top 56 | do k = botndx, topndx, -1 57 | vramp(k) = vramp(k + 1) / (pref_edge(k + 1) / pref_edge(k)) 58 | end do 59 | 60 | if (amIRoot) then 61 | write(iulog, '(A)') 'gravity_wave_drag_top_taper_init: GW taper coef (vramp):' 62 | do k = 1, pver 63 | write(iulog, "('k: ',I4,' taper coef, press(Pa): ',F12.8,E12.4)") k, vramp(k), pref_mid(k) 64 | end do 65 | end if 66 | end if 67 | end if 68 | end subroutine gravity_wave_drag_top_taper_init 69 | 70 | end module gravity_wave_drag_top_taper 71 | -------------------------------------------------------------------------------- /schemes/gravity_wave_drag/gw_utils.F90: -------------------------------------------------------------------------------- 1 | ! This module contains utility code for the gravity wave modules. 2 | module gw_utils 3 | use ccpp_kinds, only: kind_phys 4 | 5 | implicit none 6 | private 7 | 8 | public :: get_unit_vector 9 | public :: dot_2d 10 | public :: midpoint_interp 11 | public :: index_of_nearest 12 | 13 | contains 14 | 15 | ! Take two components of a vector, and find the unit vector components and 16 | ! total magnitude. 17 | subroutine get_unit_vector(u, v, u_n, v_n, mag) 18 | real(kind_phys), intent(in) :: u(:) 19 | real(kind_phys), intent(in) :: v(:) 20 | real(kind_phys), intent(out) :: u_n(:) 21 | real(kind_phys), intent(out) :: v_n(:) 22 | real(kind_phys), intent(out) :: mag(:) 23 | 24 | integer :: i 25 | 26 | mag = sqrt(u*u + v*v) 27 | 28 | ! Has to be a loop/if instead of a where, because floating point 29 | ! exceptions can trigger even on a masked divide-by-zero operation 30 | ! (especially on Intel). 31 | do i = 1, size(mag) 32 | if (mag(i) > 0._kind_phys) then 33 | u_n(i) = u(i)/mag(i) 34 | v_n(i) = v(i)/mag(i) 35 | else 36 | u_n(i) = 0._kind_phys 37 | v_n(i) = 0._kind_phys 38 | end if 39 | end do 40 | 41 | end subroutine get_unit_vector 42 | 43 | ! Vectorized version of a 2D dot product (since the intrinsic dot_product 44 | ! is more suitable for arrays of contiguous vectors). 45 | function dot_2d(u1, v1, u2, v2) 46 | real(kind_phys), intent(in) :: u1(:), v1(:) 47 | real(kind_phys), intent(in) :: u2(:), v2(:) 48 | 49 | real(kind_phys) :: dot_2d(size(u1)) 50 | 51 | dot_2d = u1*u2 + v1*v2 52 | 53 | end function dot_2d 54 | 55 | ! Pure function that interpolates the values of the input array along 56 | ! dimension 2. This is obviously not a very generic routine, unlike, say, 57 | ! CAM's lininterp. But it's used often enough that it seems worth providing 58 | ! here. 59 | pure function midpoint_interp(arr) result(interp) 60 | real(kind_phys), intent(in) :: arr(:, :) 61 | real(kind_phys) :: interp(size(arr, 1), size(arr, 2) - 1) 62 | 63 | integer :: i 64 | 65 | do i = 1, size(interp, 2) 66 | interp(:, i) = 0.5_kind_phys*(arr(:, i) + arr(:, i + 1)) 67 | end do 68 | 69 | end function midpoint_interp 70 | 71 | ! Short routine to get the indices of a set of values rounded to their 72 | ! nearest points on a grid. 73 | pure function index_of_nearest(x, grid) result(idx) 74 | real(kind_phys), intent(in) :: x(:) 75 | real(kind_phys), intent(in) :: grid(:) 76 | 77 | integer :: idx(size(x)) 78 | 79 | real(kind_phys) :: interfaces(size(grid) - 1) 80 | integer :: i, n 81 | 82 | n = size(grid) 83 | interfaces = (grid(:n - 1) + grid(2:))/2._kind_phys 84 | 85 | idx = 1 86 | do i = 1, n - 1 87 | where (x > interfaces(i)) idx = i + 1 88 | end do 89 | 90 | end function index_of_nearest 91 | 92 | end module gw_utils 93 | -------------------------------------------------------------------------------- /schemes/rrtmgp/utils/rrtmgp_dry_static_energy_tendency.F90: -------------------------------------------------------------------------------- 1 | module rrtmgp_dry_static_energy_tendency 2 | !----------------------------------------------------------------------- 3 | ! 4 | ! Purpose: Provide an interface to convert shortwave and longwave 5 | ! radiative heating terms into net heating. 6 | ! 7 | ! This module provides a hook to allow incorporating additional 8 | ! radiative terms (eUV heating and nonLTE longwave cooling). 9 | ! 10 | ! Original version: B.A. Boville 11 | !----------------------------------------------------------------------- 12 | 13 | implicit none 14 | private 15 | 16 | ! Public interfaces 17 | public :: rrtmgp_dry_static_energy_tendency_run 18 | 19 | !=============================================================================== 20 | contains 21 | !=============================================================================== 22 | 23 | !> \section arg_table_rrtmgp_dry_static_energy_tendency_run Argument Table 24 | !! \htmlinclude rrtmgp_dry_static_energy_tendency_run.html 25 | !! 26 | subroutine rrtmgp_dry_static_energy_tendency_run(pdel, calc_sw_heat, calc_lw_heat, & 27 | qrs, qrl, qrs_prime, qrl_prime, errmsg, errflg) 28 | !----------------------------------------------------------------------- 29 | ! Compute net radiative heating from qrs and qrl, and the associated net 30 | ! boundary flux. 31 | !----------------------------------------------------------------------- 32 | use ccpp_kinds, only: kind_phys 33 | 34 | ! Arguments 35 | real(kind_phys), dimension(:,:), intent(in) :: pdel ! Layer thickness 36 | logical, intent(in) :: calc_sw_heat ! Flag to calculate net shortwave heating 37 | logical, intent(in) :: calc_lw_heat ! Flag to calculate net longwave heating 38 | real(kind_phys), dimension(:,:), intent(in) :: qrs ! shortwave heating rate adjusted by air pressure thickness (J Pa kg-1 s-1) 39 | real(kind_phys), dimension(:,:), intent(in) :: qrl ! longwave heating rate adjusted by air pressure thickness (J Pa kg-1 s-1) 40 | real(kind_phys), dimension(:,:), intent(out) :: qrs_prime ! shortwave heating rate (J kg-1 s-1) 41 | real(kind_phys), dimension(:,:), intent(out) :: qrl_prime ! longwave heating rate (J kg-1 s-1) 42 | character(len=*), intent(out) :: errmsg 43 | integer, intent(out) :: errflg 44 | 45 | 46 | !----------------------------------------------------------------------- 47 | ! Set error variables 48 | errmsg = '' 49 | errflg = 0 50 | 51 | if (calc_sw_heat) then 52 | qrs_prime(:,:) = qrs(:,:) / pdel(:,:) 53 | end if 54 | 55 | if (calc_lw_heat) then 56 | qrl_prime(:,:) = qrl(:,:) / pdel(:,:) 57 | end if 58 | 59 | end subroutine rrtmgp_dry_static_energy_tendency_run 60 | 61 | !================================================================================================ 62 | end module rrtmgp_dry_static_energy_tendency 63 | -------------------------------------------------------------------------------- /to_be_ccppized/ccpp_tuvx_utils.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2024-2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | module ccpp_tuvx_utils 4 | 5 | implicit none 6 | 7 | private 8 | public :: rebin, read_extraterrestrial_flux 9 | 10 | contains 11 | 12 | !> Regrids normalized flux data to match a specified wavelength grid 13 | ! This function is copied from CAM/src/chemistry/utils/mo_util.F90 14 | subroutine rebin( source_dimension, target_dimension, source_coordinates, & 15 | target_coordinates, source, target ) 16 | use ccpp_kinds, only: kind_phys 17 | 18 | integer, intent(in) :: source_dimension 19 | integer, intent(in) :: target_dimension 20 | real(kind_phys), intent(in) :: source_coordinates(source_dimension+1) 21 | real(kind_phys), intent(in) :: target_coordinates(target_dimension+1) 22 | real(kind_phys), intent(in) :: source(source_dimension) 23 | real(kind_phys), intent(out) :: target(target_dimension) 24 | 25 | ! local variables 26 | integer :: i, si, si1, sil, siu 27 | real(kind_phys) :: y, sl, su, tl, tu 28 | 29 | do i = 1, target_dimension 30 | tl = target_coordinates(i) 31 | if( tl < source_coordinates( source_dimension + 1) ) then 32 | do sil = 1, source_dimension + 1 33 | if( tl <= source_coordinates( sil ) ) then 34 | exit 35 | end if 36 | end do 37 | tu = target_coordinates( i + 1 ) 38 | do siu = 1, source_dimension + 1 39 | if( tu <= source_coordinates( siu ) ) then 40 | exit 41 | end if 42 | end do 43 | y = 0._kind_phys 44 | sil = max( sil, 2 ) 45 | siu = min( siu, source_dimension + 1 ) 46 | do si = sil, siu 47 | si1 = si - 1 48 | sl = max( tl, source_coordinates( si1 ) ) 49 | su = min( tu, source_coordinates( si ) ) 50 | y = y + ( su - sl ) * source( si1 ) 51 | end do 52 | target(i) = y / (target_coordinates( i + 1 ) - target_coordinates( i ) ) 53 | else 54 | target(i) = 0._kind_phys 55 | end if 56 | end do 57 | 58 | end subroutine rebin 59 | 60 | !> Reads a data file to retrieve the extraterrestrial radiation flux values. 61 | ! This function is a temporary implementation and will be replaced in 62 | ! future versions of the code. 63 | subroutine read_extraterrestrial_flux() 64 | character(len=50), dimension(4) :: filepath_of_extraterrestrial_flux 65 | 66 | filepath_of_extraterrestrial_flux(1) = 'musica_configurations/chapman/tuvx/data/profiles/solar/susim_hi.flx' 67 | filepath_of_extraterrestrial_flux(2) = 'musica_configurations/chapman/tuvx/data/profiles/solar/atlas3_1994_317_a.dat' 68 | filepath_of_extraterrestrial_flux(3) = 'musica_configurations/chapman/tuvx/data/profiles/solar/sao2010.solref.converted' 69 | filepath_of_extraterrestrial_flux(4) = 'musica_configurations/chapman/tuvx/data/profiles/solar/neckel.flx' 70 | 71 | end subroutine read_extraterrestrial_flux 72 | 73 | end module ccpp_tuvx_utils -------------------------------------------------------------------------------- /schemes/musica/tuvx/musica_ccpp_tuvx_temperature.F90: -------------------------------------------------------------------------------- 1 | ! Copyright (C) 2024-2025 University Corporation for Atmospheric Research 2 | ! SPDX-License-Identifier: Apache-2.0 3 | module musica_ccpp_tuvx_temperature 4 | implicit none 5 | 6 | private 7 | public :: create_temperature_profile, set_temperature_values 8 | 9 | !> Label for temperature in TUV-x 10 | character(len=*), parameter, public :: temperature_label = "temperature" 11 | !> Unit for temperature in TUV-x 12 | character(len=*), parameter, public :: temperature_unit = "K" 13 | 14 | contains 15 | 16 | !> Creates a TUV-x temperature profile 17 | function create_temperature_profile(height_grid, errmsg, errcode) & 18 | result(profile) 19 | use musica_ccpp_util, only: has_error_occurred 20 | use musica_tuvx_grid, only: grid_t 21 | use musica_tuvx_profile, only: profile_t 22 | use musica_util, only: error_t 23 | 24 | type(grid_t), intent(in) :: height_grid 25 | character(len=*), intent(out) :: errmsg 26 | integer, intent(out) :: errcode 27 | type(profile_t), pointer :: profile 28 | 29 | ! local variables 30 | type(error_t) :: error 31 | 32 | profile => profile_t( temperature_label, temperature_unit, & 33 | height_grid, error ) 34 | if ( has_error_occurred( error, errmsg, errcode ) ) return 35 | 36 | end function create_temperature_profile 37 | 38 | !> Sets TUV-x temperature values from host-model temperatures 39 | !! 40 | !! See description of `musica_ccpp_tuvx_height_grid.F90` for 41 | !! CAM-SIMA <-> TUV-x height grid mapping 42 | subroutine set_temperature_values(profile, host_midpoint_temperatures, & 43 | host_surface_temperature, errmsg, errcode) 44 | use musica_ccpp_util, only: has_error_occurred 45 | use musica_tuvx_profile, only: profile_t 46 | use musica_util, only: error_t 47 | use ccpp_kinds, only: kind_phys 48 | 49 | type(profile_t), intent(inout) :: profile 50 | real(kind_phys), intent(in) :: host_midpoint_temperatures(:) ! K 51 | real(kind_phys), intent(in) :: host_surface_temperature ! K 52 | character(len=*), intent(out) :: errmsg 53 | integer, intent(out) :: errcode 54 | 55 | ! local variables 56 | type(error_t) :: error 57 | real(kind_phys) :: interfaces(size(host_midpoint_temperatures)+2) 58 | integer :: n_host_midpoint_temperatures 59 | 60 | n_host_midpoint_temperatures = size(host_midpoint_temperatures) 61 | 62 | interfaces(1) = host_surface_temperature 63 | interfaces(2:n_host_midpoint_temperatures+1) = host_midpoint_temperatures(n_host_midpoint_temperatures:1:-1) 64 | interfaces(n_host_midpoint_temperatures+2) = host_midpoint_temperatures(1) 65 | 66 | call profile%set_edge_values( interfaces, error ) 67 | if ( has_error_occurred( error, errmsg, errcode ) ) return 68 | 69 | end subroutine set_temperature_values 70 | 71 | end module musica_ccpp_tuvx_temperature --------------------------------------------------------------------------------