diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm
index 9562cca9bd..c88af453b5 100755
--- a/bld/CLMBuildNamelist.pm
+++ b/bld/CLMBuildNamelist.pm
@@ -5315,6 +5315,7 @@ sub write_output_files {
push @groups, "clm_canopy_inparm";
push @groups, "prigentroughness";
push @groups, "zendersoilerod";
+ push @groups, "for_testing_options";
if (remove_leading_and_trailing_quotes($nl->get_value('snow_cover_fraction_method')) eq 'SwensonLawrence2012') {
push @groups, "scf_swenson_lawrence_2012_inparm";
}
diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml
index 69a243bd27..2b5b4f2e99 100644
--- a/bld/namelist_files/namelist_definition_ctsm.xml
+++ b/bld/namelist_files/namelist_definition_ctsm.xml
@@ -1259,12 +1259,38 @@ Whether to use subgrid fluxes for snow
Whether snow on the vegetation canopy affects the radiation/albedo calculations
+
+
+
+
+
+
+For testing whether to bypass the rest of the initialization after the self test driver is run
+
+
+
+For testing whether to bypass most of the run phase other than the clock advance
+
+
+
+Whether to exit early after the initialization self tests are run. This is typically only used in automated tests.
+
+
+ group="for_testing_options" >
Whether to run some tests of ncdio_pio as part of the model run. This is
typically only used in automated tests.
+
+Whether to run some tests of decompInit (to get the gridcell to MPI task decomposition) as part of the model run. This is
+typically only used in automated tests.
+
+
If true, allocate memory for and use a second crop grain pool. This is
diff --git a/cime_config/buildlib b/cime_config/buildlib
index a4b853924e..3ce5080dc4 100755
--- a/cime_config/buildlib
+++ b/cime_config/buildlib
@@ -135,6 +135,7 @@ def _main_func():
os.path.join(lnd_root, "src", "dyn_subgrid"),
os.path.join(lnd_root, "src", "init_interp"),
os.path.join(lnd_root, "src", "self_tests"),
+ os.path.join(lnd_root, "src", "unit_test_shr"),
os.path.join(lnd_root, "src", "fates"),
os.path.join(lnd_root, "src", "fates", "main"),
os.path.join(lnd_root, "src", "fates", "biogeophys"),
diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml
index f8f05bf5f1..c5cc54e19d 100644
--- a/cime_config/testdefs/ExpectedTestFails.xml
+++ b/cime_config/testdefs/ExpectedTestFails.xml
@@ -381,45 +381,4 @@
-
-
- FAIL
- #3316
-
-
-
-
-
-
-
- FAIL
- #3383
-
-
-
-
-
- FAIL
- #3383
-
-
-
-
- FAIL
- #3494
-
-
-
-
-
- FAIL
- #3496
-
-
-
-
- FAIL
- #3507
-
-
diff --git a/cime_config/testdefs/testmods_dirs/clm/for_testing_fastsetup_bypassrun/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/for_testing_fastsetup_bypassrun/user_nl_clm
index c2a2d14793..573df5c02e 100644
--- a/cime_config/testdefs/testmods_dirs/clm/for_testing_fastsetup_bypassrun/user_nl_clm
+++ b/cime_config/testdefs/testmods_dirs/clm/for_testing_fastsetup_bypassrun/user_nl_clm
@@ -1,3 +1,6 @@
+! Exit early and bypass the run phase
+for_testing_exit_after_self_tests = .true.
+
! Turn off history, restarts, and output
hist_empty_htapes = .true.
use_noio = .true.
diff --git a/cime_config/testdefs/testmods_dirs/clm/run_self_tests/shell_commands b/cime_config/testdefs/testmods_dirs/clm/run_self_tests/shell_commands
new file mode 100755
index 0000000000..9383f70de0
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/run_self_tests/shell_commands
@@ -0,0 +1,9 @@
+#!/bin/bash
+./xmlchange CLM_FORCE_COLDSTART="on"
+
+# We use this testmod in a _Ln1 test; this requires forcing the ROF coupling frequency to every time step
+./xmlchange ROF_NCPL=48
+
+# Restarts aren't allowed for these tests, and turn off CPL history
+./xmlchange REST_OPTION="never"
+./xmlchange HIST_OPTION="never"
diff --git a/cime_config/testdefs/testmods_dirs/clm/run_self_tests/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/run_self_tests/user_nl_clm
index 9e8e0fcd04..3a71b46936 100644
--- a/cime_config/testdefs/testmods_dirs/clm/run_self_tests/user_nl_clm
+++ b/cime_config/testdefs/testmods_dirs/clm/run_self_tests/user_nl_clm
@@ -1,5 +1,14 @@
+! Bypass as much of the init phase as can be done
+! Bypassing the run phase already was inherited from the for_testing_fastsetup_bypassrun testmod
+for_testing_bypass_init = .true.
+
+! Turn on some of the self tests
for_testing_run_ncdiopio_tests = .true.
! Turn off history, restarts, and output
hist_empty_htapes = .true.
use_noio = .true.
+for_testing_run_decomp_init_tests = .true.
+
+! Exit initialization phase after the self tests
+for_testing_bypass_init = .true.
diff --git a/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90
index 3db987f2fa..6d5483ca3e 100644
--- a/src/cpl/nuopc/lnd_comp_nuopc.F90
+++ b/src/cpl/nuopc/lnd_comp_nuopc.F90
@@ -29,6 +29,7 @@ module lnd_comp_nuopc
use NUOPC_Model , only : NUOPC_ModelGet
use shr_kind_mod , only : r8 => shr_kind_r8, cl=>shr_kind_cl
use shr_sys_mod , only : shr_sys_abort
+ use shr_sys_mod , only : shr_sys_flush
use shr_log_mod , only : shr_log_setLogUnit, shr_log_getLogUnit
use shr_orb_mod , only : shr_orb_decl, shr_orb_params, SHR_ORB_UNDEF_REAL, SHR_ORB_UNDEF_INT
use shr_cal_mod , only : shr_cal_noleap, shr_cal_gregorian, shr_cal_ymd2date
@@ -39,6 +40,7 @@ module lnd_comp_nuopc
use clm_varctl , only : single_column, clm_varctl_set, iulog
use clm_varctl , only : nsrStartup, nsrContinue, nsrBranch
use clm_varctl , only : FL => fname_len
+ use clm_varctl , only : for_testing_exit_after_self_tests
use clm_time_manager , only : set_timemgr_init, advance_timestep
use clm_time_manager , only : update_rad_dtime
use clm_time_manager , only : get_nstep, get_step_size
@@ -49,6 +51,7 @@ module lnd_comp_nuopc
use lnd_import_export , only : advertise_fields, realize_fields, import_fields, export_fields
use lnd_comp_shr , only : mesh, model_meshfile, model_clock
use perf_mod , only : t_startf, t_stopf, t_barrierf
+ use SelfTestDriver , only : for_testing_exit_after_self_tests
implicit none
private ! except
@@ -80,8 +83,9 @@ module lnd_comp_nuopc
logical :: glc_present
logical :: rof_prognostic
+ logical :: atm_present
logical :: atm_prognostic
- integer, parameter :: dbug = 0
+ integer, parameter :: dbug = 1
character(*),parameter :: modName = "(lnd_comp_nuopc)"
character(len=CL) :: orb_mode ! attribute - orbital mode
@@ -196,7 +200,6 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
type(ESMF_VM) :: vm
integer :: lmpicom
integer :: ierr
- integer :: n
integer :: localPet ! local PET (Persistent Execution Threads) (both MPI tasks and OpenMP threads)
integer :: compid ! component id
integer :: shrlogunit ! original log unit
@@ -284,6 +287,11 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
else
atm_prognostic = .true.
end if
+ if (trim(atm_model) == 'satm') then
+ atm_present = .false.
+ else
+ atm_present = .true.
+ end if
call NUOPC_CompAttributeGet(gcomp, name='GLC_model', value=glc_model, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
if (trim(glc_model) == 'sglc') then
@@ -310,6 +318,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
write(iulog,'(a )')' rof component = '//trim(rof_model)
write(iulog,'(a )')' glc component = '//trim(glc_model)
write(iulog,'(a,L2)')' atm_prognostic = ',atm_prognostic
+ if (.not. atm_present) then
+ write(iulog,'(a,L2)')' atm_present = ',atm_present
+ end if
write(iulog,'(a,L2)')' rof_prognostic = ',rof_prognostic
write(iulog,'(a,L2)')' glc_present = ',glc_present
if (glc_present) then
@@ -328,7 +339,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
call control_setNL("lnd_in"//trim(inst_suffix))
- call advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, rof_prognostic, atm_prognostic, rc)
+ call advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, rof_prognostic, &
+ atm_prognostic, atm_present, rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
!----------------------------------------------------------------------------
@@ -339,6 +351,46 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
end subroutine InitializeAdvertise
+ !===============================================================================
+ subroutine ZeroState( State, flds_scalar_name, rc )
+ type(ESMF_State) :: State
+ character(len=CL), intent(IN) :: flds_scalar_name
+ integer , intent(out) :: rc
+ ! Zero the input state fields
+ integer :: fieldCount ! Number of fields on export state
+ character(CL) ,pointer :: lfieldnamelist(:) => null() ! Land field namelist item sent with land field
+ type(ESMF_Field) :: lfield ! Land field read in
+ integer :: rank ! Rank of field (0D or 2D)
+ real(r8), pointer :: fldptr1d(:) ! 1D field pointer
+ real(r8), pointer :: fldptr2d(:,:) ! 2D field pointer
+ integer :: n
+
+ rc = ESMF_SUCCESS
+ call ESMF_StateGet(State, itemCount=fieldCount, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ allocate(lfieldnamelist(fieldCount))
+ call ESMF_StateGet(State, itemNameList=lfieldnamelist, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ do n = 0, fieldCount
+ if (trim(lfieldnamelist(n)) /= flds_scalar_name) then
+ call ESMF_StateGet(State, itemName=trim(lfieldnamelist(n)), field=lfield, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call ESMF_FieldGet(lfield, rank=rank, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ if (rank == 1) then
+ call ESMF_FieldGet(lfield, farrayPtr=fldptr2d, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ fldptr2d(:,:) = 0._r8
+ else
+ call ESMF_FieldGet(lfield, farrayPtr=fldptr1d, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ fldptr1d(:) = 0._r8
+ end if
+ end if
+ enddo
+ deallocate(lfieldnamelist)
+ end subroutine ZeroState
+
!===============================================================================
subroutine InitializeRealize(gcomp, importState, exportState, clock, rc)
@@ -351,6 +403,8 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc)
use lnd_set_decomp_and_domain , only : lnd_set_decomp_and_domain_from_readmesh
use lnd_set_decomp_and_domain , only : lnd_set_mesh_for_single_column
use lnd_set_decomp_and_domain , only : lnd_set_decomp_and_domain_for_single_column
+ use SelfTestDriver , only : for_testing_bypass_init_after_self_tests, &
+ for_testing_exit_after_self_tests
! input/output variables
type(ESMF_GridComp) :: gcomp
@@ -395,12 +449,6 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc)
real(r8) :: scol_spval ! single-column special value to indicate it isn't set
character(len=FL) :: single_column_lnd_domainfile ! domain filename to use for single-column mode (i.e. SCAM)
type(bounds_type) :: bounds ! bounds
- type(ESMF_Field) :: lfield ! Land field read in
- character(CL) ,pointer :: lfieldnamelist(:) => null() ! Land field namelist item sent with land field
- integer :: fieldCount ! Number of fields on export state
- integer :: rank ! Rank of field (1D or 2D)
- real(r8), pointer :: fldptr1d(:) ! 1D field pointer
- real(r8), pointer :: fldptr2d(:,:) ! 2D field pointer
logical :: isPresent ! If attribute is present
logical :: isSet ! If attribute is present and also set
character(len=CL) :: model_version ! Model version
@@ -464,31 +512,11 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc)
! if single column is not valid - set all export state fields to zero and return
call realize_fields(importState, exportState, mesh, flds_scalar_name, flds_scalar_num, rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
- call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
- allocate(lfieldnamelist(fieldCount))
- call ESMF_StateGet(exportState, itemNameList=lfieldnamelist, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
- do n = 1, fieldCount
- if (trim(lfieldnamelist(n)) /= flds_scalar_name) then
- call ESMF_StateGet(exportState, itemName=trim(lfieldnamelist(n)), field=lfield, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
- call ESMF_FieldGet(lfield, rank=rank, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
- if (rank == 2) then
- call ESMF_FieldGet(lfield, farrayPtr=fldptr2d, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- fldptr2d(:,:) = 0._r8
- else
- call ESMF_FieldGet(lfield, farrayPtr=fldptr1d, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- fldptr1d(:) = 0._r8
- end if
- end if
- enddo
- deallocate(lfieldnamelist)
+ call ZeroState( exportState, flds_scalar_name, rc )
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
! Close the timer for the subroutine
call t_stopf ('lc_lnd_init_realize')
+
! *******************
! *** RETURN HERE ***
! *******************
@@ -500,6 +528,12 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc)
else
single_column = .false.
end if
+ !if ( for_testing_exit_after_self_tests) then
+ ! *******************
+ ! *** RETURN HERE ***
+ ! *******************
+ !RETURN
+ !end if
!----------------------------------------------------------------------------
! Reset shr logging to my log file
@@ -676,22 +710,44 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc)
call t_startf('clm_init2')
call initialize2(ni, nj, currtime)
call t_stopf('clm_init2')
+ if (for_testing_exit_after_self_tests) then
+ RETURN
+ end if
!--------------------------------
! Create land export state
!--------------------------------
+ if ( .not. for_testing_bypass_init_after_self_tests() ) then
call get_proc_bounds(bounds)
call export_fields(gcomp, bounds, glc_present, rof_prognostic, &
water_inst%waterlnd2atmbulk_inst, lnd2atm_inst, lnd2glc_inst, rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ end if
+
+ if ( for_testing_exit_after_self_tests ) then
+ if ( masterproc ) then
+ write(iulog,'(a)')' calling ZeroState'
+ call shr_sys_flush(iulog)
+ end if
+ call ZeroState( exportState, flds_scalar_name, rc )
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ end if
! Set scalars in export state
+ if ( masterproc ) then
+ write(iulog,'(a)')' calling State_SetScalar'
+ call shr_sys_flush(iulog)
+ end if
call State_SetScalar(dble(ldomain%ni), flds_scalar_index_nx, exportState, &
flds_scalar_name, flds_scalar_num, rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
call State_SetScalar(dble(ldomain%nj), flds_scalar_index_ny, exportState, &
flds_scalar_name, flds_scalar_num, rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ if ( masterproc ) then
+ write(iulog,'(a)')' after State_SetScalar'
+ call shr_sys_flush(iulog)
+ end if
!--------------------------------
! diagnostics
@@ -731,6 +787,7 @@ subroutine ModelAdvance(gcomp, rc)
use clm_instMod , only : water_inst, atm2lnd_inst, glc2lnd_inst, lnd2atm_inst, lnd2glc_inst
use decompMod , only : bounds_type, get_proc_bounds
use clm_driver , only : clm_drv
+ use SelfTestDriver, only : for_testing_bypass_init_after_self_tests
! input/output variables
type(ESMF_GridComp) :: gcomp
@@ -786,6 +843,9 @@ subroutine ModelAdvance(gcomp, rc)
if (single_column .and. .not. scol_valid) then
RETURN
end if
+ !if (for_testing_exit_after_self_tests) then
+ ! RETURN
+ !end if
!$ call omp_set_num_threads(nthrds)
@@ -818,16 +878,20 @@ subroutine ModelAdvance(gcomp, rc)
flds_scalar_index_nextsw_cday, nextsw_cday, &
flds_scalar_name, flds_scalar_num, rc)
- ! Get proc bounds
- call get_proc_bounds(bounds)
-
!--------------------------------
! Unpack import state
!--------------------------------
+ if ( .not. for_testing_bypass_init_after_self_tests() ) then
+ ! Get proc bounds for both import and export
+ call get_proc_bounds(bounds)
+
+ call t_startf ('lc_lnd_import')
call import_fields( gcomp, bounds, glc_present, rof_prognostic, &
atm2lnd_inst, glc2lnd_inst, water_inst%wateratm2lndbulk_inst, rc )
if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ call t_stopf ('lc_lnd_import')
+ end if
!--------------------------------
! Run model
@@ -902,24 +966,33 @@ subroutine ModelAdvance(gcomp, rc)
call shr_orb_decl( calday , eccen, mvelpp, lambm0, obliqr, declin , eccf )
call shr_orb_decl( nextsw_cday, eccen, mvelpp, lambm0, obliqr, declinp1, eccf )
- call t_startf ('ctsm_run')
- ! Restart File - use nexttimestr rather than currtimestr here since that is the time at the end of
- ! the timestep and is preferred for restart file names
- call ESMF_ClockGetNextTime(clock, nextTime=nextTime, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- call ESMF_TimeGet(nexttime, yy=yr_sync, mm=mon_sync, dd=day_sync, s=tod_sync, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- write(rdate,'(i4.4,"-",i2.2,"-",i2.2,"-",i5.5)') yr_sync, mon_sync, day_sync, tod_sync
- call clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, rof_prognostic)
- call t_stopf ('ctsm_run')
+ !
+ ! Run for nortmal CTSM -- but not if skipping run for testing
+ !
+ if ( .not. for_testing_exit_after_self_tests ) then
+ call t_startf ('ctsm_run')
+ ! Restart File - use nexttimestr rather than currtimestr here since that is the time at the end of
+ ! the timestep and is preferred for restart file names
+ call ESMF_ClockGetNextTime(clock, nextTime=nextTime, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ call ESMF_TimeGet(nexttime, yy=yr_sync, mm=mon_sync, dd=day_sync, s=tod_sync, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ write(rdate,'(i4.4,"-",i2.2,"-",i2.2,"-",i5.5)') yr_sync, mon_sync, day_sync, tod_sync
+ call clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, rof_prognostic)
+ call t_stopf ('ctsm_run')
+ end if
!--------------------------------
! Pack export state
!--------------------------------
+ if ( .not. for_testing_bypass_init_after_self_tests() ) then
+ call t_startf ('lc_lnd_export')
call export_fields(gcomp, bounds, glc_present, rof_prognostic, &
water_inst%waterlnd2atmbulk_inst, lnd2atm_inst, lnd2glc_inst, rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ call t_stopf ('lc_lnd_export')
+ end if
!--------------------------------
! Advance ctsm time step
@@ -1009,6 +1082,7 @@ subroutine ModelSetRunClock(gcomp, rc)
rc = ESMF_SUCCESS
call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO)
if (.not. scol_valid) return
+ !if (for_testing_exit_after_self_tests) return
! query the Component for its clocks
call NUOPC_ModelGet(gcomp, driverClock=dclock, modelClock=mclock, rc=rc)
@@ -1292,6 +1366,7 @@ subroutine clm_orbital_update(clock, logunit, mastertask, eccen, obliqr, lambm0
end subroutine clm_orbital_update
subroutine CheckImport(gcomp, rc)
+ use clm_varctl, only : for_testing_exit_after_self_tests
type(ESMF_GridComp) :: gcomp
integer, intent(out) :: rc
character(len=*) , parameter :: subname = "("//__FILE__//":CheckImport)"
@@ -1320,6 +1395,9 @@ subroutine CheckImport(gcomp, rc)
if (single_column .and. .not. scol_valid) then
RETURN
end if
+ !if (for_testing_exit_after_self_tests) then
+ !RETURN
+ !end if
! The remander of this should be equivalent to the NUOPC internal routine
! from NUOPC_ModeBase.F90
diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90
index 624590b9a6..9ffe56ddaa 100644
--- a/src/cpl/nuopc/lnd_import_export.F90
+++ b/src/cpl/nuopc/lnd_import_export.F90
@@ -156,7 +156,8 @@ module lnd_import_export
contains
!===============================================================================
- subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, rof_prognostic, atm_prognostic, rc)
+ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, rof_prognostic, &
+ atm_prognostic, atm_present, rc)
use shr_carma_mod , only : shr_carma_readnl
use shr_ndep_mod , only : shr_ndep_readnl
@@ -173,6 +174,7 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r
logical , intent(in) :: cism_evolve
logical , intent(in) :: rof_prognostic
logical , intent(in) :: atm_prognostic
+ logical , intent(in) :: atm_present
integer , intent(out) :: rc
! local variables
@@ -210,7 +212,9 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r
! Need to determine if there is no land for single column before the advertise call is done
- if (atm_prognostic .or. force_send_to_atm) then
+ if (.not. atm_present)then
+ send_to_atm = .false.
+ else if (atm_prognostic .or. force_send_to_atm) then
send_to_atm = .true.
else
send_to_atm = .false.
@@ -253,12 +257,11 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r
if (shr_megan_mechcomps_n .ne. megan_nflds) call shr_sys_abort('ERROR: megan field count mismatch')
! CARMA volumetric soil water from land
- call shr_carma_readnl('drv_flds_in', carma_fields)
! export to atm
call fldlist_add(fldsFrLnd_num, fldsFrlnd, trim(flds_scalar_name))
- call fldlist_add(fldsFrLnd_num, fldsFrlnd, 'Sl_lfrin')
if (send_to_atm) then
+ call fldlist_add(fldsFrLnd_num, fldsFrlnd, 'Sl_lfrin')
call fldlist_add(fldsFrLnd_num, fldsFrlnd, Sl_t )
call fldlist_add(fldsFrLnd_num, fldsFrlnd, Sl_tref )
call fldlist_add(fldsFrLnd_num, fldsFrlnd, Sl_qref )
@@ -339,6 +342,9 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r
call fldlist_add(fldsToLnd_num, fldsToLnd, trim(flds_scalar_name))
+ !!!!!!!!!!!!!!!!!!!!!!!!!!! new if section !!!!!!!!!!!!!!!!!!!!!!!!!!
+ if ( atm_present ) then
+
! from atm
call fldlist_add(fldsToLnd_num, fldsToLnd, Sa_z )
call fldlist_add(fldsToLnd_num, fldsToLnd, Sa_topo )
@@ -389,6 +395,9 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r
call fldlist_add(fldsToLnd_num, fldsToLnd, Sa_co2diag)
end if
+ end if ! atm_present
+ !!!!!!!!!!!!!!!!!!!!!!!!!!! new if section !!!!!!!!!!!!!!!!!!!!!!!!!!
+
if (rof_prognostic) then
! from river
call fldlist_add(fldsToLnd_num, fldsToLnd, Flrr_flood )
@@ -779,8 +788,8 @@ subroutine export_fields( gcomp, bounds, glc_present, rof_prognostic, &
! -----------------------
! output to atm
! -----------------------
-
if (send_to_atm) then
+
call state_setexport_1d(exportState, Sl_t , lnd2atm_inst%t_rad_grc(begg:), &
init_spval=.true., rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90
index 3a47a7eed3..279154f52c 100644
--- a/src/main/clm_driver.F90
+++ b/src/main/clm_driver.F90
@@ -85,6 +85,7 @@ module clm_driver
use clm_instMod
use SoilMoistureStreamMod , only : PrescribedSoilMoistureInterp, PrescribedSoilMoistureAdvance
use SoilBiogeochemDecompCascadeConType , only : no_soil_decomp, decomp_method
+ use SelfTestDriver , only : for_testing_bypass_run_except_clock_advance
!
! !PUBLIC TYPES:
implicit none
@@ -165,6 +166,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro
! CalcIrrigationNeeded. Simply declaring this variable makes the ICE go away.
real(r8), allocatable :: dummy1_to_make_pgi_happy(:)
!-----------------------------------------------------------------------
+ if ( for_testing_bypass_run_except_clock_advance() ) return
! Determine processor bounds and clumps for this processor
@@ -1576,6 +1578,8 @@ subroutine clm_drv_init(bounds, &
integer :: fp, fc ! filter indices
!-----------------------------------------------------------------------
+ if ( for_testing_bypass_run_except_clock_advance() ) return
+
associate( &
snl => col%snl , & ! Input: [integer (:) ] number of snow layers
@@ -1657,6 +1661,7 @@ subroutine clm_drv_patch2col (bounds, &
! !LOCAL VARIABLES:
integer :: c,fc ! indices
! -----------------------------------------------------------------
+ if ( for_testing_bypass_run_except_clock_advance() ) return
! Note: lake points are excluded from many of the following
! averages. For some fields, this is because the field doesn't
@@ -1752,6 +1757,8 @@ subroutine write_diagnostic (bounds, nstep, lnd2atm_inst)
integer :: status(MPI_STATUS_SIZE) ! mpi status
!------------------------------------------------------------------------
+ if ( for_testing_bypass_run_except_clock_advance() ) return
+
call get_proc_global(ng=numg)
if (masterproc) then
diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90
index 1c26b55cfd..0ffa7737a8 100644
--- a/src/main/clm_initializeMod.F90
+++ b/src/main/clm_initializeMod.F90
@@ -30,7 +30,7 @@ module clm_initializeMod
use CLMFatesInterfaceMod , only : CLMFatesGlobals1,CLMFatesGlobals2
use CLMFatesInterfaceMod , only : CLMFatesTimesteps
use dynSubgridControlMod , only : dynSubgridControl_init, get_reset_dynbal_baselines
- use SelfTestDriver , only : self_test_driver
+ use SelfTestDriver , only : self_test_driver, for_testing_bypass_init_after_self_tests
use SoilMoistureStreamMod , only : PrescribedSoilMoistureInit
use clm_instMod
!
@@ -67,6 +67,7 @@ subroutine initialize1(dtime)
use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_par_init
use CropReprPoolsMod , only: crop_repr_pools_init
use HillslopeHydrologyMod, only: hillslope_properties_init
+ use SelfTestDriver , only: self_test_readnml
!
! !ARGUMENTS
integer, intent(in) :: dtime ! model time step (seconds)
@@ -102,6 +103,8 @@ subroutine initialize1(dtime)
call surfrd_get_num_patches(fsurdat, actual_maxsoil_patches, actual_numpft, actual_numcft)
call surfrd_get_nlevurb(fsurdat, actual_nlevurb)
+ call self_test_readnml( NLFilename )
+
! If fates is on, we override actual_maxsoil_patches. FATES dictates the
! number of patches per column. We still use numcft from the surface
! file though...
@@ -182,6 +185,7 @@ subroutine initialize2(ni,nj, currtime)
use FATESFireFactoryMod , only : scalar_lightning
use dynFATESLandUseChangeMod , only : dynFatesLandUseInit
use HillslopeHydrologyMod , only : InitHillslope
+ use SelfTestDriver , only : for_testing_bypass_init_after_self_tests
!
! !ARGUMENTS
integer, intent(in) :: ni, nj ! global grid sizes
@@ -333,6 +337,7 @@ subroutine initialize2(ni,nj, currtime)
! Run any requested self-tests
call self_test_driver(bounds_proc)
+ if ( .not. for_testing_bypass_init_after_self_tests() )then
! Deallocate surface grid dynamic memory for variables that aren't needed elsewhere.
! Some things are kept until the end of initialize2; urban_valid is kept through the
! end of the run for error checking, pct_urban_max is kept through the end of the run
@@ -349,8 +354,9 @@ subroutine initialize2(ni,nj, currtime)
allocate(nutrient_competition_method, &
source=create_nutrient_competition_method(bounds_proc))
call readParameters(photosyns_inst)
-
+ end if ! End of bypass
+ ! Self test skipping should still do the time manager initialization
! Initialize time manager
if (nsrest == nsrStartup) then
call timemgr_init()
@@ -376,6 +382,7 @@ subroutine initialize2(ni,nj, currtime)
call t_stopf('clm_init2_part2')
call t_startf('clm_init2_part3')
+ if ( .not. for_testing_bypass_init_after_self_tests() )then
! Initialize Balance checking (after time-manager)
call BalanceCheckInit()
@@ -423,7 +430,9 @@ subroutine initialize2(ni,nj, currtime)
call SnowAge_init( ) ! SNICAR aging parameters:
! Print history field info to standard out
- call hist_printflds()
+ if ( .not. use_noio )then
+ call hist_printflds()
+ end if
! Initializate dynamic subgrid weights (for prescribed transient Patches, CNDV
! and/or dynamic landunits); note that these will be overwritten in a restart run
@@ -508,6 +517,7 @@ subroutine initialize2(ni,nj, currtime)
if (nsrest == nsrContinue ) then
call htapes_fieldlist()
end if
+ end if ! End of bypass
! Read restart/initial info
is_cold_start = .false.
@@ -601,6 +611,8 @@ subroutine initialize2(ni,nj, currtime)
call t_stopf('clm_init2_init_interp')
end if
+ if ( .not. for_testing_bypass_init_after_self_tests() )then
+
! If requested, reset dynbal baselines
! This needs to happen after reading the restart file (including after reading the
! interpolated restart file, if applicable).
@@ -759,6 +771,7 @@ subroutine initialize2(ni,nj, currtime)
water_inst%waterdiagnosticbulk_inst, canopystate_inst, &
soilstate_inst, soilbiogeochem_carbonflux_inst)
end if
+ end if ! end of bypass
! topo_glc_mec was allocated in initialize1, but needed to be kept around through
! initialize2 because it is used to initialize other variables; now it can be deallocated
diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90
index 9a0d2901b9..15d2c12b91 100644
--- a/src/main/clm_varctl.F90
+++ b/src/main/clm_varctl.F90
@@ -52,6 +52,12 @@ module clm_varctl
! true => run tests of ncdio_pio
logical, public :: for_testing_run_ncdiopio_tests = .false.
+ ! true => run tests of decompInit
+ logical, public :: for_testing_run_decomp_init_tests = .false.
+
+ ! true => exit after the self-tests run
+ logical, public :: for_testing_exit_after_self_tests = .false.
+
! true => allocate memory for and use a second grain pool. This is meant only for
! software testing of infrastructure to support the AgSys crop model integration. This
! option can be dropped once AgSys is integrated and we have tests of it.
diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90
index 089503dc8b..4a956e33b2 100644
--- a/src/main/controlMod.F90
+++ b/src/main/controlMod.F90
@@ -210,7 +210,7 @@ subroutine control_init(dtime)
snow_thermal_cond_method, snow_thermal_cond_glc_method, &
snow_thermal_cond_lake_method, snow_cover_fraction_method, &
irrigate, run_zero_weight_urban, all_active, &
- crop_fsat_equals_zero, for_testing_run_ncdiopio_tests, &
+ crop_fsat_equals_zero, &
for_testing_use_second_grain_pool, for_testing_use_repr_structure_pool, &
for_testing_no_crop_seed_replenishment, &
z0param_method, use_z0m_snowmelt
@@ -766,9 +766,6 @@ subroutine control_spmd()
! Crop saturated excess runoff
call mpi_bcast(crop_fsat_equals_zero, 1, MPI_LOGICAL, 0, mpicom, ier)
- ! Whether to run tests of ncdio_pio
- call mpi_bcast(for_testing_run_ncdiopio_tests, 1, MPI_LOGICAL, 0, mpicom, ier)
-
! Various flags used for testing infrastructure for having multiple crop reproductive pools
call mpi_bcast(for_testing_use_second_grain_pool, 1, MPI_LOGICAL, 0, mpicom, ier)
call mpi_bcast(for_testing_use_repr_structure_pool, 1, MPI_LOGICAL, 0, mpicom, ier)
diff --git a/src/self_tests/SelfTestDriver.F90 b/src/self_tests/SelfTestDriver.F90
index d109a27827..4536b4b946 100644
--- a/src/self_tests/SelfTestDriver.F90
+++ b/src/self_tests/SelfTestDriver.F90
@@ -6,9 +6,10 @@ module SelfTestDriver
!
! See the README file in this directory for a high-level overview of these self-tests.
- use clm_varctl, only : for_testing_run_ncdiopio_tests
use decompMod, only : bounds_type
use TestNcdioPio, only : test_ncdio_pio
+ use abortutils, only : endrun
+ use clm_varctl, only : iulog
implicit none
private
@@ -16,7 +17,17 @@ module SelfTestDriver
! Public routines
- public :: self_test_driver
+ public :: self_test_driver ! Run the self-tests asked for
+ public :: self_test_readnml ! Read in the general self testing options for overall code flow
+ public :: for_testing_bypass_init_after_self_tests ! For testing bypass the rest of the initialization after the self test driver was run
+ public :: for_testing_bypass_run_except_clock_advance ! For testing bypass most of the run phase other than the clock advance
+
+ ! Private module data
+ logical :: for_testing_bypass_init ! For testing bypass the initialization phase after the self-test driver
+ logical :: for_testing_bypass_run ! For testing bypass most of the run phase except the time advance
+ logical :: for_testing_run_ncdiopio_tests ! true => run tests of ncdio_pio
+ logical :: for_testing_run_decomp_init_tests ! true => run tests of decompInit
+ logical, public :: for_testing_exit_after_self_tests ! true => exit after running self tests
character(len=*), parameter, private :: sourcefile = &
__FILE__
@@ -32,18 +43,127 @@ subroutine self_test_driver(bounds)
! This subroutine should be called all the time, but each set of self tests is only
! run if the appropriate flag is set.
!
+ ! !USES:
+ use decompMod, only : bounds_type
+ use TestNcdioPio, only : test_ncdio_pio
+ use ESMF, only : ESMF_LogWrite, ESMF_LOGMSG_INFO, ESMF_Finalize
+ use shr_sys_mod, only : shr_sys_flush
+ use spmdMod, only : masterproc
! !ARGUMENTS:
type(bounds_type), intent(in) :: bounds
!
! !LOCAL VARIABLES:
character(len=*), parameter :: subname = 'self_test_driver'
+ integer :: ntests = 0
!-----------------------------------------------------------------------
if (for_testing_run_ncdiopio_tests) then
+ ntests = ntests + 1
call test_ncdio_pio(bounds)
end if
+ if (for_testing_run_decomp_init_tests) then
+ ntests = ntests + 1
+ end if
+ if (for_testing_exit_after_self_tests) then
+ ! Print out some messaging if we are exiting after self tests.
+ if ( masterproc ) then
+ if ( ntests == 0 )then
+ write(iulog,*) 'WARNING: You are exiting after self tests were run -- but no self tests were run.'
+ else
+ write(iulog,*) 'Exiting after running ', ntests, ' self tests.'
+ end if
+ call shr_sys_flush(iulog)
+ call ESMF_LogWrite(' exiting after running self tests', ESMF_LOGMSG_INFO)
+ end if
+ end if
end subroutine self_test_driver
+ !-----------------------------------------------------------------------
+ subroutine self_test_readnml(NLFileName)
+ !
+ ! !DESCRIPTION:
+ ! Namelist read for the self-test driver. This includes bypass options
+ ! that will be used in other parts of the code to bypass bits of the code
+ ! for testing purposes.
+ !
+ ! !USES:
+ use shr_nl_mod , only : shr_nl_find_group_name
+ use spmdMod, only : masterproc, mpicom
+ use shr_mpi_mod, only : shr_mpi_bcast
+ use clm_varctl, only : iulog
+ !
+ ! !ARGUMENTS:
+ character(len=*), intent(in) :: NLFilename ! Namelist filename
+ !
+ ! !LOCAL VARIABLES:
+ integer :: ierr ! error code
+ integer :: unitn ! unit for namelist file
+
+ ! Namelist name: this has to be matched with the name in the read stqatement
+ character(len=*), parameter :: nmlname = 'for_testing_options'
+ !-----------------------------------------------------------------------
+
+ namelist /for_testing_options/ for_testing_bypass_init, for_testing_bypass_run, &
+ for_testing_run_ncdiopio_tests, for_testing_run_decomp_init_tests, &
+ for_testing_exit_after_self_tests
+
+ ! Initialize options to default values, in case they are not specified in
+ ! the namelist
+
+ if (masterproc) then
+ write(iulog,*) 'Read in '//nmlname//' namelist'
+ open(newunit=unitn, status='old', file=NLFilename)
+ call shr_nl_find_group_name(unitn, nmlname, status=ierr)
+ if (ierr == 0) then
+ read(unit=unitn, nml=for_testing_options, iostat=ierr)
+ if (ierr /= 0) then
+ call endrun(msg="ERROR reading "//nmlname//"namelist", file=sourcefile, line=__LINE__)
+ end if
+ else
+ call endrun(msg="ERROR finding "//nmlname//"namelist", file=sourcefile, line=__LINE__)
+ end if
+ close(unitn)
+ end if
+
+ call shr_mpi_bcast (for_testing_bypass_init, mpicom)
+ call shr_mpi_bcast (for_testing_bypass_run, mpicom)
+ call shr_mpi_bcast(for_testing_run_ncdiopio_tests, mpicom)
+ call shr_mpi_bcast(for_testing_run_decomp_init_tests, mpicom)
+ call shr_mpi_bcast(for_testing_exit_after_self_tests, mpicom)
+
+ if (masterproc) then
+ write(iulog,*) ' '
+ write(iulog,*) nmlname//' settings:'
+ write(iulog,nml=for_testing_options)
+ write(iulog,*) ' '
+ end if
+
+ end subroutine self_test_readnml
+
+ !-----------------------------------------------------------------------
+
+ logical function for_testing_bypass_init_after_self_tests()
+ ! Determine if should exit initialization early after having run the self tests
+ if ( for_testing_bypass_init ) then
+ for_testing_bypass_init_after_self_tests = .true.
+ else
+ for_testing_bypass_init_after_self_tests = .false.
+ end if
+ end function for_testing_bypass_init_after_self_tests
+
+ !-----------------------------------------------------------------------
+
+ logical function for_testing_bypass_run_except_clock_advance()
+ ! Determine if should skip most of the run phase other than the clock advance
+ if ( for_testing_bypass_init ) then
+ for_testing_bypass_run_except_clock_advance = .true.
+ else
+ for_testing_bypass_run_except_clock_advance = .false.
+ end if
+ end function for_testing_bypass_run_except_clock_advance
+
+ !-----------------------------------------------------------------------
+
end module SelfTestDriver