From f32045cefaa64c984118ff0f255d086f06872db6 Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Wed, 3 Oct 2018 12:45:15 -0600 Subject: [PATCH 1/4] Move unit test of sens_heat_from_precip_conversion to a higher level I think this will make it easier to introduce some upcoming changes that I think will require changing the interface of this routine. --- src/main/atm2lndMod.F90 | 16 +++---- src/main/test/atm2lnd_test/CMakeLists.txt | 3 +- .../atm2lnd_test/test_partition_precip.pf | 27 +++++++++--- .../test_sens_heat_from_precip_conversion.pf | 43 ------------------- 4 files changed, 31 insertions(+), 58 deletions(-) delete mode 100644 src/main/test/atm2lnd_test/test_sens_heat_from_precip_conversion.pf diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index c54ddcd12a..eef475d589 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -31,17 +31,17 @@ module atm2lndMod ! !PUBLIC MEMBER FUNCTIONS: public :: downscale_forcings ! Downscale atm forcing fields from gridcell to column - ! The following routines are public for the sake of unit testing; they should not be + ! The following routine is public for the sake of unit testing; it should not be ! called by production code outside this module - public :: partition_precip ! Partition precipitation into rain/snow - public :: sens_heat_from_precip_conversion ! Compute sensible heat flux needed to compensate for rain-snow conversion + public :: partition_precip ! Partition precipitation into rain/snow ! ! !PRIVATE MEMBER FUNCTIONS: - private :: rhos ! calculate atmospheric density - private :: repartition_rain_snow_one_col ! Re-partition precipitation for a single column - private :: downscale_longwave ! Downscale longwave radiation from gridcell to column - private :: build_normalization ! Compute normalization factors so that downscaled fields are conservative - private :: check_downscale_consistency ! Check consistency of downscaling + private :: rhos ! calculate atmospheric density + private :: repartition_rain_snow_one_col ! Re-partition precipitation for a single column + private :: sens_heat_from_precip_conversion ! Compute sensible heat flux needed to compensate for rain-snow conversion + private :: downscale_longwave ! Downscale longwave radiation from gridcell to column + private :: build_normalization ! Compute normalization factors so that downscaled fields are conservative + private :: check_downscale_consistency ! Check consistency of downscaling character(len=*), parameter, private :: sourcefile = & __FILE__ diff --git a/src/main/test/atm2lnd_test/CMakeLists.txt b/src/main/test/atm2lnd_test/CMakeLists.txt index 018b875a27..e42192b45b 100644 --- a/src/main/test/atm2lnd_test/CMakeLists.txt +++ b/src/main/test/atm2lnd_test/CMakeLists.txt @@ -1,7 +1,6 @@ set(pfunit_sources test_downscale_forcings.pf - test_partition_precip.pf - test_sens_heat_from_precip_conversion.pf) + test_partition_precip.pf) create_pFUnit_test(atm2lnd test_atm2lnd_exe "${pfunit_sources}" "") diff --git a/src/main/test/atm2lnd_test/test_partition_precip.pf b/src/main/test/atm2lnd_test/test_partition_precip.pf index 4e996988d0..d24cc7347e 100644 --- a/src/main/test/atm2lnd_test/test_partition_precip.pf +++ b/src/main/test/atm2lnd_test/test_partition_precip.pf @@ -121,21 +121,38 @@ contains end subroutine highTemp_resultsInCorrectPartitioning @Test - subroutine intermediateTemp_resultsInCorrectPartitioning(this) + subroutine intermediateTemp_resultsInCorrectPartitioningAndHeatFlux(this) + ! Unlike other tests, where we check for either correct partitioning or correct heat + ! flux in a given test: This test checks both for convenience (to avoid duplication + ! between two tests which would require us to update both of them if the ramp for + ! rain-snow conversion changed). class(TestPartitionPrecip), intent(inout) :: this + real(r8), parameter :: rain_orig = 1._r8 + real(r8), parameter :: snow_orig = 2._r8 + real(r8) :: tot_precip + real(r8) :: expected_rain + real(r8) :: expected_snow + real(r8) :: expected_heat_flux call setup_single_veg_patch(pft_type=1) - call this%set_inputs(rain=[1._r8], snow=[2._r8], temperature=[SHR_CONST_TKFRZ + 1.5_r8]) + call this%set_inputs(rain=[rain_orig], snow=[snow_orig], temperature=[SHR_CONST_TKFRZ + 1.5_r8]) call partition_precip(bounds, this%atm2lnd_inst, this%sh_from_conversion) associate(& rain_col => this%atm2lnd_inst%forc_rain_downscaled_col, & snow_col => this%atm2lnd_inst%forc_snow_downscaled_col) - @assertEqual(3._r8 * 0.75_r8, rain_col(begc), tolerance=tol) - @assertEqual(3._r8 * 0.25_r8, snow_col(begc), tolerance=tol) + tot_precip = rain_orig + snow_orig + expected_rain = tot_precip * 0.75_r8 + expected_snow = tot_precip * 0.25_r8 + @assertEqual(expected_rain, rain_col(begc), tolerance=tol) + @assertEqual(expected_snow, snow_col(begc), tolerance=tol) + + ! Snow to rain extracts energy, so results in a negative heat flux to atm + expected_heat_flux = (rain_orig - expected_rain) * mm_to_m * denh2o * hfus + @assertEqual([expected_heat_flux], this%sh_from_conversion, tolerance=tol) end associate - end subroutine intermediateTemp_resultsInCorrectPartitioning + end subroutine intermediateTemp_resultsInCorrectPartitioningAndHeatFlux @Test subroutine intermediateTemp_glacier_resultsInCorrectPartitioning(this) diff --git a/src/main/test/atm2lnd_test/test_sens_heat_from_precip_conversion.pf b/src/main/test/atm2lnd_test/test_sens_heat_from_precip_conversion.pf deleted file mode 100644 index 44ca36b9ec..0000000000 --- a/src/main/test/atm2lnd_test/test_sens_heat_from_precip_conversion.pf +++ /dev/null @@ -1,43 +0,0 @@ -module test_sens_heat_from_precip_conversion - - ! Tests of atm2lndMod: sens_heat_from_precip_conversion - ! This module just tests edge cases that would be difficult to test from the - ! multi-point wrapper. - - use pfunit_mod - use atm2lndMod - use shr_kind_mod, only : r8 => shr_kind_r8 - use clm_varcon, only : hfus ! latent heat of fusion for ice [J/kg] - use clm_varcon, only : denh2o ! density of liquid water [kg/m3] - - implicit none - - real(r8), parameter :: tol = 1.e-13_r8 - real(r8), parameter :: mm_to_m = 1.e-3_r8 ! multiply by this to convert from mm to m - -contains - - @Test - subroutine partialConversion_resultsInCorrectHeatFlux() - real(r8), parameter :: rain_old = 2._r8 ! [mm] - real(r8), parameter :: snow_old = 5._r8 ! [mm] - real(r8), parameter :: rain_new = 6._r8 ! [mm] - real(r8), parameter :: snow_new = 1._r8 ! [mm] - real(r8) :: sens_heat_flux ! [W/m2 to atm] - real(r8) :: expected - - call sens_heat_from_precip_conversion( & - rain_old = rain_old, & - snow_old = snow_old, & - rain_new = rain_new, & - snow_new = snow_new, & - sens_heat_flux = sens_heat_flux) - - ! Snow to rain extracts energy, so results in a negative heat flux to atm - expected = -4._r8 * mm_to_m * denh2o * hfus - @assertEqual(expected, sens_heat_flux, tolerance=tol) - - end subroutine partialConversion_resultsInCorrectHeatFlux - -end module test_sens_heat_from_precip_conversion - From 71b3a0a93d174ff13e888d7638c0729fdc8936d8 Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Wed, 5 Dec 2018 09:31:47 -0700 Subject: [PATCH 2/4] Option for rain-to-snow to immediately run off in some regions Up until now: When repartition_rain_snow is .true. (which is the default for CLM5), rain that falls when the near-surface temperature is cold is converted to snow. This repartitioning was put in place for two reasons: (1) Downscaling to elevation classes: changing the balance between rain and snow for different elevation classes; (2) Correcting problems in CAM. However, members of the Land Ice Working Group would like to change this behavior so that, when CAM produces cold-temperature rain, this rain immediately runs off rather than being converted to snow. The purpose of this is to reduce the too-high SMB over portions of Greenland in CESM2 coupled runs (which results in part from CAM's generation of liquid precipitation despite very cold temperatures). This new behavior is implemented in a glacier region-specific manner, based on a new namelist flag, glacier_region_rain_to_snow_behavior. It is not at all ideal to make this aspect of the physics differ by region, but this has been requested by members of the Land Ice Working Group in order to address biases over Greenland while having minimal impact on the climate (so that the climate can stay very similar to that of the official CMIP6 runs). Note that, unlike other glacier region-specific behaviors, this one applies to all landunits, not just glaciers. This also seems a bit non-ideal, but we want the physics to be the same for all landunit types in a given region, and we also want this behavior to apply to vegetated columns because they are used for glacial inception (and we want this alternate behavior to apply to glacial inception, too, in order to decrease some instances of inception). The justification for this new physics is: In the case of (1) above: If CAM is generating rain at a given elevation / temperature, that doesn't necessarily imply that an equal water equivalent of snow would be generated at a higher elevation / lower temperature: indeed, in reality, there might not be any precipitation falling at that higher elevation / lower temperature. In the case of (2) above: There seem to be problems with CAM's microphysics that cause it to produce too much rain when temperatures are very cold; it seems (at least to some people) equally justifiable to throw this cold rain away (by sending it to the ocean as runoff) as it is to convert this cold rain to snow. Note: I don't think any changes are needed in BalanceCheck (unfortunately), since BalanceCheck currently uses the post-downscaling precipitation fluxes, and the pre-lnd2atm runoff fluxes (i.e., the new runoff flux isn't included in the terms in BalanceCheck, and it doesn't need to be because BalanceCheck uses the post-downscaling precipitation fluxes). (See also https://github.com/ESCOMP/ctsm/issues/201#issuecomment-444264954 .) --- bld/CLMBuildNamelist.pm | 1 + .../namelist_defaults_clm4_5.xml | 2 + .../namelist_definition_clm4_5.xml | 17 +++ src/biogeophys/WaterfluxType.F90 | 8 ++ src/main/atm2lndMod.F90 | 47 +++++-- src/main/clm_driver.F90 | 7 +- src/main/glcBehaviorMod.F90 | 118 +++++++++++++++--- src/main/lnd2atmMod.F90 | 12 +- .../atm2lnd_test/test_downscale_forcings.pf | 13 +- .../atm2lnd_test/test_partition_precip.pf | 98 +++++++++++++-- .../test/glcBehavior_test/test_glcBehavior.pf | 63 ++++++++-- 11 files changed, 335 insertions(+), 51 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 46840cdaf7..9cfa537ff8 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -2039,6 +2039,7 @@ sub setup_logic_glacier { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_behavior'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_melt_behavior'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_ice_runoff_behavior'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_rain_to_snow_behavior'); } } diff --git a/bld/namelist_files/namelist_defaults_clm4_5.xml b/bld/namelist_files/namelist_defaults_clm4_5.xml index 21809bcf9c..280217f661 100644 --- a/bld/namelist_files/namelist_defaults_clm4_5.xml +++ b/bld/namelist_files/namelist_defaults_clm4_5.xml @@ -336,6 +336,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). Antarctica: remains_ice --> 'melted','melted','remains_ice','remains_ice' +'converted_to_snow','converted_to_snow','converted_to_snow','converted_to_snow' +