diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index c6a613d449..6b8342375a 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -1874,10 +1874,15 @@ sub process_namelist_inline_logic { ######################################### setup_logic_initinterp($opts, $nl_flags, $definition, $defaults, $nl); - ############################### - # namelist group: exice_streams # - ############################### - setup_logic_exice($opts, $nl_flags, $definition, $defaults, $nl); + ################################# + # namelist group: exice_streams # + ################################# + setup_logic_exice($opts, $nl_flags, $definition, $defaults, $nl, $physv); + + ########################################## + # namelist group: clm_temperature_inparm # + ########################################## + setup_logic_coldstart_temp($opts,$nl_flags, $definition, $defaults, $nl); } #------------------------------------------------------------------------------- @@ -2381,7 +2386,6 @@ sub setup_logic_soilstate { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'organic_frac_squared' ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_bedrock', 'use_fates'=>$nl_flags->{'use_fates'}, 'vichydro'=>$nl_flags->{'vichydro'} ); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_excess_ice'); # excess ice flag should be read before stream vars my $var1 = "soil_layerstruct_predefined"; my $var2 = "soil_layerstruct_userdefined"; @@ -4930,13 +4934,31 @@ sub setup_logic_exice { # # excess ice streams # - my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_excess_ice', 'phys'=>$physv->as_string()); my $use_exice = $nl->get_value( 'use_excess_ice' ); my $use_exice_streams = $nl->get_value( 'use_excess_ice_streams' ); - # IF excess ice streams is on + my $finidat = $nl->get_value('finidat'); + # If coldstart and use_excess_ice is on: + if ( ( (not defined($use_exice_streams)) && value_is_true($use_exice) ) && string_is_undef_or_empty($finidat) ) { + $nl->set_variable_value('exice_streams', 'use_excess_ice_streams' , '.true.'); + $use_exice_streams = '.true.'; + # if excess ice is turned off + } elsif ( (not defined($use_exice_streams)) && (not value_is_true($use_exice)) ) { + $use_exice_streams = '.false.'; + # Checking for cold clm_start_type and not finidat here since finidat can be not set set in branch/hybrid runs and + # These cases are handled in the restart routines in the model + } elsif ( defined($use_exice_streams) && (not value_is_true($use_exice_streams)) && value_is_true($use_exice) && + ( $nl_flags->{'clm_start_type'} eq "'cold'" || $nl_flags->{'clm_start_type'} eq "'arb_ic'" )) { + $log->fatal_error("use_excess_ice_streams can NOT be FALSE when use_excess_ice is TRUE on the cold start" ); + } + + # Put use_exice_streams into nl_flags so can be referenced later + $nl_flags->{'use_excice_streams'} = $use_exice_streams; + # If excess ice streams is on if (defined($use_exice_streams) && value_is_true($use_exice_streams)) { # Can only be true if excess ice is also on, otherwise fail - if (defined($use_exice) && not value_is_true($use_exice)) { + if ( defined($use_exice) && (not value_is_true($use_exice)) ) { $log->fatal_error("use_excess_ice_streams can NOT be TRUE when use_excess_ice is FALSE" ); } # Otherwise if ice streams are off @@ -4973,6 +4995,46 @@ sub setup_logic_exice { } # end exice streams +sub setup_logic_coldstart_temp { + + my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; + + # set initial temperatures for excess ice gridcells: needs to be set whether excess ice is on or not + + my $use_exice = $nl->get_value( 'use_excess_ice' ); + my $finidat = $nl->get_value('finidat'); + + my @list = ( "excess_ice_coldstart_temp", "excess_ice_coldstart_depth" ); + + # Only needs to be set by the user if it's a coldstart + if ( ! string_is_undef_or_empty($finidat) ) { + foreach my $var ( @list ) { + my $val = $nl->get_value( $var ); + if ( defined($val) ) { + $log->warning("$var only needs to be set if this is a cold-start, although InitCold is always called"); + } + } + } + + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'excess_ice_coldstart_temp', + 'use_excess_ice'=>$use_exice); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'excess_ice_coldstart_depth', + 'use_excess_ice'=>$use_exice); + + my $use_exice_streams = $nl_flags->{'use_excice_streams'}; + my $exice_cs_temp = $nl->get_value( 'excess_ice_coldstart_temp' ); + my $exice_cs_depth = $nl->get_value( 'excess_ice_coldstart_depth' ); + + if (defined($use_exice_streams) && value_is_true($use_exice_streams)) { + if (defined($exice_cs_depth) && $exice_cs_depth <= 0.0 ) { + $log->fatal_error("excess_ice_coldstart_depth is <= 0.0" ); + } + if (defined($exice_cs_temp) && $exice_cs_temp >= 0.0 ) { + $log->fatal_error("excess_ice_coldstart_temp is >= 0.0, no excess ice will be present in this run" ); + } + } +} + #------------------------------------------------------------------------------- sub setup_logic_z0param { @@ -5068,6 +5130,7 @@ sub write_output_files { push @groups, "lifire_inparm"; push @groups, "ch4finundated"; push @groups, "exice_streams"; + push @groups, "clm_temperature_inparm"; push @groups, "soilbgc_decomp"; push @groups, "clm_canopy_inparm"; push @groups, "zendersoilerod"; diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 3594fe5c38..fc72b36942 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2635,7 +2635,10 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c .false. - +-1.0 +0.5 +-3.15 +0.5 lnd/clm2/paramdata/exice_init_0.125x0.125_c20220516.nc lnd/clm2/paramdata/exice_init_0.125x0.125_ESMFmesh_cdf5_c20220802.nc bilinear diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 9cbcc5e692..bd348716d8 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -2946,6 +2946,18 @@ use case.) If TRUE turn on the excess ice physics, (Lee et al., 2014; Cai et al., 2020) + +Initial soil temperature to use for gridcells with excess ice present during a run starting with coldstart (deg C). Value only applys if use_excess_ice is true. + + + +Soil depth below which initial excess ice concentration will be applied during a run starting with coldstart (m). Value only applys if use_excess_ice is true. +If this is set below depth of the soil depth, only the last soil layer will get excess ice. + + + If TRUE and use_excess_ice is TRUE, use the excess ice stream to determine the initial values of the excess ice field diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 5bccb3b77c..fe6591c16b 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 3329; +my $ntests = 3338; if ( defined($opts{'compare'}) ) { $ntests += 1999; @@ -322,7 +322,7 @@ sub cat_and_create_namelistinfile { "-res 0.9x1.25 -namelist '&a irrigate=.true./'", "-res 0.9x1.25 -verbose", "-res 0.9x1.25 -ssp_rcp SSP2-4.5", "-res 0.9x1.25 -test", "-res 0.9x1.25 -sim_year 1850", "-res 0.9x1.25 -namelist '&a use_lai_streams=.true.,use_soil_moisture_streams=.true./'", "-res 0.9x1.25 -namelist '&a use_excess_ice=.true. use_excess_ice_streams=.true./'", - "-res 0.9x1.25 -namelist '&a use_excess_ice=.true. use_excess_ice_streams=.false./'", + "-res 0.9x1.25 --clm_start_type cold -namelist '&a use_excess_ice=.true. use_excess_ice_streams=.true./'", "-res 0.9x1.25 -use_case 1850_control", "-res 1x1pt_US-UMB -clm_usr_name 1x1pt_US-UMB -namelist '&a fsurdat=\"/dev/null\"/'", "-res 1x1_brazil", @@ -537,6 +537,21 @@ sub cat_and_create_namelistinfile { namelst=>"use_excess_ice=.true., use_excess_ice_streams = .false.,stream_mapalgo_exice='bilinear'", phys=>"clm5_0", }, + "coldstart exice on wo stream"=>{ options=>"-res 0.9x1.25 -envxml_dir . --clm_start_type cold", + namelst=>"use_excess_ice=.true., use_excess_ice_streams = .false.", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm6_0", + }, + "coldstart exice on bad temp" =>{ options=>"-res 0.9x1.25 -envxml_dir . --clm_start_type cold", + namelst=>"use_excess_ice=.true., use_excess_ice_streams = .true., excess_ice_coldstart_temp=0.0", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm6_0", + }, + "coldstart exice on bad depth" =>{ options=>"-res 0.9x1.25 -envxml_dir . --clm_start_type cold", + namelst=>"use_excess_ice=.true., use_excess_ice_streams = .true., excess_ice_coldstart_depth=0.0", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm6_0", + }, "clm50CNDVwtransient" =>{ options=>" -envxml_dir . -use_case 20thC_transient -dynamic_vegetation -res 10x15 -ignore_warnings", namelst=>"", phys=>"clm5_0", @@ -1256,6 +1271,16 @@ sub cat_and_create_namelistinfile { namelst=>"use_fun=.true.,use_flexiblecn=.false.", phys=>"clm6_0", }, + "Set coldtemp wo coldstart" =>{ options=>"-envxml_dir . --clm_start_type startup", + namelst=>"use_excess_ice=.true.,excess_ice_coldstart_temp=-10.", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm6_0", + }, + "Set colddepth wo coldstart" =>{ options=>"-envxml_dir . --clm_start_type startup", + namelst=>"use_excess_ice=.true.,excess_ice_coldstart_depth=0.5", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm6_0", + }, "NotNEONbutNEONlightres" =>{ options=>"--res CLM_USRDAT --clm_usr_name regional --envxml_dir . --bgc bgc --light_res 106x174", namelst=>"fsurdat='build-namelist_test.pl'", phys=>"clm6_0", diff --git a/doc/ChangeLog b/doc/ChangeLog index aeb7b2972f..f5cf28096c 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,118 @@ =============================================================== +Tag name: ctsm5.2.018 +Originator(s): mvdebolskiy +Date: Fri 02 Aug 2024 09:26:33 AM MDT +One-line Summary: Fix/excess ice cold start + +Purpose and description of changes +---------------------------------- + +Changed the way soil temperature is initialized when excess ice is on and the model starts from cold. + +Specific notes + +TemperatureType now has a private ReadNL subroutine that reads two new namelist options: excess_ice_coldstart_depth and excess_ice_coldstart_temp which control top depth (higher layers get default initial temperature) and soil temperature for soil layers ONLY in columns where excess ice is present. Other columns get their default soil temperature. + +New namelist options belong to a new group "clm_temperature_inparm" with its own logic routine. This is done so in the future hardcoded cold start temperatures can be moved to the namelists. Two namelist tests have been added to check for invalid values logic as well as a test for use_excess_ice_streams logic. use_excess_ice_streams has no default value (due to options for restart) and default value set in the CLMBuildNamelist.pm. + +excessicestream_type has been taken out of waterstate_type and its routines are called directly in clm_inst%Init. Checks for UseExcessIceStreams() are still in place in WaterStateType.F90 for double-checking. clm_inst%Init now has a new local variable with excess ice concentration that are read from streams (or zeros if use_excess_ice is false). Arguments for temperature_type%Init and water_type%Init (and children types) have been changed to include this new variable. Fortran unit tests are also updated to account for these new arguments. + + + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- + +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + Fixes #2384 -- Cold start temperature init when excess ice is on + Fixes #2373 -- SMS_Lm3_D_Mmpi-serial.1x1_brazil.I2000Clm50FatesCruRsGs.izumi_intel.clm-FatesColdHydro fails + +Notes of particular relevance for users +--------------------------------------- + +Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): + Added: excess_ice_coldstart_temp and excess_ice_coldstart_depth + +Changes made to namelist defaults (e.g., changed parameter values): + Set new namelist items differently when excess ice is on or off + +Notes of particular relevance for developers: +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + Note that the coldstart variables are always used even without excess ice or with an finidat file. + InitCold is always called so the variables are always set. + +Changes to tests or testing: + New tests for build-namelist unit tester + +Testing summary: regular +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - PASS (998 are different from baseline) + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + derecho - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + any other testing (give details below): + + SMS_Lm12.f09_f09_mg17.I1850Clm60Sp.derecho_intel.clm-ExcessIceStartup_output_sp_exice + derecho ---- PASS + +Answer changes +-------------- + +Changes answers relative to baseline: + + Summarize any changes to answers, i.e., + - what code configurations: excess ice on, with coldstart or with finidat file interpolation + - what platforms/compilers: all + - nature of change: different at startup + Different for cold-start and can be different for a few points where the cold-start + values are still used on interpoaltion of an existing finidat file + + Tests that compare different to baseline: + ERS_D.f10_f10_mg37.I1850Clm60Sp.izumi_nag.clm-ExcessIceStreams + failed baseline comparison (though answers for default physics configurations have not changed). + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +(https://github.com/ESCOMP/ctsm/pull) + #2465 -- fix excess ice cold starts + +=============================================================== +=============================================================== Tag name: ctsm5.2.017 Originator(s): erik (Erik Kluzek,UCAR/TSS,303-497-1326) Date: Tue 30 Jul 2024 08:39:20 AM MDT diff --git a/doc/ChangeSum b/doc/ChangeSum index 15a67bcf04..3d9d70bc54 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,6 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.2.018 mvdebols 08/02/2024 Fix/excess ice cold start ctsm5.2.017 erik 07/30/2024 Dust emissions control moved to cmeps ctsm5.2.016 samrabin 07/27/2024 Enable new crop calendars for clm60 compsets ctsm5.2.015 multiple 07/22/2024 Update submodule tags to pass runoff from cism to rof diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 707218cc27..899da6b882 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -9,7 +9,7 @@ module TemperatureType use abortutils , only : endrun use clm_varctl , only : use_cndv, iulog, use_luna, use_crop, use_biomass_heat_storage use clm_varctl , only : flush_gdd20 - use clm_varpar , only : nlevsno, nlevgrnd, nlevlak, nlevurb, nlevmaxurbgrnd + use clm_varpar , only : nlevsno, nlevgrnd, nlevlak, nlevurb, nlevmaxurbgrnd, nlevsoi use clm_varcon , only : spval, ispval use GridcellType , only : grc use LandunitType , only : lun @@ -119,6 +119,10 @@ module TemperatureType real(r8), pointer :: xmf_h2osfc_col (:) ! latent heat of phase change of surface water real(r8), pointer :: fact_col (:,:) ! used in computing tridiagonal matrix real(r8), pointer :: c_h2osfc_col (:) ! heat capacity of surface water + + ! Namelist parameters for initialization + real(r8) :: excess_ice_coldstart_depth ! depth below which excess ice will be present + real(r8) :: excess_ice_coldstart_temp ! coldstart temperature of layers with excess ice present contains @@ -132,6 +136,8 @@ module TemperatureType procedure, public :: UpdateAccVars procedure, private :: UpdateAccVars_CropGDDs + procedure, private :: ReadNL + end type temperature_type character(len=*), parameter, private :: sourcefile = & @@ -143,7 +149,7 @@ module TemperatureType !------------------------------------------------------------------------ subroutine Init(this, bounds, & em_roof_lun, em_wall_lun, em_improad_lun, em_perroad_lun, & - is_simple_buildtemp, is_prog_buildtemp) + is_simple_buildtemp, is_prog_buildtemp, exice_init_conc_col, NLFileName) ! ! !DESCRIPTION: ! @@ -158,7 +164,16 @@ subroutine Init(this, bounds, & real(r8) , intent(in) :: em_perroad_lun(bounds%begl:) logical , intent(in) :: is_simple_buildtemp ! Simple building temp is being used logical , intent(in) :: is_prog_buildtemp ! Prognostic building temp is being used + real(r8) , intent(in) :: exice_init_conc_col(bounds%begc:) ! initial coldstart excess ice concentration (from the stream file) + character(len=*) , intent(in), optional :: NLFilename ! Namelist filename + + if ( present(NLFilename) ) then + call this%ReadNL(NLFilename) + else ! this is needed for testing + this%excess_ice_coldstart_depth = 0.5_r8 + this%excess_ice_coldstart_temp = -5.0_r8 + endif call this%InitAllocate ( bounds ) call this%InitHistory ( bounds, is_simple_buildtemp, is_prog_buildtemp ) call this%InitCold ( bounds, & @@ -166,7 +181,8 @@ subroutine Init(this, bounds, & em_wall_lun(bounds%begl:bounds%endl), & em_improad_lun(bounds%begl:bounds%endl), & em_perroad_lun(bounds%begl:bounds%endl), & - is_simple_buildtemp, is_prog_buildtemp) + is_simple_buildtemp, is_prog_buildtemp, & + exice_init_conc_col(bounds%begc:bounds%endc) ) end subroutine Init @@ -654,7 +670,7 @@ end subroutine InitHistory !----------------------------------------------------------------------- subroutine InitCold(this, bounds, & em_roof_lun, em_wall_lun, em_improad_lun, em_perroad_lun, & - is_simple_buildtemp, is_prog_buildtemp) + is_simple_buildtemp, is_prog_buildtemp, exice_init_conc_col) ! ! !DESCRIPTION: ! Initialize cold start conditions for module variables @@ -662,11 +678,13 @@ subroutine InitCold(this, bounds, & ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use shr_const_mod , only : SHR_CONST_TKFRZ - use clm_varcon , only : denice, denh2o + use clm_varcon , only : denice, denh2o, zisoi use landunit_varcon, only : istwet, istsoil, istdlak, istice, istcrop use column_varcon , only : icol_road_imperv, icol_roof, icol_sunwall use column_varcon , only : icol_shadewall, icol_road_perv - use clm_varctl , only : iulog, use_vancouver, use_mexicocity, use_excess_ice + use clm_varctl , only : iulog, use_vancouver, use_mexicocity + use clm_varctl , only : use_excess_ice + use initVerticalMod , only : find_soil_layer_containing_depth ! ! !ARGUMENTS: class(temperature_type) :: this @@ -677,6 +695,7 @@ subroutine InitCold(this, bounds, & real(r8) , intent(in) :: em_perroad_lun(bounds%begl:) logical , intent(in) :: is_simple_buildtemp ! Simple building temp is being used logical , intent(in) :: is_prog_buildtemp ! Prognostic building temp is being used + real(r8) , intent(in) :: exice_init_conc_col(bounds%begc:) ! initial coldstart excess ice concentration (from the stream file) ! ! !LOCAL VARIABLES: integer :: j,l,c,p ! indices @@ -684,6 +703,7 @@ subroutine InitCold(this, bounds, & real(r8) :: snowbd ! temporary calculation of snow bulk density (kg/m3) real(r8) :: fmelt ! snowbd/100 integer :: lev + integer :: nexice_start ! layer number containing 0.5 meter depth !----------------------------------------------------------------------- SHR_ASSERT_ALL_FL((ubound(em_roof_lun) == (/bounds%endl/)), sourcefile, __LINE__) @@ -757,8 +777,23 @@ subroutine InitCold(this, bounds, & end if else this%t_soisno_col(c,1:nlevgrnd) = 272._r8 - if (use_excess_ice .and. (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop)) then - this%t_soisno_col(c,1:nlevgrnd) = SHR_CONST_TKFRZ - 5.0_r8 !needs to be below freezing to properly initiate excess ice + if (use_excess_ice .and. exice_init_conc_col(c) > 0.0_r8) then + nexice_start = nlevsoi - 1 + if (this%excess_ice_coldstart_depth <= 0.0_r8) then + ! we double check this here, and when building namelists + call endrun(msg="ERROR excess_ice_coldstart_depth <= 0.0. Set a positive value in the namelist"//errmsg(sourcefile, __LINE__)) + endif + if (zisoi(nlevsoi) >= this%excess_ice_coldstart_depth) then + call find_soil_layer_containing_depth(this%excess_ice_coldstart_depth,nexice_start) + else + nexice_start=nlevsoi-1 + endif + if (this%excess_ice_coldstart_temp >= 0.0_r8) then + ! this is here, since we care about excess_ice_coldstart_temp only when there is excess ice in the gridcell + ! which happens only when the streams are read. + call endrun(msg="ERROR excess_ice_coldstart_temp is not below freezing point"//errmsg(sourcefile, __LINE__)) + endif + this%t_soisno_col(c,nexice_start:nlevgrnd) = SHR_CONST_TKFRZ + this%excess_ice_coldstart_temp end if endif endif @@ -1718,4 +1753,67 @@ subroutine Clean(this) end subroutine Clean + !----------------------------------------------------------------------- + subroutine ReadNL( this, NLFilename ) + ! + ! !DESCRIPTION: + ! Read namelist for Temperature type + ! right now (17.07.2024) it only reads variables related to excess ice coldstart initialization + ! but can be extended to replace hardocded values in InitCold by namelist variables + ! + ! !USES: + use shr_mpi_mod , only : shr_mpi_bcast + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc, mpicom + use fileutils , only : getavu, relavu, opnfil + use clm_nlUtilsMod , only : find_nlgroup_name + use clm_varctl , only : iulog + use abortutils , only : endrun + ! + ! !ARGUMENTS: + class(temperature_type) :: this + character(len=*), intent(in) :: NLFilename ! Namelist filename + ! + ! !LOCAL VARIABLES: + integer :: ierr ! error code + integer :: unitn ! unit for namelist file + real(r8) :: excess_ice_coldstart_temp = spval ! coldstart temperature of layers with excess ice present (deg C) + real(r8) :: excess_ice_coldstart_depth = spval ! depth below which excess ice will be present (m) + character(len=32) :: subname = 'Temperature_readnl' ! subroutine name + !----------------------------------------------------------------------- + + namelist / clm_temperature_inparm / excess_ice_coldstart_depth, excess_ice_coldstart_temp + + if ( masterproc )then + + unitn = getavu() + write(iulog,*) 'Read in clm_temperature_inparm namelist' + call opnfil (NLFilename, unitn, 'F') + call find_nlgroup_name(unitn, 'clm_temperature_inparm', status=ierr) + if (ierr == 0) then + read(unitn, nml=clm_temperature_inparm, iostat=ierr) + if (ierr /= 0) then + call endrun(msg="ERROR reading clm_temperature_inparm namelist"//errmsg(sourcefile, __LINE__)) + end if + else + call endrun(msg="ERROR finding clm_temperature_inparm namelist"//errmsg(sourcefile, __LINE__)) + end if + call relavu( unitn ) + ! namelist might be read but the values not properly set + if ( excess_ice_coldstart_depth == spval ) then + call endrun(msg="ERROR exice_coldstart_depth namelist value is not properly set"//errmsg(sourcefile, __LINE__)) + endif + if ( excess_ice_coldstart_temp == spval ) then + call endrun(msg="ERROR exice_coldstart_temp namelist value is not properly set"//errmsg(sourcefile, __LINE__)) + endif + end if + + call shr_mpi_bcast(excess_ice_coldstart_depth, mpicom) + call shr_mpi_bcast(excess_ice_coldstart_temp, mpicom) + + this%excess_ice_coldstart_depth = excess_ice_coldstart_depth + this%excess_ice_coldstart_temp = excess_ice_coldstart_temp + + end subroutine ReadNL + end module TemperatureType diff --git a/src/biogeophys/WaterStateBulkType.F90 b/src/biogeophys/WaterStateBulkType.F90 index ba3f0513c5..4cd425c976 100644 --- a/src/biogeophys/WaterStateBulkType.F90 +++ b/src/biogeophys/WaterStateBulkType.F90 @@ -47,7 +47,7 @@ module WaterStateBulkType !------------------------------------------------------------------------ subroutine InitBulk(this, bounds, info, vars, & - h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer, NLFilename) + h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer, exice_coldstart_depth, exice_init_conc_col) class(waterstatebulk_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds @@ -57,7 +57,8 @@ subroutine InitBulk(this, bounds, info, vars, & real(r8) , intent(in) :: watsat_col(bounds%begc:, 1:) ! volumetric soil water at saturation (porosity) real(r8) , intent(in) :: t_soisno_col(bounds%begc:, -nlevsno+1:) ! col soil temperature (Kelvin) logical , intent(in) :: use_aquifer_layer ! whether an aquifer layer is used in this run - character(len=*) , intent(in) :: NLFilename ! Namelist filename + real(r8) , intent(in) :: exice_coldstart_depth ! depth below which excess ice will be present + real(r8) , intent(in) :: exice_init_conc_col(bounds%begc:) ! initial coldstart excess ice concentration (from the stream file) call this%Init(bounds = bounds, & info = info, & @@ -66,7 +67,7 @@ subroutine InitBulk(this, bounds, info, vars, & watsat_col = watsat_col, & t_soisno_col = t_soisno_col, & use_aquifer_layer = use_aquifer_layer, & - NLFilename = NLFilename) + exice_coldstart_depth = exice_coldstart_depth, exice_init_conc_col = exice_init_conc_col(bounds%begc:bounds%endc)) call this%InitBulkAllocate(bounds) diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 390e9e8691..35441d65d9 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -56,8 +56,6 @@ module WaterStateType real(r8), pointer :: excess_ice_col (:,:) ! col excess ice (kg/m2) (new) (-nlevsno+1:nlevgrnd) real(r8), pointer :: exice_bulk_init (:) ! inital value for excess ice (new) (unitless) - type(excessicestream_type), private :: exicestream ! stream type for excess ice initialization NUOPC only - ! Hillslope stream variables real(r8), pointer :: stream_water_volume_lun(:) ! landunit volume of water in the streams (m3) @@ -82,7 +80,7 @@ module WaterStateType !------------------------------------------------------------------------ subroutine Init(this, bounds, info, tracer_vars, & - h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer, NLFilename) + h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer, exice_coldstart_depth, exice_init_conc_col) class(waterstate_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds @@ -91,8 +89,9 @@ subroutine Init(this, bounds, info, tracer_vars, & real(r8) , intent(in) :: h2osno_input_col(bounds%begc:) real(r8) , intent(in) :: watsat_col(bounds%begc:, 1:) ! volumetric soil water at saturation (porosity) real(r8) , intent(in) :: t_soisno_col(bounds%begc:, -nlevsno+1:) ! col soil temperature (Kelvin) - logical , intent(in) :: use_aquifer_layer ! whether an aquifer layer is used in this run - character(len=*) , intent(in) :: NLFilename ! Namelist filename + logical , intent(in) :: use_aquifer_layer ! whether an aquifer layer is used in this run + real(r8) , intent(in) :: exice_coldstart_depth ! depth below which excess ice will be present + real(r8) , intent(in) :: exice_init_conc_col(bounds%begc:bounds%endc) ! initial coldstart excess ice concentration (from the stream file) this%info => info @@ -104,7 +103,7 @@ subroutine Init(this, bounds, info, tracer_vars, & watsat_col = watsat_col, & t_soisno_col = t_soisno_col, & use_aquifer_layer = use_aquifer_layer, & - NLFilename = NLFilename) + exice_coldstart_depth = exice_coldstart_depth , exice_init_conc_col = exice_init_conc_col) end subroutine Init @@ -323,7 +322,7 @@ end subroutine InitHistory !----------------------------------------------------------------------- subroutine InitCold(this, bounds, & - h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer, NLFilename) + h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer, exice_coldstart_depth, exice_init_conc_col) ! ! !DESCRIPTION: ! Initialize time constant variables and cold start conditions @@ -343,11 +342,12 @@ subroutine InitCold(this, bounds, & real(r8) , intent(in) :: watsat_col(bounds%begc:, 1:) ! volumetric soil water at saturation (porosity) real(r8) , intent(in) :: t_soisno_col(bounds%begc:, -nlevsno+1:) ! col soil temperature (Kelvin) logical , intent(in) :: use_aquifer_layer ! whether an aquifer layer is used in this run - character(len=*) , intent(in) :: NLFilename ! Namelist filename + real(r8) , intent(in) :: exice_coldstart_depth ! depth below which excess ice will be present + real(r8) , intent(in) :: exice_init_conc_col(bounds%begc:bounds%endc) ! initial coldstart excess ice concentration (from the stream file) ! ! !LOCAL VARIABLES: integer :: c,j,l,nlevs,g - integer :: nbedrock, n05m ! layer containing 0.5 m + integer :: nbedrock, nexice ! layer containing 0.5 m real(r8) :: ratio !----------------------------------------------------------------------- @@ -550,52 +550,40 @@ subroutine InitCold(this, bounds, & this%dynbal_baseline_ice_col(bounds%begc:bounds%endc) = 0._r8 !Initialize excess ice - if (use_excess_ice .and. NLFilename /= '') then - ! enforce initialization with 0 for everything - this%excess_ice_col(bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd)=0.0_r8 - this%exice_bulk_init(bounds%begc:bounds%endc)=0.0_r8 - call this%exicestream%Init(bounds, NLFilename) ! get initial fraction of excess ice per column - ! - ! If excess ice is being read from streams, use the streams to - ! initialize - ! - if ( UseExcessIceStreams() )then - call this%exicestream%CalcExcessIce(bounds, this%exice_bulk_init) - do c = bounds%begc,bounds%endc - g = col%gridcell(c) - l = col%landunit(c) - if (.not. lun%lakpoi(l)) then !not lake - if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then - if (zisoi(nlevsoi) >= 0.5_r8) then - call find_soil_layer_containing_depth(0.5_r8,n05m) - else - n05m=nlevsoi-1 - endif - if (use_bedrock .and. col%nbedrock(c) <=nlevsoi) then - nbedrock = col%nbedrock(c) - else - nbedrock = nlevsoi - endif - do j = 2, nlevmaxurbgrnd ! ignore first layer - if (n05m= n05m .and. j= exice_coldstart_depth) then + call find_soil_layer_containing_depth(exice_coldstart_depth,nexice) + else + nexice=nlevsoi-1 + endif + if (use_bedrock .and. col%nbedrock(c) <=nlevsoi) then + nbedrock = col%nbedrock(c) + else + nbedrock = nlevsoi endif - else ! just in case zeros for lakes and other columns - this%excess_ice_col(c,-nlevsno+1:nlevmaxurbgrnd) = 0.0_r8 + do j = 2, nlevmaxurbgrnd ! ignore first layer + if (nexice= nexice .and. j use excess ice physics diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 787b827605..0b4366a0cb 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -259,7 +259,8 @@ subroutine control_init(dtime) namelist /clm_inparm/ use_soil_moisture_streams - namelist /clm_inparm/ use_excess_ice + ! excess ice flag + namelist /clm_inparm/ use_excess_ice namelist /clm_inparm/ use_lai_streams diff --git a/src/unit_test_shr/unittestDustEmisInputs.F90 b/src/unit_test_shr/unittestDustEmisInputs.F90 index 6b15680ef7..af3ad63890 100644 --- a/src/unit_test_shr/unittestDustEmisInputs.F90 +++ b/src/unit_test_shr/unittestDustEmisInputs.F90 @@ -50,6 +50,7 @@ subroutine setUp(this) character(len=5) :: NLFilename = 'none' real(r8), allocatable :: urb_em(:) + real(r8), allocatable :: exice_init_conc_col(:) integer :: begl, endl, begc, endc integer :: c type(atm2lnd_params_type) :: atm2lnd_params @@ -91,12 +92,15 @@ subroutine setUp(this) call this%frictionvel_inst%InitForTesting(bounds) allocate( urb_em(begl:endl) ) urb_em(begl:endl) = 0.99_r8 ! Arbitrary won't matter here + allocate( exice_init_conc_col(begc:endc) ) + exice_init_conc_col(begc:endc) = 0.0_r8 ! zero, so it doesn't affect anything. call this%temperature_inst%Init(bounds, & em_roof_lun=urb_em(begl:endl), & em_wall_lun=urb_em(begl:endl), & em_improad_lun=urb_em(begl:endl), & em_perroad_lun=urb_em(begl:endl), & - is_simple_buildtemp=.true., is_prog_buildtemp=.false.) + is_simple_buildtemp=.true., is_prog_buildtemp=.false., & + exice_init_conc_col = exice_init_conc_col(begc:endc)) deallocate( urb_em ) end subroutine setUp diff --git a/src/unit_test_shr/unittestWaterTypeFactory.F90 b/src/unit_test_shr/unittestWaterTypeFactory.F90 index f5f417f9ce..2d83fd0058 100644 --- a/src/unit_test_shr/unittestWaterTypeFactory.F90 +++ b/src/unit_test_shr/unittestWaterTypeFactory.F90 @@ -91,6 +91,7 @@ end subroutine setup_after_subgrid subroutine create_water_type(this, water_inst, & t_soisno_col, watsat_col, & + exice_coldstart_depth, exice_init_conc_col, & enable_consistency_checks, enable_isotopes) ! Initialize water_inst ! @@ -113,6 +114,13 @@ subroutine create_water_type(this, water_inst, & ! 1..nlevgrnd. If not provided, we use arbitrary values for this variable. real(r8), intent(in), optional :: watsat_col( bounds%begc: , 1: ) + ! Depth below which excess ice is present on coldstart. + ! If not provided, we use an arbitrary value. + real(r8), intent(in), optional :: exice_coldstart_depth + ! Excess initial concentration for each column. + ! If not provided, is set to 0. + real(r8), intent(in), optional :: exice_init_conc_col(bounds%begc:) + logical, intent(in), optional :: enable_consistency_checks logical, intent(in), optional :: enable_isotopes @@ -121,6 +129,8 @@ subroutine create_water_type(this, water_inst, & type(water_params_type) :: params real(r8) :: l_watsat_col(bounds%begc:bounds%endc, nlevgrnd) real(r8) :: l_t_soisno_col(bounds%begc:bounds%endc, -nlevsno+1:nlevgrnd) + real(r8) :: l_exice_coldstart_depth + real(r8) :: l_exice_init_conc_col(bounds%begc:bounds%endc) if (present(t_soisno_col)) then SHR_ASSERT_ALL_FL((ubound(t_soisno_col) == [bounds%endc, nlevgrnd]), sourcefile, __LINE__) @@ -129,6 +139,10 @@ subroutine create_water_type(this, water_inst, & SHR_ASSERT_ALL_FL((ubound(watsat_col) == [bounds%endc, nlevgrnd]), sourcefile, __LINE__) end if + if (present(exice_init_conc_col)) then + SHR_ASSERT_ALL_FL((ubound(exice_init_conc_col,1) == bounds%endc), sourcefile, __LINE__) + endif + if (present(enable_consistency_checks)) then l_enable_consistency_checks = enable_consistency_checks else @@ -157,12 +171,24 @@ subroutine create_water_type(this, water_inst, & l_t_soisno_col(:,:) = 275._r8 end if + if (present(exice_coldstart_depth)) then + l_exice_coldstart_depth = exice_coldstart_depth + else + l_exice_coldstart_depth = 0.5_r8 + endif + if (present(exice_init_conc_col)) then + l_exice_init_conc_col(:) = exice_init_conc_col + else + l_exice_init_conc_col(:) = 0.0_r8 + endif + call water_inst%InitForTesting(bounds, params, & h2osno_col = col_array(0._r8), & snow_depth_col = col_array(0._r8), & watsat_col = l_watsat_col, & t_soisno_col = l_t_soisno_col, & - NLFilename = ' ') + exice_coldstart_depth = l_exice_coldstart_depth, & + exice_init_conc_col = l_exice_init_conc_col) end subroutine create_water_type subroutine teardown(this, water_inst)