From 6b171e8af18b30c2b3dfb8ef7b87333c6ca8edd1 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 25 Jun 2025 17:37:28 -0600 Subject: [PATCH 01/36] Some updates to CMakeLists that get closer, but aren't quite working yet. FATES code is still having problems like not getting the shr_log_mod and errMsg subroutine in it, and this is setup for the shr_mpi_mod stub, but the testing will need to use the full shr_mpi_mod code. It also looks like getting the CESM unit testing to work with MPI would be an effort as we don't even build pFUnit with MPI libraries (although we did on Cheyenne) --- src/CMakeLists.txt | 11 ++- src/main/CMakeLists.txt | 2 + src/main/test/CMakeLists.txt | 1 + src/main/test/decomp_test/CMakeLists.txt | 8 ++ src/main/test/decomp_test/test_decompInit.pf | 88 ++++++++++++++++++++ src/utils/CMakeLists.txt | 1 + 6 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/main/test/decomp_test/CMakeLists.txt create mode 100644 src/main/test/decomp_test/test_decompInit.pf diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9707af4f0b..3cc02f03ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,6 +57,14 @@ add_subdirectory(${CLM_ROOT}/src/main clm_main) add_subdirectory(${CLM_ROOT}/src/init_interp clm_init_interp) add_subdirectory(${CLM_ROOT}/src/self_tests clm_self_tests) +# Add FATES source directories +add_subdirectory(${CLM_ROOT}/src/fates/main fates_main) +add_subdirectory(${CLM_ROOT}/src/fates/biogeochem fates_biogeochem) +add_subdirectory(${CLM_ROOT}/src/fates/biogeophys fates_biogeophys) +add_subdirectory(${CLM_ROOT}/src/fates/parteh fates_parteh) +add_subdirectory(${CLM_ROOT}/src/fates/fire fates_fire) +add_subdirectory(${CLM_ROOT}/src/fates/radiation fates_radiation) + # Add general unit test directories (stubbed out files, etc.) add_subdirectory(unit_test_stubs) add_subdirectory(unit_test_shr) @@ -90,8 +98,9 @@ endforeach() add_library(csm_share ${share_sources} ${drv_sources_needed}) declare_generated_dependencies(csm_share "${share_genf90_sources}") add_library(clm ${clm_sources}) +add_library(fates ${fates_sources}) declare_generated_dependencies(clm "${clm_genf90_sources}") -add_dependencies(clm csm_share esmf) +add_dependencies(clm csm_share esmf fates) # We need to look for header files here, in order to pick up shr_assert.h include_directories(${CLM_ROOT}/share/include) diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index 53a6edb8a5..d249a1da8d 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -19,6 +19,7 @@ list(APPEND clm_sources clm_varsur.F90 column_varcon.F90 decompMod.F90 + decompInitMod.F90 filterColMod.F90 glc2lndMod.F90 glcBehaviorMod.F90 @@ -29,6 +30,7 @@ list(APPEND clm_sources ncdio_utils.F90 organicFileMod.F90 paramUtilMod.F90 + subgridMod.F90 subgridAveMod.F90 subgridWeightsMod.F90 surfrdUtilsMod.F90 diff --git a/src/main/test/CMakeLists.txt b/src/main/test/CMakeLists.txt index 97bbf081cc..588bc5a50e 100644 --- a/src/main/test/CMakeLists.txt +++ b/src/main/test/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory(filter_test) add_subdirectory(initVertical_test) add_subdirectory(ncdio_utils_test) add_subdirectory(topo_test) +add_subdirectory(decomp_test) diff --git a/src/main/test/decomp_test/CMakeLists.txt b/src/main/test/decomp_test/CMakeLists.txt new file mode 100644 index 0000000000..3499774292 --- /dev/null +++ b/src/main/test/decomp_test/CMakeLists.txt @@ -0,0 +1,8 @@ +set(pfunit_sources + test_decompInit.pf) + +add_pfunit_ctest(decomp + TEST_SOURCES "${pfunit_sources}" + LINK_LIBRARIES clm csm_share esmf + EXTRA_FINALIZE unittest_finalize_esmf + EXTRA_USE unittestInitializeAndFinalize) diff --git a/src/main/test/decomp_test/test_decompInit.pf b/src/main/test/decomp_test/test_decompInit.pf new file mode 100644 index 0000000000..c7f71e8ea2 --- /dev/null +++ b/src/main/test/decomp_test/test_decompInit.pf @@ -0,0 +1,88 @@ +module test_decompInit + + ! Tests of decompInitMod + + use funit + use decompMod, only : bounds + use decompInitMod + use unittestSubgridMod + use unittestSimpleSubgridSetupsMod, only : setup_single_veg_patch, setup_n_veg_patches + use glcBehaviorMod, only: glc_behavior_type + use shr_kind_mod , only : r8 => shr_kind_r8 + + implicit none + + @TestCase + type, extends(TestCase) :: TestDecomp + contains + procedure :: setUp + procedure :: tearDown + procedure :: create_glc_behavior + end type TestDecomp + +contains + + ! ======================================================================== + ! Helper routines + ! ======================================================================== + + subroutine setUp(this) + class(TestDecomp), intent(inout) :: this + end subroutine setUp + + subroutine tearDown(this) + class(TestDecomp), intent(inout) :: this + + end subroutine tearDown + + !----------------------------------------------------------------------- + function create_glc_behavior() result(glc_behavior) + ! + ! !DESCRIPTION: + ! Creates a glc_behavior instance with collapse_to_atm_topo set for all + ! + ! Must be called *after* setting up the subgrid structure. + ! + use unittestArrayMod, only : grc_array + ! !ARGUMENTS: + type(glc_behavior_type) :: glc_behavior ! function result + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'create_glc_behavior' + !----------------------------------------------------------------------- + + call glc_behavior%InitSetDirectly(bounds%begg, bounds%endg, & + has_virtual_columns = grc_array(.false.), & + collapse_to_atm_topo = grc_array(collapse_to_atm_topo=.true.)) + + end function create_glc_behavior + + ! ======================================================================== + ! Begin tests + ! ======================================================================== + + @Test + subroutine decompInitClumps_basic(this) + use glcBehaviorMod, only : glc_behavior_type + ! Test basic operation of decompInit_clumps + class(TestDecomp), intent(inout) :: this + + ! Local + type(glc_behavior_type) :: glc_behavior + integer :: ni, nj + + ! Setup a single grid cell + nj = 1 + ni = 1 + call setup_single_veg_patch(pft_type=1) + glc_behavior = create_glc_behavior() + + ! Exercise + ! Determine decomposition of subgrid scale landunits, columns, patches + call decompInit_clumps(ni, nj, glc_behavior) + + ! Verify + end subroutine decompInitClumps_basic + +end module test_decompInit diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 04ad683517..9038b6dbca 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -22,6 +22,7 @@ list(APPEND clm_sources SparseMatrixMultiplyMod.F90 IssueFixedMetadataHandler.F90 NumericsMod.F90 + spmdMod.F90 ) sourcelist_to_parent(clm_sources) From d00588bb64c6fd4d3dac959033309f99669b3a01 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 10 Oct 2025 15:59:06 -0600 Subject: [PATCH 02/36] Add some basic unit tests of vegtype_str2int(). One fails. --- python/ctsm/test/test_unit_cropcal_utils.py | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100755 python/ctsm/test/test_unit_cropcal_utils.py diff --git a/python/ctsm/test/test_unit_cropcal_utils.py b/python/ctsm/test/test_unit_cropcal_utils.py new file mode 100755 index 0000000000..8baf83cffe --- /dev/null +++ b/python/ctsm/test/test_unit_cropcal_utils.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +"""Unit tests for cropcal_utils.py""" + +import unittest + +from ctsm import unit_testing +from ctsm.crop_calendars import cropcal_utils as ccu + +# Allow names that pylint doesn't like, because otherwise I find it hard +# to make readable unit test names +# pylint: disable=invalid-name + + +class TestCropCalUtils(unittest.TestCase): + """Tests of cropcal_utils.py""" + + def setUp(self): + self.vegtype_mainlist = ["crop_1", "crop_2", "crop_3"] + + def test_vegtype_str2int_1string(self): + """ + Tests vegtype_str2int() for a single string + """ + ccu.vegtype_str2int("crop_1", vegtype_mainlist=self.vegtype_mainlist) + + def test_vegtype_str2int_2strings(self): + """ + Tests vegtype_str2int() for two strings + """ + result = ccu.vegtype_str2int(["crop_1", "crop_3"], vegtype_mainlist=self.vegtype_mainlist) + self.assertListEqual(result, [0, 2]) + + +if __name__ == "__main__": + unit_testing.setup_for_tests() + unittest.main() From 471086a3d5297a010059499b87aa64a0a7dbc8b9 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 10 Oct 2025 16:00:06 -0600 Subject: [PATCH 03/36] vegtype_str2int(): Fix for single string inputs. --- python/ctsm/crop_calendars/cropcal_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ctsm/crop_calendars/cropcal_utils.py b/python/ctsm/crop_calendars/cropcal_utils.py index c7e8b6ac52..84d129e453 100644 --- a/python/ctsm/crop_calendars/cropcal_utils.py +++ b/python/ctsm/crop_calendars/cropcal_utils.py @@ -265,6 +265,7 @@ def vegtype_str2int(vegtype_str, vegtype_mainlist=None): convert_to_ndarray = not isinstance(vegtype_str, np.ndarray) if convert_to_ndarray: vegtype_str = np.array(vegtype_str) + vegtype_str = np.atleast_1d(vegtype_str) if isinstance(vegtype_mainlist, xr.Dataset): vegtype_mainlist = vegtype_mainlist.vegtype_str.values From 5bd62977cea26edb76cc5b66d31d037ecbc1aaab Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 10 Oct 2025 16:07:34 -0600 Subject: [PATCH 04/36] grid_one_variable: Replace np.NaN with np.nan. --- python/ctsm/crop_calendars/grid_one_variable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/grid_one_variable.py b/python/ctsm/crop_calendars/grid_one_variable.py index d7c7126e54..b83f37ae13 100644 --- a/python/ctsm/crop_calendars/grid_one_variable.py +++ b/python/ctsm/crop_calendars/grid_one_variable.py @@ -100,7 +100,7 @@ def create_filled_array(this_ds, fill_value, thisvar_da, new_dims): if fill_value: thisvar_gridded[:] = fill_value else: - thisvar_gridded[:] = np.NaN + thisvar_gridded[:] = np.nan return thisvar_gridded From e0bac6d653affd9a232a5ad51637e52f3bbe92f7 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 10 Oct 2025 16:09:00 -0600 Subject: [PATCH 05/36] When calling vegtype_str2int for a single string, return a single int, not list. --- python/ctsm/crop_calendars/check_rx_obeyed.py | 2 +- python/ctsm/crop_calendars/cropcal_utils.py | 5 +++++ python/ctsm/crop_calendars/generate_gdd20_baseline.py | 4 ++-- python/ctsm/crop_calendars/generate_gdds_functions.py | 4 ++-- python/ctsm/test/test_unit_cropcal_utils.py | 7 ++++--- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/python/ctsm/crop_calendars/check_rx_obeyed.py b/python/ctsm/crop_calendars/check_rx_obeyed.py index c8c5410faf..68a37fb146 100644 --- a/python/ctsm/crop_calendars/check_rx_obeyed.py +++ b/python/ctsm/crop_calendars/check_rx_obeyed.py @@ -144,7 +144,7 @@ def check_rx_obeyed( continue ds_thisveg = dates_ds.isel(patch=thisveg_patches) - vegtype_int = utils.vegtype_str2int(vegtype_str)[0] + vegtype_int = utils.vegtype_str2int(vegtype_str) rx_da = rx_ds[f"gs1_{vegtype_int}"] rx_array = rx_da.values[ ds_thisveg.patches1d_jxy.values.astype(int) - 1, diff --git a/python/ctsm/crop_calendars/cropcal_utils.py b/python/ctsm/crop_calendars/cropcal_utils.py index 84d129e453..4f2929de37 100644 --- a/python/ctsm/crop_calendars/cropcal_utils.py +++ b/python/ctsm/crop_calendars/cropcal_utils.py @@ -265,6 +265,7 @@ def vegtype_str2int(vegtype_str, vegtype_mainlist=None): convert_to_ndarray = not isinstance(vegtype_str, np.ndarray) if convert_to_ndarray: vegtype_str = np.array(vegtype_str) + was_0d = vegtype_str.ndim == 0 vegtype_str = np.atleast_1d(vegtype_str) if isinstance(vegtype_mainlist, xr.Dataset): @@ -290,6 +291,10 @@ def vegtype_str2int(vegtype_str, vegtype_mainlist=None): indices[np.where(vegtype_str == vegtype_str_2)] = vegtype_mainlist.index(vegtype_str_2) if convert_to_ndarray: indices = [int(x) for x in indices] + + if was_0d: + indices = indices[0] + return indices diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index ee942eba21..ea2519db88 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -182,7 +182,7 @@ def _get_gddn_for_cft(cft_str, variable): def _get_output_varname(cft_str): - cft_int = utils.vegtype_str2int(cft_str)[0] + cft_int = utils.vegtype_str2int(cft_str) return f"gdd20bl_{cft_int}" @@ -275,7 +275,7 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab # Process all crops encoding_dict = {} for cft_str in MGDCROP_LIST: - cft_int = utils.vegtype_str2int(cft_str)[0] + cft_int = utils.vegtype_str2int(cft_str) print(f"{cft_str} ({cft_int})") # Which GDDN history variable does this crop use? E.g., GDD0, GDD10 diff --git a/python/ctsm/crop_calendars/generate_gdds_functions.py b/python/ctsm/crop_calendars/generate_gdds_functions.py index f80f1e55f7..de737a6077 100644 --- a/python/ctsm/crop_calendars/generate_gdds_functions.py +++ b/python/ctsm/crop_calendars/generate_gdds_functions.py @@ -607,7 +607,7 @@ def import_and_process_1yr( log(logger, f" SKIPPING {vegtype_str}") continue - vegtype_int = utils.vegtype_str2int(vegtype_str)[0] + vegtype_int = utils.vegtype_str2int(vegtype_str) this_crop_full_patchlist = list(xr_flexsel(h2_ds, vegtype=vegtype_str).patch.values) # Get time series for each patch of this type @@ -1166,7 +1166,7 @@ def make_figures( raise RuntimeError(f"If mapping {vegtype_str}, you must provide land use dataset") else: vegtypes_str = [x for x in incl_vegtypes_str if vegtype_str.lower() in x] - vegtypes_int = [utils.vegtype_str2int(x)[0] for x in vegtypes_str] + vegtypes_int = [utils.vegtype_str2int(x) for x in vegtypes_str] # Crop fraction map (for masking and weighting) if lu_ds: diff --git a/python/ctsm/test/test_unit_cropcal_utils.py b/python/ctsm/test/test_unit_cropcal_utils.py index 8baf83cffe..edbb81bd7b 100755 --- a/python/ctsm/test/test_unit_cropcal_utils.py +++ b/python/ctsm/test/test_unit_cropcal_utils.py @@ -20,13 +20,14 @@ def setUp(self): def test_vegtype_str2int_1string(self): """ - Tests vegtype_str2int() for a single string + Tests vegtype_str2int() for a single string. Result should be an int. """ - ccu.vegtype_str2int("crop_1", vegtype_mainlist=self.vegtype_mainlist) + result = ccu.vegtype_str2int("crop_1", vegtype_mainlist=self.vegtype_mainlist) + self.assertEqual(result, 0) def test_vegtype_str2int_2strings(self): """ - Tests vegtype_str2int() for two strings + Tests vegtype_str2int() for two strings. result should be a list of ints. """ result = ccu.vegtype_str2int(["crop_1", "crop_3"], vegtype_mainlist=self.vegtype_mainlist) self.assertListEqual(result, [0, 2]) From 11a471cd486ba88d12ff7cf10d62bb7d1c5c51c5 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 10 Oct 2025 16:32:18 -0600 Subject: [PATCH 06/36] Add some basic unit tests of create_filled_array(). 1 failing. --- .../ctsm/test/test_unit_grid_one_variable.py | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100755 python/ctsm/test/test_unit_grid_one_variable.py diff --git a/python/ctsm/test/test_unit_grid_one_variable.py b/python/ctsm/test/test_unit_grid_one_variable.py new file mode 100755 index 0000000000..e5d8f9b7a0 --- /dev/null +++ b/python/ctsm/test/test_unit_grid_one_variable.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +""" +Unit tests for grid_one_variable +""" + +import unittest + +import numpy as np +import xarray as xr + +from ctsm import unit_testing +from ctsm.crop_calendars import grid_one_variable as g1v + +# Allow test names that pylint doesn't like; otherwise hard to make them +# readable +# pylint: disable=invalid-name + +# pylint: disable=protected-access + +## Too many instant variables as part of the class (too many self. in the SetUp) +# pylint: disable=too-many-instance-attributes + + +class TestCreateFilledArray(unittest.TestCase): + """Unit tests for create_filled_array""" + + def setUp(self): + # Set up this_ds, which will provide us with sizes of dimensions in most cases + lat_vals = [55.0, 56.0, 57.0] + lat_da = xr.DataArray( + data=lat_vals, + dims=["lat"], + coords={"lat": lat_vals}, + ) + lon_vals = [255.0, 256.0, 257.0] + lon_da = xr.DataArray( + data=lon_vals, + dims=["lon"], + coords={"lon": lon_vals}, + ) + self.this_ds = xr.Dataset( + data_vars={ + "lat": lat_da, + "lon": lon_da, + } + ) + + def test_create_filled_array_fillNone(self): + """ + Test create_filled_array() with fill_value None: Should be filled with NaN + """ + + fill_value = None + thisvar_da_dummy = xr.DataArray() + new_dims = ["lat", "lon"] + + result = g1v.create_filled_array(self.this_ds, fill_value, thisvar_da_dummy, new_dims) + + self.assertTrue(np.all(np.isnan(result))) + + def test_create_filled_array_fill1(self): + """ + Test create_filled_array() with fill_value 1: Should be filled with 1 + """ + + fill_value = 1.0 + thisvar_da_dummy = xr.DataArray() + new_dims = ["lat", "lon"] + + result = g1v.create_filled_array(self.this_ds, fill_value, thisvar_da_dummy, new_dims) + + self.assertTrue(np.all(result == fill_value)) + + def test_create_filled_array_fill0(self): + """ + Test create_filled_array() with fill_value 0: Should be filled with 0 + """ + + fill_value = 0.0 + thisvar_da_dummy = xr.DataArray() + new_dims = ["lat", "lon"] + + result = g1v.create_filled_array(self.this_ds, fill_value, thisvar_da_dummy, new_dims) + + self.assertTrue(np.all(result == fill_value)) From c3f9be28ef0c067d61dc7d048ac7573c88771489 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 10 Oct 2025 16:34:06 -0600 Subject: [PATCH 07/36] create_filled_array(): Fix behavior with fill_value=0. --- python/ctsm/crop_calendars/grid_one_variable.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/ctsm/crop_calendars/grid_one_variable.py b/python/ctsm/crop_calendars/grid_one_variable.py index b83f37ae13..01eaf84ca0 100644 --- a/python/ctsm/crop_calendars/grid_one_variable.py +++ b/python/ctsm/crop_calendars/grid_one_variable.py @@ -87,6 +87,10 @@ def create_filled_array(this_ds, fill_value, thisvar_da, new_dims): """ Create a Numpy array to be filled with gridded data """ + + if fill_value is None: + fill_value = np.nan + dim_size_list = [] for dim in new_dims: if dim == "ivt_str": @@ -97,10 +101,7 @@ def create_filled_array(this_ds, fill_value, thisvar_da, new_dims): dim_size = this_ds.sizes[dim] dim_size_list = dim_size_list + [dim_size] thisvar_gridded = np.empty(dim_size_list) - if fill_value: - thisvar_gridded[:] = fill_value - else: - thisvar_gridded[:] = np.nan + thisvar_gridded[:] = fill_value return thisvar_gridded From a73eb84a97a3794fce9f962a621644a49de08558 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 10 Oct 2025 16:35:23 -0600 Subject: [PATCH 08/36] grid_one_variable(): Fix behavior with fill_value=0. --- python/ctsm/crop_calendars/grid_one_variable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/grid_one_variable.py b/python/ctsm/crop_calendars/grid_one_variable.py index 01eaf84ca0..c06ed50b16 100644 --- a/python/ctsm/crop_calendars/grid_one_variable.py +++ b/python/ctsm/crop_calendars/grid_one_variable.py @@ -161,7 +161,7 @@ def grid_one_variable(this_ds, var, fill_value=None, **kwargs): # Get DataArrays needed for gridding thisvar_da, vt_da, spatial_unit, ixy_da, jxy_da = get_ixy_jxy_das(this_ds, var) - if not fill_value and "_FillValue" in thisvar_da.attrs: + if fill_value is None and "_FillValue" in thisvar_da.attrs: fill_value = thisvar_da.attrs["_FillValue"] # Renumber vt_da to work as indices on new ivt dimension, if needed. From a728bda43ab16c9535bee4ca9692ce7b869059ed Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 10 Oct 2025 17:12:36 -0600 Subject: [PATCH 09/36] generate_gdd20_baseline: Move time slice from _parse_args() to generate_gdd20_baseline(). --- .../crop_calendars/generate_gdd20_baseline.py | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index ea2519db88..5fa066fe79 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -109,22 +109,7 @@ def _parse_args(): if not os.path.exists(filename): raise FileNotFoundError(f"Input file not found: {filename}") - # Process time slice - # Assumes CESM behavior where data for e.g. 1987 is saved as 1988-01-01. - # It would be more robust, accounting for upcoming behavior (where timestamp for a year is the - # middle of that year), to do slice("YEAR1-01-03", "YEARN-01-02"), but that's not compatible - # with ctsm_pylib as of the version using python 3.7.9. See safer_timeslice() in cropcal_utils. - if args.first_year is not None: - date_1 = f"{args.first_year+1}-01-01" - else: - date_1 = "0000-01-01" - if args.last_year is not None: - date_n = f"{args.last_year+1}-01-01" - else: - date_n = "9999-12-31" - time_slice = slice(date_1, date_n) - - return args, time_slice + return args def _get_cft_list(crop_list): @@ -232,7 +217,7 @@ def setup_output_dataset(input_files, author, variable, year_args, ds_in): return ds_out -def generate_gdd20_baseline(input_files, output_file, author, time_slice, variable, year_args): +def generate_gdd20_baseline(input_files, output_file, author, variable, year_args): """ Generate stream_fldFileName_gdd20_baseline file from CTSM outputs """ @@ -252,6 +237,23 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab input_files = list(set(input_files)) input_files.sort() + # Process time slice + # Assumes CESM behavior where data for e.g. 1987 is saved as 1988-01-01. + # It would be more robust, accounting for upcoming behavior (where timestamp for a year is the + # middle of that year), to do slice("YEAR1-01-03", "YEARN-01-02"), but that's not compatible + # with ctsm_pylib as of the version using python 3.7.9. See safer_timeslice() in cropcal_utils. + first_year = year_args[0] + last_year = year_args[1] + if first_year is not None: + date_1 = f"{first_year+1}-01-01" + else: + date_1 = "0000-01-01" + if last_year is not None: + date_n = f"{last_year+1}-01-01" + else: + date_n = "9999-12-31" + time_slice = slice(date_1, date_n) + # Import history files and ensure they have lat/lon dims ds_in = import_ds(input_files, my_vars=var_list_in + GRIDDING_VAR_LIST, time_slice=time_slice) if not all(x in ds_in.dims for x in ["lat", "lon"]): @@ -323,12 +325,11 @@ def main(): """ main() function for calling generate_gdd20_baseline.py from command line. """ - args, time_slice = _parse_args() + args = _parse_args() generate_gdd20_baseline( args.input_files, args.output_file, args.author, - time_slice, args.variable, [args.first_year, args.last_year], ) From fd55e311455d363fea61db7aa6cb92d05479fe5e Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 10 Oct 2025 17:14:46 -0600 Subject: [PATCH 10/36] generate_gdd20_baseline: Simplify time slice, assuming modern ctsm_pylib. --- .../ctsm/crop_calendars/generate_gdd20_baseline.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 5fa066fe79..c41c607a08 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -238,19 +238,13 @@ def generate_gdd20_baseline(input_files, output_file, author, variable, year_arg input_files.sort() # Process time slice - # Assumes CESM behavior where data for e.g. 1987 is saved as 1988-01-01. - # It would be more robust, accounting for upcoming behavior (where timestamp for a year is the - # middle of that year), to do slice("YEAR1-01-03", "YEARN-01-02"), but that's not compatible - # with ctsm_pylib as of the version using python 3.7.9. See safer_timeslice() in cropcal_utils. first_year = year_args[0] last_year = year_args[1] - if first_year is not None: - date_1 = f"{first_year+1}-01-01" - else: + date_1 = f"{first_year}-01-01" + date_n = f"{last_year}-12-31" + if first_year is None: date_1 = "0000-01-01" - if last_year is not None: - date_n = f"{last_year+1}-01-01" - else: + if last_year is None: date_n = "9999-12-31" time_slice = slice(date_1, date_n) From 9c9a313967a55ffd566baa2495d8b88b8286621b Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 Oct 2025 11:17:40 -0600 Subject: [PATCH 11/36] generate_gdd20_baseline.py: Refactor to new function _get_time_slice(). --- .../crop_calendars/generate_gdd20_baseline.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index c41c607a08..fa42eb58b4 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -217,6 +217,22 @@ def setup_output_dataset(input_files, author, variable, year_args, ds_in): return ds_out +def _get_time_slice(year_args): + """ + Based on years from input arguments, return a time slice for selecting from dataset + """ + first_year = year_args[0] + last_year = year_args[1] + date_1 = f"{first_year}-01-01" + date_n = f"{last_year}-12-31" + if first_year is None: + date_1 = "0000-01-01" + if last_year is None: + date_n = "9999-12-31" + time_slice = slice(date_1, date_n) + return time_slice + + def generate_gdd20_baseline(input_files, output_file, author, variable, year_args): """ Generate stream_fldFileName_gdd20_baseline file from CTSM outputs @@ -238,15 +254,7 @@ def generate_gdd20_baseline(input_files, output_file, author, variable, year_arg input_files.sort() # Process time slice - first_year = year_args[0] - last_year = year_args[1] - date_1 = f"{first_year}-01-01" - date_n = f"{last_year}-12-31" - if first_year is None: - date_1 = "0000-01-01" - if last_year is None: - date_n = "9999-12-31" - time_slice = slice(date_1, date_n) + time_slice = _get_time_slice(year_args) # Import history files and ensure they have lat/lon dims ds_in = import_ds(input_files, my_vars=var_list_in + GRIDDING_VAR_LIST, time_slice=time_slice) From 5bf0c522ae1a0e2eaf3202cc31f2932979bdd2ea Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 Oct 2025 11:18:06 -0600 Subject: [PATCH 12/36] test_unit_grid_one_variable: Add unit_testing.setup_for_tests(). --- python/ctsm/test/test_unit_grid_one_variable.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/ctsm/test/test_unit_grid_one_variable.py b/python/ctsm/test/test_unit_grid_one_variable.py index e5d8f9b7a0..400b4ede7e 100755 --- a/python/ctsm/test/test_unit_grid_one_variable.py +++ b/python/ctsm/test/test_unit_grid_one_variable.py @@ -84,3 +84,8 @@ def test_create_filled_array_fill0(self): result = g1v.create_filled_array(self.this_ds, fill_value, thisvar_da_dummy, new_dims) self.assertTrue(np.all(result == fill_value)) + + +if __name__ == "__main__": + unit_testing.setup_for_tests() + unittest.main() From 6278885c333102429b2ca5e1479bda5492728bba Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 4 Dec 2025 01:09:37 -0700 Subject: [PATCH 13/36] Update to cime version from Jin that solves the check_input_data --download problem --- .gitmodules | 7 +++++-- cime | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 69ace57fc3..146cc90bdf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -75,8 +75,11 @@ fxDONOTUSEurl = https://github.com/ESMCI/ccs_config_cesm.git [submodule "cime"] path = cime -url = https://github.com/ESMCI/cime -fxtag = cime6.1.128 +url = https://github.com/jedwards4b/cime +#url = https://github.com/ESMCI/cime +#fxtag = cime6.1.144 +#fxtag = jedwards4b:fix/spider_mode_disabled +fxtag = d2ddac622c7b4679dbb3c2f07070dd9c7ed57478 fxrequired = ToplevelRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/ESMCI/cime diff --git a/cime b/cime index 9b1d9d1bcd..d2ddac622c 160000 --- a/cime +++ b/cime @@ -1 +1 @@ -Subproject commit 9b1d9d1bcd9ed66a331ee3d2da1d617967b14f5b +Subproject commit d2ddac622c7b4679dbb3c2f07070dd9c7ed57478 From 6dde6097f5ef3f1c5d435b6912b8387f4bbe6eb1 Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:00:58 -0700 Subject: [PATCH 14/36] Add FSA_U --- src/biogeophys/SolarAbsorbedType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/SolarAbsorbedType.F90 b/src/biogeophys/SolarAbsorbedType.F90 index d1941f68cc..fa1de4a753 100644 --- a/src/biogeophys/SolarAbsorbedType.F90 +++ b/src/biogeophys/SolarAbsorbedType.F90 @@ -206,7 +206,7 @@ subroutine InitHistory(this, bounds) this%fsa_u_patch(begp:endp) = spval call hist_addfld1d (fname='FSA_U', units='W/m^2', & avgflag='A', long_name='Urban absorbed solar radiation', & - ptr_patch=this%fsa_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') + ptr_patch=this%fsa_u_patch, c2l_scale_type='urbanf', set_nourb=spval) this%fsr_patch(begp:endp) = spval call hist_addfld1d (fname='FSR', units='W/m^2', & From dd22ced0907e58698f6e209e59a30d45926aedc7 Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:02:46 -0700 Subject: [PATCH 15/36] Add RH2M_U --- src/biogeophys/WaterDiagnosticBulkType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/WaterDiagnosticBulkType.F90 b/src/biogeophys/WaterDiagnosticBulkType.F90 index f91aaca761..bf4d2d04f6 100644 --- a/src/biogeophys/WaterDiagnosticBulkType.F90 +++ b/src/biogeophys/WaterDiagnosticBulkType.F90 @@ -355,7 +355,7 @@ subroutine InitBulkHistory(this, bounds) units='%', & avgflag='A', & long_name=this%info%lname('Urban 2m relative humidity'), & - ptr_patch=this%rh_ref2m_u_patch, set_nourb=spval, default='inactive') + ptr_patch=this%rh_ref2m_u_patch, set_nourb=spval) this%rh_af_patch(begp:endp) = spval call hist_addfld1d ( & From df0bd4c679965c59c2beb72c3944ca46d2c13a9d Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:03:54 -0700 Subject: [PATCH 16/36] Add SoilAlpha_U --- src/biogeophys/SoilStateType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/SoilStateType.F90 b/src/biogeophys/SoilStateType.F90 index 4b9ced3466..e491613ceb 100644 --- a/src/biogeophys/SoilStateType.F90 +++ b/src/biogeophys/SoilStateType.F90 @@ -280,7 +280,7 @@ subroutine InitHistory(this, bounds) this%soilalpha_u_col(begc:endc) = spval call hist_addfld1d (fname='SoilAlpha_U', units='unitless', & avgflag='A', long_name='urban factor limiting ground evap', & - ptr_col=this%soilalpha_u_col, set_nourb=spval, default='inactive') + ptr_col=this%soilalpha_u_col, set_nourb=spval) if (use_cn) then this%watsat_col(begc:endc,:) = spval From f1d99ae3142f61afcb456d1800fc096b687e2251 Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:05:01 -0700 Subject: [PATCH 17/36] Add TG_U --- src/biogeophys/TemperatureType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 58e4c93e7b..1ac5a1a85b 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -343,7 +343,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_grnd_u_col(begc:endc) = spval call hist_addfld1d (fname='TG_U', units='K', & avgflag='A', long_name='Urban ground temperature', & - ptr_col=this%t_grnd_u_col, set_nourb=spval, c2l_scale_type='urbans', default='inactive') + ptr_col=this%t_grnd_u_col, set_nourb=spval, c2l_scale_type='urbans') this%t_lake_col(begc:endc,:) = spval call hist_addfld2d (fname='TLAKE', units='K', type2d='levlak', & From d22ae076ba566ed2ae0dbb85473399869265b912 Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:15:51 -0700 Subject: [PATCH 18/36] Add TSA_U and TSA_R --- src/biogeophys/TemperatureType.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 1ac5a1a85b..525f23ed41 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -373,7 +373,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='TSA_R', units='K', & avgflag='A', long_name='Rural 2m air temperature', & - ptr_patch=this%t_ref2m_r_patch, set_spec=spval, default='inactive') + ptr_patch=this%t_ref2m_r_patch, set_spec=spval) this%t_ref2m_min_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMNAV', units='K', & @@ -398,7 +398,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='TSA_U', units='K', & avgflag='A', long_name='Urban 2m air temperature', & - ptr_patch=this%t_ref2m_u_patch, set_nourb=spval, default='inactive') + ptr_patch=this%t_ref2m_u_patch, set_nourb=spval) this%t_ref2m_min_u_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMNAV_U', units='K', & From 9e8b41476952f93ca1796d1b775ff06e655932c7 Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:18:19 -0700 Subject: [PATCH 19/36] Add TREFMNAV_U and TREFMNAV_R --- src/biogeophys/TemperatureType.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 525f23ed41..c411c961ae 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -388,7 +388,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_ref2m_min_r_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMNAV_R', units='K', & avgflag='A', long_name='Rural daily minimum of average 2-m temperature', & - ptr_patch=this%t_ref2m_min_r_patch, set_spec=spval, default='inactive') + ptr_patch=this%t_ref2m_min_r_patch, set_spec=spval) this%t_ref2m_max_r_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMXAV_R', units='K', & @@ -403,7 +403,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_ref2m_min_u_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMNAV_U', units='K', & avgflag='A', long_name='Urban daily minimum of average 2-m temperature', & - ptr_patch=this%t_ref2m_min_u_patch, set_nourb=spval, default='inactive') + ptr_patch=this%t_ref2m_min_u_patch, set_nourb=spval) this%t_ref2m_max_u_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMXAV_U', units='K', & From 8d99015c96729918a6c9552244eca05696c9246e Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:21:44 -0700 Subject: [PATCH 20/36] Add TREFMXAV_U and TREFMXAV_R --- src/biogeophys/TemperatureType.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index c411c961ae..6fd8faf037 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -393,7 +393,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_ref2m_max_r_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMXAV_R', units='K', & avgflag='A', long_name='Rural daily maximum of average 2-m temperature', & - ptr_patch=this%t_ref2m_max_r_patch, set_spec=spval, default='inactive') + ptr_patch=this%t_ref2m_max_r_patch, set_spec=spval) this%t_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='TSA_U', units='K', & @@ -408,7 +408,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_ref2m_max_u_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMXAV_U', units='K', & avgflag='A', long_name='Urban daily maximum of average 2-m temperature', & - ptr_patch=this%t_ref2m_max_u_patch, set_nourb=spval, default='inactive') + ptr_patch=this%t_ref2m_max_u_patch, set_nourb=spval) if (use_biomass_heat_storage) then this%t_stem_patch(begp:endp) = spval From 4fa4b45a15ab7083bb860d75b9ff852219e215f3 Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:25:56 -0700 Subject: [PATCH 21/36] Add FSM_U --- src/biogeophys/EnergyFluxType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/EnergyFluxType.F90 b/src/biogeophys/EnergyFluxType.F90 index 6a31293fa3..dc8daeae0f 100644 --- a/src/biogeophys/EnergyFluxType.F90 +++ b/src/biogeophys/EnergyFluxType.F90 @@ -340,7 +340,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp) this%eflx_snomelt_u_col(begc:endc) = spval call hist_addfld1d (fname='FSM_U', units='W/m^2', & avgflag='A', long_name='Urban snow melt heat flux', & - ptr_col=this%eflx_snomelt_u_col, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') + ptr_col=this%eflx_snomelt_u_col, c2l_scale_type='urbanf', set_nourb=spval) this%eflx_lwrad_net_patch(begp:endp) = spval call hist_addfld1d (fname='FIRA', units='W/m^2', & From 0da0e6b42c2e967536c8e9f16c2c2ffd9e0858ea Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:29:37 -0700 Subject: [PATCH 22/36] Add FIRA_U --- src/biogeophys/EnergyFluxType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/EnergyFluxType.F90 b/src/biogeophys/EnergyFluxType.F90 index dc8daeae0f..c383927523 100644 --- a/src/biogeophys/EnergyFluxType.F90 +++ b/src/biogeophys/EnergyFluxType.F90 @@ -480,7 +480,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp) this%eflx_lwrad_net_u_patch(begp:endp) = spval call hist_addfld1d (fname='FIRA_U', units='W/m^2', & avgflag='A', long_name='Urban net infrared (longwave) radiation', & - ptr_patch=this%eflx_lwrad_net_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') + ptr_patch=this%eflx_lwrad_net_u_patch, c2l_scale_type='urbanf', set_nourb=spval) this%eflx_soil_grnd_patch(begp:endp) = spval call hist_addfld1d (fname='EFLX_SOIL_GRND', units='W/m^2', & From 42b6c80561469c3130250e62dee8437de3f8534c Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:30:56 -0700 Subject: [PATCH 23/36] Add FIRA_U --- src/biogeophys/EnergyFluxType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/EnergyFluxType.F90 b/src/biogeophys/EnergyFluxType.F90 index c383927523..9279e3d100 100644 --- a/src/biogeophys/EnergyFluxType.F90 +++ b/src/biogeophys/EnergyFluxType.F90 @@ -490,7 +490,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp) this%eflx_lwrad_out_u_patch(begp:endp) = spval call hist_addfld1d (fname='FIRE_U', units='W/m^2', & avgflag='A', long_name='Urban emitted infrared (longwave) radiation', & - ptr_patch=this%eflx_lwrad_out_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') + ptr_patch=this%eflx_lwrad_out_u_patch, c2l_scale_type='urbanf', set_nourb=spval) this%eflx_sh_tot_u_patch(begp:endp) = spval call hist_addfld1d (fname='FSH_U', units='W/m^2', & From 68a15de52192d9997bd33dbe3dbb6c9ac9062c2e Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:32:44 -0700 Subject: [PATCH 24/36] Add FSH_U --- src/biogeophys/EnergyFluxType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/EnergyFluxType.F90 b/src/biogeophys/EnergyFluxType.F90 index 9279e3d100..5515ee0ed1 100644 --- a/src/biogeophys/EnergyFluxType.F90 +++ b/src/biogeophys/EnergyFluxType.F90 @@ -495,7 +495,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp) this%eflx_sh_tot_u_patch(begp:endp) = spval call hist_addfld1d (fname='FSH_U', units='W/m^2', & avgflag='A', long_name='Urban sensible heat', & - ptr_patch=this%eflx_sh_tot_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') + ptr_patch=this%eflx_sh_tot_u_patch, c2l_scale_type='urbanf', set_nourb=spval) this%eflx_sh_precip_conversion_col(begc:endc) = spval call hist_addfld1d (fname = 'FSH_PRECIP_CONVERSION', units='W/m^2', & From ec16a9a53e579e915fc8a036c3e12726f2d2dba4 Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:34:16 -0700 Subject: [PATCH 25/36] Add EFLX_LH_TOT_U --- src/biogeophys/EnergyFluxType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/EnergyFluxType.F90 b/src/biogeophys/EnergyFluxType.F90 index 5515ee0ed1..86df187c28 100644 --- a/src/biogeophys/EnergyFluxType.F90 +++ b/src/biogeophys/EnergyFluxType.F90 @@ -505,7 +505,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp) this%eflx_lh_tot_u_patch(begp:endp) = spval call hist_addfld1d (fname='EFLX_LH_TOT_U', units='W/m^2', & avgflag='A', long_name='Urban total evaporation', & - ptr_patch=this%eflx_lh_tot_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') + ptr_patch=this%eflx_lh_tot_u_patch, c2l_scale_type='urbanf', set_nourb=spval) this%eflx_soil_grnd_u_patch(begp:endp) = spval call hist_addfld1d (fname='FGR_U', units='W/m^2', & From 825320d148c48031e356535266b913442d105dec Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:35:50 -0700 Subject: [PATCH 26/36] Add FGR_U --- src/biogeophys/EnergyFluxType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/EnergyFluxType.F90 b/src/biogeophys/EnergyFluxType.F90 index 86df187c28..655a00d4d3 100644 --- a/src/biogeophys/EnergyFluxType.F90 +++ b/src/biogeophys/EnergyFluxType.F90 @@ -510,7 +510,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp) this%eflx_soil_grnd_u_patch(begp:endp) = spval call hist_addfld1d (fname='FGR_U', units='W/m^2', & avgflag='A', long_name='Urban heat flux into soil/snow including snow melt', & - ptr_patch=this%eflx_soil_grnd_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') + ptr_patch=this%eflx_soil_grnd_u_patch, c2l_scale_type='urbanf', set_nourb=spval) this%netrad_patch(begp:endp) = spval call hist_addfld1d (fname='Rnet', units='W/m^2', & From 9820d4b04dea3f381d4fc85e63f7917145bbd521 Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:36:48 -0700 Subject: [PATCH 27/36] Add QRUNOFF_U --- src/biogeophys/WaterFluxType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/WaterFluxType.F90 b/src/biogeophys/WaterFluxType.F90 index 23980a21c9..88b1b3e5cf 100644 --- a/src/biogeophys/WaterFluxType.F90 +++ b/src/biogeophys/WaterFluxType.F90 @@ -578,7 +578,7 @@ subroutine InitHistory(this, bounds) units='mm/s', & avgflag='A', & long_name=this%info%lname('Urban total runoff'), & - ptr_col=this%qflx_runoff_u_col, set_nourb=spval, c2l_scale_type='urbanf', default='inactive') + ptr_col=this%qflx_runoff_u_col, set_nourb=spval, c2l_scale_type='urbanf') this%qflx_runoff_r_col(begc:endc) = spval call hist_addfld1d ( & From 04014d276761b68f7af8bd3206e2b2724ea13ab4 Mon Sep 17 00:00:00 2001 From: Keith Oleson Date: Tue, 16 Dec 2025 12:42:25 -0700 Subject: [PATCH 28/36] Add RH2M_R --- src/biogeophys/WaterDiagnosticBulkType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/WaterDiagnosticBulkType.F90 b/src/biogeophys/WaterDiagnosticBulkType.F90 index bf4d2d04f6..48aeef73aa 100644 --- a/src/biogeophys/WaterDiagnosticBulkType.F90 +++ b/src/biogeophys/WaterDiagnosticBulkType.F90 @@ -347,7 +347,7 @@ subroutine InitBulkHistory(this, bounds) units='%', & avgflag='A', & long_name=this%info%lname('Rural 2m relative humidity'), & - ptr_patch=this%rh_ref2m_r_patch, set_spec=spval, default='inactive') + ptr_patch=this%rh_ref2m_r_patch, set_spec=spval) this%rh_ref2m_u_patch(begp:endp) = spval call hist_addfld1d ( & From 5629699f3074e0698ddb89f41cbbf94e098fea3f Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 15 Jan 2026 13:37:52 -0700 Subject: [PATCH 29/36] Update cime submodule URL and fxtag version Use the cime tag now that the PR was merged --- .gitmodules | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index 146cc90bdf..bf2ffa51be 100644 --- a/.gitmodules +++ b/.gitmodules @@ -75,11 +75,8 @@ fxDONOTUSEurl = https://github.com/ESMCI/ccs_config_cesm.git [submodule "cime"] path = cime -url = https://github.com/jedwards4b/cime -#url = https://github.com/ESMCI/cime -#fxtag = cime6.1.144 -#fxtag = jedwards4b:fix/spider_mode_disabled -fxtag = d2ddac622c7b4679dbb3c2f07070dd9c7ed57478 +url = https://github.com/ESMCI/cime +fxtag = cime6.1.145 fxrequired = ToplevelRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/ESMCI/cime From e56de4c83d9e54c3f557024a27da3e70a429b022 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sat, 17 Jan 2026 14:16:44 -0700 Subject: [PATCH 30/36] Get a simple test of DecompMod for get_proc_bounds and get_clump_bounds working, had to remove decompInitMod and subgridMod --- src/main/CMakeLists.txt | 2 - src/main/test/decomp_test/CMakeLists.txt | 2 +- src/main/test/decomp_test/test_decompInit.pf | 88 --------------- src/main/test/decomp_test/test_decompMod.pf | 106 +++++++++++++++++++ 4 files changed, 107 insertions(+), 91 deletions(-) delete mode 100644 src/main/test/decomp_test/test_decompInit.pf create mode 100644 src/main/test/decomp_test/test_decompMod.pf diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index 3884e0ba36..fc324efeb9 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -19,7 +19,6 @@ list(APPEND clm_sources clm_varsur.F90 column_varcon.F90 decompMod.F90 - decompInitMod.F90 filterColMod.F90 FireMethodType.F90 glc2lndMod.F90 @@ -31,7 +30,6 @@ list(APPEND clm_sources ncdio_utils.F90 organicFileMod.F90 paramUtilMod.F90 - subgridMod.F90 subgridAveMod.F90 subgridWeightsMod.F90 surfrdUtilsMod.F90 diff --git a/src/main/test/decomp_test/CMakeLists.txt b/src/main/test/decomp_test/CMakeLists.txt index 3499774292..b8c6fea3cf 100644 --- a/src/main/test/decomp_test/CMakeLists.txt +++ b/src/main/test/decomp_test/CMakeLists.txt @@ -1,5 +1,5 @@ set(pfunit_sources - test_decompInit.pf) + test_decompMod.pf) add_pfunit_ctest(decomp TEST_SOURCES "${pfunit_sources}" diff --git a/src/main/test/decomp_test/test_decompInit.pf b/src/main/test/decomp_test/test_decompInit.pf deleted file mode 100644 index c7f71e8ea2..0000000000 --- a/src/main/test/decomp_test/test_decompInit.pf +++ /dev/null @@ -1,88 +0,0 @@ -module test_decompInit - - ! Tests of decompInitMod - - use funit - use decompMod, only : bounds - use decompInitMod - use unittestSubgridMod - use unittestSimpleSubgridSetupsMod, only : setup_single_veg_patch, setup_n_veg_patches - use glcBehaviorMod, only: glc_behavior_type - use shr_kind_mod , only : r8 => shr_kind_r8 - - implicit none - - @TestCase - type, extends(TestCase) :: TestDecomp - contains - procedure :: setUp - procedure :: tearDown - procedure :: create_glc_behavior - end type TestDecomp - -contains - - ! ======================================================================== - ! Helper routines - ! ======================================================================== - - subroutine setUp(this) - class(TestDecomp), intent(inout) :: this - end subroutine setUp - - subroutine tearDown(this) - class(TestDecomp), intent(inout) :: this - - end subroutine tearDown - - !----------------------------------------------------------------------- - function create_glc_behavior() result(glc_behavior) - ! - ! !DESCRIPTION: - ! Creates a glc_behavior instance with collapse_to_atm_topo set for all - ! - ! Must be called *after* setting up the subgrid structure. - ! - use unittestArrayMod, only : grc_array - ! !ARGUMENTS: - type(glc_behavior_type) :: glc_behavior ! function result - ! - ! !LOCAL VARIABLES: - - character(len=*), parameter :: subname = 'create_glc_behavior' - !----------------------------------------------------------------------- - - call glc_behavior%InitSetDirectly(bounds%begg, bounds%endg, & - has_virtual_columns = grc_array(.false.), & - collapse_to_atm_topo = grc_array(collapse_to_atm_topo=.true.)) - - end function create_glc_behavior - - ! ======================================================================== - ! Begin tests - ! ======================================================================== - - @Test - subroutine decompInitClumps_basic(this) - use glcBehaviorMod, only : glc_behavior_type - ! Test basic operation of decompInit_clumps - class(TestDecomp), intent(inout) :: this - - ! Local - type(glc_behavior_type) :: glc_behavior - integer :: ni, nj - - ! Setup a single grid cell - nj = 1 - ni = 1 - call setup_single_veg_patch(pft_type=1) - glc_behavior = create_glc_behavior() - - ! Exercise - ! Determine decomposition of subgrid scale landunits, columns, patches - call decompInit_clumps(ni, nj, glc_behavior) - - ! Verify - end subroutine decompInitClumps_basic - -end module test_decompInit diff --git a/src/main/test/decomp_test/test_decompMod.pf b/src/main/test/decomp_test/test_decompMod.pf new file mode 100644 index 0000000000..6bef1690d5 --- /dev/null +++ b/src/main/test/decomp_test/test_decompMod.pf @@ -0,0 +1,106 @@ +module test_decompMod + + ! Tests of decompMod + + use funit + use decompMod + use shr_kind_mod , only : r8 => shr_kind_r8 + + implicit none + + @TestCase + type, extends(TestCase) :: TestDecompMod + contains + procedure :: setUp + procedure :: tearDown + procedure :: create_simpleSingleDecomp + end type TestDecompMod + + integer, parameter :: ni = 2 + integer, parameter :: nj = 2 + +contains + + ! ======================================================================== + ! Helper routines + ! ======================================================================== + + subroutine setUp(this) + class(TestDecompMod), intent(inout) :: this + + call this%create_simpleSingleDecomp() + end subroutine setUp + + subroutine tearDown(this) + class(TestDecompMod), intent(inout) :: this + + call decompmod_clean() + + end subroutine tearDown + + subroutine create_simpleSingleDecomp(this) + use spmdMod, only : iam + class(TestDecompMod), intent(inout) :: this + + integer :: clump_pproc + ! TOTO: When decompMod has it's own allocate method that could be used here + nclumps = 1 + clump_pproc = nclumps + allocate(procinfo%cid(clump_pproc)) + allocate(clumps(nclumps)) + ! Set the procinfo and clumps values + ! TOD: Use initialization method when available (currently in decompInitMod) + procinfo%cid = 1 + procinfo%ncells = ni*nj + procinfo%begg = 1 + procinfo%endg = procinfo%ncells + procinfo%nclumps = nclumps + clumps(:)%owner = iam + clumps(:)%begg = 1 + clumps(:)%endg = procinfo%ncells + + end subroutine create_simpleSingleDecomp + ! ======================================================================== + ! Begin tests + ! ======================================================================== + + @Test + subroutine test_get_clump_bounds(this) + class(TestDecompMod), intent(inout) :: this + + type(bounds_type) :: bounds + integer :: n + + do n = 1, procinfo%nclumps + call get_clump_bounds(n, bounds) + @assertEqual(bounds%level, bounds_level_clump) + @assertEqual(bounds%clump_index, n) + end do + end subroutine test_get_clump_bounds + + @Test + subroutine test_get_proc_bounds(this) + class(TestDecompMod), intent(inout) :: this + + type(bounds_type) :: bounds + + ! Add optional argument, just to test that it can handle it + call get_proc_bounds(bounds, allow_call_from_threaded_region=.true.) + @assertEqual(bounds%level, bounds_level_proc) + @assertEqual(bounds%clump_index, -1) + end subroutine test_get_proc_bounds + + @Test + subroutine test_proc_clump_bounds_equal(this) + class(TestDecompMod), intent(inout) :: this + + type(bounds_type) :: bounds_clump, bounds_proc + + @assertTrue(procinfo%nclumps == 1) + call get_clump_bounds(1, bounds_clump) + call get_proc_bounds(bounds_proc) + @assertEqual(bounds_proc%begg, bounds_clump%begg) + @assertEqual(bounds_proc%endg, bounds_clump%endg) + end subroutine test_proc_clump_bounds_equal + +end module test_decompMod From 0461ea58a312d690e7e141ee0117de1c9f8ae00c Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sun, 18 Jan 2026 00:13:11 -0700 Subject: [PATCH 31/36] These changes build in using mpi-serial, on Derecho it requires setting the env variable MPISERIAL to \/glade/u/apps/derecho/23.09/spack/opt/spack/mpi-serial/2.5.0/oneapi/2023.2.1/p3fw and it appears that you have to run the build twice for it to work, as such I'll revert this afterwards. But, I'm saving the commit so it could be done easily in the future --- src/CMakeLists.txt | 22 +- src/unit_test_stubs/CMakeLists.txt | 1 - src/unit_test_stubs/csm_share/CMakeLists.txt | 5 - .../csm_share/shr_mpi_mod_stub.F90 | 487 ------------------ 4 files changed, 14 insertions(+), 501 deletions(-) delete mode 100644 src/unit_test_stubs/csm_share/CMakeLists.txt delete mode 100644 src/unit_test_stubs/csm_share/shr_mpi_mod_stub.F90 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 52c8422055..70e9b364bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,20 @@ include(CIME_utils) # NetCDF is required -- because PIO and NetCDF are required by the standard default ESMF libraries find_package(NetCDF 4.7.4 REQUIRED Fortran) +# The following - for finding MPISERIAL - is copied from the share CMakeLists.txt +if(DEFINED MPILIB) + if(${MPILIB} STREQUAL "mpi-serial") + find_package(MPISERIAL COMPONENTS C Fortran REQUIRED) + + # We need this for the sake of includes of mpif.h + include_directories(${MPISERIAL_Fortran_INCLUDE_DIR}) + else() + find_package(MPI REQUIRED) + endif() +else() + find_package(MPI REQUIRED) +endif() + # The following - for finding ESMF - is copied from the share CMakeLists.txt if(DEFINED ENV{ESMF_ROOT}) list(APPEND CMAKE_MODULE_PATH $ENV{ESMF_ROOT}/cmake) @@ -80,14 +94,6 @@ add_subdirectory(unit_test_shr) # Then each removal could be replaced with a single call, like: # remove_source_file(${share_sources} "shr_mpi_mod.F90") foreach(sourcefile ${share_sources}) - # Remove shr_mpi_mod from share_sources. - # This is needed because we want to use the mock shr_mpi_mod in place of the real one - string(REGEX MATCH "shr_mpi_mod.F90" match_found ${sourcefile}) - - if(match_found) - list(REMOVE_ITEM share_sources ${sourcefile}) - endif() - # Remove shr_pio_mod from share_sources. This is needed to avoid an explicit dependency # on PIO. This removal is needed on some systems but not on others: the unit test build # works without this removal on a Mac with a pre-built PIO library, but failed (with diff --git a/src/unit_test_stubs/CMakeLists.txt b/src/unit_test_stubs/CMakeLists.txt index 2d7fe23378..5b1232be6e 100644 --- a/src/unit_test_stubs/CMakeLists.txt +++ b/src/unit_test_stubs/CMakeLists.txt @@ -1,4 +1,3 @@ -add_subdirectory(csm_share) add_subdirectory(dyn_subgrid) add_subdirectory(main) add_subdirectory(share_esmf) diff --git a/src/unit_test_stubs/csm_share/CMakeLists.txt b/src/unit_test_stubs/csm_share/CMakeLists.txt deleted file mode 100644 index 33ddbfb342..0000000000 --- a/src/unit_test_stubs/csm_share/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -list(APPEND share_sources - shr_mpi_mod_stub.F90 - ) - -sourcelist_to_parent(share_sources) diff --git a/src/unit_test_stubs/csm_share/shr_mpi_mod_stub.F90 b/src/unit_test_stubs/csm_share/shr_mpi_mod_stub.F90 deleted file mode 100644 index 44d57a96b0..0000000000 --- a/src/unit_test_stubs/csm_share/shr_mpi_mod_stub.F90 +++ /dev/null @@ -1,487 +0,0 @@ -!=============================================================================== -! SVN $Id: shr_mpi_mod.F90 59033 2014-04-11 01:55:15Z santos@ucar.edu $ -! SVN $URL: https://svn-ccsm-models.cgd.ucar.edu/csm_share/trunk_tags/share3_140723/shr/shr_mpi_mod.F90 $ -!=============================================================================== - -Module shr_mpi_mod - -!------------------------------------------------------------------------------- -! PURPOSE: general layer on MPI functions -!------------------------------------------------------------------------------- - - use shr_kind_mod - use shr_log_mod, only: s_loglev => shr_log_Level - use shr_log_mod, only: s_logunit => shr_log_Unit - - implicit none - private - -! PUBLIC: Public interfaces - - public :: shr_mpi_chkerr - public :: shr_mpi_bcast - public :: shr_mpi_sum - public :: shr_mpi_commsize - public :: shr_mpi_commrank - public :: shr_mpi_initialized - public :: shr_mpi_abort - public :: shr_mpi_barrier - public :: shr_mpi_init - public :: shr_mpi_finalize - - interface shr_mpi_bcast ; module procedure & - shr_mpi_bcastc0, & - shr_mpi_bcastc1, & - shr_mpi_bcastl0, & - shr_mpi_bcastl1, & - shr_mpi_bcasti0, & - shr_mpi_bcasti1, & - shr_mpi_bcasti2, & - shr_mpi_bcastr0, & - shr_mpi_bcastr1, & - shr_mpi_bcastr2, & - shr_mpi_bcastr3 - end interface - -!=============================================================================== -CONTAINS -!=============================================================================== - -SUBROUTINE shr_mpi_chkerr(rcode,string) - - IMPLICIT none - - !----- arguments --- - integer(SHR_KIND_IN), intent(in) :: rcode ! input MPI error code - character(*), intent(in) :: string ! message - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_chkerr) ' - -!------------------------------------------------------------------------------- -! PURPOSE: layer on MPI error checking -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_chkerr - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcasti0(vec,comm,string,pebcast) - - IMPLICIT none - - !----- arguments --- - integer(SHR_KIND_IN), intent(inout):: vec ! vector of 1 - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_bcasti0) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast an integer -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcasti0 - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcastl0(vec,comm,string,pebcast) - - IMPLICIT none - - !----- arguments --- - logical, intent(inout):: vec ! vector of 1 - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_bcastl0) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast a logical -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcastl0 - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcastc0(vec,comm,string,pebcast) - - IMPLICIT none - - !----- arguments --- - character(len=*), intent(inout) :: vec ! vector of 1 - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_bcastc0) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast a character string -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcastc0 - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcastc1(vec,comm,string,pebcast) - - IMPLICIT none - - !----- arguments --- - character(len=*), intent(inout) :: vec(:) ! 1D vector - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_bcastc1) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast a character string -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcastc1 - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcastr0(vec,comm,string,pebcast) - - IMPLICIT none - - !----- arguments --- - real(SHR_KIND_R8), intent(inout):: vec ! vector of 1 - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_bcastr0) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast a real -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcastr0 - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcasti1(vec,comm,string,pebcast) - - IMPLICIT none - - !----- arguments --- - integer(SHR_KIND_IN), intent(inout):: vec(:) ! vector - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_bcasti1) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast a vector of integers -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcasti1 - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcastl1(vec,comm,string,pebcast) - - IMPLICIT none - - !----- arguments --- - logical, intent(inout):: vec(:) ! vector of 1 - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_bcastl1) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast a logical -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcastl1 - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcastr1(vec,comm,string,pebcast) - - IMPLICIT none - - !----- arguments --- - real(SHR_KIND_R8), intent(inout):: vec(:) ! vector - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_bcastr1) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast a vector of reals -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcastr1 - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcastr2(arr,comm,string,pebcast) - - IMPLICIT none - - !----- arguments ----- - real(SHR_KIND_R8), intent(inout):: arr(:,:) ! array, 2d - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local ----- - - !----- formats ----- - character(*),parameter :: subName = '(shr_mpi_bcastr2) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast a 2d array of reals -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcastr2 - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcasti2(arr,comm,string,pebcast) - - IMPLICIT none - - !----- arguments ----- - integer, intent(inout):: arr(:,:) ! array, 2d - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local ----- - character(*),parameter :: subName = '(shr_mpi_bcasti2) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast a 2d array of integers -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcasti2 - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_bcastr3(arr,comm,string,pebcast) - - IMPLICIT none - - !----- arguments ----- - real(SHR_KIND_R8), intent(inout):: arr(:,:,:) ! array, 3d - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) - - !----- local ----- - character(*),parameter :: subName = '(shr_mpi_bcastr3) ' - -!------------------------------------------------------------------------------- -! PURPOSE: Broadcast a 3d array of reals -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_bcastr3 - -!=============================================================================== - -SUBROUTINE shr_mpi_sum(lvec,gvec,comm,string,all) - - IMPLICIT none - - !----- arguments --- - integer(SHR_KIND_IN), intent(in) :: lvec ! in/out local values - integer(SHR_KIND_IN), intent(out):: gvec ! in/out global values - integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator - character(*),optional,intent(in) :: string ! message - logical, optional,intent(in) :: all ! allreduce if true - !----- local ----- - character(*),parameter :: subName = '(shr_mpi_sumi0) ' - -!=============================================================================== -END SUBROUTINE shr_mpi_sum - -!=============================================================================== - -SUBROUTINE shr_mpi_commsize(comm,size,string) - - IMPLICIT none - - !----- arguments --- - integer,intent(in) :: comm - integer,intent(out) :: size - character(*),optional,intent(in) :: string ! message - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_commsize) ' - -!------------------------------------------------------------------------------- -! PURPOSE: MPI commsize -!------------------------------------------------------------------------------- - size = 1 - -END SUBROUTINE shr_mpi_commsize - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_commrank(comm,rank,string) - - IMPLICIT none - - !----- arguments --- - integer,intent(in) :: comm - integer,intent(out) :: rank - character(*),optional,intent(in) :: string ! message - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_commrank) ' - -!------------------------------------------------------------------------------- -! PURPOSE: MPI commrank -!------------------------------------------------------------------------------- - rank = 0 - -END SUBROUTINE shr_mpi_commrank - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_initialized(flag,string) - - IMPLICIT none - - !----- arguments --- - logical,intent(out) :: flag - character(*),optional,intent(in) :: string ! message - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_initialized) ' - -!------------------------------------------------------------------------------- -! PURPOSE: MPI initialized -!------------------------------------------------------------------------------- - flag = .true. - -END SUBROUTINE shr_mpi_initialized - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_abort(string,rcode) - - IMPLICIT none - - !----- arguments --- - character(*),optional,intent(in) :: string ! message - integer,optional,intent(in) :: rcode ! optional code - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_abort) ' - integer :: rc ! return code - -!------------------------------------------------------------------------------- -! PURPOSE: MPI abort -!------------------------------------------------------------------------------- - - if ( present(string) .and. present(rcode) ) then - write(s_logunit,*) trim(subName),":",trim(string),rcode - endif - if ( present(rcode) )then - rc = rcode - else - rc = 1001 - end if - stop - -END SUBROUTINE shr_mpi_abort - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_barrier(comm,string) - - IMPLICIT none - - !----- arguments --- - integer,intent(in) :: comm - character(*),optional,intent(in) :: string ! message - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_barrier) ' - -!------------------------------------------------------------------------------- -! PURPOSE: MPI barrier -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_barrier - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_init(string) - - IMPLICIT none - - !----- arguments --- - character(*),optional,intent(in) :: string ! message - - !----- local --- - character(*),parameter :: subName = '(shr_mpi_init) ' - -!------------------------------------------------------------------------------- -! PURPOSE: MPI init -!------------------------------------------------------------------------------- - -END SUBROUTINE shr_mpi_init - -!=============================================================================== -!=============================================================================== - -SUBROUTINE shr_mpi_finalize(string) - - IMPLICIT none - - !----- arguments --- - character(*),optional,intent(in) :: string ! message - - !----- local --- - -!------------------------------------------------------------------------------- -! PURPOSE: MPI finalize -!------------------------------------------------------------------------------- - if ( present(string) ) & - write(s_logunit,*) trim(string) - call shr_mpi_abort("MPI Finalize") - -END SUBROUTINE shr_mpi_finalize - -!=============================================================================== -!=============================================================================== - -END MODULE shr_mpi_mod From 5e4fc9a5c28f96decedae3f2e4020e6baac4d7c9 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sun, 18 Jan 2026 00:13:24 -0700 Subject: [PATCH 32/36] Revert "These changes build in using mpi-serial, on Derecho it requires setting the env variable MPISERIAL to \/glade/u/apps/derecho/23.09/spack/opt/spack/mpi-serial/2.5.0/oneapi/2023.2.1/p3fw and it appears that you have to run the build twice for it to work, as such I'll revert this afterwards. But, I'm saving the commit so it could be done easily in the future" This reverts commit 0461ea58a312d690e7e141ee0117de1c9f8ae00c. --- src/CMakeLists.txt | 22 +- src/unit_test_stubs/CMakeLists.txt | 1 + src/unit_test_stubs/csm_share/CMakeLists.txt | 5 + .../csm_share/shr_mpi_mod_stub.F90 | 487 ++++++++++++++++++ 4 files changed, 501 insertions(+), 14 deletions(-) create mode 100644 src/unit_test_stubs/csm_share/CMakeLists.txt create mode 100644 src/unit_test_stubs/csm_share/shr_mpi_mod_stub.F90 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70e9b364bb..52c8422055 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,20 +17,6 @@ include(CIME_utils) # NetCDF is required -- because PIO and NetCDF are required by the standard default ESMF libraries find_package(NetCDF 4.7.4 REQUIRED Fortran) -# The following - for finding MPISERIAL - is copied from the share CMakeLists.txt -if(DEFINED MPILIB) - if(${MPILIB} STREQUAL "mpi-serial") - find_package(MPISERIAL COMPONENTS C Fortran REQUIRED) - - # We need this for the sake of includes of mpif.h - include_directories(${MPISERIAL_Fortran_INCLUDE_DIR}) - else() - find_package(MPI REQUIRED) - endif() -else() - find_package(MPI REQUIRED) -endif() - # The following - for finding ESMF - is copied from the share CMakeLists.txt if(DEFINED ENV{ESMF_ROOT}) list(APPEND CMAKE_MODULE_PATH $ENV{ESMF_ROOT}/cmake) @@ -94,6 +80,14 @@ add_subdirectory(unit_test_shr) # Then each removal could be replaced with a single call, like: # remove_source_file(${share_sources} "shr_mpi_mod.F90") foreach(sourcefile ${share_sources}) + # Remove shr_mpi_mod from share_sources. + # This is needed because we want to use the mock shr_mpi_mod in place of the real one + string(REGEX MATCH "shr_mpi_mod.F90" match_found ${sourcefile}) + + if(match_found) + list(REMOVE_ITEM share_sources ${sourcefile}) + endif() + # Remove shr_pio_mod from share_sources. This is needed to avoid an explicit dependency # on PIO. This removal is needed on some systems but not on others: the unit test build # works without this removal on a Mac with a pre-built PIO library, but failed (with diff --git a/src/unit_test_stubs/CMakeLists.txt b/src/unit_test_stubs/CMakeLists.txt index 5b1232be6e..2d7fe23378 100644 --- a/src/unit_test_stubs/CMakeLists.txt +++ b/src/unit_test_stubs/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(csm_share) add_subdirectory(dyn_subgrid) add_subdirectory(main) add_subdirectory(share_esmf) diff --git a/src/unit_test_stubs/csm_share/CMakeLists.txt b/src/unit_test_stubs/csm_share/CMakeLists.txt new file mode 100644 index 0000000000..33ddbfb342 --- /dev/null +++ b/src/unit_test_stubs/csm_share/CMakeLists.txt @@ -0,0 +1,5 @@ +list(APPEND share_sources + shr_mpi_mod_stub.F90 + ) + +sourcelist_to_parent(share_sources) diff --git a/src/unit_test_stubs/csm_share/shr_mpi_mod_stub.F90 b/src/unit_test_stubs/csm_share/shr_mpi_mod_stub.F90 new file mode 100644 index 0000000000..44d57a96b0 --- /dev/null +++ b/src/unit_test_stubs/csm_share/shr_mpi_mod_stub.F90 @@ -0,0 +1,487 @@ +!=============================================================================== +! SVN $Id: shr_mpi_mod.F90 59033 2014-04-11 01:55:15Z santos@ucar.edu $ +! SVN $URL: https://svn-ccsm-models.cgd.ucar.edu/csm_share/trunk_tags/share3_140723/shr/shr_mpi_mod.F90 $ +!=============================================================================== + +Module shr_mpi_mod + +!------------------------------------------------------------------------------- +! PURPOSE: general layer on MPI functions +!------------------------------------------------------------------------------- + + use shr_kind_mod + use shr_log_mod, only: s_loglev => shr_log_Level + use shr_log_mod, only: s_logunit => shr_log_Unit + + implicit none + private + +! PUBLIC: Public interfaces + + public :: shr_mpi_chkerr + public :: shr_mpi_bcast + public :: shr_mpi_sum + public :: shr_mpi_commsize + public :: shr_mpi_commrank + public :: shr_mpi_initialized + public :: shr_mpi_abort + public :: shr_mpi_barrier + public :: shr_mpi_init + public :: shr_mpi_finalize + + interface shr_mpi_bcast ; module procedure & + shr_mpi_bcastc0, & + shr_mpi_bcastc1, & + shr_mpi_bcastl0, & + shr_mpi_bcastl1, & + shr_mpi_bcasti0, & + shr_mpi_bcasti1, & + shr_mpi_bcasti2, & + shr_mpi_bcastr0, & + shr_mpi_bcastr1, & + shr_mpi_bcastr2, & + shr_mpi_bcastr3 + end interface + +!=============================================================================== +CONTAINS +!=============================================================================== + +SUBROUTINE shr_mpi_chkerr(rcode,string) + + IMPLICIT none + + !----- arguments --- + integer(SHR_KIND_IN), intent(in) :: rcode ! input MPI error code + character(*), intent(in) :: string ! message + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_chkerr) ' + +!------------------------------------------------------------------------------- +! PURPOSE: layer on MPI error checking +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_chkerr + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcasti0(vec,comm,string,pebcast) + + IMPLICIT none + + !----- arguments --- + integer(SHR_KIND_IN), intent(inout):: vec ! vector of 1 + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_bcasti0) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast an integer +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcasti0 + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcastl0(vec,comm,string,pebcast) + + IMPLICIT none + + !----- arguments --- + logical, intent(inout):: vec ! vector of 1 + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_bcastl0) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast a logical +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcastl0 + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcastc0(vec,comm,string,pebcast) + + IMPLICIT none + + !----- arguments --- + character(len=*), intent(inout) :: vec ! vector of 1 + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_bcastc0) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast a character string +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcastc0 + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcastc1(vec,comm,string,pebcast) + + IMPLICIT none + + !----- arguments --- + character(len=*), intent(inout) :: vec(:) ! 1D vector + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_bcastc1) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast a character string +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcastc1 + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcastr0(vec,comm,string,pebcast) + + IMPLICIT none + + !----- arguments --- + real(SHR_KIND_R8), intent(inout):: vec ! vector of 1 + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_bcastr0) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast a real +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcastr0 + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcasti1(vec,comm,string,pebcast) + + IMPLICIT none + + !----- arguments --- + integer(SHR_KIND_IN), intent(inout):: vec(:) ! vector + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_bcasti1) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast a vector of integers +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcasti1 + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcastl1(vec,comm,string,pebcast) + + IMPLICIT none + + !----- arguments --- + logical, intent(inout):: vec(:) ! vector of 1 + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_bcastl1) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast a logical +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcastl1 + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcastr1(vec,comm,string,pebcast) + + IMPLICIT none + + !----- arguments --- + real(SHR_KIND_R8), intent(inout):: vec(:) ! vector + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_bcastr1) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast a vector of reals +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcastr1 + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcastr2(arr,comm,string,pebcast) + + IMPLICIT none + + !----- arguments ----- + real(SHR_KIND_R8), intent(inout):: arr(:,:) ! array, 2d + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local ----- + + !----- formats ----- + character(*),parameter :: subName = '(shr_mpi_bcastr2) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast a 2d array of reals +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcastr2 + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcasti2(arr,comm,string,pebcast) + + IMPLICIT none + + !----- arguments ----- + integer, intent(inout):: arr(:,:) ! array, 2d + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local ----- + character(*),parameter :: subName = '(shr_mpi_bcasti2) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast a 2d array of integers +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcasti2 + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_bcastr3(arr,comm,string,pebcast) + + IMPLICIT none + + !----- arguments ----- + real(SHR_KIND_R8), intent(inout):: arr(:,:,:) ! array, 3d + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + integer(SHR_KIND_IN), optional, intent(in) :: pebcast ! bcast pe (otherwise zero) + + !----- local ----- + character(*),parameter :: subName = '(shr_mpi_bcastr3) ' + +!------------------------------------------------------------------------------- +! PURPOSE: Broadcast a 3d array of reals +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_bcastr3 + +!=============================================================================== + +SUBROUTINE shr_mpi_sum(lvec,gvec,comm,string,all) + + IMPLICIT none + + !----- arguments --- + integer(SHR_KIND_IN), intent(in) :: lvec ! in/out local values + integer(SHR_KIND_IN), intent(out):: gvec ! in/out global values + integer(SHR_KIND_IN), intent(in) :: comm ! mpi communicator + character(*),optional,intent(in) :: string ! message + logical, optional,intent(in) :: all ! allreduce if true + !----- local ----- + character(*),parameter :: subName = '(shr_mpi_sumi0) ' + +!=============================================================================== +END SUBROUTINE shr_mpi_sum + +!=============================================================================== + +SUBROUTINE shr_mpi_commsize(comm,size,string) + + IMPLICIT none + + !----- arguments --- + integer,intent(in) :: comm + integer,intent(out) :: size + character(*),optional,intent(in) :: string ! message + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_commsize) ' + +!------------------------------------------------------------------------------- +! PURPOSE: MPI commsize +!------------------------------------------------------------------------------- + size = 1 + +END SUBROUTINE shr_mpi_commsize + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_commrank(comm,rank,string) + + IMPLICIT none + + !----- arguments --- + integer,intent(in) :: comm + integer,intent(out) :: rank + character(*),optional,intent(in) :: string ! message + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_commrank) ' + +!------------------------------------------------------------------------------- +! PURPOSE: MPI commrank +!------------------------------------------------------------------------------- + rank = 0 + +END SUBROUTINE shr_mpi_commrank + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_initialized(flag,string) + + IMPLICIT none + + !----- arguments --- + logical,intent(out) :: flag + character(*),optional,intent(in) :: string ! message + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_initialized) ' + +!------------------------------------------------------------------------------- +! PURPOSE: MPI initialized +!------------------------------------------------------------------------------- + flag = .true. + +END SUBROUTINE shr_mpi_initialized + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_abort(string,rcode) + + IMPLICIT none + + !----- arguments --- + character(*),optional,intent(in) :: string ! message + integer,optional,intent(in) :: rcode ! optional code + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_abort) ' + integer :: rc ! return code + +!------------------------------------------------------------------------------- +! PURPOSE: MPI abort +!------------------------------------------------------------------------------- + + if ( present(string) .and. present(rcode) ) then + write(s_logunit,*) trim(subName),":",trim(string),rcode + endif + if ( present(rcode) )then + rc = rcode + else + rc = 1001 + end if + stop + +END SUBROUTINE shr_mpi_abort + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_barrier(comm,string) + + IMPLICIT none + + !----- arguments --- + integer,intent(in) :: comm + character(*),optional,intent(in) :: string ! message + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_barrier) ' + +!------------------------------------------------------------------------------- +! PURPOSE: MPI barrier +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_barrier + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_init(string) + + IMPLICIT none + + !----- arguments --- + character(*),optional,intent(in) :: string ! message + + !----- local --- + character(*),parameter :: subName = '(shr_mpi_init) ' + +!------------------------------------------------------------------------------- +! PURPOSE: MPI init +!------------------------------------------------------------------------------- + +END SUBROUTINE shr_mpi_init + +!=============================================================================== +!=============================================================================== + +SUBROUTINE shr_mpi_finalize(string) + + IMPLICIT none + + !----- arguments --- + character(*),optional,intent(in) :: string ! message + + !----- local --- + +!------------------------------------------------------------------------------- +! PURPOSE: MPI finalize +!------------------------------------------------------------------------------- + if ( present(string) ) & + write(s_logunit,*) trim(string) + call shr_mpi_abort("MPI Finalize") + +END SUBROUTINE shr_mpi_finalize + +!=============================================================================== +!=============================================================================== + +END MODULE shr_mpi_mod From 1297aa10cf49deffe519e5d253a8e4c6db312559 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 21 Jan 2026 14:43:37 -0700 Subject: [PATCH 33/36] Update src/main/test/decomp_test/test_decompMod.pf Co-authored-by: Samuel Levis --- src/main/test/decomp_test/test_decompMod.pf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/test/decomp_test/test_decompMod.pf b/src/main/test/decomp_test/test_decompMod.pf index 6bef1690d5..a9c364dd64 100644 --- a/src/main/test/decomp_test/test_decompMod.pf +++ b/src/main/test/decomp_test/test_decompMod.pf @@ -43,7 +43,7 @@ contains class(TestDecompMod), intent(inout) :: this integer :: clump_pproc - ! TOTO: When decompMod has it's own allocate method that could be used here + ! TODO: When decompMod has it's own allocate method that could be used here nclumps = 1 clump_pproc = nclumps allocate(procinfo%cid(clump_pproc)) From e744db51bb78b1c74cf1329eddce4fde267fb2d5 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 21 Jan 2026 14:44:10 -0700 Subject: [PATCH 34/36] Update src/main/test/decomp_test/test_decompMod.pf Correction from review. Co-authored-by: Samuel Levis --- src/main/test/decomp_test/test_decompMod.pf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/test/decomp_test/test_decompMod.pf b/src/main/test/decomp_test/test_decompMod.pf index a9c364dd64..8112e4c6ce 100644 --- a/src/main/test/decomp_test/test_decompMod.pf +++ b/src/main/test/decomp_test/test_decompMod.pf @@ -49,7 +49,7 @@ contains allocate(procinfo%cid(clump_pproc)) allocate(clumps(nclumps)) ! Set the procinfo and clumps values - ! TOD: Use initialization method when available (currently in decompInitMod) + ! TODO: Use initialization method when available (currently in decompInitMod) procinfo%cid = 1 procinfo%ncells = ni*nj procinfo%begg = 1 From 5ac060d3100e072a23b319b2e8de11dac1466c73 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 21 Jan 2026 18:06:23 -0700 Subject: [PATCH 35/36] Remove the addition of FATES directories as it causes a fail on the first time it's built, you have to build it twice for it to work. I commented it out and added some notes around it --- src/CMakeLists.txt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 52c8422055..67a8b32308 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,12 +63,16 @@ add_subdirectory(${CLM_ROOT}/src/init_interp clm_init_interp) add_subdirectory(${CLM_ROOT}/src/self_tests clm_self_tests) # Add FATES source directories -add_subdirectory(${CLM_ROOT}/src/fates/main fates_main) -add_subdirectory(${CLM_ROOT}/src/fates/biogeochem fates_biogeochem) -add_subdirectory(${CLM_ROOT}/src/fates/biogeophys fates_biogeophys) -add_subdirectory(${CLM_ROOT}/src/fates/parteh fates_parteh) -add_subdirectory(${CLM_ROOT}/src/fates/fire fates_fire) -add_subdirectory(${CLM_ROOT}/src/fates/radiation fates_radiation) +# Adding FATES directories is commented out -- because of the problem in: +# https://github.com/ESCOMP/CTSM/issues/3704 +# add_subdirectory(${CLM_ROOT}/src/fates/main fates_main) +# add_subdirectory(${CLM_ROOT}/src/fates/biogeochem fates_biogeochem) +# add_subdirectory(${CLM_ROOT}/src/fates/biogeophys fates_biogeophys) +# add_subdirectory(${CLM_ROOT}/src/fates/parteh fates_parteh) +# add_subdirectory(${CLM_ROOT}/src/fates/fire fates_fire) +# add_subdirectory(${CLM_ROOT}/src/fates/radiation fates_radiation) +# NOTE: Need to add the fates library and dependencies below +# ### End add of FATES directories # Add general unit test directories (stubbed out files, etc.) add_subdirectory(unit_test_stubs) @@ -105,9 +109,8 @@ endforeach() add_library(csm_share ${share_sources} ${drv_sources_needed}) declare_generated_dependencies(csm_share "${share_genf90_sources}") add_library(clm ${clm_sources}) -add_library(fates ${fates_sources}) declare_generated_dependencies(clm "${clm_genf90_sources}") -add_dependencies(clm csm_share ESMF fates) +add_dependencies(clm csm_share ESMF) # We need to look for header files here, in order to pick up shr_assert.h include_directories(${SRCROOT}/share/include) From 0cf11e06e399ea46fde8106d0e9c81248ab69703 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 22 Jan 2026 16:18:29 -0700 Subject: [PATCH 36/36] Update ChangeLog/Sum --- doc/ChangeLog | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ doc/ChangeSum | 1 + 2 files changed, 64 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index 034a0278c9..55b07fbe05 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,67 @@ =============================================================== +Tag name: ctsm5.4.011 +Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310) +Date: Thu Jan 22 04:01:52 PM MST 2026 +One-line Summary: Merge b4b-dev to master + +Purpose and description of changes +---------------------------------- + Change some _U and _R history fields to be on by default PR #3667 by Keith Oleson + Update to cime version that fixes the check_input_data --download issue PR #3647 by Erik Kluzek; #3647 updated to cime6.1.145, while updating b4b-dev to master in this PR gets us to cime6.1.146. + Initial fixes to generate_gdd20_baseline PR #3543 + Decomp mod unittest PR #3699 + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + No issues were opened for the PRs listed above. + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - OK + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + derecho - OK + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + +Answer changes +-------------- +Changes answers relative to baseline: No + +Other details +------------- +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/3709 + +=============================================================== +=============================================================== Tag name: ctsm5.4.010 Originator(s): erik (Erik Kluzek,UCAR/TSS,303-497-1326) Date: Wed Jan 21 11:49:59 AM MST 2026 diff --git a/doc/ChangeSum b/doc/ChangeSum index 0c778259da..d97c686a6d 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,6 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.4.011 slevis 01/22/2026 Merge b4b-dev to master ctsm5.4.010 erik 01/21/2026 Update cime to version that changes answers for ERI tests ctsm5.4.009 olyson 01/19/2026 Dewpoint Temperature check for bare ground ctsm5.4.008 swensosc 01/12/2026 Add a correction for oversaturated soil layers in SoilWaterMovement (erik)