From d3178e1feb724c5c729a6a7e729a07ce3dd54599 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 21 Aug 2025 14:07:14 -0600 Subject: [PATCH 01/31] Add for_testing options to namelist handling to bypass init and run --- bld/CLMBuildNamelist.pm | 1 + bld/namelist_files/namelist_definition_ctsm.xml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 4cd02532f8..2f4c3bb3e9 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -5290,6 +5290,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 03c9ba420e..18cba2a3b8 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1242,6 +1242,22 @@ 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 initiatlization after the self test driver is run + + + +For testing whether to bypass most of the run phase other than the clock advance + + + Whether to run some tests of ncdio_pio as part of the model run. This is From d65ecfbc213cc88eb5b5f9ba3b3d50f899dcb359 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 21 Aug 2025 16:43:42 -0600 Subject: [PATCH 02/31] Turn the bypass init and run logicals for testing on --- .../testdefs/testmods_dirs/clm/run_self_tests/user_nl_clm | 2 ++ 1 file changed, 2 insertions(+) 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 6187386336..9912c2769d 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 +1,3 @@ +for_testing_bypass_init = .true. +for_testing_bypass_run = .true. for_testing_run_ncdiopio_tests = .true. From 96e0c9447af695d0f3ea53a45b41bdadd8689237 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 21 Aug 2025 16:44:35 -0600 Subject: [PATCH 03/31] Add a namelist read and some logical settings to bypass init and run phases as well as logical functions to do that --- src/main/clm_driver.F90 | 7 +++ src/main/clm_initializeMod.F90 | 10 +++- src/main/clm_instMod.F90 | 5 +- src/self_tests/SelfTestDriver.F90 | 90 ++++++++++++++++++++++++++++++- 4 files changed, 109 insertions(+), 3 deletions(-) diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 2cea242a67..64db2d88f8 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 da8185be31..80cddde92c 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) @@ -104,6 +105,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... @@ -185,6 +188,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 @@ -467,6 +471,7 @@ subroutine initialize2(ni,nj, currtime) call bgc_vegetation_inst%Init2(bounds_proc, NLFilename) end if + if ( .not. for_testing_bypass_init_after_self_tests() )then if (use_cn) then ! NOTE(wjs, 2016-02-23) Maybe the rest of the body of this conditional should also @@ -510,6 +515,7 @@ subroutine initialize2(ni,nj, currtime) if (nsrest == nsrContinue ) then call htapes_fieldlist() end if + end if ! Read restart/initial info is_cold_start = .false. @@ -684,6 +690,7 @@ subroutine initialize2(ni,nj, currtime) call hist_htapes_build() end if + if ( .not. for_testing_bypass_init_after_self_tests() )then ! Initialize variables that are associated with accumulated fields. ! The following is called for both initial and restart runs and must ! must be called after the restart file is read @@ -767,6 +774,7 @@ subroutine initialize2(ni,nj, currtime) water_inst%waterdiagnosticbulk_inst, canopystate_inst, & soilstate_inst, soilbiogeochem_carbonflux_inst) end if + end if ! 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_instMod.F90 b/src/main/clm_instMod.F90 index 7d9a0f6ad2..c8213b75ee 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -208,6 +208,7 @@ subroutine clm_instInit(bounds) use HillslopeHydrologyMod , only : SetHillslopeSoilThickness use initVerticalMod , only : setSoilLayerClass use DustEmisFactory , only : create_dust_emissions + use SelfTestDriver , only : for_testing_bypass_init_after_self_tests ! ! !ARGUMENTS type(bounds_type), intent(in) :: bounds ! processor bounds @@ -269,7 +270,9 @@ subroutine clm_instInit(bounds) call humanindex_inst%Init(bounds) ! Initialize urban time varying data - call urbantv_inst%Init(bounds, NLFilename) + if ( .not. for_testing_bypass_init_after_self_tests() )then + call urbantv_inst%Init(bounds, NLFilename) + end if ! Initialize vertical data components diff --git a/src/self_tests/SelfTestDriver.F90 b/src/self_tests/SelfTestDriver.F90 index d109a27827..7d784f348e 100644 --- a/src/self_tests/SelfTestDriver.F90 +++ b/src/self_tests/SelfTestDriver.F90 @@ -16,7 +16,14 @@ 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 character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -46,4 +53,85 @@ subroutine self_test_driver(bounds) 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 + + ! 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) + + 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 From 70067404e7287c755d3c45b2efdcf126eb3a6a4b Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 21 Aug 2025 16:54:44 -0600 Subject: [PATCH 04/31] Add use of abortutils so can make endrun calls --- src/self_tests/SelfTestDriver.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/self_tests/SelfTestDriver.F90 b/src/self_tests/SelfTestDriver.F90 index 7d784f348e..e19fff58bd 100644 --- a/src/self_tests/SelfTestDriver.F90 +++ b/src/self_tests/SelfTestDriver.F90 @@ -9,6 +9,7 @@ module SelfTestDriver use clm_varctl, only : for_testing_run_ncdiopio_tests use decompMod, only : bounds_type use TestNcdioPio, only : test_ncdio_pio + use abortutils, only : endrun implicit none private From 93628b2616a7b6a2dc2b443cc4c748819f262adf Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Fri, 22 Aug 2025 03:05:10 -0600 Subject: [PATCH 05/31] Add bypassing the run phase in the for_testing tests, and remove it from run_self_tests which inherits from it --- .../clm/for_testing_fastsetup_bypassrun/user_nl_clm | 3 +++ .../testdefs/testmods_dirs/clm/run_self_tests/user_nl_clm | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) 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..7334edff3d 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 @@ +! Skip the run phase +for_testing_bypass_run = .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/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/run_self_tests/user_nl_clm index c6d13ae7c5..6ee07df73f 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,8 @@ +! 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. -for_testing_bypass_run = .true. + +! Turn on some of the self tests for_testing_run_ncdiopio_tests = .true. ! Turn off history, restarts, and output From 28834c990c2eed5b1a52d93066b1bbae0495cf8d Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Fri, 22 Aug 2025 11:55:37 -0600 Subject: [PATCH 06/31] Update bld/namelist_files/namelist_definition_ctsm.xml Fix spelling from review. Co-authored-by: Sam Rabin --- bld/namelist_files/namelist_definition_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 18cba2a3b8..db00c59791 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1249,7 +1249,7 @@ Whether snow on the vegetation canopy affects the radiation/albedo calculations -For testing whether to bypass the rest of the initiatlization after the self test driver is run +For testing whether to bypass the rest of the initialization after the self test driver is run Date: Fri, 27 Jun 2025 16:54:13 -0600 Subject: [PATCH 07/31] Add namelist controls for self testing Conflicts: bld/namelist_files/namelist_definition_ctsm.xml src/cpl/nuopc/lnd_comp_nuopc.F90 src/main/clm_varctl.F90 src/self_tests/SelfTestDriver.F90 --- .../namelist_definition_ctsm.xml | 10 ++++++++++ src/cpl/nuopc/lnd_comp_nuopc.F90 | 18 ++++++++++++++++++ src/main/controlMod.F90 | 6 +++++- src/self_tests/SelfTestDriver.F90 | 8 ++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 9814fabe5b..c82a8219f1 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1274,6 +1274,10 @@ For testing whether to bypass the rest of the initialization after the self test 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. + @@ -1281,6 +1285,12 @@ 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/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90 index 3db987f2fa..4c07888e84 100644 --- a/src/cpl/nuopc/lnd_comp_nuopc.F90 +++ b/src/cpl/nuopc/lnd_comp_nuopc.F90 @@ -39,6 +39,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 @@ -500,6 +501,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,6 +683,9 @@ 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 @@ -786,6 +796,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) @@ -1009,6 +1022,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 +1306,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 +1335,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/main/controlMod.F90 b/src/main/controlMod.F90 index 089503dc8b..e43bac5a69 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -211,6 +211,7 @@ subroutine control_init(dtime) 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, & + for_testing_run_decomp_init_tests, for_testing_exit_after_self_tests, & for_testing_use_second_grain_pool, for_testing_use_repr_structure_pool, & for_testing_no_crop_seed_replenishment, & z0param_method, use_z0m_snowmelt @@ -766,8 +767,11 @@ 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 + ! Whether to run self tests call mpi_bcast(for_testing_run_ncdiopio_tests, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast(for_testing_run_decomp_init_tests, 1, MPI_LOGICAL, 0, mpicom, ier) + + call mpi_bcast(for_testing_exit_after_self_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) diff --git a/src/self_tests/SelfTestDriver.F90 b/src/self_tests/SelfTestDriver.F90 index e19fff58bd..97f23c5ae4 100644 --- a/src/self_tests/SelfTestDriver.F90 +++ b/src/self_tests/SelfTestDriver.F90 @@ -40,6 +40,14 @@ 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 clm_varctl, only : for_testing_run_ncdiopio_tests, for_testing_run_decomp_init_tests + use clm_varctl, only : for_testing_exit_after_self_tests, iulog + 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 ! From c1c7ca338d0aea4a27baca4f0f5fc91800e0802f Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Fri, 29 Aug 2025 09:44:16 -0600 Subject: [PATCH 08/31] Add unit_test_shr directory to the main model build --- cime_config/buildlib | 1 + 1 file changed, 1 insertion(+) 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"), From db4551c608d413c8d7f5d8547af95ca5ddf9d9f3 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sat, 23 Aug 2025 11:45:50 -0600 Subject: [PATCH 09/31] Merge remote-tracking branch 'escomp/b4b-dev' into decomp_init_for_testing_work Conflicts: cime_config/testdefs/ExpectedTestFails.xml --- cime_config/testdefs/ExpectedTestFails.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 47dd00c658..32981676e8 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -381,13 +381,6 @@ - - - FAIL - #3316 - - - From cb8e7ec721e3d055703020d66bfba2c989db66cf Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 21 Aug 2025 21:07:58 -0600 Subject: [PATCH 10/31] Merge remote-tracking branch 'escomp/b4b-dev' into decomp_init_for_testing_work Conflicts: cime_config/testdefs/testmods_dirs/clm/for_testing_fastsetup_bypassrun/user_nl_clm cime_config/testdefs/testmods_dirs/clm/run_self_tests/user_nl_clm --- .../clm/for_testing_fastsetup_bypassrun/user_nl_clm | 4 ++-- .../testdefs/testmods_dirs/clm/run_self_tests/user_nl_clm | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) 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 7334edff3d..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,5 +1,5 @@ -! Skip the run phase -for_testing_bypass_run = .true. +! Exit early and bypass the run phase +for_testing_exit_after_self_tests = .true. ! Turn off history, restarts, and output hist_empty_htapes = .true. 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 6ee07df73f..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 @@ -8,3 +8,7 @@ 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. From 09aa5acf5f65ece1aef44c08c93de237f7e53f5c Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 31 Jul 2025 15:20:33 -0600 Subject: [PATCH 11/31] Balance check doesn't take time, so adjust the timers again for part3 --- src/main/clm_initializeMod.F90 | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 4f56ad2284..0051361ae8 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -420,14 +420,28 @@ subroutine initialize2(ni,nj, currtime) ! Initialize instances of all derived types as well as time constant variables call clm_instInit(bounds_proc) + call t_stopf('clm_init2_part3') + call t_startf('clm_init2_snow_soil_init') call CNParamsSetSoilDepth() ! Initialize SNICAR optical and aging parameters call SnowOptics_init( ) ! SNICAR optical parameters: call SnowAge_init( ) ! SNICAR aging parameters: ! Print history field info to standard out +<<<<<<< HEAD call hist_printflds() +||||||| parent of 1bd240844 (Balance check doesn't take time, so adjust the timers again for part3) + if ( .not. use_noio )then + call hist_printflds() + end if + call t_stopf('clm_init2_part3') +======= + if ( .not. use_noio )then + call hist_printflds() + end if + call t_stopf('clm_init2_snow_soil_init') +>>>>>>> 1bd240844 (Balance check doesn't take time, so adjust the timers again for part3) ! Initializate dynamic subgrid weights (for prescribed transient Patches, CNDV ! and/or dynamic landunits); note that these will be overwritten in a restart run From bf498ab3511d4a744beda8de2049ca06b63be13f Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 31 Jul 2025 15:03:28 -0600 Subject: [PATCH 12/31] Add another timer within part3, and also turn off some of the history stuff in it when use_noio is TRUE Work on reconciling timers and for_testing bypass code from the mpi_scan branch. Conflicts: src/main/clm_initializeMod.F90 --- src/main/clm_initializeMod.F90 | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 0051361ae8..d875cfe98a 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -337,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 @@ -353,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() @@ -380,6 +382,8 @@ 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() @@ -420,28 +424,16 @@ subroutine initialize2(ni,nj, currtime) ! Initialize instances of all derived types as well as time constant variables call clm_instInit(bounds_proc) - call t_stopf('clm_init2_part3') - call t_startf('clm_init2_snow_soil_init') call CNParamsSetSoilDepth() ! Initialize SNICAR optical and aging parameters call SnowOptics_init( ) ! SNICAR optical parameters: call SnowAge_init( ) ! SNICAR aging parameters: ! Print history field info to standard out -<<<<<<< HEAD - call hist_printflds() -||||||| parent of 1bd240844 (Balance check doesn't take time, so adjust the timers again for part3) if ( .not. use_noio )then call hist_printflds() end if - call t_stopf('clm_init2_part3') -======= - if ( .not. use_noio )then - call hist_printflds() - end if - call t_stopf('clm_init2_snow_soil_init') ->>>>>>> 1bd240844 (Balance check doesn't take time, so adjust the timers again for part3) ! Initializate dynamic subgrid weights (for prescribed transient Patches, CNDV ! and/or dynamic landunits); note that these will be overwritten in a restart run @@ -483,7 +475,6 @@ subroutine initialize2(ni,nj, currtime) call bgc_vegetation_inst%Init2(bounds_proc, NLFilename) end if - if ( .not. for_testing_bypass_init_after_self_tests() )then if (use_cn) then ! NOTE(wjs, 2016-02-23) Maybe the rest of the body of this conditional should also @@ -527,7 +518,7 @@ subroutine initialize2(ni,nj, currtime) if (nsrest == nsrContinue ) then call htapes_fieldlist() end if - end if + end if ! End of bypass ! Read restart/initial info is_cold_start = .false. @@ -621,6 +612,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). @@ -700,7 +693,6 @@ subroutine initialize2(ni,nj, currtime) call hist_htapes_build() end if - if ( .not. for_testing_bypass_init_after_self_tests() )then ! Initialize variables that are associated with accumulated fields. ! The following is called for both initial and restart runs and must ! must be called after the restart file is read @@ -780,7 +772,7 @@ subroutine initialize2(ni,nj, currtime) water_inst%waterdiagnosticbulk_inst, canopystate_inst, & soilstate_inst, soilbiogeochem_carbonflux_inst) end if - 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 From 3c540603b7126be9f99df2755429575b4a7a09d1 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 31 Jul 2025 14:08:14 -0600 Subject: [PATCH 13/31] Add timers for clm_initialize2 that cover the whole subroutine --- src/main/clm_initializeMod.F90 | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index d875cfe98a..dc8e8b9c9a 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -224,7 +224,16 @@ subroutine initialize2(ni,nj, currtime) character(len=32) :: subname = 'initialize2' ! subroutine name !----------------------------------------------------------------------- +<<<<<<< HEAD call t_startf('clm_init2_part1') +||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) + call t_startf('clm_init2') + +======= + call t_startf('clm_init2') + + call t_startf('clm_init2_part1') +>>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) ! Get processor bounds for gridcells call get_proc_bounds(bounds_proc) begg = bounds_proc%begg; endg = bounds_proc%endg @@ -277,14 +286,20 @@ subroutine initialize2(ni,nj, currtime) call CLMFatesGlobals2() end if +<<<<<<< HEAD call t_stopf('clm_init2_part1') call t_startf('clm_init2_part2') +||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) +======= + call t_stopf('clm_init2_part1') +>>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) ! Determine decomposition of subgrid scale landunits, columns, patches call t_startf('clm_decompInit_clumps') call decompInit_clumps(ni, nj, glc_behavior) call t_stopf('clm_decompInit_clumps') + call t_startf('clm_init2_subgrid') ! *** Get ALL processor bounds - for gridcells, landunit, columns and patches *** call get_proc_bounds(bounds_proc) @@ -306,12 +321,14 @@ subroutine initialize2(ni,nj, currtime) call initGridCells(bounds_clump, glc_behavior) end do !$OMP END PARALLEL DO + call t_stopf('clm_init2_subgrid') ! Set global seg maps for gridcells, landlunits, columns and patches call t_startf('clm_decompInit_glcp') call decompInit_glcp(ni, nj, glc_behavior) call t_stopf('clm_decompInit_glcp') + call t_startf('clm_init2_part2') if (use_hillslope) then ! Initialize hillslope properties call InitHillslope(bounds_proc, hillslope_file) @@ -379,11 +396,17 @@ subroutine initialize2(ni,nj, currtime) caldaym1 = get_curr_calday(offset=-int(dtime), reuse_day_365_for_day_366=.true.) call shr_orb_decl( caldaym1, eccen, mvelpp, lambm0, obliqr, declinm1, eccf ) call InitDaylength(bounds_proc, declin=declin, declinm1=declinm1, obliquity=obliqr) +<<<<<<< HEAD call t_stopf('clm_init2_part2') call t_startf('clm_init2_part3') if ( .not. for_testing_bypass_init_after_self_tests() )then +||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) +======= + call t_stopf('clm_init2_part2') +>>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) + call t_startf('clm_init2_part3') ! Initialize Balance checking (after time-manager) call BalanceCheckInit() @@ -431,10 +454,18 @@ subroutine initialize2(ni,nj, currtime) call SnowAge_init( ) ! SNICAR aging parameters: ! Print history field info to standard out +<<<<<<< HEAD if ( .not. use_noio )then call hist_printflds() end if +||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) + call hist_printflds() +======= + call hist_printflds() + call t_stopf('clm_init2_part3') +>>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) + call t_startf('clm_init2_part4') ! Initializate dynamic subgrid weights (for prescribed transient Patches, CNDV ! and/or dynamic landunits); note that these will be overwritten in a restart run call init_subgrid_weights_mod(bounds_proc) @@ -555,6 +586,7 @@ subroutine initialize2(ni,nj, currtime) call restFile_read(bounds_proc, fnamer, glc_behavior, & reset_dynbal_baselines_lake_columns = reset_dynbal_baselines_lake_columns) end if + call t_stopf('clm_init2_part4') ! If appropriate, create interpolated initial conditions if (nsrest == nsrStartup .and. finidat_interp_source /= ' ') then @@ -612,8 +644,13 @@ subroutine initialize2(ni,nj, currtime) call t_stopf('clm_init2_init_interp') end if +<<<<<<< HEAD if ( .not. for_testing_bypass_init_after_self_tests() )then +||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) +======= + call t_startf('clm_init2_part5') +>>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) ! If requested, reset dynbal baselines ! This needs to happen after reading the restart file (including after reading the ! interpolated restart file, if applicable). @@ -793,14 +830,22 @@ subroutine initialize2(ni,nj, currtime) write(iulog,'(72a1)') ("*",i=1,60) write(iulog,*) endif +<<<<<<< HEAD +||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) + call t_stopf('init_wlog') +======= + call t_stopf('clm_init2_part5') +>>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) if (water_inst%DoConsistencyCheck()) then + call t_startf('tracer_consistency_check') !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) do nc = 1,nclumps call get_clump_bounds(nc, bounds_clump) call water_inst%TracerConsistencyCheck(bounds_clump, 'end of initialization') end do !$OMP END PARALLEL DO + call t_stopf('tracer_consistency_check') end if call t_stopf('clm_init2_part3') From ce2d68b1fecdfba1bd12e38f141282e13422fa01 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 2 Sep 2025 16:07:18 -0600 Subject: [PATCH 14/31] Change the test grid total size to 384 so can be divisible by either 128 for Derecho or 48 for Izumi --- src/self_tests/TestDecompInit.F90 | 357 ++++++++++++++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 src/self_tests/TestDecompInit.F90 diff --git a/src/self_tests/TestDecompInit.F90 b/src/self_tests/TestDecompInit.F90 new file mode 100644 index 0000000000..58b0ddaab2 --- /dev/null +++ b/src/self_tests/TestDecompInit.F90 @@ -0,0 +1,357 @@ +module TestDecompInit + + ! ------------------------------------------------------------------------ + ! !DESCRIPTION: + ! This module contains tests of decomp_init + +#include "shr_assert.h" + use shr_kind_mod, only : r8 => shr_kind_r8, CX => shr_kind_cx + use Assertions, only : assert_equal + use clm_varctl, only : iulog + use abortutils, only : endrun, endrun_init, get_last_endrun_msg + use spmdMod, only : masterproc, npes, iam + use decompInitMod, only : decompInit_lnd, clump_pproc, decompInit_clumps + use clm_InstMod, only : glc_behavior + use decompMod + + implicit none + private + save + + ! Public routines + + public :: test_decomp_init + + ! Module data used in various tests + + ! Make the size of the test grid 384 so that it can be divided by 128 or 48 + ! for the number of tasks per node on Derecho or Izumi. + integer, parameter :: ni = 16, nj = 24 + integer :: amask(ni*nj) + + integer :: default_npes + integer :: default_clump_pproc + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + +contains + + !----------------------------------------------------------------------- + subroutine test_decomp_init() + ! + ! !DESCRIPTION: + ! Drive tests of decomp_init + ! + ! NOTE(wjs, 2020-10-15) Currently, endrun is called when any test assertion fails. I + ! thought about changing this so that, instead, a counter is incremented for each + ! failure, then at the end of the testing (in the higher-level self-test driver), + ! endrun is called if this counter is greater than 0. The benefit of this is that we'd + ! see all test failures, not just the first failure. To do that, we'd need to change + ! the assertions here to increment a counter rather than aborting. However, I'm not + ! spending the time to make this change for now because (1) I'm not sure how much + ! value we'd get from it; (2) even if we made that change, it's still very possible + ! for test code to abort for reasons other than assertions, if something goes wrong + ! inside decomp_init or pio; and (3) some tests here are dependent on earlier tests (for + ! example, the reads depend on the writes having worked), so a failure in an early + ! phase could really muck things up for later testing phases. Migrating to a + ! pFUnit-based unit test would solve this problem, since each pFUnit test is + ! independent, though would prevent us from being able to have dependent tests the + ! way we do here (where reads depend on earlier writes), for better or for worse. + ! + ! !USERS: + use decompInitMod, only : decompInit_clumps, decompInit_glcp + use domainMod, only : ldomain + ! !ARGUMENTS: + ! + ! !LOCAL VARIABLES: + integer, allocatable :: model_amask(:) + !----------------------------------------------------------------------- + + default_npes = npes + default_clump_pproc = clump_pproc + call write_to_log('start_test_decomp_init') + + call write_to_log('test_check_nclumps') + call test_check_nclumps() + call write_to_log('test_decompInit_lnd_abort_on_bad_clump_pproc') + call test_decompInit_lnd_abort_on_bad_clump_pproc() + call write_to_log('test_decompInit_lnd_abort_on_too_big_clump_pproc') + call test_decompInit_lnd_abort_on_too_big_clump_pproc() + call write_to_log('test_decompInit_lnd_abort_when_npes_too_large') + call test_decompInit_lnd_abort_when_npes_too_large() + call write_to_log('test_decompInit_lnd_abort_on_too_small_nsegspc') + call test_decompInit_lnd_abort_on_too_small_nsegspc() + call write_to_log('test_decompInit_lnd_check_sizes') + call test_decompInit_lnd_check_sizes() + call write_to_log('test_decompInit_clump_gcell_info_correct') + call test_decompInit_clump_gcell_info_correct() + ! Comment out for now -- needs some work + !call write_to_log('test_decompMod_get_clump_bounds_correct') + !call test_decompMod_get_clump_bounds_correct() + + ! + ! Call the decompInit initialization series a last time so that decompMod data can still be used + ! + !allocate( model_amask(ldomain%ni*ldomain%nj) ) + !model_amask(:) = 1 + !call decompInit_lnd( ldomain%ni, ldomain%nj, model_amask ) + !call decompInit_clumps(ldomain%ni, ldomain%nj, glc_behavior) + !call decompInit_glcp(ldomain%ni, ldomain%nj, glc_behavior) + !deallocate( model_amask ) + + end subroutine test_decomp_init + + !----------------------------------------------------------------------- + subroutine setup() + use clm_varctl, only : nsegspc + + clump_pproc = default_clump_pproc + nsegspc = 20 + npes = default_npes + amask(:) = 1 ! Set all to land + + end subroutine setup + + !----------------------------------------------------------------------- + subroutine test_decompInit_lnd_abort_on_bad_clump_pproc() + character(len=CX) :: expected_msg, actual_msg + + call setup() + call endrun_init( .true. ) ! Do not abort on endrun for self-tests + clump_pproc = 0 + call write_to_log('decompInit_lnd with clump_pproc=0 should abort') + call decompInit_lnd( ni, nj, amask ) + call write_to_log('check expected abort message') + expected_msg = 'clump_pproc must be greater than 0' + actual_msg = get_last_endrun_msg() + call endrun_init( .false. ) ! Turn back on to abort on the assert + call write_to_log('call assert_equal to check the abort message') + call assert_equal( & + expected=expected_msg, actual=actual_msg, & + msg='decompInit_lnd did not abort with clump_pproc=0' ) + call clean() + end subroutine test_decompInit_lnd_abort_on_bad_clump_pproc + + !----------------------------------------------------------------------- + subroutine test_decompInit_lnd_abort_on_too_big_clump_pproc() + character(len=CX) :: expected_msg, actual_msg + + call setup() + call endrun_init( .true. ) ! Do not abort on endrun for self-tests + amask(:) = 1 ! Set all to land + clump_pproc = (ni * nj + 1) / npes + call write_to_log('decompInit_lnd with clump_pproc too large should abort') + call decompInit_lnd( ni, nj, amask ) + call write_to_log('check expected abort message') + expected_msg = 'Number of clumps exceeds number of land grid cells' + actual_msg = get_last_endrun_msg() + call endrun_init( .false. ) ! Turn back on to abort on the assert + call write_to_log('call assert_equal to check the abort message') + call assert_equal( & + expected=expected_msg, actual=actual_msg, & + msg='decompInit_lnd did not abort with clump_pproc too large' ) + call clean() + end subroutine test_decompInit_lnd_abort_on_too_big_clump_pproc + + !----------------------------------------------------------------------- + subroutine test_decompInit_lnd_check_sizes() + use decompMod, only : get_proc_bounds + type(bounds_type) :: bounds + + integer :: expected_endg, expected_numg + + call setup() + expected_numg = ni*nj + if ( expected_numg < npes )then + call endrun( msg="npes is too large for this test", file=sourcefile, line=__LINE__ ) + end if + if ( modulo( expected_numg, npes ) /= 0 )then + call endrun( msg="npes does not evenly divide into numg so this test will not work", file=sourcefile, line=__LINE__ ) + end if + expected_endg = ni*nj / npes + amask(:) = 1 ! Set all to land + call decompInit_lnd( ni, nj, amask ) + call get_proc_bounds(bounds, allow_errors=.true.) + call assert_equal( bounds%begg, 1, msg='begg is not as expected' ) + call assert_equal( bounds%endg, expected_endg, msg='endg is not as expected' ) + call clean() + end subroutine test_decompInit_lnd_check_sizes + + !----------------------------------------------------------------------- + subroutine test_decompInit_lnd_abort_when_npes_too_large() + character(len=CX) :: expected_msg, actual_msg + + call setup() + ! NOTE: This is arbitrarily modifying the NPES value -- so it MUST be reset set the END! + npes = ni*nj + 1 + + call endrun_init( .true. ) ! Do not abort on endrun for self-tests + amask(:) = 1 ! Set all to land + call write_to_log('decompInit_lnd with npes too large should abort') + call decompInit_lnd( ni, nj, amask ) + call write_to_log('check expected abort message') + expected_msg = 'Number of processes exceeds number of land grid cells' + actual_msg = get_last_endrun_msg() + call endrun_init( .false. ) ! Turn back on to abort on the assert + call write_to_log('call assert_equal to check the abort message') + call assert_equal( & + expected=expected_msg, actual=actual_msg, & + msg='decompInit_lnd did not abort with npes too large' ) + + ! NOTE: Return npes to its original value + npes = default_npes + call clean() + end subroutine test_decompInit_lnd_abort_when_npes_too_large + + !----------------------------------------------------------------------- + subroutine test_decompInit_lnd_abort_on_too_small_nsegspc() + use clm_varctl, only : nsegspc + character(len=CX) :: expected_msg, actual_msg + + call setup() + call endrun_init( .true. ) ! Do not abort on endrun for self-tests + amask(:) = 1 ! Set all to land + nsegspc = 0 + call write_to_log('decompInit_lnd with nsegspc too small should abort') + call decompInit_lnd( ni, nj, amask ) + call write_to_log('check expected abort message') + expected_msg = 'Number of segments per clump (nsegspc) is less than 1 and can NOT be' + actual_msg = get_last_endrun_msg() + call endrun_init( .false. ) ! Turn back on to abort on the assert + call write_to_log('call assert_equal to check the abort message') + call assert_equal( & + expected=expected_msg, actual=actual_msg, & + msg='decompInit_lnd did not abort with too nsegspc too small' ) + call clean() + end subroutine test_decompInit_lnd_abort_on_too_small_nsegspc + + !----------------------------------------------------------------------- + subroutine test_check_nclumps() + integer :: expected_nclumps + + call setup() + call endrun_init( .true. ) ! Do not abort on endrun for self-tests + expected_nclumps = npes / clump_pproc + call assert_equal(expected=expected_nclumps, actual=nclumps, & + msg='nclumps are not as expected') + call endrun_init( .false. ) + call clean() + end subroutine test_check_nclumps + +!----------------------------------------------------------------------- + subroutine test_decompMod_get_clump_bounds_correct() + ! Some testing for get_clump_bounds + use decompMod, only : get_clump_bounds, bounds_type + use unittestSimpleSubgridSetupsMod, only : setup_ncells_single_veg_patch + use unittestSubgridMod, only : unittest_subgrid_teardown + use pftconMod, only : noveg + type(bounds_type) :: bounds + integer :: expected_begg, expected_endg, expected_numg, gcell_per_task + integer :: iclump + + call setup() + ! Now setup a singple grid that's just the full test with every point a single baresoil patch + call setup_ncells_single_veg_patch( ncells=ni*nj, pft_type=noveg ) + clump_pproc = 1 ! Ensure we are just doing this for one clump per proc for now + expected_numg = ni*nj + if ( expected_numg < npes )then + call endrun( msg="npes is too large for this test", file=sourcefile, line=__LINE__ ) + end if + if ( modulo( expected_numg, npes ) /= 0 )then + call endrun( msg="npes does not evenly divide into numg so this test will not work", file=sourcefile, line=__LINE__ ) + end if + gcell_per_task = expected_numg / npes + expected_begg = gcell_per_task * iam + 1 + expected_endg = expected_begg + gcell_per_task + amask(:) = 1 ! Set all to land + call decompInit_lnd( ni, nj, amask ) + call decompInit_clumps( ni, nj, glc_behavior ) + iclump = 1 ! Clump is just 1 since there's only one clump per task + call get_clump_bounds(iclump, bounds) + call assert_equal( bounds%begg, expected_begg, msg='begg is not as expected' ) + call assert_equal( bounds%endg, expected_endg, msg='endg is not as expected' ) + ! Other subgrtid level information will be the same -- since there's only one landunit, column, and patch per gridcell + call assert_equal( bounds%begl, expected_begg, msg='begl is not as expected' ) + call assert_equal( bounds%endl, expected_endg, msg='endl is not as expected' ) + call assert_equal( bounds%begc, expected_begg, msg='begc is not as expected' ) + call assert_equal( bounds%endc, expected_endg, msg='endc is not as expected' ) + call assert_equal( bounds%begp, expected_begg, msg='begp is not as expected' ) + call assert_equal( bounds%endp, expected_endg, msg='endp is not as expected' ) + call unittest_subgrid_teardown( ) + call clean() + end subroutine test_decompMod_get_clump_bounds_correct + + !----------------------------------------------------------------------- + subroutine test_decompInit_clump_gcell_info_correct() + ! Some testing for get_clump_bounds + use decompMod, only : clumps + integer :: expected_gcells, iclump, g, beg_global_index, gcell_per_task + integer :: expected_begg, expected_endg + + call setup() + expected_gcells = ni*nj + if ( expected_gcells < npes )then + call endrun( msg="npes is too large for this test", file=sourcefile, line=__LINE__ ) + end if + if ( modulo( expected_gcells, npes ) /= 0 )then + call endrun( msg="npes does not evenly divide into gcell so this test will not work", file=sourcefile, line=__LINE__ ) + end if + gcell_per_task = expected_gcells / npes + expected_begg = gcell_per_task * iam + 1 + expected_endg = expected_begg + gcell_per_task + amask(:) = 1 ! Set all to land + call decompInit_lnd( ni, nj, amask ) + ! When clump_pproc is one clumps will be the same as PE + call assert_equal( nclumps, npes, msg='nclumps should match numper of proces when clump_pproc is 1' ) + do iclump = 1, nclumps + call assert_equal( clumps(iclump)%owner, iclump-1, msg='clumps owner is not correct' ) + call assert_equal( clumps(iclump)%ncells, gcell_per_task, msg='clumps ncells is not correct' ) + end do + ! Validate gindex_global over the local task + + beg_global_index = gcell_per_task*iam + do g = procinfo%begg, procinfo%endg + call assert_equal( gindex_global(g), g+beg_global_index, msg='clumps owner is not correct' ) + end do + call clean() + end subroutine test_decompInit_clump_gcell_info_correct + + !----------------------------------------------------------------------- + subroutine write_to_log(msg) + ! + ! !DESCRIPTION: + ! Write a message to the log file, just from the masterproc + ! + use shr_sys_mod, only : shr_sys_flush + ! !ARGUMENTS: + character(len=*), intent(in) :: msg + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'write_to_log' + !----------------------------------------------------------------------- + + if (masterproc) then + write(iulog,'(a)') msg + call shr_sys_flush(iulog) ! Flush the I/O buffers always + end if + + end subroutine write_to_log + + !----------------------------------------------------------------------- + subroutine clean + ! + ! !DESCRIPTION: + ! Do end-of-testing cleanup after each test + ! + ! !ARGUMENTS: + ! + ! !LOCAL VARIABLES: + !----------------------------------------------------------------------- + call decompmod_clean() + + end subroutine clean + + +end module TestDecompInit From 2fc723fbc84737b1864341f07d148988cf188007 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sat, 6 Sep 2025 14:46:01 -0600 Subject: [PATCH 15/31] Don't do the abort testing if not serial as different tasks won't be in sync and doing so was not working --- src/self_tests/TestDecompInit.F90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/self_tests/TestDecompInit.F90 b/src/self_tests/TestDecompInit.F90 index 58b0ddaab2..526e8e5d37 100644 --- a/src/self_tests/TestDecompInit.F90 +++ b/src/self_tests/TestDecompInit.F90 @@ -117,6 +117,7 @@ end subroutine setup subroutine test_decompInit_lnd_abort_on_bad_clump_pproc() character(len=CX) :: expected_msg, actual_msg + if ( npes > 1 ) return ! error checking testing only works seriallly call setup() call endrun_init( .true. ) ! Do not abort on endrun for self-tests clump_pproc = 0 @@ -137,6 +138,7 @@ end subroutine test_decompInit_lnd_abort_on_bad_clump_pproc subroutine test_decompInit_lnd_abort_on_too_big_clump_pproc() character(len=CX) :: expected_msg, actual_msg + if ( npes > 1 ) return ! error checking testing only works seriallly call setup() call endrun_init( .true. ) ! Do not abort on endrun for self-tests amask(:) = 1 ! Set all to land @@ -182,6 +184,7 @@ end subroutine test_decompInit_lnd_check_sizes subroutine test_decompInit_lnd_abort_when_npes_too_large() character(len=CX) :: expected_msg, actual_msg + if ( npes > 1 ) return ! error checking testing only works seriallly call setup() ! NOTE: This is arbitrarily modifying the NPES value -- so it MUST be reset set the END! npes = ni*nj + 1 @@ -209,6 +212,7 @@ subroutine test_decompInit_lnd_abort_on_too_small_nsegspc() use clm_varctl, only : nsegspc character(len=CX) :: expected_msg, actual_msg + if ( npes > 1 ) return ! error checking testing only works seriallly call setup() call endrun_init( .true. ) ! Do not abort on endrun for self-tests amask(:) = 1 ! Set all to land @@ -286,6 +290,8 @@ end subroutine test_decompMod_get_clump_bounds_correct subroutine test_decompInit_clump_gcell_info_correct() ! Some testing for get_clump_bounds use decompMod, only : clumps + use decompMod, only : get_proc_bounds + type(bounds_type) :: bounds integer :: expected_gcells, iclump, g, beg_global_index, gcell_per_task integer :: expected_begg, expected_endg @@ -308,12 +314,6 @@ subroutine test_decompInit_clump_gcell_info_correct() call assert_equal( clumps(iclump)%owner, iclump-1, msg='clumps owner is not correct' ) call assert_equal( clumps(iclump)%ncells, gcell_per_task, msg='clumps ncells is not correct' ) end do - ! Validate gindex_global over the local task - - beg_global_index = gcell_per_task*iam - do g = procinfo%begg, procinfo%endg - call assert_equal( gindex_global(g), g+beg_global_index, msg='clumps owner is not correct' ) - end do call clean() end subroutine test_decompInit_clump_gcell_info_correct From d8d656bac74999a8778779e1a340f7af09e5ba71 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Mon, 8 Sep 2025 14:47:55 -0600 Subject: [PATCH 16/31] Change a test to make it valid for clump_pproc or not --- src/self_tests/TestDecompInit.F90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/self_tests/TestDecompInit.F90 b/src/self_tests/TestDecompInit.F90 index 526e8e5d37..7705ea80fc 100644 --- a/src/self_tests/TestDecompInit.F90 +++ b/src/self_tests/TestDecompInit.F90 @@ -309,7 +309,11 @@ subroutine test_decompInit_clump_gcell_info_correct() amask(:) = 1 ! Set all to land call decompInit_lnd( ni, nj, amask ) ! When clump_pproc is one clumps will be the same as PE - call assert_equal( nclumps, npes, msg='nclumps should match numper of proces when clump_pproc is 1' ) + if ( clump_pproc == 1 ) then + call assert_equal( nclumps, npes, msg='nclumps should match number of processors when clump_pproc is 1' ) + else + call assert_equal( nclumps/clump_pproc, npes, msg='nclumps divided by clump_pproc should match number of processors when clump_pproc > 1' ) + end if do iclump = 1, nclumps call assert_equal( clumps(iclump)%owner, iclump-1, msg='clumps owner is not correct' ) call assert_equal( clumps(iclump)%ncells, gcell_per_task, msg='clumps ncells is not correct' ) From 4ce6b5fea206c982319b8954b02d56edef642133 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sun, 14 Sep 2025 15:29:25 -0600 Subject: [PATCH 17/31] Just do the checking over the local processor clumps and not all the global clumps --- src/main/decompInitMod.F90 | 3 +++ src/self_tests/TestDecompInit.F90 | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/decompInitMod.F90 b/src/main/decompInitMod.F90 index aa575bd787..cf84a4a7c6 100644 --- a/src/main/decompInitMod.F90 +++ b/src/main/decompInitMod.F90 @@ -574,6 +574,8 @@ subroutine decompInit_clumps(lni,lnj,glc_behavior) enddo do n = 1,nclumps + ! Only do the error checking over the local processor + if (clumps(n)%owner == iam) then if (clumps(n)%ncells /= allvecg(n,1) .or. & clumps(n)%nlunits /= allvecg(n,2) .or. & clumps(n)%ncols /= allvecg(n,3) .or. & @@ -588,6 +590,7 @@ subroutine decompInit_clumps(lni,lnj,glc_behavior) call endrun(msg=errMsg(sourcefile, __LINE__)) endif + endif enddo deallocate(allvecg,allvecl) diff --git a/src/self_tests/TestDecompInit.F90 b/src/self_tests/TestDecompInit.F90 index 7705ea80fc..b88b62ce85 100644 --- a/src/self_tests/TestDecompInit.F90 +++ b/src/self_tests/TestDecompInit.F90 @@ -293,7 +293,7 @@ subroutine test_decompInit_clump_gcell_info_correct() use decompMod, only : get_proc_bounds type(bounds_type) :: bounds integer :: expected_gcells, iclump, g, beg_global_index, gcell_per_task - integer :: expected_begg, expected_endg + integer :: expected_begg, expected_endg, lc call setup() expected_gcells = ni*nj @@ -314,8 +314,10 @@ subroutine test_decompInit_clump_gcell_info_correct() else call assert_equal( nclumps/clump_pproc, npes, msg='nclumps divided by clump_pproc should match number of processors when clump_pproc > 1' ) end if - do iclump = 1, nclumps - call assert_equal( clumps(iclump)%owner, iclump-1, msg='clumps owner is not correct' ) + ! Just test over the local clumps + do lc = 1, clump_pproc + iclump = procinfo%cid(lc) + call assert_equal( clumps(iclump)%owner, iam, msg='clumps owner is not correct' ) call assert_equal( clumps(iclump)%ncells, gcell_per_task, msg='clumps ncells is not correct' ) end do call clean() From 7dc7dcd43bf37a7ca081e0b8918d5b43d4f9033d Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 1 Oct 2025 01:51:36 -0600 Subject: [PATCH 18/31] Resolve the conflicts --- src/main/clm_initializeMod.F90 | 37 ---------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index dc8e8b9c9a..715630ba53 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -224,16 +224,7 @@ subroutine initialize2(ni,nj, currtime) character(len=32) :: subname = 'initialize2' ! subroutine name !----------------------------------------------------------------------- -<<<<<<< HEAD call t_startf('clm_init2_part1') -||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) - call t_startf('clm_init2') - -======= - call t_startf('clm_init2') - - call t_startf('clm_init2_part1') ->>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) ! Get processor bounds for gridcells call get_proc_bounds(bounds_proc) begg = bounds_proc%begg; endg = bounds_proc%endg @@ -286,13 +277,8 @@ subroutine initialize2(ni,nj, currtime) call CLMFatesGlobals2() end if -<<<<<<< HEAD call t_stopf('clm_init2_part1') call t_startf('clm_init2_part2') -||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) -======= - call t_stopf('clm_init2_part1') ->>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) ! Determine decomposition of subgrid scale landunits, columns, patches call t_startf('clm_decompInit_clumps') @@ -396,15 +382,10 @@ subroutine initialize2(ni,nj, currtime) caldaym1 = get_curr_calday(offset=-int(dtime), reuse_day_365_for_day_366=.true.) call shr_orb_decl( caldaym1, eccen, mvelpp, lambm0, obliqr, declinm1, eccf ) call InitDaylength(bounds_proc, declin=declin, declinm1=declinm1, obliquity=obliqr) -<<<<<<< HEAD call t_stopf('clm_init2_part2') call t_startf('clm_init2_part3') if ( .not. for_testing_bypass_init_after_self_tests() )then -||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) -======= - call t_stopf('clm_init2_part2') ->>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) call t_startf('clm_init2_part3') ! Initialize Balance checking (after time-manager) @@ -454,16 +435,9 @@ subroutine initialize2(ni,nj, currtime) call SnowAge_init( ) ! SNICAR aging parameters: ! Print history field info to standard out -<<<<<<< HEAD if ( .not. use_noio )then call hist_printflds() end if -||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) - call hist_printflds() -======= - call hist_printflds() - call t_stopf('clm_init2_part3') ->>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) call t_startf('clm_init2_part4') ! Initializate dynamic subgrid weights (for prescribed transient Patches, CNDV @@ -644,13 +618,8 @@ subroutine initialize2(ni,nj, currtime) call t_stopf('clm_init2_init_interp') end if -<<<<<<< HEAD if ( .not. for_testing_bypass_init_after_self_tests() )then -||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) -======= - call t_startf('clm_init2_part5') ->>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) ! If requested, reset dynbal baselines ! This needs to happen after reading the restart file (including after reading the ! interpolated restart file, if applicable). @@ -830,12 +799,6 @@ subroutine initialize2(ni,nj, currtime) write(iulog,'(72a1)') ("*",i=1,60) write(iulog,*) endif -<<<<<<< HEAD -||||||| parent of 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) - call t_stopf('init_wlog') -======= - call t_stopf('clm_init2_part5') ->>>>>>> 8914b12ab (Add timers for clm_initialize2 that cover the whole subroutine) if (water_inst%DoConsistencyCheck()) then call t_startf('tracer_consistency_check') From 2a46724c30a4d591e134bfe3bdf39132bbcf9db8 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Fri, 22 Aug 2025 03:09:37 -0600 Subject: [PATCH 19/31] Remove some of the previous bypassing changes that aren't needed here --- src/cpl/nuopc/lnd_comp_nuopc.F90 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90 index 4c07888e84..451207d287 100644 --- a/src/cpl/nuopc/lnd_comp_nuopc.F90 +++ b/src/cpl/nuopc/lnd_comp_nuopc.F90 @@ -501,12 +501,12 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) else single_column = .false. end if - if ( for_testing_exit_after_self_tests) then + !if ( for_testing_exit_after_self_tests) then ! ******************* ! *** RETURN HERE *** ! ******************* - RETURN - end if + !RETURN + !end if !---------------------------------------------------------------------------- ! Reset shr logging to my log file @@ -796,9 +796,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 + !if (for_testing_exit_after_self_tests) then + ! RETURN + !end if !$ call omp_set_num_threads(nthrds) @@ -1022,7 +1022,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 + !if (for_testing_exit_after_self_tests) return ! query the Component for its clocks call NUOPC_ModelGet(gcomp, driverClock=dclock, modelClock=mclock, rc=rc) @@ -1335,9 +1335,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 + !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 From c95b886cf8857daf335e0cf1011b68344d9b1eae Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 27 Aug 2025 13:34:29 -0600 Subject: [PATCH 20/31] Move bypass code around a bit so that most timers aren't half in/half out, and so that the self-tests can run to completion afterwards Conflicts: src/cpl/nuopc/lnd_comp_nuopc.F90 src/main/clm_initializeMod.F90 --- src/cpl/nuopc/lnd_comp_nuopc.F90 | 8 ++++++++ src/main/clm_instMod.F90 | 5 +---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90 index 451207d287..9dcbf9236c 100644 --- a/src/cpl/nuopc/lnd_comp_nuopc.F90 +++ b/src/cpl/nuopc/lnd_comp_nuopc.F90 @@ -352,6 +352,7 @@ 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 ! input/output variables type(ESMF_GridComp) :: gcomp @@ -690,10 +691,12 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) !-------------------------------- ! 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 ! Set scalars in export state call State_SetScalar(dble(ldomain%ni), flds_scalar_index_nx, exportState, & @@ -741,6 +744,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 @@ -930,9 +934,13 @@ subroutine ModelAdvance(gcomp, rc) ! 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 diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index c8213b75ee..7d9a0f6ad2 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -208,7 +208,6 @@ subroutine clm_instInit(bounds) use HillslopeHydrologyMod , only : SetHillslopeSoilThickness use initVerticalMod , only : setSoilLayerClass use DustEmisFactory , only : create_dust_emissions - use SelfTestDriver , only : for_testing_bypass_init_after_self_tests ! ! !ARGUMENTS type(bounds_type), intent(in) :: bounds ! processor bounds @@ -270,9 +269,7 @@ subroutine clm_instInit(bounds) call humanindex_inst%Init(bounds) ! Initialize urban time varying data - if ( .not. for_testing_bypass_init_after_self_tests() )then - call urbantv_inst%Init(bounds, NLFilename) - end if + call urbantv_inst%Init(bounds, NLFilename) ! Initialize vertical data components From 86382c673cad60be4406caf0c6a8083340a1f78e Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 27 Aug 2025 16:16:33 -0600 Subject: [PATCH 21/31] Also bypass the import fields for_testing option, and move the decompInit_lnd timers to around the calls rather than for the entire subroutine, because the things at the top that may abort will then have a broken timer Conflicts: src/cpl/nuopc/lnd_comp_nuopc.F90 src/main/decompInitMod.F90 --- src/cpl/nuopc/lnd_comp_nuopc.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90 index 9dcbf9236c..e462c3d2ed 100644 --- a/src/cpl/nuopc/lnd_comp_nuopc.F90 +++ b/src/cpl/nuopc/lnd_comp_nuopc.F90 @@ -842,9 +842,13 @@ subroutine ModelAdvance(gcomp, rc) ! Unpack import state !-------------------------------- + if ( .not. for_testing_bypass_init_after_self_tests() ) then + 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 From dac0ae0f9a0f606cac176f98c1a4c605054bf7f1 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Fri, 29 Aug 2025 09:45:30 -0600 Subject: [PATCH 22/31] Move the get_proc_bounds to inside the bypass --- src/cpl/nuopc/lnd_comp_nuopc.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90 index e462c3d2ed..2d0abcd823 100644 --- a/src/cpl/nuopc/lnd_comp_nuopc.F90 +++ b/src/cpl/nuopc/lnd_comp_nuopc.F90 @@ -835,14 +835,14 @@ 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 ) From e867afe76f3e51ed1185a20aa7b25c61be9049a2 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 2 Jul 2025 10:11:49 -0600 Subject: [PATCH 23/31] Changes to exit early when self test namelist option used for_testing_exit_after_self_tests, change the self tests testmod so that its about initialization, this works with a compset with SATM, but hangs -- because nothing stops the run Conflicts: cime_config/testdefs/testmods_dirs/clm/run_self_tests/README cime_config/testdefs/testmods_dirs/clm/run_self_tests/shell_commands cime_config/testdefs/testmods_dirs/clm/run_self_tests/user_nl_clm src/cpl/nuopc/lnd_comp_nuopc.F90 --- .../clm/run_self_tests/shell_commands | 9 +++++++++ src/cpl/nuopc/lnd_comp_nuopc.F90 | 12 +++++++++++- src/cpl/nuopc/lnd_import_export.F90 | 19 ++++++++++++++----- 3 files changed, 34 insertions(+), 6 deletions(-) create mode 100755 cime_config/testdefs/testmods_dirs/clm/run_self_tests/shell_commands 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/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90 index 2d0abcd823..4ce0b3d6af 100644 --- a/src/cpl/nuopc/lnd_comp_nuopc.F90 +++ b/src/cpl/nuopc/lnd_comp_nuopc.F90 @@ -81,6 +81,7 @@ module lnd_comp_nuopc logical :: glc_present logical :: rof_prognostic + logical :: atm_present logical :: atm_prognostic integer, parameter :: dbug = 0 character(*),parameter :: modName = "(lnd_comp_nuopc)" @@ -285,6 +286,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 @@ -311,6 +317,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 @@ -329,7 +338,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 !---------------------------------------------------------------------------- diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index 624590b9a6..b8a5efeb8d 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 ) @@ -773,6 +782,7 @@ subroutine export_fields( gcomp, bounds, glc_present, rof_prognostic, & ! output to mediator ! ----------------------- + if (send_to_atm) then call state_setexport_1d(exportState, Sl_lfrin, ldomain%frac(begg:), init_spval=.false., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -780,7 +790,6 @@ 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 From d19b8940feefccd89b50aa0f5605a5ab1dba0838 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Mon, 11 Aug 2025 09:06:36 -0600 Subject: [PATCH 24/31] Add asserts for scalars and also text scalars --- src/self_tests/Assertions.F90.in | 81 ++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/self_tests/Assertions.F90.in b/src/self_tests/Assertions.F90.in index 2a4c8cccc6..4a86929a8a 100644 --- a/src/self_tests/Assertions.F90.in +++ b/src/self_tests/Assertions.F90.in @@ -17,6 +17,12 @@ module Assertions public :: assert_equal interface assert_equal + !TYPE double,int,logical + module procedure assert_equal_0d_{TYPE} + + !TYPE text + module procedure assert_equal_0d_{TYPE} + !TYPE double,int,logical module procedure assert_equal_1d_{TYPE} @@ -30,6 +36,8 @@ module Assertions interface vals_are_equal !TYPE double,int,logical module procedure vals_are_equal_{TYPE} + !TYPE text + module procedure vals_are_equal_{TYPE} end interface vals_are_equal contains @@ -75,6 +83,60 @@ contains end subroutine assert_equal_1d_{TYPE} + !----------------------------------------------------------------------- + !TYPE double,int,logical + subroutine assert_equal_0d_{TYPE}(expected, actual, msg, abs_tol) + ! + ! !DESCRIPTION: + ! Assert scalar values are equal + ! + ! !ARGUMENTS: + {VTYPE}, intent(in) :: expected + {VTYPE}, intent(in) :: actual + character(len=*), intent(in) :: msg + + ! absolute tolerance; if not specified, require exact equality; ignored for logicals + real(r8), intent(in), optional :: abs_tol + ! + ! !LOCAL VARIABLES: + integer :: i + + character(len=*), parameter :: subname = 'assert_equal_0d_{TYPE}' + !----------------------------------------------------------------------- + + if (.not. vals_are_equal(actual, expected, abs_tol)) then + write(iulog,*) 'ERROR in assert_equal: ', msg + write(iulog,*) 'Actual : ', actual + write(iulog,*) 'Expected: ', expected + call endrun('ERROR in assert_equal') + end if + + end subroutine assert_equal_0d_{TYPE} + + !----------------------------------------------------------------------- + !TYPE text + subroutine assert_equal_0d_{TYPE}(expected, actual, msg) + ! + ! !DESCRIPTION: + ! Assert scalar values are equal + ! + ! !ARGUMENTS: + {VTYPE}, intent(in) :: expected + {VTYPE}, intent(in) :: actual + character(len=*), intent(in) :: msg + ! + ! !LOCAL VARIABLES: + !----------------------------------------------------------------------- + + if (.not. vals_are_equal(actual, expected)) then + write(iulog,*) 'ERROR in assert_equal: ', msg + write(iulog,*) 'Actual : ', actual + write(iulog,*) 'Expected: ', expected + call endrun('ERROR in assert_equal') + end if + + end subroutine assert_equal_0d_{TYPE} + !----------------------------------------------------------------------- !TYPE double,int,logical subroutine assert_equal_2d_{TYPE}(expected, actual, msg, abs_tol) @@ -198,4 +260,23 @@ contains end function vals_are_equal_{TYPE} + !----------------------------------------------------------------------- + !TYPE text + function vals_are_equal_{TYPE}(actual, expected) result(vals_equal) + ! + ! !DESCRIPTION: + ! Returns true if actual is the same as expected, false otherwise + ! + ! !ARGUMENTS: + logical :: vals_equal ! function result + {VTYPE}, intent(in) :: actual + {VTYPE}, intent(in) :: expected + ! + ! !LOCAL VARIABLES: + !----------------------------------------------------------------------- + + vals_equal = actual == expected + + end function vals_are_equal_{TYPE} + end module Assertions From a5d5b5cb705be625212fd36539f201ceb9ded2b3 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 1 Oct 2025 09:32:13 -0600 Subject: [PATCH 25/31] Revert most of 2fd081b544 so removing the changes regarding the addition of atm_present and adjustments to how send_to_atm was done --- src/cpl/nuopc/lnd_comp_nuopc.F90 | 11 +---------- src/cpl/nuopc/lnd_import_export.F90 | 16 ++++------------ 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90 index 4ce0b3d6af..173981341d 100644 --- a/src/cpl/nuopc/lnd_comp_nuopc.F90 +++ b/src/cpl/nuopc/lnd_comp_nuopc.F90 @@ -81,7 +81,6 @@ module lnd_comp_nuopc logical :: glc_present logical :: rof_prognostic - logical :: atm_present logical :: atm_prognostic integer, parameter :: dbug = 0 character(*),parameter :: modName = "(lnd_comp_nuopc)" @@ -286,11 +285,6 @@ 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 @@ -317,9 +311,6 @@ 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 @@ -339,7 +330,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, rof_prognostic, & - atm_prognostic, atm_present, rc) + atm_prognostic, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return !---------------------------------------------------------------------------- diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index b8a5efeb8d..909caf094b 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -157,7 +157,7 @@ module lnd_import_export !=============================================================================== subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, rof_prognostic, & - atm_prognostic, atm_present, rc) + atm_prognostic, rc) use shr_carma_mod , only : shr_carma_readnl use shr_ndep_mod , only : shr_ndep_readnl @@ -174,7 +174,6 @@ 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 @@ -212,9 +211,7 @@ 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 (.not. atm_present)then - send_to_atm = .false. - else if (atm_prognostic .or. force_send_to_atm) then + if (atm_prognostic .or. force_send_to_atm) then send_to_atm = .true. else send_to_atm = .false. @@ -257,6 +254,7 @@ 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)) @@ -342,9 +340,6 @@ 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 ) @@ -395,9 +390,6 @@ 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 ) @@ -782,7 +774,6 @@ subroutine export_fields( gcomp, bounds, glc_present, rof_prognostic, & ! output to mediator ! ----------------------- - if (send_to_atm) then call state_setexport_1d(exportState, Sl_lfrin, ldomain%frac(begg:), init_spval=.false., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -790,6 +781,7 @@ 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 From b3185c0922640df0b21ccefc58aa2aa43b1c538d Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 1 Oct 2025 10:49:11 -0600 Subject: [PATCH 26/31] Move some for_testing namelist items into the selftests driver namelist --- bld/namelist_files/namelist_definition_ctsm.xml | 6 +++--- src/cpl/nuopc/lnd_comp_nuopc.F90 | 6 +++--- src/main/controlMod.F90 | 9 +-------- src/self_tests/SelfTestDriver.F90 | 14 ++++++++++---- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index c82a8219f1..2b5b4f2e99 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1275,18 +1275,18 @@ For testing whether to bypass most of the run phase other than the clock advance + group="for_testing_options" > 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. + group="for_testing_options" > 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. diff --git a/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90 index 173981341d..a6e7efb054 100644 --- a/src/cpl/nuopc/lnd_comp_nuopc.F90 +++ b/src/cpl/nuopc/lnd_comp_nuopc.F90 @@ -39,7 +39,6 @@ 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 @@ -50,6 +49,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 @@ -353,7 +353,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 + use SelfTestDriver , only : for_testing_bypass_init_after_self_tests, & + for_testing_exit_after_self_tests ! input/output variables type(ESMF_GridComp) :: gcomp @@ -1319,7 +1320,6 @@ 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)" diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index e43bac5a69..4a956e33b2 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -210,8 +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, & - for_testing_run_decomp_init_tests, for_testing_exit_after_self_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 @@ -767,12 +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 self tests - call mpi_bcast(for_testing_run_ncdiopio_tests, 1, MPI_LOGICAL, 0, mpicom, ier) - call mpi_bcast(for_testing_run_decomp_init_tests, 1, MPI_LOGICAL, 0, mpicom, ier) - - call mpi_bcast(for_testing_exit_after_self_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 97f23c5ae4..208c60c1db 100644 --- a/src/self_tests/SelfTestDriver.F90 +++ b/src/self_tests/SelfTestDriver.F90 @@ -6,10 +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 @@ -25,6 +25,9 @@ module SelfTestDriver ! 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__ @@ -41,8 +44,6 @@ subroutine self_test_driver(bounds) ! run if the appropriate flag is set. ! ! !USES: - use clm_varctl, only : for_testing_run_ncdiopio_tests, for_testing_run_decomp_init_tests - use clm_varctl, only : for_testing_exit_after_self_tests, iulog use decompMod, only : bounds_type use TestNcdioPio, only : test_ncdio_pio use ESMF, only : ESMF_LogWrite, ESMF_LOGMSG_INFO, ESMF_Finalize @@ -87,7 +88,9 @@ subroutine self_test_readnml(NLFileName) character(len=*), parameter :: nmlname = 'for_testing_options' !----------------------------------------------------------------------- - namelist /for_testing_options/ for_testing_bypass_init, for_testing_bypass_run + 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 @@ -109,6 +112,9 @@ subroutine self_test_readnml(NLFileName) 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,*) ' ' From 1acf630483c81badfc2435ae0963693cf439b81c Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 1 Oct 2025 01:37:38 -0600 Subject: [PATCH 27/31] Remove the uneeded timers and get back to the 3 part timers as they should be Conflicts: src/main/clm_initializeMod.F90 --- src/main/clm_initializeMod.F90 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 715630ba53..4ebf88b10c 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -314,7 +314,6 @@ subroutine initialize2(ni,nj, currtime) call decompInit_glcp(ni, nj, glc_behavior) call t_stopf('clm_decompInit_glcp') - call t_startf('clm_init2_part2') if (use_hillslope) then ! Initialize hillslope properties call InitHillslope(bounds_proc, hillslope_file) @@ -386,8 +385,6 @@ subroutine initialize2(ni,nj, currtime) call t_startf('clm_init2_part3') if ( .not. for_testing_bypass_init_after_self_tests() )then - - call t_startf('clm_init2_part3') ! Initialize Balance checking (after time-manager) call BalanceCheckInit() @@ -439,7 +436,6 @@ subroutine initialize2(ni,nj, currtime) call hist_printflds() end if - call t_startf('clm_init2_part4') ! Initializate dynamic subgrid weights (for prescribed transient Patches, CNDV ! and/or dynamic landunits); note that these will be overwritten in a restart run call init_subgrid_weights_mod(bounds_proc) @@ -560,7 +556,6 @@ subroutine initialize2(ni,nj, currtime) call restFile_read(bounds_proc, fnamer, glc_behavior, & reset_dynbal_baselines_lake_columns = reset_dynbal_baselines_lake_columns) end if - call t_stopf('clm_init2_part4') ! If appropriate, create interpolated initial conditions if (nsrest == nsrStartup .and. finidat_interp_source /= ' ') then From 2636975bd21457620dea28a5c9e622a7b903ccdb Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 1 Oct 2025 11:07:52 -0600 Subject: [PATCH 28/31] Remove some changes from the baseline code that aren't needed especially some timers accidentally brought in again --- src/cpl/nuopc/lnd_comp_nuopc.F90 | 3 +-- src/cpl/nuopc/lnd_import_export.F90 | 5 ++--- src/main/clm_initializeMod.F90 | 4 ---- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90 index a6e7efb054..3e0fc3c2f7 100644 --- a/src/cpl/nuopc/lnd_comp_nuopc.F90 +++ b/src/cpl/nuopc/lnd_comp_nuopc.F90 @@ -329,8 +329,7 @@ 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, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return !---------------------------------------------------------------------------- diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index 909caf094b..624590b9a6 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -156,8 +156,7 @@ 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, rc) use shr_carma_mod , only : shr_carma_readnl use shr_ndep_mod , only : shr_ndep_readnl @@ -258,8 +257,8 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r ! 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 ) diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 4ebf88b10c..0ffa7737a8 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -285,7 +285,6 @@ subroutine initialize2(ni,nj, currtime) call decompInit_clumps(ni, nj, glc_behavior) call t_stopf('clm_decompInit_clumps') - call t_startf('clm_init2_subgrid') ! *** Get ALL processor bounds - for gridcells, landunit, columns and patches *** call get_proc_bounds(bounds_proc) @@ -307,7 +306,6 @@ subroutine initialize2(ni,nj, currtime) call initGridCells(bounds_clump, glc_behavior) end do !$OMP END PARALLEL DO - call t_stopf('clm_init2_subgrid') ! Set global seg maps for gridcells, landlunits, columns and patches call t_startf('clm_decompInit_glcp') @@ -796,14 +794,12 @@ subroutine initialize2(ni,nj, currtime) endif if (water_inst%DoConsistencyCheck()) then - call t_startf('tracer_consistency_check') !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) do nc = 1,nclumps call get_clump_bounds(nc, bounds_clump) call water_inst%TracerConsistencyCheck(bounds_clump, 'end of initialization') end do !$OMP END PARALLEL DO - call t_stopf('tracer_consistency_check') end if call t_stopf('clm_init2_part3') From def2c979f428d26736004380e7fd90a4f9d38140 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 2 Oct 2025 00:58:04 -0600 Subject: [PATCH 29/31] Remove TestDecompInit for now, bring it in, in another PR --- src/self_tests/TestDecompInit.F90 | 363 ------------------------------ 1 file changed, 363 deletions(-) delete mode 100644 src/self_tests/TestDecompInit.F90 diff --git a/src/self_tests/TestDecompInit.F90 b/src/self_tests/TestDecompInit.F90 deleted file mode 100644 index b88b62ce85..0000000000 --- a/src/self_tests/TestDecompInit.F90 +++ /dev/null @@ -1,363 +0,0 @@ -module TestDecompInit - - ! ------------------------------------------------------------------------ - ! !DESCRIPTION: - ! This module contains tests of decomp_init - -#include "shr_assert.h" - use shr_kind_mod, only : r8 => shr_kind_r8, CX => shr_kind_cx - use Assertions, only : assert_equal - use clm_varctl, only : iulog - use abortutils, only : endrun, endrun_init, get_last_endrun_msg - use spmdMod, only : masterproc, npes, iam - use decompInitMod, only : decompInit_lnd, clump_pproc, decompInit_clumps - use clm_InstMod, only : glc_behavior - use decompMod - - implicit none - private - save - - ! Public routines - - public :: test_decomp_init - - ! Module data used in various tests - - ! Make the size of the test grid 384 so that it can be divided by 128 or 48 - ! for the number of tasks per node on Derecho or Izumi. - integer, parameter :: ni = 16, nj = 24 - integer :: amask(ni*nj) - - integer :: default_npes - integer :: default_clump_pproc - - character(len=*), parameter, private :: sourcefile = & - __FILE__ - -contains - - !----------------------------------------------------------------------- - subroutine test_decomp_init() - ! - ! !DESCRIPTION: - ! Drive tests of decomp_init - ! - ! NOTE(wjs, 2020-10-15) Currently, endrun is called when any test assertion fails. I - ! thought about changing this so that, instead, a counter is incremented for each - ! failure, then at the end of the testing (in the higher-level self-test driver), - ! endrun is called if this counter is greater than 0. The benefit of this is that we'd - ! see all test failures, not just the first failure. To do that, we'd need to change - ! the assertions here to increment a counter rather than aborting. However, I'm not - ! spending the time to make this change for now because (1) I'm not sure how much - ! value we'd get from it; (2) even if we made that change, it's still very possible - ! for test code to abort for reasons other than assertions, if something goes wrong - ! inside decomp_init or pio; and (3) some tests here are dependent on earlier tests (for - ! example, the reads depend on the writes having worked), so a failure in an early - ! phase could really muck things up for later testing phases. Migrating to a - ! pFUnit-based unit test would solve this problem, since each pFUnit test is - ! independent, though would prevent us from being able to have dependent tests the - ! way we do here (where reads depend on earlier writes), for better or for worse. - ! - ! !USERS: - use decompInitMod, only : decompInit_clumps, decompInit_glcp - use domainMod, only : ldomain - ! !ARGUMENTS: - ! - ! !LOCAL VARIABLES: - integer, allocatable :: model_amask(:) - !----------------------------------------------------------------------- - - default_npes = npes - default_clump_pproc = clump_pproc - call write_to_log('start_test_decomp_init') - - call write_to_log('test_check_nclumps') - call test_check_nclumps() - call write_to_log('test_decompInit_lnd_abort_on_bad_clump_pproc') - call test_decompInit_lnd_abort_on_bad_clump_pproc() - call write_to_log('test_decompInit_lnd_abort_on_too_big_clump_pproc') - call test_decompInit_lnd_abort_on_too_big_clump_pproc() - call write_to_log('test_decompInit_lnd_abort_when_npes_too_large') - call test_decompInit_lnd_abort_when_npes_too_large() - call write_to_log('test_decompInit_lnd_abort_on_too_small_nsegspc') - call test_decompInit_lnd_abort_on_too_small_nsegspc() - call write_to_log('test_decompInit_lnd_check_sizes') - call test_decompInit_lnd_check_sizes() - call write_to_log('test_decompInit_clump_gcell_info_correct') - call test_decompInit_clump_gcell_info_correct() - ! Comment out for now -- needs some work - !call write_to_log('test_decompMod_get_clump_bounds_correct') - !call test_decompMod_get_clump_bounds_correct() - - ! - ! Call the decompInit initialization series a last time so that decompMod data can still be used - ! - !allocate( model_amask(ldomain%ni*ldomain%nj) ) - !model_amask(:) = 1 - !call decompInit_lnd( ldomain%ni, ldomain%nj, model_amask ) - !call decompInit_clumps(ldomain%ni, ldomain%nj, glc_behavior) - !call decompInit_glcp(ldomain%ni, ldomain%nj, glc_behavior) - !deallocate( model_amask ) - - end subroutine test_decomp_init - - !----------------------------------------------------------------------- - subroutine setup() - use clm_varctl, only : nsegspc - - clump_pproc = default_clump_pproc - nsegspc = 20 - npes = default_npes - amask(:) = 1 ! Set all to land - - end subroutine setup - - !----------------------------------------------------------------------- - subroutine test_decompInit_lnd_abort_on_bad_clump_pproc() - character(len=CX) :: expected_msg, actual_msg - - if ( npes > 1 ) return ! error checking testing only works seriallly - call setup() - call endrun_init( .true. ) ! Do not abort on endrun for self-tests - clump_pproc = 0 - call write_to_log('decompInit_lnd with clump_pproc=0 should abort') - call decompInit_lnd( ni, nj, amask ) - call write_to_log('check expected abort message') - expected_msg = 'clump_pproc must be greater than 0' - actual_msg = get_last_endrun_msg() - call endrun_init( .false. ) ! Turn back on to abort on the assert - call write_to_log('call assert_equal to check the abort message') - call assert_equal( & - expected=expected_msg, actual=actual_msg, & - msg='decompInit_lnd did not abort with clump_pproc=0' ) - call clean() - end subroutine test_decompInit_lnd_abort_on_bad_clump_pproc - - !----------------------------------------------------------------------- - subroutine test_decompInit_lnd_abort_on_too_big_clump_pproc() - character(len=CX) :: expected_msg, actual_msg - - if ( npes > 1 ) return ! error checking testing only works seriallly - call setup() - call endrun_init( .true. ) ! Do not abort on endrun for self-tests - amask(:) = 1 ! Set all to land - clump_pproc = (ni * nj + 1) / npes - call write_to_log('decompInit_lnd with clump_pproc too large should abort') - call decompInit_lnd( ni, nj, amask ) - call write_to_log('check expected abort message') - expected_msg = 'Number of clumps exceeds number of land grid cells' - actual_msg = get_last_endrun_msg() - call endrun_init( .false. ) ! Turn back on to abort on the assert - call write_to_log('call assert_equal to check the abort message') - call assert_equal( & - expected=expected_msg, actual=actual_msg, & - msg='decompInit_lnd did not abort with clump_pproc too large' ) - call clean() - end subroutine test_decompInit_lnd_abort_on_too_big_clump_pproc - - !----------------------------------------------------------------------- - subroutine test_decompInit_lnd_check_sizes() - use decompMod, only : get_proc_bounds - type(bounds_type) :: bounds - - integer :: expected_endg, expected_numg - - call setup() - expected_numg = ni*nj - if ( expected_numg < npes )then - call endrun( msg="npes is too large for this test", file=sourcefile, line=__LINE__ ) - end if - if ( modulo( expected_numg, npes ) /= 0 )then - call endrun( msg="npes does not evenly divide into numg so this test will not work", file=sourcefile, line=__LINE__ ) - end if - expected_endg = ni*nj / npes - amask(:) = 1 ! Set all to land - call decompInit_lnd( ni, nj, amask ) - call get_proc_bounds(bounds, allow_errors=.true.) - call assert_equal( bounds%begg, 1, msg='begg is not as expected' ) - call assert_equal( bounds%endg, expected_endg, msg='endg is not as expected' ) - call clean() - end subroutine test_decompInit_lnd_check_sizes - - !----------------------------------------------------------------------- - subroutine test_decompInit_lnd_abort_when_npes_too_large() - character(len=CX) :: expected_msg, actual_msg - - if ( npes > 1 ) return ! error checking testing only works seriallly - call setup() - ! NOTE: This is arbitrarily modifying the NPES value -- so it MUST be reset set the END! - npes = ni*nj + 1 - - call endrun_init( .true. ) ! Do not abort on endrun for self-tests - amask(:) = 1 ! Set all to land - call write_to_log('decompInit_lnd with npes too large should abort') - call decompInit_lnd( ni, nj, amask ) - call write_to_log('check expected abort message') - expected_msg = 'Number of processes exceeds number of land grid cells' - actual_msg = get_last_endrun_msg() - call endrun_init( .false. ) ! Turn back on to abort on the assert - call write_to_log('call assert_equal to check the abort message') - call assert_equal( & - expected=expected_msg, actual=actual_msg, & - msg='decompInit_lnd did not abort with npes too large' ) - - ! NOTE: Return npes to its original value - npes = default_npes - call clean() - end subroutine test_decompInit_lnd_abort_when_npes_too_large - - !----------------------------------------------------------------------- - subroutine test_decompInit_lnd_abort_on_too_small_nsegspc() - use clm_varctl, only : nsegspc - character(len=CX) :: expected_msg, actual_msg - - if ( npes > 1 ) return ! error checking testing only works seriallly - call setup() - call endrun_init( .true. ) ! Do not abort on endrun for self-tests - amask(:) = 1 ! Set all to land - nsegspc = 0 - call write_to_log('decompInit_lnd with nsegspc too small should abort') - call decompInit_lnd( ni, nj, amask ) - call write_to_log('check expected abort message') - expected_msg = 'Number of segments per clump (nsegspc) is less than 1 and can NOT be' - actual_msg = get_last_endrun_msg() - call endrun_init( .false. ) ! Turn back on to abort on the assert - call write_to_log('call assert_equal to check the abort message') - call assert_equal( & - expected=expected_msg, actual=actual_msg, & - msg='decompInit_lnd did not abort with too nsegspc too small' ) - call clean() - end subroutine test_decompInit_lnd_abort_on_too_small_nsegspc - - !----------------------------------------------------------------------- - subroutine test_check_nclumps() - integer :: expected_nclumps - - call setup() - call endrun_init( .true. ) ! Do not abort on endrun for self-tests - expected_nclumps = npes / clump_pproc - call assert_equal(expected=expected_nclumps, actual=nclumps, & - msg='nclumps are not as expected') - call endrun_init( .false. ) - call clean() - end subroutine test_check_nclumps - -!----------------------------------------------------------------------- - subroutine test_decompMod_get_clump_bounds_correct() - ! Some testing for get_clump_bounds - use decompMod, only : get_clump_bounds, bounds_type - use unittestSimpleSubgridSetupsMod, only : setup_ncells_single_veg_patch - use unittestSubgridMod, only : unittest_subgrid_teardown - use pftconMod, only : noveg - type(bounds_type) :: bounds - integer :: expected_begg, expected_endg, expected_numg, gcell_per_task - integer :: iclump - - call setup() - ! Now setup a singple grid that's just the full test with every point a single baresoil patch - call setup_ncells_single_veg_patch( ncells=ni*nj, pft_type=noveg ) - clump_pproc = 1 ! Ensure we are just doing this for one clump per proc for now - expected_numg = ni*nj - if ( expected_numg < npes )then - call endrun( msg="npes is too large for this test", file=sourcefile, line=__LINE__ ) - end if - if ( modulo( expected_numg, npes ) /= 0 )then - call endrun( msg="npes does not evenly divide into numg so this test will not work", file=sourcefile, line=__LINE__ ) - end if - gcell_per_task = expected_numg / npes - expected_begg = gcell_per_task * iam + 1 - expected_endg = expected_begg + gcell_per_task - amask(:) = 1 ! Set all to land - call decompInit_lnd( ni, nj, amask ) - call decompInit_clumps( ni, nj, glc_behavior ) - iclump = 1 ! Clump is just 1 since there's only one clump per task - call get_clump_bounds(iclump, bounds) - call assert_equal( bounds%begg, expected_begg, msg='begg is not as expected' ) - call assert_equal( bounds%endg, expected_endg, msg='endg is not as expected' ) - ! Other subgrtid level information will be the same -- since there's only one landunit, column, and patch per gridcell - call assert_equal( bounds%begl, expected_begg, msg='begl is not as expected' ) - call assert_equal( bounds%endl, expected_endg, msg='endl is not as expected' ) - call assert_equal( bounds%begc, expected_begg, msg='begc is not as expected' ) - call assert_equal( bounds%endc, expected_endg, msg='endc is not as expected' ) - call assert_equal( bounds%begp, expected_begg, msg='begp is not as expected' ) - call assert_equal( bounds%endp, expected_endg, msg='endp is not as expected' ) - call unittest_subgrid_teardown( ) - call clean() - end subroutine test_decompMod_get_clump_bounds_correct - - !----------------------------------------------------------------------- - subroutine test_decompInit_clump_gcell_info_correct() - ! Some testing for get_clump_bounds - use decompMod, only : clumps - use decompMod, only : get_proc_bounds - type(bounds_type) :: bounds - integer :: expected_gcells, iclump, g, beg_global_index, gcell_per_task - integer :: expected_begg, expected_endg, lc - - call setup() - expected_gcells = ni*nj - if ( expected_gcells < npes )then - call endrun( msg="npes is too large for this test", file=sourcefile, line=__LINE__ ) - end if - if ( modulo( expected_gcells, npes ) /= 0 )then - call endrun( msg="npes does not evenly divide into gcell so this test will not work", file=sourcefile, line=__LINE__ ) - end if - gcell_per_task = expected_gcells / npes - expected_begg = gcell_per_task * iam + 1 - expected_endg = expected_begg + gcell_per_task - amask(:) = 1 ! Set all to land - call decompInit_lnd( ni, nj, amask ) - ! When clump_pproc is one clumps will be the same as PE - if ( clump_pproc == 1 ) then - call assert_equal( nclumps, npes, msg='nclumps should match number of processors when clump_pproc is 1' ) - else - call assert_equal( nclumps/clump_pproc, npes, msg='nclumps divided by clump_pproc should match number of processors when clump_pproc > 1' ) - end if - ! Just test over the local clumps - do lc = 1, clump_pproc - iclump = procinfo%cid(lc) - call assert_equal( clumps(iclump)%owner, iam, msg='clumps owner is not correct' ) - call assert_equal( clumps(iclump)%ncells, gcell_per_task, msg='clumps ncells is not correct' ) - end do - call clean() - end subroutine test_decompInit_clump_gcell_info_correct - - !----------------------------------------------------------------------- - subroutine write_to_log(msg) - ! - ! !DESCRIPTION: - ! Write a message to the log file, just from the masterproc - ! - use shr_sys_mod, only : shr_sys_flush - ! !ARGUMENTS: - character(len=*), intent(in) :: msg - ! - ! !LOCAL VARIABLES: - - character(len=*), parameter :: subname = 'write_to_log' - !----------------------------------------------------------------------- - - if (masterproc) then - write(iulog,'(a)') msg - call shr_sys_flush(iulog) ! Flush the I/O buffers always - end if - - end subroutine write_to_log - - !----------------------------------------------------------------------- - subroutine clean - ! - ! !DESCRIPTION: - ! Do end-of-testing cleanup after each test - ! - ! !ARGUMENTS: - ! - ! !LOCAL VARIABLES: - !----------------------------------------------------------------------- - call decompmod_clean() - - end subroutine clean - - -end module TestDecompInit From bf947fbd778df6d8ed3325ad840bc9c687bd4b6d Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 2 Oct 2025 00:58:32 -0600 Subject: [PATCH 30/31] Remove the update to Assertions and bring it in, in another PR --- src/self_tests/Assertions.F90.in | 81 -------------------------------- 1 file changed, 81 deletions(-) diff --git a/src/self_tests/Assertions.F90.in b/src/self_tests/Assertions.F90.in index 4a86929a8a..2a4c8cccc6 100644 --- a/src/self_tests/Assertions.F90.in +++ b/src/self_tests/Assertions.F90.in @@ -17,12 +17,6 @@ module Assertions public :: assert_equal interface assert_equal - !TYPE double,int,logical - module procedure assert_equal_0d_{TYPE} - - !TYPE text - module procedure assert_equal_0d_{TYPE} - !TYPE double,int,logical module procedure assert_equal_1d_{TYPE} @@ -36,8 +30,6 @@ module Assertions interface vals_are_equal !TYPE double,int,logical module procedure vals_are_equal_{TYPE} - !TYPE text - module procedure vals_are_equal_{TYPE} end interface vals_are_equal contains @@ -83,60 +75,6 @@ contains end subroutine assert_equal_1d_{TYPE} - !----------------------------------------------------------------------- - !TYPE double,int,logical - subroutine assert_equal_0d_{TYPE}(expected, actual, msg, abs_tol) - ! - ! !DESCRIPTION: - ! Assert scalar values are equal - ! - ! !ARGUMENTS: - {VTYPE}, intent(in) :: expected - {VTYPE}, intent(in) :: actual - character(len=*), intent(in) :: msg - - ! absolute tolerance; if not specified, require exact equality; ignored for logicals - real(r8), intent(in), optional :: abs_tol - ! - ! !LOCAL VARIABLES: - integer :: i - - character(len=*), parameter :: subname = 'assert_equal_0d_{TYPE}' - !----------------------------------------------------------------------- - - if (.not. vals_are_equal(actual, expected, abs_tol)) then - write(iulog,*) 'ERROR in assert_equal: ', msg - write(iulog,*) 'Actual : ', actual - write(iulog,*) 'Expected: ', expected - call endrun('ERROR in assert_equal') - end if - - end subroutine assert_equal_0d_{TYPE} - - !----------------------------------------------------------------------- - !TYPE text - subroutine assert_equal_0d_{TYPE}(expected, actual, msg) - ! - ! !DESCRIPTION: - ! Assert scalar values are equal - ! - ! !ARGUMENTS: - {VTYPE}, intent(in) :: expected - {VTYPE}, intent(in) :: actual - character(len=*), intent(in) :: msg - ! - ! !LOCAL VARIABLES: - !----------------------------------------------------------------------- - - if (.not. vals_are_equal(actual, expected)) then - write(iulog,*) 'ERROR in assert_equal: ', msg - write(iulog,*) 'Actual : ', actual - write(iulog,*) 'Expected: ', expected - call endrun('ERROR in assert_equal') - end if - - end subroutine assert_equal_0d_{TYPE} - !----------------------------------------------------------------------- !TYPE double,int,logical subroutine assert_equal_2d_{TYPE}(expected, actual, msg, abs_tol) @@ -260,23 +198,4 @@ contains end function vals_are_equal_{TYPE} - !----------------------------------------------------------------------- - !TYPE text - function vals_are_equal_{TYPE}(actual, expected) result(vals_equal) - ! - ! !DESCRIPTION: - ! Returns true if actual is the same as expected, false otherwise - ! - ! !ARGUMENTS: - logical :: vals_equal ! function result - {VTYPE}, intent(in) :: actual - {VTYPE}, intent(in) :: expected - ! - ! !LOCAL VARIABLES: - !----------------------------------------------------------------------- - - vals_equal = actual == expected - - end function vals_are_equal_{TYPE} - end module Assertions From 80192dca65e14b6d78d9561aba4c32ce9b0b45ee Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 2 Oct 2025 01:21:19 -0600 Subject: [PATCH 31/31] Remove update in DecompInitMod for now --- src/main/decompInitMod.F90 | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/decompInitMod.F90 b/src/main/decompInitMod.F90 index cf84a4a7c6..aa575bd787 100644 --- a/src/main/decompInitMod.F90 +++ b/src/main/decompInitMod.F90 @@ -574,8 +574,6 @@ subroutine decompInit_clumps(lni,lnj,glc_behavior) enddo do n = 1,nclumps - ! Only do the error checking over the local processor - if (clumps(n)%owner == iam) then if (clumps(n)%ncells /= allvecg(n,1) .or. & clumps(n)%nlunits /= allvecg(n,2) .or. & clumps(n)%ncols /= allvecg(n,3) .or. & @@ -590,7 +588,6 @@ subroutine decompInit_clumps(lni,lnj,glc_behavior) call endrun(msg=errMsg(sourcefile, __LINE__)) endif - endif enddo deallocate(allvecg,allvecl)