From 2785caf1882324ffaeced04f6ec2aede2b57cda6 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Fri, 27 May 2022 09:25:13 -0600 Subject: [PATCH 001/444] Seperate out nrepr loops into ones for matrixcn off and on --- src/biogeochem/CNCStateUpdate1Mod.F90 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/biogeochem/CNCStateUpdate1Mod.F90 b/src/biogeochem/CNCStateUpdate1Mod.F90 index 717b524383..8c6fc11602 100644 --- a/src/biogeochem/CNCStateUpdate1Mod.F90 +++ b/src/biogeochem/CNCStateUpdate1Mod.F90 @@ -430,18 +430,18 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & end if cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_livestemc_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_livestemc_storage_patch(p)*dt - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_reproductivec_patch(p,1)*dt - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_reproductivec_storage_patch(p,1)*dt + do k = 1, nrepr + cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_reproductivec_patch(p,k)*dt + cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_reproductivec_storage_patch(p,k)*dt + end do if(.not. use_matrixcn)then cs_veg%livestemc_patch(p) = cs_veg%livestemc_patch(p) + cf_veg%cpool_to_livestemc_patch(p)*dt cs_veg%livestemc_storage_patch(p) = cs_veg%livestemc_storage_patch(p) + cf_veg%cpool_to_livestemc_storage_patch(p)*dt do k = 1, nrepr - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_reproductivec_patch(p,k)*dt - cs_veg%reproductivec_patch(p,k) = cs_veg%reproductivec_patch(p,k) & - + cf_veg%cpool_to_reproductivec_patch(p,k)*dt - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_reproductivec_storage_patch(p,k)*dt + cs_veg%reproductivec_patch(p,k) = cs_veg%reproductivec_patch(p,k) & + + cf_veg%cpool_to_reproductivec_patch(p,k)*dt cs_veg%reproductivec_storage_patch(p,k) = cs_veg%reproductivec_storage_patch(p,k) & - + cf_veg%cpool_to_reproductivec_storage_patch(p,k)*dt + + cf_veg%cpool_to_reproductivec_storage_patch(p,k)*dt end do else ! NOTE: The equivalent changes for matrix code are in CNPhenology EBK (11/26/2019) From effacf2b1db196c7bf4c4fa87d45628fd25e9e00 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 28 Nov 2023 14:27:07 -0700 Subject: [PATCH 002/444] Corrections for cheyenne test-suite to pass --- src/biogeochem/CNCStateUpdate1Mod.F90 | 6 ------ src/biogeochem/CNNStateUpdate1Mod.F90 | 14 ++++++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/biogeochem/CNCStateUpdate1Mod.F90 b/src/biogeochem/CNCStateUpdate1Mod.F90 index 8c6fc11602..76b14585b4 100644 --- a/src/biogeochem/CNCStateUpdate1Mod.F90 +++ b/src/biogeochem/CNCStateUpdate1Mod.F90 @@ -325,15 +325,9 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%cropseedc_deficit_patch(p) = cs_veg%cropseedc_deficit_patch(p) & - cf_veg%crop_seedc_to_leaf_patch(p) * dt do k = repr_grain_min, repr_grain_max - cs_veg%reproductivec_patch(p,k) = cs_veg%reproductivec_patch(p,k) & - - (cf_veg%repr_grainc_to_food_patch(p,k) + cf_veg%repr_grainc_to_seed_patch(p,k))*dt cs_veg%cropseedc_deficit_patch(p) = cs_veg%cropseedc_deficit_patch(p) & + cf_veg%repr_grainc_to_seed_patch(p,k) * dt end do - do k = repr_structure_min, repr_structure_max - cs_veg%reproductivec_patch(p,k) = cs_veg%reproductivec_patch(p,k) & - - (cf_veg%repr_structurec_to_cropprod_patch(p,k) + cf_veg%repr_structurec_to_litter_patch(p,k))*dt - end do end if end if !not use_matrixcn diff --git a/src/biogeochem/CNNStateUpdate1Mod.F90 b/src/biogeochem/CNNStateUpdate1Mod.F90 index 8aa24e3aa3..4a9e081583 100644 --- a/src/biogeochem/CNNStateUpdate1Mod.F90 +++ b/src/biogeochem/CNNStateUpdate1Mod.F90 @@ -226,21 +226,23 @@ subroutine NStateUpdate1(num_soilc, filter_soilc, num_soilp, filter_soilp, & ns_veg%leafn_patch(p) = ns_veg%leafn_patch(p) - nf_veg%leafn_to_biofueln_patch(p)*dt ns_veg%livestemn_patch(p) = ns_veg%livestemn_patch(p) - nf_veg%livestemn_to_retransn_patch(p)*dt ns_veg%retransn_patch(p) = ns_veg%retransn_patch(p) + nf_veg%livestemn_to_retransn_patch(p)*dt + do k = repr_grain_min, repr_grain_max + ns_veg%reproductiven_patch(p,k) = ns_veg%reproductiven_patch(p,k) & + - (nf_veg%repr_grainn_to_food_patch(p,k) + nf_veg%repr_grainn_to_seed_patch(p,k))*dt + end do + do k = repr_structure_min, repr_structure_max + ns_veg%reproductiven_patch(p,k) = ns_veg%reproductiven_patch(p,k) & + - (nf_veg%repr_structuren_to_cropprod_patch(p,k) + nf_veg%repr_structuren_to_litter_patch(p,k))*dt + end do else ! NOTE: The equivalent changes for matrix code are in CNPhenology EBK (11/26/2019) end if !not use_matrixcn ns_veg%cropseedn_deficit_patch(p) = ns_veg%cropseedn_deficit_patch(p) & - nf_veg%crop_seedn_to_leaf_patch(p) * dt do k = repr_grain_min, repr_grain_max - ns_veg%reproductiven_patch(p,k) = ns_veg%reproductiven_patch(p,k) & - - (nf_veg%repr_grainn_to_food_patch(p,k) + nf_veg%repr_grainn_to_seed_patch(p,k))*dt ns_veg%cropseedn_deficit_patch(p) = ns_veg%cropseedn_deficit_patch(p) & + nf_veg%repr_grainn_to_seed_patch(p,k) * dt end do - do k = repr_structure_min, repr_structure_max - ns_veg%reproductiven_patch(p,k) = ns_veg%reproductiven_patch(p,k) & - - (nf_veg%repr_structuren_to_cropprod_patch(p,k) + nf_veg%repr_structuren_to_litter_patch(p,k))*dt - end do end if ! uptake from soil mineral N pool From ffc6acc0184df317314d5d2cdd36076627d854a1 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Wed, 29 Nov 2023 17:47:40 -0700 Subject: [PATCH 003/444] Upd. expected fails, test list, and relevant error checks --- bld/CLMBuildNamelist.pm | 7 ++++ cime_config/testdefs/ExpectedTestFails.xml | 28 +++++++++++++++ cime_config/testdefs/testlist_clm.xml | 40 ++++++++++++++++++++++ src/biogeochem/CropReprPoolsMod.F90 | 11 ++++++ 4 files changed, 86 insertions(+) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index b0d533ebde..b92acc34c7 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4222,6 +4222,13 @@ sub setup_logic_cnmatrix { } # Otherwise for CN or BGC mode } else { + # If matrixcn is on, for_testing_use_second_grain_pool and for_testing_use_repr_structure_pool must be off + if ( &value_is_true($nl->get_value("use_matrixcn")) && &value_is_true($nl_flags->{"for_testing_use_second_grain_pool"}) ) { + $log->fatal_error("for_testing_use_second_grain_pool can NOT be on when use_matrixcn is on" ); + } + if ( &value_is_true($nl->get_value("use_matrixcn")) && &value_is_true($nl_flags->{"for_testing_use_repr_structure_pool"}) ) { + $log->fatal_error("for_testing_use_repr_structure_pool can NOT be on when use_matrixcn is on" ); + } # If both matrixcn and soil_matrix are off outmatrix can't be on if ( ! &value_is_true($nl->get_value("use_matrixcn")) && ! &value_is_true($nl_flags->{"use_soil_matrixcn"}) ) { my $var = "is_outmatrix"; diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 2656079bf7..a55ce73634 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -44,6 +44,34 @@ + + + FAIL + #640, same test with clm-ciso_soil_matrixcn_only works + + + + + + FAIL + #640, same test with clm-ciso_soil_matrixcn_only works + + + + + + FAIL + #640, same test with clm-ciso_soil_matrixcn_only works + + + + + + FAIL + #640, same test with clm-ciso_soil_matrixcn_only works + + + diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index e570603ff7..100067f90d 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2599,6 +2599,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/biogeochem/CropReprPoolsMod.F90 b/src/biogeochem/CropReprPoolsMod.F90 index 780b9f2d52..82469b074f 100644 --- a/src/biogeochem/CropReprPoolsMod.F90 +++ b/src/biogeochem/CropReprPoolsMod.F90 @@ -57,6 +57,11 @@ subroutine crop_repr_pools_init() ! !DESCRIPTION: ! Initialize module-level data ! + ! !USES: + use clm_varctl, only: use_matrixcn + use abortutils, only: endrun + use shr_log_mod, only: errmsg => shr_log_errMsg + ! ! !ARGUMENTS: ! ! !LOCAL VARIABLES: @@ -77,11 +82,17 @@ subroutine crop_repr_pools_init() ! repr_hist_fnames(1) = 'GRAIN_MEAL', grain_hist_fnames(2) = 'GRAIN_OIL', etc. if (for_testing_use_second_grain_pool) then nrepr_grain = 2 + if (use_matrixcn) then + call endrun(msg="ERROR: for_testing_use_second_grain_pool should be .false. when use_matrixcn = .true."//errmsg(sourcefile, __LINE__)) + end if else nrepr_grain = 1 end if if (for_testing_use_repr_structure_pool) then nrepr_structure = 2 + if (use_matrixcn) then + call endrun(msg="ERROR: for_testing_use_repr_structure_pool should be .false. when use_matrixcn = .true."//errMsg(sourcefile, __LINE__)) + end if else nrepr_structure = 0 end if From 040111314eb439f6815b4519174d179882650c42 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 1 Dec 2023 15:50:14 -0700 Subject: [PATCH 004/444] Update expected fails and testlist files --- bld/CLMBuildNamelist.pm | 5 +++++ cime_config/testdefs/ExpectedTestFails.xml | 13 +++---------- cime_config/testdefs/testlist_clm.xml | 12 ------------ 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index b92acc34c7..f02be0c91a 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4222,6 +4222,11 @@ sub setup_logic_cnmatrix { } # Otherwise for CN or BGC mode } else { + # TODO (slevis 2023/12/1) The next two if statements do nothing. Erik K and Sam L found that + # for_testing_use_second_grain_pool and for_testing_use_repr_structure_pool + # are empty rather than .true. or .false., but we did not get to the bottom + # of why, yet. The same error-check in the code does get triggered at run-time, + # so we will not pursue fixing this right now. # If matrixcn is on, for_testing_use_second_grain_pool and for_testing_use_repr_structure_pool must be off if ( &value_is_true($nl->get_value("use_matrixcn")) && &value_is_true($nl_flags->{"for_testing_use_second_grain_pool"}) ) { $log->fatal_error("for_testing_use_second_grain_pool can NOT be on when use_matrixcn is on" ); diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index a55ce73634..18619818fa 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -30,17 +30,10 @@ - - + + FAIL - PGI problems with the nuopc driver - - - - - - FAIL - PGI problems with the nuopc driver + Accessing incorrect url for neon data; will resolve itself when we update cnmatrix to some newer tag diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 100067f90d..ede4f6d278 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -1177,7 +1177,6 @@ - @@ -1431,7 +1430,6 @@ - @@ -1446,15 +1444,6 @@ - - - - - - - - - @@ -1548,7 +1537,6 @@ - From def2f7506284508182898bc0d1edeb2c12812572 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 12 Dec 2023 12:16:39 -0700 Subject: [PATCH 005/444] Change failing SMS_Ln9_P72x2 test to passing SMS_Ln9_P360x2 --- cime_config/testdefs/testlist_clm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 81ad8bced4..52ccfbf2db 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -322,7 +322,7 @@ - + From 08768f9b877caed6efd3c8fbb38f1ac3bbf29991 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Mon, 18 Dec 2023 15:25:38 -0700 Subject: [PATCH 006/444] To pass test, add use_matrixcn=.false. to luna testmod --- cime_config/testdefs/testmods_dirs/clm/luna/user_nl_clm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/luna/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/luna/user_nl_clm index cbfbb9f525..fb796ebfaf 100644 --- a/cime_config/testdefs/testmods_dirs/clm/luna/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/luna/user_nl_clm @@ -1,3 +1,3 @@ use_luna = .true. use_flexibleCN = .false. - + use_matrixcn = .false. From 8b2cb728ac99a2e6c8a7be5738f8b709b5e336b5 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 19 Dec 2023 12:46:43 -0700 Subject: [PATCH 007/444] Remove two clm45 tests from ExpectedTestFails --- cime_config/testdefs/ExpectedTestFails.xml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 18619818fa..8a43eb0acc 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -44,13 +44,6 @@ - - - FAIL - #640, same test with clm-ciso_soil_matrixcn_only works - - - FAIL @@ -58,13 +51,6 @@ - - - FAIL - #640, same test with clm-ciso_soil_matrixcn_only works - - - From ddfac7b299d8143fdf2c2d7438cf2729fe1a047d Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 22 Dec 2023 15:35:13 -0700 Subject: [PATCH 008/444] Backed dev100 mods out of 3 more files for 1x1_brazil test to pass --- src/biogeochem/CNCStateUpdate1Mod.F90 | 232 ++---- src/biogeochem/CNPhenologyMod.F90 | 680 +++++++++--------- .../SoilBiogeochemNStateUpdate1Mod.F90 | 70 +- 3 files changed, 429 insertions(+), 553 deletions(-) diff --git a/src/biogeochem/CNCStateUpdate1Mod.F90 b/src/biogeochem/CNCStateUpdate1Mod.F90 index 8cac85824e..f73453476e 100644 --- a/src/biogeochem/CNCStateUpdate1Mod.F90 +++ b/src/biogeochem/CNCStateUpdate1Mod.F90 @@ -2,9 +2,6 @@ module CNCStateUpdate1Mod !----------------------------------------------------------------------- ! Module for carbon state variable update, non-mortality fluxes. - ! When the matrix solution is being used (use_matrixcn and use_soil_matrixcn) - ! only some state updates are done here, the other state updates happen - ! after the matrix is solved in VegMatrix and SoilMatrix. ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 @@ -19,7 +16,8 @@ module CNCStateUpdate1Mod use CNVegCarbonFluxType , only : cnveg_carbonflux_type use CropType , only : crop_type use CropReprPoolsMod , only : nrepr, repr_grain_min, repr_grain_max, repr_structure_min, repr_structure_max - use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con, use_soil_matrixcn + use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con + use SoilBiogeochemDecompCascadeConType , only : use_soil_matrixcn use SoilBiogeochemCarbonFluxType , only : soilbiogeochem_carbonflux_type use SoilBiogeochemCarbonStateType , only : soilbiogeochem_carbonstate_type use PatchType , only : patch @@ -193,9 +191,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & do j = 1,nlevdecomp do fc = 1,num_soilc c = filter_soilc(fc) - ! - ! State update without the matrix solution - ! if (.not. use_soil_matrixcn) then ! phenology and dynamic land cover fluxes do i = i_litr_min, i_litr_max @@ -207,12 +202,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & ! terms have been moved to CStateUpdateDynPatch. I think this is zeroed every ! time step, but to be safe, I'm explicitly setting it to zero here. cf_soil%decomp_cpools_sourcesink_col(c,j,i_cwd) = 0._r8 - ! - ! For the matrix solution the actual state update comes after the matrix - ! multiply in SoilMatrix, but the matrix needs to be setup with - ! the equivalent of above. Those changes can be here or in the - ! native subroutines dealing with that field - ! else ! phenology and dynamic land cover fluxes do i = i_litr_min, i_litr_max @@ -243,15 +232,11 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & do j = 1,nlevdecomp do fc = 1,num_soilc c = filter_soilc(fc) - ! - ! State update without the matrix solution - ! if (.not. use_soil_matrixcn) then cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) = & - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) & - - ( cf_soil%decomp_cascade_hr_vr_col(c,j,k) + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)) *dt - ! else ! not needed here? - end if !not use_soil_matrixcn + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) & + - ( cf_soil%decomp_cascade_hr_vr_col(c,j,k) + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)) *dt + end if !not use_soil_matrixcn end do end do end do @@ -260,14 +245,10 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & do j = 1,nlevdecomp do fc = 1,num_soilc c = filter_soilc(fc) - ! - ! State update without the matrix solution - ! if (.not. use_soil_matrixcn) then cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) = & - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) & - + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)*dt - ! else ! not needed here? + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) & + + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)*dt end if !not use_soil_matrixcn end do end do @@ -275,17 +256,13 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & end do end if - if (.not. use_fates) then + if (.not. use_fates) then ptch: do fp = 1,num_soilp p = filter_soilp(fp) c = patch%column(p) ! phenology: transfer growth fluxes - - ! - ! State update without the matrix solution - ! - if(.not. use_matrixcn)then + if(.not. use_matrixcn)then ! NOTE: Any changes that go here MUST be applied to the matrix ! version as well cs_veg%leafc_patch(p) = cs_veg%leafc_patch(p) + cf_veg%leafc_xfer_to_leafc_patch(p)*dt @@ -314,11 +291,11 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & end do end if - ! phenology: litterfall fluxes + ! phenology: litterfall fluxes cs_veg%leafc_patch(p) = cs_veg%leafc_patch(p) - cf_veg%leafc_to_litter_patch(p)*dt cs_veg%frootc_patch(p) = cs_veg%frootc_patch(p) - cf_veg%frootc_to_litter_patch(p)*dt - - ! livewood turnover fluxes + + ! livewood turnover fluxes if (woody(ivt(p)) == 1._r8) then cs_veg%livestemc_patch(p) = cs_veg%livestemc_patch(p) - cf_veg%livestemc_to_deadstemc_patch(p)*dt cs_veg%deadstemc_patch(p) = cs_veg%deadstemc_patch(p) + cf_veg%livestemc_to_deadstemc_patch(p)*dt @@ -342,81 +319,57 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & - (cf_veg%repr_structurec_to_cropprod_patch(p,k) + cf_veg%repr_structurec_to_litter_patch(p,k))*dt end do end if - ! - ! For the matrix solution the actual state update comes after the matrix - ! multiply in VegMatrix, but the matrix needs to be setup with - ! the equivalent of above. Those changes can be here or in the - ! native subroutines dealing with that field - ! - else - ! NOTE: Changes for above that apply for matrix code are in CNPhenology EBK (11/26/2019) - - ! This part below MUST match exactly the code for the non-matrix part - ! above! - if (ivt(p) >= npcropmin) then - cs_veg%cropseedc_deficit_patch(p) = cs_veg%cropseedc_deficit_patch(p) & - - cf_veg%crop_seedc_to_leaf_patch(p) * dt - do k = repr_grain_min, repr_grain_max - cs_veg%cropseedc_deficit_patch(p) = cs_veg%cropseedc_deficit_patch(p) & - + cf_veg%repr_grainc_to_seed_patch(p,k) * dt - end do -! else ! slevis: I think I rejected this alternative due to a balance error -! ! NOTE: Changes for above that apply for matrix code are in CNPhenology EBK (11/26/2019) - -! ! This part below MUST match exactly the code for the non-matrix part -! ! above! -! if (ivt(p) >= npcropmin) then -! cs_veg%cropseedc_deficit_patch(p) = cs_veg%cropseedc_deficit_patch(p) & -! - cf_veg%crop_seedc_to_leaf_patch(p) * dt -! do k = repr_grain_min, repr_grain_max -! cs_veg%reproductivec_patch(p,k) = cs_veg%reproductivec_patch(p,k) & -! - (cf_veg%repr_grainc_to_food_patch(p,k) + cf_veg%repr_grainc_to_seed_patch(p,k))*dt -! cs_veg%cropseedc_deficit_patch(p) = cs_veg%cropseedc_deficit_patch(p) & -! + cf_veg%repr_grainc_to_seed_patch(p,k) * dt -! end do -! do k = repr_structure_min, repr_structure_max -! cs_veg%reproductivec_patch(p,k) = cs_veg%reproductivec_patch(p,k) & -! - (cf_veg%repr_structurec_to_cropprod_patch(p,k) + cf_veg%repr_structurec_to_litter_patch(p,k))*dt -! end do - end if - end if !not use_matrixcn + else + ! NOTE: Changes for above that apply for matrix code are in CNPhenology EBK (11/26/2019) + + ! This part below MUST match exactly the code for the non-matrix part + ! above! + if (ivt(p) >= npcropmin) then + cs_veg%cropseedc_deficit_patch(p) = cs_veg%cropseedc_deficit_patch(p) & + - cf_veg%crop_seedc_to_leaf_patch(p) * dt + do k = repr_grain_min, repr_grain_max + cs_veg%cropseedc_deficit_patch(p) = cs_veg%cropseedc_deficit_patch(p) & + + cf_veg%repr_grainc_to_seed_patch(p,k) * dt + end do + end if + end if !not use_matrixcn - check_cpool = cs_veg%cpool_patch(p)- cf_veg%psnsun_to_cpool_patch(p)*dt-cf_veg%psnshade_to_cpool_patch(p)*dt - cpool_delta = cs_veg%cpool_patch(p) + check_cpool = cs_veg%cpool_patch(p)- cf_veg%psnsun_to_cpool_patch(p)*dt-cf_veg%psnshade_to_cpool_patch(p)*dt + cpool_delta = cs_veg%cpool_patch(p) - ! maintenance respiration fluxes from cpool + ! maintenance respiration fluxes from cpool - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_xsmrpool_patch(p)*dt - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%leaf_curmr_patch(p)*dt - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%froot_curmr_patch(p)*dt - If (woody(ivt(p)) == 1._r8) then + cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_xsmrpool_patch(p)*dt + cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%leaf_curmr_patch(p)*dt + cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%froot_curmr_patch(p)*dt + If (woody(ivt(p)) == 1._r8) then cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%livestem_curmr_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%livecroot_curmr_patch(p)*dt - end if - if (ivt(p) >= npcropmin) then ! skip 2 generic crops + end if + if (ivt(p) >= npcropmin) then ! skip 2 generic crops cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%livestem_curmr_patch(p)*dt do k = 1, nrepr cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%reproductive_curmr_patch(p,k)*dt end do - end if + end if - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_resp_patch(p)*dt + cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_resp_patch(p)*dt - !RF Add in the carbon spent on uptake respiration - cs_veg%cpool_patch(p)= cs_veg%cpool_patch(p) - cf_veg%soilc_change_patch(p)*dt + !RF Add in the carbon spent on uptake respiration. + cs_veg%cpool_patch(p)= cs_veg%cpool_patch(p) - cf_veg%soilc_change_patch(p)*dt - ! maintenance respiration fluxes from xsmrpool - cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) + cf_veg%cpool_to_xsmrpool_patch(p)*dt - cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%leaf_xsmr_patch(p)*dt - cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%froot_xsmr_patch(p)*dt - if (woody(ivt(p)) == 1._r8) then + ! maintenance respiration fluxes from xsmrpool + cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) + cf_veg%cpool_to_xsmrpool_patch(p)*dt + cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%leaf_xsmr_patch(p)*dt + cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%froot_xsmr_patch(p)*dt + if (woody(ivt(p)) == 1._r8) then cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%livestem_xsmr_patch(p)*dt cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%livecroot_xsmr_patch(p)*dt - end if + end if - ! allocation fluxes - if (carbon_resp_opt == 1) then + ! allocation fluxes + if (carbon_resp_opt == 1) then cf_veg%cpool_to_leafc_patch(p) = cf_veg%cpool_to_leafc_patch(p) - cf_veg%cpool_to_leafc_resp_patch(p) cf_veg%cpool_to_leafc_storage_patch(p) = cf_veg%cpool_to_leafc_storage_patch(p) - & cf_veg%cpool_to_leafc_storage_resp_patch(p) @@ -427,21 +380,12 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_leafc_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_leafc_storage_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_frootc_patch(p)*dt - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_frootc_storage_patch(p)*dt - ! - ! State update without the matrix solution - ! - if(.not. use_matrixcn) then + cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_frootc_storage_patch(p)*dt + if(.not. use_matrixcn) then cs_veg%leafc_patch(p) = cs_veg%leafc_patch(p) + cf_veg%cpool_to_leafc_patch(p)*dt cs_veg%leafc_storage_patch(p) = cs_veg%leafc_storage_patch(p) + cf_veg%cpool_to_leafc_storage_patch(p)*dt cs_veg%frootc_patch(p) = cs_veg%frootc_patch(p) + cf_veg%cpool_to_frootc_patch(p)*dt cs_veg%frootc_storage_patch(p) = cs_veg%frootc_storage_patch(p) + cf_veg%cpool_to_frootc_storage_patch(p)*dt - ! - ! For the matrix solution the actual state update comes after the matrix - ! multiply in VegMatrix, but the matrix needs to be setup with - ! the equivalent of above. Those changes can be here or in the - ! native subroutines dealing with that field - ! else ! NOTE: The equivalent changes for matrix code are in CNPhenology EBK (11/26/2019) end if !not use_matrixcn @@ -461,10 +405,7 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_livecrootc_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_livecrootc_storage_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_deadcrootc_patch(p)*dt - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_deadcrootc_storage_patch(p)*dt - ! - ! State update without the matrix solution - ! + cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_deadcrootc_storage_patch(p)*dt if(.not. use_matrixcn)then cs_veg%livestemc_patch(p) = cs_veg%livestemc_patch(p) + cf_veg%cpool_to_livestemc_patch(p)*dt cs_veg%livestemc_storage_patch(p) = cs_veg%livestemc_storage_patch(p) + cf_veg%cpool_to_livestemc_storage_patch(p)*dt @@ -474,12 +415,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%livecrootc_storage_patch(p) = cs_veg%livecrootc_storage_patch(p) + cf_veg%cpool_to_livecrootc_storage_patch(p)*dt cs_veg%deadcrootc_patch(p) = cs_veg%deadcrootc_patch(p) + cf_veg%cpool_to_deadcrootc_patch(p)*dt cs_veg%deadcrootc_storage_patch(p) = cs_veg%deadcrootc_storage_patch(p) + cf_veg%cpool_to_deadcrootc_storage_patch(p)*dt - ! - ! For the matrix solution the actual state update comes after the matrix - ! multiply in VegMatrix, but the matrix needs to be setup with - ! the equivalent of above. Those changes can be here or in the - ! native subroutines dealing with that field - ! else ! NOTE: The equivalent changes for matrix code are in CNPhenology EBK (11/26/2019) end if !not use_matrixcn @@ -496,9 +431,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_reproductivec_patch(p,k)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_reproductivec_storage_patch(p,k)*dt end do - ! - ! State update without the matrix solution - ! if(.not. use_matrixcn)then cs_veg%livestemc_patch(p) = cs_veg%livestemc_patch(p) + cf_veg%cpool_to_livestemc_patch(p)*dt cs_veg%livestemc_storage_patch(p) = cs_veg%livestemc_storage_patch(p) + cf_veg%cpool_to_livestemc_storage_patch(p)*dt @@ -508,12 +440,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%reproductivec_storage_patch(p,k) = cs_veg%reproductivec_storage_patch(p,k) & + cf_veg%cpool_to_reproductivec_storage_patch(p,k)*dt end do - ! - ! For the matrix solution the actual state update comes after the matrix - ! multiply in VegMatrix, but the matrix needs to be setup with - ! the equivalent of above. Those changes can be here or in the - ! native subroutines dealing with that field - ! else ! NOTE: The equivalent changes for matrix code are in CNPhenology EBK (11/26/2019) end if !not use_matrixcn @@ -576,30 +502,17 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%gresp_storage_patch(p) = cs_veg%gresp_storage_patch(p) + cf_veg%cpool_to_gresp_storage_patch(p)*dt ! move storage pools into transfer pools - - ! - ! State update without the matrix solution - ! - if(.not. use_matrixcn)then - cs_veg%leafc_storage_patch(p) = cs_veg%leafc_storage_patch(p) - cf_veg%leafc_storage_to_xfer_patch(p)*dt - cs_veg%leafc_xfer_patch(p) = cs_veg%leafc_xfer_patch(p) + cf_veg%leafc_storage_to_xfer_patch(p)*dt - cs_veg%frootc_storage_patch(p) = cs_veg%frootc_storage_patch(p) - cf_veg%frootc_storage_to_xfer_patch(p)*dt - cs_veg%frootc_xfer_patch(p) = cs_veg%frootc_xfer_patch(p) + cf_veg%frootc_storage_to_xfer_patch(p)*dt - ! - ! For the matrix solution the actual state update comes after the matrix - ! multiply in VegMatrix, but the matrix needs to be setup with - ! the equivalent of above. Those changes can be here or in the - ! native subroutines dealing with that field - ! + if(.not. use_matrixcn)then + cs_veg%leafc_storage_patch(p) = cs_veg%leafc_storage_patch(p) - cf_veg%leafc_storage_to_xfer_patch(p)*dt + cs_veg%leafc_xfer_patch(p) = cs_veg%leafc_xfer_patch(p) + cf_veg%leafc_storage_to_xfer_patch(p)*dt + cs_veg%frootc_storage_patch(p) = cs_veg%frootc_storage_patch(p) - cf_veg%frootc_storage_to_xfer_patch(p)*dt + cs_veg%frootc_xfer_patch(p) = cs_veg%frootc_xfer_patch(p) + cf_veg%frootc_storage_to_xfer_patch(p)*dt else - ! NOTE: The equivalent changes for matrix code are in CNPhenology EBK (11/26/2019) + ! NOTE: The equivalent changes for matrix code are in CNPhenology EBK (11/26/2019) end if !not use_matrixcn if (woody(ivt(p)) == 1._r8) then cs_veg%gresp_storage_patch(p) = cs_veg%gresp_storage_patch(p) - cf_veg%gresp_storage_to_xfer_patch(p)*dt cs_veg%gresp_xfer_patch(p) = cs_veg%gresp_xfer_patch(p) + cf_veg%gresp_storage_to_xfer_patch(p)*dt - ! - ! State update without the matrix solution - ! if(.not. use_matrixcn)then cs_veg%livestemc_storage_patch(p) = cs_veg%livestemc_storage_patch(p) - cf_veg%livestemc_storage_to_xfer_patch(p)*dt cs_veg%livestemc_xfer_patch(p) = cs_veg%livestemc_xfer_patch(p) + cf_veg%livestemc_storage_to_xfer_patch(p)*dt @@ -609,21 +522,12 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%livecrootc_xfer_patch(p) = cs_veg%livecrootc_xfer_patch(p) + cf_veg%livecrootc_storage_to_xfer_patch(p)*dt cs_veg%deadcrootc_storage_patch(p) = cs_veg%deadcrootc_storage_patch(p)- cf_veg%deadcrootc_storage_to_xfer_patch(p)*dt cs_veg%deadcrootc_xfer_patch(p) = cs_veg%deadcrootc_xfer_patch(p) + cf_veg%deadcrootc_storage_to_xfer_patch(p)*dt - ! - ! For the matrix solution the actual state update comes after the matrix - ! multiply in VegMatrix, but the matrix needs to be setup with - ! the equivalent of above. Those changes can be here or in the - ! native subroutines dealing with that field - ! else ! NOTE: The equivalent changes for matrix code are in CNPhenology EBK (11/26/2019) end if !not use_matrixcn end if if (ivt(p) >= npcropmin) then ! skip 2 generic crops ! lines here for consistency; the transfer terms are zero - ! - ! State update without the matrix solution - ! if(.not. use_matrixcn)then ! lines here for consistency; the transfer terms are zero cs_veg%livestemc_storage_patch(p) = cs_veg%livestemc_storage_patch(p) - cf_veg%livestemc_storage_to_xfer_patch(p)*dt @@ -634,12 +538,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%reproductivec_xfer_patch(p,k) = cs_veg%reproductivec_xfer_patch(p,k) & + cf_veg%reproductivec_storage_to_xfer_patch(p,k)*dt end do - ! - ! For the matrix solution the actual state update comes after the matrix - ! multiply in VegMatrix, but the matrix needs to be setup with - ! the equivalent of above. Those changes can be here or in the - ! native subroutines dealing with that field - ! else ! NOTE: The equivalent changes for matrix code are in CNPhenology EBK (11/26/2019) end if !not use_matrixcn @@ -655,20 +553,16 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & ! an intent(inout) ! fluxes should not be updated in this module - not sure where ! this belongs - ! DML (06-20-2017) While debugging crop isotope code, found that cpool_patch and frootc_patch - ! could occasionally be very small but nonzero numbers after crop harvest, which persists + ! DML (06-20-2017) While debugging crop isotope code, found that cpool_patch and frootc_patch + ! could occasionally be very small but nonzero numbers after crop harvest, which persists ! through to next planting and for reasons that could not 100% ! isolate, caused C12/C13 ratios to occasionally go out of ! bounds. Zeroing out these small pools and putting them into the flux to the ! atmosphere solved many of the crop isotope problems - ! Instantly release XSMRPOOL to atmosphere if ( .not. dribble_crophrv_xsmrpool_2atm ) then cf_veg%xsmrpool_to_atm_patch(p) = cf_veg%xsmrpool_to_atm_patch(p) + cs_veg%xsmrpool_patch(p)/dt cf_veg%xsmrpool_to_atm_patch(p) = cf_veg%xsmrpool_to_atm_patch(p) + cs_veg%cpool_patch(p)/dt - ! - ! State update without the matrix solution - ! if(.not. use_matrixcn)then cf_veg%xsmrpool_to_atm_patch(p) = cf_veg%xsmrpool_to_atm_patch(p) + cs_veg%frootc_patch(p)/dt else @@ -684,9 +578,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%xsmrpool_loss_patch(p) = cs_veg%xsmrpool_loss_patch(p) + & cs_veg%xsmrpool_patch(p) + & cs_veg%cpool_patch(p) - ! - ! State update without the matrix solution - ! if(.not. use_matrixcn)then cs_veg%xsmrpool_loss_patch(p) = cs_veg%xsmrpool_loss_patch(p) + cs_veg%frootc_patch(p) else @@ -694,9 +585,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & + cs_veg%frootc_patch(p) * matrix_update_phc(p,cf_veg%ifroot_to_iout_ph,1._r8/dt,dt,cnveg_carbonflux_inst,.true.,.true.) end if end if - ! - ! State update without the matrix solution - ! if (.not. use_matrixcn) then cs_veg%frootc_patch(p) = 0._r8 end if @@ -713,8 +601,8 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & end if end if - end do ptch ! end of patch loop - end if ! end of NOT fates + end do ptch ! end of patch loop + end if ! end of NOT fates end associate diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index 5d666c0ffb..e804c0658b 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -136,10 +136,8 @@ module CNPhenologyMod integer, allocatable :: maxplantjday(:,:) ! maximum planting julian day integer :: jdayyrstart(inSH) ! julian day of start of year - ! Two matrix check parameters that will be invoked when the matrix solution - ! comes in (use_matrixcn) - logical,parameter :: matrixcheck_ph = .True. ! Matrix solution check - logical,parameter :: acc_ph = .False. ! Another matrix solution check + logical,parameter :: matrixcheck_ph = .True. ! Matrix check + logical,parameter :: acc_ph = .False. ! Another matrix check real(r8), private :: initial_seed_at_planting = 3._r8 ! Initial seed at planting @@ -641,114 +639,115 @@ subroutine CNEvergreenPhenology (num_soilp, filter_soilp , & integer :: p ! indices integer :: fp ! lake filter patch index - real(r8):: tranr + real(r8):: tranr real(r8):: t1 ! temporary variable !----------------------------------------------------------------------- associate( & - ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type + ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type - evergreen => pftcon%evergreen , & ! Input: binary flag for evergreen leaf habit (0 or 1) - leaf_long => pftcon%leaf_long , & ! Input: leaf longevity (yrs) + evergreen => pftcon%evergreen , & ! Input: binary flag for evergreen leaf habit (0 or 1) + leaf_long => pftcon%leaf_long , & ! Input: leaf longevity (yrs) - woody => pftcon%woody , & ! Input: binary flag for woody lifeform (1=woody, 0=not woody) + woody => pftcon%woody , & ! Input: binary flag for woody lifeform (1=woody, 0=not woody) - leafc_storage => cnveg_carbonstate_inst%leafc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) leaf C storage - frootc_storage => cnveg_carbonstate_inst%frootc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) fine root C storage - livestemc_storage => cnveg_carbonstate_inst%livestemc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) live stem C storage - deadstemc_storage => cnveg_carbonstate_inst%deadstemc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) dead stem C storage - livecrootc_storage => cnveg_carbonstate_inst%livecrootc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) live coarse root C storage - deadcrootc_storage => cnveg_carbonstate_inst%deadcrootc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) dead coarse root C storage - gresp_storage => cnveg_carbonstate_inst%gresp_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) growth respiration storage - leafc_xfer => cnveg_carbonstate_inst%leafc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) leaf C transfer - frootc_xfer => cnveg_carbonstate_inst%frootc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) fine root C transfer - livestemc_xfer => cnveg_carbonstate_inst%livestemc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) live stem C transfer - deadstemc_xfer => cnveg_carbonstate_inst%deadstemc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) dead stem C transfer - livecrootc_xfer => cnveg_carbonstate_inst%livecrootc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) live coarse root C transfer - deadcrootc_xfer => cnveg_carbonstate_inst%deadcrootc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) dead coarse root C transfer - - leafn_storage => cnveg_nitrogenstate_inst%leafn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) leaf N storage - frootn_storage => cnveg_nitrogenstate_inst%frootn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) fine root N storage - livestemn_storage => cnveg_nitrogenstate_inst%livestemn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) live stem N storage - deadstemn_storage => cnveg_nitrogenstate_inst%deadstemn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) dead stem N storage - livecrootn_storage => cnveg_nitrogenstate_inst%livecrootn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) live coarse root N storage - deadcrootn_storage => cnveg_nitrogenstate_inst%deadcrootn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) dead coarse root N storage - leafn_xfer => cnveg_nitrogenstate_inst%leafn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) leaf N transfer - frootn_xfer => cnveg_nitrogenstate_inst%frootn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) fine root N transfer - livestemn_xfer => cnveg_nitrogenstate_inst%livestemn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) live stem N transfer - deadstemn_xfer => cnveg_nitrogenstate_inst%deadstemn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) dead stem N transfer - livecrootn_xfer => cnveg_nitrogenstate_inst%livecrootn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) live coarse root N transfer - deadcrootn_xfer => cnveg_nitrogenstate_inst%deadcrootn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) dead coarse root N transfer - - leafc_storage_to_xfer => cnveg_carbonflux_inst%leafc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - frootc_storage_to_xfer => cnveg_carbonflux_inst%frootc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - livestemc_storage_to_xfer => cnveg_carbonflux_inst%livestemc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - deadstemc_storage_to_xfer => cnveg_carbonflux_inst%deadstemc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - livecrootc_storage_to_xfer => cnveg_carbonflux_inst%livecrootc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - deadcrootc_storage_to_xfer => cnveg_carbonflux_inst%deadcrootc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - gresp_storage_to_xfer => cnveg_carbonflux_inst%gresp_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - leafc_xfer_to_leafc => cnveg_carbonflux_inst%leafc_xfer_to_leafc_patch , & ! InOut: [real(r8) (:)] - frootc_xfer_to_frootc => cnveg_carbonflux_inst%frootc_xfer_to_frootc_patch , & ! InOut: [real(r8) (:)] - livestemc_xfer_to_livestemc => cnveg_carbonflux_inst%livestemc_xfer_to_livestemc_patch , & ! InOut: [real(r8) (:)] - deadstemc_xfer_to_deadstemc => cnveg_carbonflux_inst%deadstemc_xfer_to_deadstemc_patch , & ! InOut: [real(r8) (:)] - livecrootc_xfer_to_livecrootc => cnveg_carbonflux_inst%livecrootc_xfer_to_livecrootc_patch , & ! InOut: [real(r8) (:)] - deadcrootc_xfer_to_deadcrootc => cnveg_carbonflux_inst%deadcrootc_xfer_to_deadcrootc_patch , & ! InOut: [real(r8) (:)] - - leafn_storage_to_xfer => cnveg_nitrogenflux_inst%leafn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - frootn_storage_to_xfer => cnveg_nitrogenflux_inst%frootn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - livestemn_storage_to_xfer => cnveg_nitrogenflux_inst%livestemn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - deadstemn_storage_to_xfer => cnveg_nitrogenflux_inst%deadstemn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - livecrootn_storage_to_xfer => cnveg_nitrogenflux_inst%livecrootn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - deadcrootn_storage_to_xfer => cnveg_nitrogenflux_inst%deadcrootn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] - leafn_xfer_to_leafn => cnveg_nitrogenflux_inst%leafn_xfer_to_leafn_patch , & ! InOut: [real(r8) (:)] - frootn_xfer_to_frootn => cnveg_nitrogenflux_inst%frootn_xfer_to_frootn_patch , & ! InOut: [real(r8) (:)] - livestemn_xfer_to_livestemn => cnveg_nitrogenflux_inst%livestemn_xfer_to_livestemn_patch , & ! InOut: [real(r8) (:)] - deadstemn_xfer_to_deadstemn => cnveg_nitrogenflux_inst%deadstemn_xfer_to_deadstemn_patch , & ! InOut: [real(r8) (:)] - livecrootn_xfer_to_livecrootn => cnveg_nitrogenflux_inst%livecrootn_xfer_to_livecrootn_patch , & ! InOut: [real(r8) (:)] - deadcrootn_xfer_to_deadcrootn => cnveg_nitrogenflux_inst%deadcrootn_xfer_to_deadcrootn_patch , & ! InOut: [real(r8) (:)] - - bglfr => cnveg_state_inst%bglfr_patch , & ! Output: [real(r8) (:) ] background litterfall rate (1/s) - bgtr => cnveg_state_inst%bgtr_patch , & ! Output: [real(r8) (:) ] background transfer growth rate (1/s) - lgsf => cnveg_state_inst%lgsf_patch , & ! Output: [real(r8) (:) ] long growing season factor [0-1] - ileafst_to_ileafxf_phc => cnveg_carbonflux_inst%ileafst_to_ileafxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf storage pool to leaf transfer pool - ileafxf_to_ileaf_phc => cnveg_carbonflux_inst%ileafxf_to_ileaf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf transfer pool to leaf pool - ifrootst_to_ifrootxf_phc => cnveg_carbonflux_inst%ifrootst_to_ifrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root storage pool to fine root transfer pool - ifrootxf_to_ifroot_phc => cnveg_carbonflux_inst%ifrootxf_to_ifroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root transfer pool to fine root pool - ilivestemst_to_ilivestemxf_phc => cnveg_carbonflux_inst%ilivestemst_to_ilivestemxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem storage pool to live stem transfer pool - ilivestemxf_to_ilivestem_phc => cnveg_carbonflux_inst%ilivestemxf_to_ilivestem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem transfer pool to live stem pool - ideadstemst_to_ideadstemxf_phc => cnveg_carbonflux_inst%ideadstemst_to_ideadstemxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead stem storage pool to dead stem transfer pool - ideadstemxf_to_ideadstem_phc => cnveg_carbonflux_inst%ideadstemxf_to_ideadstem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead stem transfer pool to dead stem pool - ilivecrootst_to_ilivecrootxf_phc => cnveg_carbonflux_inst%ilivecrootst_to_ilivecrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root storage pool to live coarse root transfer pool - ilivecrootxf_to_ilivecroot_phc => cnveg_carbonflux_inst%ilivecrootxf_to_ilivecroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root transfer pool to live coarse root pool - ideadcrootst_to_ideadcrootxf_phc => cnveg_carbonflux_inst%ideadcrootst_to_ideadcrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead coarse root storage pool to dead coarse root transfer pool - ideadcrootxf_to_ideadcroot_phc => cnveg_carbonflux_inst%ideadcrootxf_to_ideadcroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead coarse root transfer pool to dead coarse root pool - ilivestem_to_ideadstem_phc => cnveg_carbonflux_inst%ilivestem_to_ideadstem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem pool to dead stem pool - ilivecroot_to_ideadcroot_phc => cnveg_carbonflux_inst%ilivecroot_to_ideadcroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root to dead coarse root pool - ileaf_to_iout_phc => cnveg_carbonflux_inst%ileaf_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf pool to outside of vegetation pools - ifroot_to_iout_phc => cnveg_carbonflux_inst%ifroot_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root pool to outside of vegetation pools - ilivestem_to_iout_phc => cnveg_carbonflux_inst%ilivestem_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem pool to outside of vegetation pools - igrain_to_iout_phc => cnveg_carbonflux_inst%igrain_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from grain pool to outside of vegetation pools - ileafst_to_ileafxf_phn => cnveg_nitrogenflux_inst%ileafst_to_ileafxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf storage pool to leaf transfer pool - ileafxf_to_ileaf_phn => cnveg_nitrogenflux_inst%ileafxf_to_ileaf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf transfer pool to leaf pool - ifrootst_to_ifrootxf_phn => cnveg_nitrogenflux_inst%ifrootst_to_ifrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root storage pool to fine root transfer pool - ifrootxf_to_ifroot_phn => cnveg_nitrogenflux_inst%ifrootxf_to_ifroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root transfer pool to fine root pool - ilivestemst_to_ilivestemxf_phn => cnveg_nitrogenflux_inst%ilivestemst_to_ilivestemxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem storage pool to live stem transfer pool - ilivestemxf_to_ilivestem_phn => cnveg_nitrogenflux_inst%ilivestemxf_to_ilivestem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem transfer pool to live stem pool - ideadstemst_to_ideadstemxf_phn => cnveg_nitrogenflux_inst%ideadstemst_to_ideadstemxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead stem storage pool to dead stem transfer pool - ideadstemxf_to_ideadstem_phn => cnveg_nitrogenflux_inst%ideadstemxf_to_ideadstem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead stem transfer pool to dead stem pool - ilivecrootst_to_ilivecrootxf_phn => cnveg_nitrogenflux_inst%ilivecrootst_to_ilivecrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root storage pool to live coarse root transfer pool - ilivecrootxf_to_ilivecroot_phn => cnveg_nitrogenflux_inst%ilivecrootxf_to_ilivecroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root transfer pool to live coarse root pool - ideadcrootst_to_ideadcrootxf_phn => cnveg_nitrogenflux_inst%ideadcrootst_to_ideadcrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead coarse root storage pool to dead coarse root transfer pool - ideadcrootxf_to_ideadcroot_phn => cnveg_nitrogenflux_inst%ideadcrootxf_to_ideadcroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead coarse root transfer pool to dead coarse root pool - ilivestem_to_ideadstem_phn => cnveg_nitrogenflux_inst%ilivestem_to_ideadstem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem pool to dead stem pool - ilivecroot_to_ideadcroot_phn => cnveg_nitrogenflux_inst%ilivecroot_to_ideadcroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root to dead coarse root pool - ileaf_to_iout_phn => cnveg_nitrogenflux_inst%ileaf_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf pool to outside of vegetation pools - ifroot_to_iout_phn => cnveg_nitrogenflux_inst%ifroot_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root pool to outside of vegetation pools - ilivestem_to_iout_phn => cnveg_nitrogenflux_inst%ilivestem_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem pool to outside of vegetation pools - ileaf_to_iretransn_phn => cnveg_nitrogenflux_inst%ileaf_to_iretransn_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf pool to retranslocation pool - ilivestem_to_iretransn_phn => cnveg_nitrogenflux_inst%ilivestem_to_iretransn_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem pool to retranslocation pool - ilivecroot_to_iretransn_phn => cnveg_nitrogenflux_inst%ilivecroot_to_iretransn_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root pool to retranslocation pool - igrain_to_iout_phn => cnveg_nitrogenflux_inst%igrain_to_iout_ph & ! Input: [integer (:)] Index of phenology related C transfer from grain pool to outside of vegetation pools + leafc_storage => cnveg_carbonstate_inst%leafc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) leaf C storage + frootc_storage => cnveg_carbonstate_inst%frootc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) fine root C storage + livestemc_storage => cnveg_carbonstate_inst%livestemc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) live stem C storage + deadstemc_storage => cnveg_carbonstate_inst%deadstemc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) dead stem C storage + livecrootc_storage => cnveg_carbonstate_inst%livecrootc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) live coarse root C storage + deadcrootc_storage => cnveg_carbonstate_inst%deadcrootc_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) dead coarse root C storage + gresp_storage => cnveg_carbonstate_inst%gresp_storage_patch , & ! Input: [real(r8) (:)] (gC/m2) growth respiration storage + leafc_xfer => cnveg_carbonstate_inst%leafc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) leaf C transfer + frootc_xfer => cnveg_carbonstate_inst%frootc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) fine root C transfer + livestemc_xfer => cnveg_carbonstate_inst%livestemc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) live stem C transfer + deadstemc_xfer => cnveg_carbonstate_inst%deadstemc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) dead stem C transfer + livecrootc_xfer => cnveg_carbonstate_inst%livecrootc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) live coarse root C transfer + deadcrootc_xfer => cnveg_carbonstate_inst%deadcrootc_xfer_patch , & ! InOut: [real(r8) (:)] (gC/m2) dead coarse root C transfer + + leafn_storage => cnveg_nitrogenstate_inst%leafn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) leaf N storage + frootn_storage => cnveg_nitrogenstate_inst%frootn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) fine root N storage + livestemn_storage => cnveg_nitrogenstate_inst%livestemn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) live stem N storage + deadstemn_storage => cnveg_nitrogenstate_inst%deadstemn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) dead stem N storage + livecrootn_storage => cnveg_nitrogenstate_inst%livecrootn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) live coarse root N storage + deadcrootn_storage => cnveg_nitrogenstate_inst%deadcrootn_storage_patch , & ! Input: [real(r8) (:)] (gN/m2) dead coarse root N storage + leafn_xfer => cnveg_nitrogenstate_inst%leafn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) leaf N transfer + frootn_xfer => cnveg_nitrogenstate_inst%frootn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) fine root N transfer + livestemn_xfer => cnveg_nitrogenstate_inst%livestemn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) live stem N transfer + deadstemn_xfer => cnveg_nitrogenstate_inst%deadstemn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) dead stem N transfer + livecrootn_xfer => cnveg_nitrogenstate_inst%livecrootn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) live coarse root N transfer + deadcrootn_xfer => cnveg_nitrogenstate_inst%deadcrootn_xfer_patch , & ! InOut: [real(r8) (:)] (gN/m2) dead coarse root N transfer + + leafc_storage_to_xfer => cnveg_carbonflux_inst%leafc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + frootc_storage_to_xfer => cnveg_carbonflux_inst%frootc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + livestemc_storage_to_xfer => cnveg_carbonflux_inst%livestemc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + deadstemc_storage_to_xfer => cnveg_carbonflux_inst%deadstemc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + livecrootc_storage_to_xfer => cnveg_carbonflux_inst%livecrootc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + deadcrootc_storage_to_xfer => cnveg_carbonflux_inst%deadcrootc_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + gresp_storage_to_xfer => cnveg_carbonflux_inst%gresp_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + leafc_xfer_to_leafc => cnveg_carbonflux_inst%leafc_xfer_to_leafc_patch , & ! InOut: [real(r8) (:)] + frootc_xfer_to_frootc => cnveg_carbonflux_inst%frootc_xfer_to_frootc_patch , & ! InOut: [real(r8) (:)] + livestemc_xfer_to_livestemc => cnveg_carbonflux_inst%livestemc_xfer_to_livestemc_patch , & ! InOut: [real(r8) (:)] + deadstemc_xfer_to_deadstemc => cnveg_carbonflux_inst%deadstemc_xfer_to_deadstemc_patch , & ! InOut: [real(r8) (:)] + livecrootc_xfer_to_livecrootc => cnveg_carbonflux_inst%livecrootc_xfer_to_livecrootc_patch , & ! InOut: [real(r8) (:)] + deadcrootc_xfer_to_deadcrootc => cnveg_carbonflux_inst%deadcrootc_xfer_to_deadcrootc_patch , & ! InOut: [real(r8) (:)] + + leafn_storage_to_xfer => cnveg_nitrogenflux_inst%leafn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + frootn_storage_to_xfer => cnveg_nitrogenflux_inst%frootn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + livestemn_storage_to_xfer => cnveg_nitrogenflux_inst%livestemn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + deadstemn_storage_to_xfer => cnveg_nitrogenflux_inst%deadstemn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + livecrootn_storage_to_xfer => cnveg_nitrogenflux_inst%livecrootn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + deadcrootn_storage_to_xfer => cnveg_nitrogenflux_inst%deadcrootn_storage_to_xfer_patch , & ! InOut: [real(r8) (:)] + leafn_xfer_to_leafn => cnveg_nitrogenflux_inst%leafn_xfer_to_leafn_patch , & ! InOut: [real(r8) (:)] + frootn_xfer_to_frootn => cnveg_nitrogenflux_inst%frootn_xfer_to_frootn_patch , & ! InOut: [real(r8) (:)] + livestemn_xfer_to_livestemn => cnveg_nitrogenflux_inst%livestemn_xfer_to_livestemn_patch , & ! InOut: [real(r8) (:)] + deadstemn_xfer_to_deadstemn => cnveg_nitrogenflux_inst%deadstemn_xfer_to_deadstemn_patch , & ! InOut: [real(r8) (:)] + livecrootn_xfer_to_livecrootn => cnveg_nitrogenflux_inst%livecrootn_xfer_to_livecrootn_patch , & ! InOut: [real(r8) (:)] + deadcrootn_xfer_to_deadcrootn => cnveg_nitrogenflux_inst%deadcrootn_xfer_to_deadcrootn_patch , & ! InOut: [real(r8) (:)] + + bglfr => cnveg_state_inst%bglfr_patch , & ! Output: [real(r8) (:) ] background litterfall rate (1/s) + bgtr => cnveg_state_inst%bgtr_patch , & ! Output: [real(r8) (:) ] background transfer growth rate (1/s) + lgsf => cnveg_state_inst%lgsf_patch , & ! Output: [real(r8) (:) ] long growing season factor [0-1] + + ileafst_to_ileafxf_phc => cnveg_carbonflux_inst%ileafst_to_ileafxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf storage pool to leaf transfer pool + ileafxf_to_ileaf_phc => cnveg_carbonflux_inst%ileafxf_to_ileaf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf transfer pool to leaf pool + ifrootst_to_ifrootxf_phc => cnveg_carbonflux_inst%ifrootst_to_ifrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root storage pool to fine root transfer pool + ifrootxf_to_ifroot_phc => cnveg_carbonflux_inst%ifrootxf_to_ifroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root transfer pool to fine root pool + ilivestemst_to_ilivestemxf_phc => cnveg_carbonflux_inst%ilivestemst_to_ilivestemxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem storage pool to live stem transfer pool + ilivestemxf_to_ilivestem_phc => cnveg_carbonflux_inst%ilivestemxf_to_ilivestem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem transfer pool to live stem pool + ideadstemst_to_ideadstemxf_phc => cnveg_carbonflux_inst%ideadstemst_to_ideadstemxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead stem storage pool to dead stem transfer pool + ideadstemxf_to_ideadstem_phc => cnveg_carbonflux_inst%ideadstemxf_to_ideadstem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead stem transfer pool to dead stem pool + ilivecrootst_to_ilivecrootxf_phc => cnveg_carbonflux_inst%ilivecrootst_to_ilivecrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root storage pool to live coarse root transfer pool + ilivecrootxf_to_ilivecroot_phc => cnveg_carbonflux_inst%ilivecrootxf_to_ilivecroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root transfer pool to live coarse root pool + ideadcrootst_to_ideadcrootxf_phc => cnveg_carbonflux_inst%ideadcrootst_to_ideadcrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead coarse root storage pool to dead coarse root transfer pool + ideadcrootxf_to_ideadcroot_phc => cnveg_carbonflux_inst%ideadcrootxf_to_ideadcroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead coarse root transfer pool to dead coarse root pool + ilivestem_to_ideadstem_phc => cnveg_carbonflux_inst%ilivestem_to_ideadstem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem pool to dead stem pool + ilivecroot_to_ideadcroot_phc => cnveg_carbonflux_inst%ilivecroot_to_ideadcroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root to dead coarse root pool + ileaf_to_iout_phc => cnveg_carbonflux_inst%ileaf_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf pool to outside of vegetation pools + ifroot_to_iout_phc => cnveg_carbonflux_inst%ifroot_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root pool to outside of vegetation pools + ilivestem_to_iout_phc => cnveg_carbonflux_inst%ilivestem_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem pool to outside of vegetation pools + igrain_to_iout_phc => cnveg_carbonflux_inst%igrain_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from grain pool to outside of vegetation pools + ileafst_to_ileafxf_phn => cnveg_nitrogenflux_inst%ileafst_to_ileafxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf storage pool to leaf transfer pool + ileafxf_to_ileaf_phn => cnveg_nitrogenflux_inst%ileafxf_to_ileaf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf transfer pool to leaf pool + ifrootst_to_ifrootxf_phn => cnveg_nitrogenflux_inst%ifrootst_to_ifrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root storage pool to fine root transfer pool + ifrootxf_to_ifroot_phn => cnveg_nitrogenflux_inst%ifrootxf_to_ifroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root transfer pool to fine root pool + ilivestemst_to_ilivestemxf_phn => cnveg_nitrogenflux_inst%ilivestemst_to_ilivestemxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem storage pool to live stem transfer pool + ilivestemxf_to_ilivestem_phn => cnveg_nitrogenflux_inst%ilivestemxf_to_ilivestem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem transfer pool to live stem pool + ideadstemst_to_ideadstemxf_phn => cnveg_nitrogenflux_inst%ideadstemst_to_ideadstemxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead stem storage pool to dead stem transfer pool + ideadstemxf_to_ideadstem_phn => cnveg_nitrogenflux_inst%ideadstemxf_to_ideadstem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead stem transfer pool to dead stem pool + ilivecrootst_to_ilivecrootxf_phn => cnveg_nitrogenflux_inst%ilivecrootst_to_ilivecrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root storage pool to live coarse root transfer pool + ilivecrootxf_to_ilivecroot_phn => cnveg_nitrogenflux_inst%ilivecrootxf_to_ilivecroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root transfer pool to live coarse root pool + ideadcrootst_to_ideadcrootxf_phn => cnveg_nitrogenflux_inst%ideadcrootst_to_ideadcrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead coarse root storage pool to dead coarse root transfer pool + ideadcrootxf_to_ideadcroot_phn => cnveg_nitrogenflux_inst%ideadcrootxf_to_ideadcroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from dead coarse root transfer pool to dead coarse root pool + ilivestem_to_ideadstem_phn => cnveg_nitrogenflux_inst%ilivestem_to_ideadstem_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem pool to dead stem pool + ilivecroot_to_ideadcroot_phn => cnveg_nitrogenflux_inst%ilivecroot_to_ideadcroot_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root to dead coarse root pool + ileaf_to_iout_phn => cnveg_nitrogenflux_inst%ileaf_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf pool to outside of vegetation pools + ifroot_to_iout_phn => cnveg_nitrogenflux_inst%ifroot_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root pool to outside of vegetation pools + ilivestem_to_iout_phn => cnveg_nitrogenflux_inst%ilivestem_to_iout_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem pool to outside of vegetation pools + ileaf_to_iretransn_phn => cnveg_nitrogenflux_inst%ileaf_to_iretransn_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf pool to retranslocation pool + ilivestem_to_iretransn_phn => cnveg_nitrogenflux_inst%ilivestem_to_iretransn_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live stem pool to retranslocation pool + ilivecroot_to_iretransn_phn => cnveg_nitrogenflux_inst%ilivecroot_to_iretransn_ph , & ! Input: [integer (:)] Index of phenology related C transfer from live coarse root pool to retranslocation pool + igrain_to_iout_phn => cnveg_nitrogenflux_inst%igrain_to_iout_ph & ! Input: [integer (:)] Index of phenology related C transfer from grain pool to outside of vegetation pools ) avg_dayspyr = get_average_days_per_year() @@ -770,17 +769,7 @@ subroutine CNEvergreenPhenology (num_soilp, filter_soilp , & tranr=0.0002_r8 ! set carbon fluxes for shifting storage pools to transfer pools - if (.not. use_matrixcn) then - leafc_storage_to_xfer(p) = tranr * leafc_storage(p)/dt - frootc_storage_to_xfer(p) = tranr * frootc_storage(p)/dt - if (woody(ivt(p)) == 1.0_r8) then - livestemc_storage_to_xfer(p) = tranr * livestemc_storage(p)/dt - deadstemc_storage_to_xfer(p) = tranr * deadstemc_storage(p)/dt - livecrootc_storage_to_xfer(p) = tranr * livecrootc_storage(p)/dt - deadcrootc_storage_to_xfer(p) = tranr * deadcrootc_storage(p)/dt - gresp_storage_to_xfer(p) = tranr * gresp_storage(p)/dt - end if - else + if (use_matrixcn) then leafc_storage_to_xfer(p) = leafc_storage(p) * matrix_update_phc(p,ileafst_to_ileafxf_phc,tranr/dt,dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) frootc_storage_to_xfer(p) = frootc_storage(p) * matrix_update_phc(p,ifrootst_to_ifrootxf_phc,tranr/dt,dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) if (woody(ivt(p)) == 1.0_r8) then @@ -789,7 +778,18 @@ subroutine CNEvergreenPhenology (num_soilp, filter_soilp , & livecrootc_storage_to_xfer(p) = livecrootc_storage(p) * matrix_update_phc(p,ilivecrootst_to_ilivecrootxf_phc,tranr/dt,dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) deadcrootc_storage_to_xfer(p) = deadcrootc_storage(p) * matrix_update_phc(p,ideadcrootst_to_ideadcrootxf_phc,tranr/dt,dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) end if - end if !not use_matrixcn + else + ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) + leafc_storage_to_xfer(p) = tranr * leafc_storage(p)/dt + frootc_storage_to_xfer(p) = tranr * frootc_storage(p)/dt + if (woody(ivt(p)) == 1.0_r8) then + livestemc_storage_to_xfer(p) = tranr * livestemc_storage(p)/dt + deadstemc_storage_to_xfer(p) = tranr * deadstemc_storage(p)/dt + livecrootc_storage_to_xfer(p) = tranr * livecrootc_storage(p)/dt + deadcrootc_storage_to_xfer(p) = tranr * deadcrootc_storage(p)/dt + gresp_storage_to_xfer(p) = tranr * gresp_storage(p)/dt + end if + end if !use_matrixcn ! set nitrogen fluxes for shifting storage pools to transfer pools if (use_matrixcn) then @@ -1849,37 +1849,36 @@ subroutine CNStressDecidPhenology (num_soilp, filter_soilp , & ! between leafc and leafc_store in the flux. RosieF, Nov5 2015. leafc_storage_to_xfer(p) = max(0.0_r8,(leafc_storage(p)-leafc(p))) * bgtr(p) frootc_storage_to_xfer(p) = max(0.0_r8,(frootc_storage(p)-frootc(p))) * bgtr(p) - if (use_matrixcn) then - if(leafc_storage(p) > 0._r8)then + if(leafc_storage(p) .gt. 0)then leafc_storage_to_xfer(p) = leafc_storage(p) * matrix_update_phc(p,ileafst_to_ileafxf_phc,& leafc_storage_to_xfer(p) / leafc_storage(p), dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - leafc_storage_to_xfer(p) = 0._r8 + leafc_storage_to_xfer(p) = 0 end if - if(frootc_storage(p) > 0._r8)then + if(frootc_storage(p) .gt. 0)then frootc_storage_to_xfer(p) = frootc_storage(p) * matrix_update_phc(p,ifrootst_to_ifrootxf_phc,& frootc_storage_to_xfer(p) / frootc_storage(p), dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - frootc_storage_to_xfer(p) = 0._r8 + frootc_storage_to_xfer(p) = 0 end if - if (woody(ivt(p)) == 1.0_r8) then + if (woody(ivt(p)) == 1.0_r8) then livestemc_storage_to_xfer(p) = livestemc_storage(p) * matrix_update_phc(p,ilivestemst_to_ilivestemxf_phc ,bgtr(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) deadstemc_storage_to_xfer(p) = deadstemc_storage(p) * matrix_update_phc(p,ideadstemst_to_ideadstemxf_phc ,bgtr(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) livecrootc_storage_to_xfer(p) = livecrootc_storage(p) * matrix_update_phc(p,ilivecrootst_to_ilivecrootxf_phc,bgtr(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) deadcrootc_storage_to_xfer(p) = deadcrootc_storage(p) * matrix_update_phc(p,ideadcrootst_to_ideadcrootxf_phc,bgtr(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) - end if - else - ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) - ! and CNNStateUpdate1::NStateUpdate1 - if (woody(ivt(p)) == 1.0_r8) then - livestemc_storage_to_xfer(p) = livestemc_storage(p) * bgtr(p) - deadstemc_storage_to_xfer(p) = deadstemc_storage(p) * bgtr(p) - livecrootc_storage_to_xfer(p) = livecrootc_storage(p) * bgtr(p) - deadcrootc_storage_to_xfer(p) = deadcrootc_storage(p) * bgtr(p) - gresp_storage_to_xfer(p) = gresp_storage(p) * bgtr(p) - end if - end if !use_matrixcn + end if + else + ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) + ! and CNNStateUpdate1::NStateUpdate1 + if (woody(ivt(p)) == 1.0_r8) then + livestemc_storage_to_xfer(p) = livestemc_storage(p) * bgtr(p) + deadstemc_storage_to_xfer(p) = deadstemc_storage(p) * bgtr(p) + livecrootc_storage_to_xfer(p) = livecrootc_storage(p) * bgtr(p) + deadcrootc_storage_to_xfer(p) = deadcrootc_storage(p) * bgtr(p) + gresp_storage_to_xfer(p) = gresp_storage(p) * bgtr(p) + end if + end if !use_matrixcn ! set nitrogen fluxes for shifting storage pools to transfer pools if (use_matrixcn) then @@ -2920,22 +2919,7 @@ subroutine CNOnsetGrowth (num_soilp, filter_soilp, & ! pools should be moved to displayed growth in each timestep. if (bgtr(p) > 0._r8) then - if(.not. use_matrixcn)then - leafc_xfer_to_leafc(p) = leafc_xfer(p) / dt - frootc_xfer_to_frootc(p) = frootc_xfer(p) / dt - leafn_xfer_to_leafn(p) = leafn_xfer(p) / dt - frootn_xfer_to_frootn(p) = frootn_xfer(p) / dt - if (woody(ivt(p)) == 1.0_r8) then - livestemc_xfer_to_livestemc(p) = livestemc_xfer(p) / dt - deadstemc_xfer_to_deadstemc(p) = deadstemc_xfer(p) / dt - livecrootc_xfer_to_livecrootc(p) = livecrootc_xfer(p) / dt - deadcrootc_xfer_to_deadcrootc(p) = deadcrootc_xfer(p) / dt - livestemn_xfer_to_livestemn(p) = livestemn_xfer(p) / dt - deadstemn_xfer_to_deadstemn(p) = deadstemn_xfer(p) / dt - livecrootn_xfer_to_livecrootn(p) = livecrootn_xfer(p) / dt - deadcrootn_xfer_to_deadcrootn(p) = deadcrootn_xfer(p) / dt - end if - else + if(use_matrixcn)then leafc_xfer_to_leafc(p) = leafc_xfer(p) * matrix_update_phc(p,ileafxf_to_ileaf_phc,1._r8 / dt,dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) frootc_xfer_to_frootc(p) = frootc_xfer(p) * matrix_update_phc(p,ifrootxf_to_ifroot_phc,1._r8 / dt,dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) leafn_xfer_to_leafn(p) = leafn_xfer(p) * matrix_update_phn(p,ileafxf_to_ileaf_phn,1._r8 / dt,dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) @@ -2952,7 +2936,24 @@ subroutine CNOnsetGrowth (num_soilp, filter_soilp, & livecrootn_xfer_to_livecrootn(p) = livecrootn_xfer(p) * matrix_update_phn(p,ilivecrootxf_to_ilivecroot_phn,1._r8 / dt,dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) deadcrootn_xfer_to_deadcrootn(p) = deadcrootn_xfer(p) * matrix_update_phn(p,ideadcrootxf_to_ideadcroot_phn,1._r8 / dt,dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) end if - end if !not use_matrixcn + else + ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) + ! and CNNStateUpdate1::NStateUpdate1 + leafc_xfer_to_leafc(p) = leafc_xfer(p) / dt + frootc_xfer_to_frootc(p) = frootc_xfer(p) / dt + leafn_xfer_to_leafn(p) = leafn_xfer(p) / dt + frootn_xfer_to_frootn(p) = frootn_xfer(p) / dt + if (woody(ivt(p)) == 1.0_r8) then + livestemc_xfer_to_livestemc(p) = livestemc_xfer(p) / dt + deadstemc_xfer_to_deadstemc(p) = deadstemc_xfer(p) / dt + livecrootc_xfer_to_livecrootc(p) = livecrootc_xfer(p) / dt + deadcrootc_xfer_to_deadcrootc(p) = deadcrootc_xfer(p) / dt + livestemn_xfer_to_livestemn(p) = livestemn_xfer(p) / dt + deadstemn_xfer_to_deadstemn(p) = deadstemn_xfer(p) / dt + livecrootn_xfer_to_livecrootn(p) = livecrootn_xfer(p) / dt + deadcrootn_xfer_to_deadcrootn(p) = deadcrootn_xfer(p) / dt + end if + end if !use_matrixcn end if ! end if bgtr end do ! end patch loop @@ -3113,26 +3114,26 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & if (abs(offset_counter(p) - dt) <= dt/2._r8) then t1 = 1.0_r8 / dt + frootc_to_litter(p) = t1 * frootc(p) + cpool_to_frootc(p) + + ! biofuel_harvfrac is only non-zero for prognostic crops. + leafc_to_litter(p) = t1 * leafc(p)*(1._r8-biofuel_harvfrac(ivt(p))) + cpool_to_leafc(p) - ! leafc_litter and frootc_to_litter for matrix if (use_matrixcn) then - if(leafc(p) > 0._r8)then + if(leafc(p) .gt. 0)then leafc_to_litter(p) = leafc(p) * matrix_update_phc(p,ileaf_to_iout_phc,leafc_to_litter(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - leafc_to_litter(p) = 0._r8 + leafc_to_litter(p) = 0 end if - if(frootc(p) > 0._r8)then + if(frootc(p) .gt. 0)then frootc_to_litter(p) = frootc(p) * matrix_update_phc(p,ifroot_to_iout_phc,frootc_to_litter(p) / frootc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - frootc_to_litter(p) = 0._r8 + frootc_to_litter(p) = 0 end if else - frootc_to_litter(p) = t1 * frootc(p) + cpool_to_frootc(p) - - ! biofuel_harvfrac is only non-zero for prognostic crops. - leafc_to_litter(p) = t1 * leafc(p)*(1._r8-biofuel_harvfrac(ivt(p))) + cpool_to_leafc(p) + ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) + ! and CNNStateUpdate1::NStateUpdate1 end if ! use_matrixcn - ! this assumes that offset_counter == dt for crops ! if this were ever changed, we'd need to add code to the "else" if (ivt(p) >= npcropmin) then @@ -3176,101 +3177,105 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & * (1._r8 - repr_structure_harvfrac(ivt(p), k)) end do - ! Matrix for grain, livestem to litter and biofuel + ! Cut a certain fraction (i.e., biofuel_harvfrac(ivt(p))) (e.g., biofuel_harvfrac(ivt(p)=70% for bioenergy crops) of leaf C + ! and move this fration of leaf C to biofuel C, rather than move it to litter + leafc_to_biofuelc(p) = t1 * leafc(p) * biofuel_harvfrac(ivt(p)) + leafn_to_biofueln(p) = t1 * leafn(p) * biofuel_harvfrac(ivt(p)) + + ! Cut a certain fraction (i.e., biofuel_harvfrac(ivt(p))) (e.g., biofuel_harvfrac(ivt(p)=70% for bioenergy crops) of livestem C + ! and move this fration of leaf C to biofuel C, rather than move it to litter + livestemc_to_litter(p) = t1 * livestemc(p)*(1._r8-biofuel_harvfrac(ivt(p))) + cpool_to_livestemc(p) + livestemc_to_biofuelc(p) = t1 * livestemc(p) * biofuel_harvfrac(ivt(p)) + livestemn_to_biofueln(p) = t1 * livestemn(p) * biofuel_harvfrac(ivt(p)) + if(use_matrixcn)then - if(reproductivec(p,1) > 0._r8)then + if(reproductivec(p,1) .gt. 0)then grainc_to_out = reproductivec(p,1) * matrix_update_phc(p,igrain_to_iout_phc,(repr_grainc_to_seed(p,1) + repr_grainc_to_food(p,1)) / reproductivec(p,1),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - repr_grainc_to_seed(p,1) = 0._r8 - repr_grainc_to_food(p,1) = 0._r8 + repr_grainc_to_seed(p,1) = 0 + repr_grainc_to_food(p,1) = 0 end if - if(reproductiven(p,1) > 0._r8)then + if(reproductiven(p,1) .gt. 0)then grainn_to_out = reproductiven(p,1) * matrix_update_phn(p,igrain_to_iout_phn,(repr_grainn_to_seed(p,1) + repr_grainn_to_food(p,1)) / reproductiven(p,1),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else - repr_grainn_to_seed(p,1) = 0._r8 - repr_grainn_to_food(p,1) = 0._r8 + repr_grainn_to_seed(p,1) = 0 + repr_grainn_to_food(p,1) = 0 end if - if(livestemc(p) > 0._r8)then + if(livestemc(p) .gt. 0)then livestemc_to_litter(p) = livestemc(p) * matrix_update_phc(p,ilivestem_to_iout_phc,livestemc_to_litter(p) / livestemc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - livestemc_to_litter(p) = 0._r8 + livestemc_to_litter(p) = 0 end if - if(livestemn(p) > 0._r8)then + if(livestemn(p) .gt. 0)then livestemn_to_biofueln(p) = livestemn(p) * matrix_update_gmn(p,ilivestem_to_iout_gmn,livestemn_to_biofueln(p) / livestemn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,.True.) else - livestemn_to_biofueln(p) = 0._r8 + livestemn_to_biofueln(p) = 0 end if - if(leafn(p) > 0._r8)then + if(leafn(p) > 0)then leafn_to_biofueln(p) = leafn(p) * matrix_update_gmn(p,ileaf_to_iout_gmn,leafn_to_biofueln(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,.True.) else - leafn_to_biofueln(p) = 0._r8 + leafn_to_biofueln(p) = 0 end if - if (leafc(p) > 0._r8)then + if (leafc(p) > 0)then leafc_to_biofuelc(p) = leafc(p) * matrix_update_gmc(p,ileaf_to_iout_gmc,leafc_to_biofuelc(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) else - leafc_to_biofuelc(p) = 0._r8 + leafc_to_biofuelc(p) = 0 end if - if(livestemc(p) > 0._r8)then + if(livestemc(p) .gt. 0)then livestemc_to_biofuelc(p) = livestemc(p) * matrix_update_gmc(p,ilivestem_to_iout_gmc,livestemc_to_biofuelc(p) / livestemc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) else - livestemc_to_biofuelc(p) = 0._r8 + livestemc_to_biofuelc(p) = 0 end if else - ! Cut a certain fraction (i.e., biofuel_harvfrac(ivt(p))) (e.g., biofuel_harvfrac(ivt(p)=70% for bioenergy crops) of leaf C - ! and move this fration of leaf C to biofuel C, rather than move it to litter - leafc_to_biofuelc(p) = t1 * leafc(p) * biofuel_harvfrac(ivt(p)) - leafn_to_biofueln(p) = t1 * leafn(p) * biofuel_harvfrac(ivt(p)) - - ! Cut a certain fraction (i.e., biofuel_harvfrac(ivt(p))) (e.g., biofuel_harvfrac(ivt(p)=70% for bioenergy crops) of livestem C - ! and move this fration of leaf C to biofuel C, rather than move it to litter - livestemc_to_litter(p) = t1 * livestemc(p)*(1._r8-biofuel_harvfrac(ivt(p))) + cpool_to_livestemc(p) - livestemc_to_biofuelc(p) = t1 * livestemc(p) * biofuel_harvfrac(ivt(p)) - livestemn_to_biofueln(p) = t1 * livestemn(p) * biofuel_harvfrac(ivt(p)) + ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) + ! and CNNStateUpdate1::NStateUpdate1 end if ! use_matrixcn end if else - ! Matrix for leafc and frootc to litter + t1 = dt * 2.0_r8 / (offset_counter(p) * offset_counter(p)) + leafc_to_litter(p) = prev_leafc_to_litter(p) + t1*(leafc(p) - prev_leafc_to_litter(p)*offset_counter(p)) + frootc_to_litter(p) = prev_frootc_to_litter(p) + t1*(frootc(p) - prev_frootc_to_litter(p)*offset_counter(p)) + if (use_matrixcn) then - if(leafc(p) > 0._r8)then + if(leafc(p) .gt. 0)then leafc_to_litter(p) = leafc(p) * matrix_update_phc(p,ileaf_to_iout_phc,leafc_to_litter(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - leafc_to_litter(p) = 0._r8 + leafc_to_litter(p) = 0 end if - if(frootc(p) > 0._r8)then + if(frootc(p) .gt. 0)then frootc_to_litter(p) = frootc(p) * matrix_update_phc(p,ifroot_to_iout_phc,frootc_to_litter(p) / frootc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - frootc_to_litter(p) = 0._r8 + frootc_to_litter(p) = 0 end if else - t1 = dt * 2.0_r8 / (offset_counter(p) * offset_counter(p)) - leafc_to_litter(p) = prev_leafc_to_litter(p) + t1*(leafc(p) - prev_leafc_to_litter(p)*offset_counter(p)) - frootc_to_litter(p) = prev_frootc_to_litter(p) + t1*(frootc(p) - prev_frootc_to_litter(p)*offset_counter(p)) + ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) + ! and CNNStateUpdate1::NStateUpdate1 end if !use_matrixcn end if if ( use_fun ) then if(leafc_to_litter(p)*dt.gt.leafc(p))then - ! Matrix for leafc to litter - if (use_matrixcn) then - if(leafc(p) > 0._r8)then + leafc_to_litter(p) = leafc(p)/dt + cpool_to_leafc(p) + if (use_matrixcn) then + if(leafc(p) .gt. 0)then leafc_to_litter(p) = leafc(p) * matrix_update_phc(p,ileaf_to_iout_phc,leafc_to_litter(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - leafc_to_litter(p) = 0._r8 + leafc_to_litter(p) = 0 end if - else - leafc_to_litter(p) = leafc(p)/dt + cpool_to_leafc(p) - end if !use_matrixcn + else + ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) + end if !use_matrixcn endif if(frootc_to_litter(p)*dt.gt.frootc(p))then - ! Matrix update for frootc to litter + frootc_to_litter(p) = frootc(p)/dt + cpool_to_frootc(p) if (use_matrixcn) then - if(frootc(p) > 0._r8)then + if(frootc(p) .gt. 0)then frootc_to_litter(p) = frootc(p) * matrix_update_phc(p,ifroot_to_iout_phc,frootc_to_litter(p) / frootc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - frootc_to_litter(p) = 0._r8 + frootc_to_litter(p) = 0 end if else - frootc_to_litter(p) = frootc(p)/dt + cpool_to_frootc(p) + ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) end if !use_matrixcn endif end if @@ -3279,8 +3284,8 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & if ( use_fun ) then leafc_to_litter_fun(p) = leafc_to_litter(p) leafn_to_retransn(p) = paid_retransn_to_npool(p) + free_retransn_to_npool(p) - if (leafn(p) > 0._r8) then - if (leafn(p)-leafn_to_retransn(p)*dt > 0._r8) then + if (leafn(p).gt.0._r8) then + if (leafn(p)-leafn_to_retransn(p)*dt.gt.0._r8) then leafcn_offset(p) = leafc(p)/(leafn(p)-leafn_to_retransn(p)*dt) else leafcn_offset(p) = leafc(p)/leafn(p) @@ -3290,15 +3295,13 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & end if leafn_to_litter(p) = leafc_to_litter(p)/leafcn_offset(p) - leafn_to_retransn(p) leafn_to_litter(p) = max(leafn_to_litter(p),0._r8) - - ! Matrix update for leafn to litter and retrans if (use_matrixcn) then - if(leafn(p) > 0._r8)then + if(leafn(p) .gt. 0)then leafn_to_litter(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iout_phn,leafn_to_litter(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) leafn_to_retransn(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iretransn_phn,leafn_to_retransn(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else - leafn_to_litter(p) = 0._r8 - leafn_to_retransn(p) = 0._r8 + leafn_to_litter(p) = 0 + leafn_to_retransn(p) = 0 end if else ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) @@ -3315,21 +3318,20 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & end if else - if (CNratio_floating) then + if (CNratio_floating .eqv. .true.) then fr_leafn_to_litter = 0.5_r8 ! assuming 50% of nitrogen turnover goes to litter end if ! calculate the leaf N litterfall and retranslocation leafn_to_litter(p) = leafc_to_litter(p) / lflitcn(ivt(p)) leafn_to_retransn(p) = (leafc_to_litter(p) / leafcn(ivt(p))) - leafn_to_litter(p) - ! Matrix update for leafn to litter and retrans if (use_matrixcn) then - if(leafn(p) > 0._r8)then + if(leafn(p) .gt. 0)then leafn_to_litter(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iout_phn,leafn_to_litter(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) leafn_to_retransn(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iretransn_phn,leafn_to_retransn(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else - leafn_to_litter(p) = 0._r8 - leafn_to_retransn(p) = 0._r8 + leafn_to_litter(p) = 0 + leafn_to_retransn(p) = 0 end if else ! NOTE: The non matrix version of this is in CNNStateUpdate1::NStateUpdate1 EBK (11/26/2019) @@ -3338,49 +3340,44 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & ! calculate fine root N litterfall (no retranslocation of fine root N) frootn_to_litter(p) = frootc_to_litter(p) / frootcn(ivt(p)) - - ! Matrix update for frootn to litter if (use_matrixcn) then - if(frootn(p) > 0._r8)then + if(frootn(p) .gt. 0)then frootn_to_litter(p) = frootn(p) * matrix_update_phn(p,ifroot_to_iout_phn,frootn_to_litter(p) / frootn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else - frootn_to_litter(p) = 0._r8 + frootn_to_litter(p) = 0 end if else ! NOTE: The non matrix version of this is in CNNStateUpdate1::NStateUpdate1 EBK (11/26/2019) end if !use_matrixcn - if (CNratio_floating) then - if (.not. use_matrixcn) then - if (leafc(p) == 0.0_r8) then - ntovr_leaf = 0.0_r8 - else - ntovr_leaf = leafc_to_litter(p) * (leafn(p) / leafc(p)) - end if + if (CNratio_floating .eqv. .true.) then + if (leafc(p) == 0.0_r8) then + ntovr_leaf = 0.0_r8 + else + ntovr_leaf = leafc_to_litter(p) * (leafn(p) / leafc(p)) + end if - leafn_to_litter(p) = fr_leafn_to_litter * ntovr_leaf - leafn_to_retransn(p) = ntovr_leaf - leafn_to_litter(p) - else ! Matrix update for leafn to litter and retrans - if(leafn(p) > 0._r8)then + leafn_to_litter(p) = fr_leafn_to_litter * ntovr_leaf + leafn_to_retransn(p) = ntovr_leaf - leafn_to_litter(p) + if (use_matrixcn) then + if(leafn(p) .gt. 0)then leafn_to_litter(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iout_phn,leafn_to_litter(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) leafn_to_retransn(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iretransn_phn,leafn_to_retransn(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else - leafn_to_litter(p) = 0._r8 - leafn_to_retransn(p) = 0._r8 + leafn_to_litter(p) = 0 + leafn_to_retransn(p) = 0 end if - end if ! .not. use_matrixcn + end if !use_matrixcn if (frootc(p) == 0.0_r8) then frootn_to_litter(p) = 0.0_r8 - else + else frootn_to_litter(p) = frootc_to_litter(p) * (frootn(p) / frootc(p)) - end if - - ! Matrix update for frootn to litter + end if if (use_matrixcn) then - if(frootn(p) > 0._r8)then + if(frootn(p) .gt. 0)then frootn_to_litter(p) = frootn(p) * matrix_update_phn(p,ifroot_to_iout_phn,frootn_to_litter(p) / frootn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else - frootn_to_litter(p) = 0._r8 + frootn_to_litter(p) = 0 end if else ! NOTE: The non matrix version of this is in CNNStateUpdate1::NStateUpdate1 EBK (11/26/2019) @@ -3389,26 +3386,21 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & if ( use_fun ) then if(frootn_to_litter(p)*dt.gt.frootn(p))then - - ! Send all frootn to litter if (.not. use_matrixcn) then frootn_to_litter(p) = frootn(p)/dt else - ! Matrix update for frootn to litter frootn_to_litter(p) = frootn(p) * matrix_update_phn(p,ifroot_to_iout_phn,1._r8/dt,dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) end if endif end if if (ivt(p) >= npcropmin) then - ! Matrix update for livestemn to litter + ! NOTE(slevis, 2014-12) results in -ve livestemn and -ve totpftn + !X! livestemn_to_litter(p) = livestemc_to_litter(p) / livewdcn(ivt(p)) + ! NOTE(slevis, 2014-12) Beth Drewniak suggested this instead + livestemn_to_litter(p) = livestemn(p) / dt * (1._r8 - biofuel_harvfrac(ivt(p))) if(use_matrixcn)then livestemn_to_litter(p) = livestemn(p) * matrix_update_phn(p,ilivestem_to_iout_phn, (1._r8- biofuel_harvfrac(ivt(p)))/dt, dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) - else - ! NOTE(slevis, 2014-12) results in -ve livestemn and -ve totpftn - !X! livestemn_to_litter(p) = livestemc_to_litter(p) / livewdcn(ivt(p)) - ! NOTE(slevis, 2014-12) Beth Drewniak suggested this instead - livestemn_to_litter(p) = livestemn(p) / dt * (1._r8 - biofuel_harvfrac(ivt(p))) end if end if @@ -3477,7 +3469,7 @@ subroutine CNBackgroundLitterfall (num_soilp, filter_soilp, & leafc_to_litter_fun => cnveg_carbonflux_inst%leafc_to_litter_fun_patch, & ! Output: [real(r8) (:) ] leaf C litterfall used by FUN (gC/m2/s) leafcn_offset => cnveg_state_inst%leafcn_offset_patch , & ! Output: [real(r8) (:) ] Leaf C:N used by FUN free_retransn_to_npool=> cnveg_nitrogenflux_inst%free_retransn_to_npool_patch , & ! Input: [real(r8) (:) ] free leaf N to retranslocated N pool (gN/m2/s) - paid_retransn_to_npool=> cnveg_nitrogenflux_inst%retransn_to_npool_patch , & ! Input: [real(r8) (:) ] free leaf N to retranslocated N pool (gN/m2/s) + paid_retransn_to_npool=> cnveg_nitrogenflux_inst%retransn_to_npool_patch , & ! Input: [real(r8) (:) ] free leaf N to retranslocated N pool (gN/m2/s) ileafst_to_ileafxf_phc => cnveg_carbonflux_inst%ileafst_to_ileafxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf storage pool to leaf transfer pool ileafxf_to_ileaf_phc => cnveg_carbonflux_inst%ileafxf_to_ileaf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf transfer pool to leaf pool @@ -3526,36 +3518,35 @@ subroutine CNBackgroundLitterfall (num_soilp, filter_soilp, & ! only calculate these fluxes if the background litterfall rate is non-zero if (bglfr(p) > 0._r8) then - ! Matrix update for leafc and frootc to litter + ! units for bglfr are already 1/s + leafc_to_litter(p) = bglfr(p) * leafc(p) + frootc_to_litter(p) = bglfr(p) * frootc(p) if (use_matrixcn) then leafc_to_litter(p) = leafc(p) * matrix_update_phc(p,ileaf_to_iout_phc,bglfr(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) frootc_to_litter(p) = frootc(p) * matrix_update_phc(p,ifroot_to_iout_phc,bglfr(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) - else - ! units for bglfr are already 1/s - leafc_to_litter(p) = bglfr(p) * leafc(p) - frootc_to_litter(p) = bglfr(p) * frootc(p) end if if ( use_fun ) then - if(.not. use_matrixcn)then - leafc_to_litter_fun(p) = leafc_to_litter(p) - leafn_to_retransn(p) = paid_retransn_to_npool(p) + free_retransn_to_npool(p) - if (leafn(p).gt.0._r8) then - if (leafn(p)-leafn_to_retransn(p)*dt.gt.0._r8) then - leafcn_offset(p) = leafc(p)/(leafn(p)-leafn_to_retransn(p)*dt) - else - leafcn_offset(p) = leafc(p)/leafn(p) - end if + leafc_to_litter_fun(p) = leafc_to_litter(p) + leafn_to_retransn(p) = paid_retransn_to_npool(p) + free_retransn_to_npool(p) + if (leafn(p).gt.0._r8) then + if (leafn(p)-leafn_to_retransn(p)*dt.gt.0._r8) then + leafcn_offset(p) = leafc(p)/(leafn(p)-leafn_to_retransn(p)*dt) else - leafcn_offset(p) = leafcn(ivt(p)) + leafcn_offset(p) = leafc(p)/leafn(p) end if - leafn_to_litter(p) = leafc_to_litter(p)/leafcn_offset(p) - leafn_to_retransn(p) - leafn_to_litter(p) = max(leafn_to_litter(p),0._r8) - else ! Matrix update for leafn to litter and retrans + else + leafcn_offset(p) = leafcn(ivt(p)) + end if + leafn_to_litter(p) = leafc_to_litter(p)/leafcn_offset(p) - leafn_to_retransn(p) + leafn_to_litter(p) = max(leafn_to_litter(p),0._r8) + if(use_matrixcn)then if(leafn(p) .ne. 0._r8)then leafn_to_litter(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iout_phn,leafn_to_litter(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) leafn_to_retransn(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iretransn_phn,leafn_to_retransn(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) end if - end if ! .not. use_matrixcn + else + ! NOTE: The non matrix version of this is in CNNStateUpdate1::NStateUpdate1 EBK (11/26/2019) + end if !use_matrixcn denom = ( leafn_to_retransn(p) + leafn_to_litter(p) ) if ( denom /= 0.0_r8 ) then @@ -3568,45 +3559,46 @@ subroutine CNBackgroundLitterfall (num_soilp, filter_soilp, & else - if (CNratio_floating) then + if (CNratio_floating .eqv. .true.) then fr_leafn_to_litter = 0.5_r8 ! assuming 50% of nitrogen turnover goes to litter end if - ! Matrix update for leafn to litter and retrans + ! calculate the leaf N litterfall and retranslocation + leafn_to_litter(p) = leafc_to_litter(p) / lflitcn(ivt(p)) + leafn_to_retransn(p) = (leafc_to_litter(p) / leafcn(ivt(p))) - leafn_to_litter(p) + if (use_matrixcn) then - if(leafn(p) .ne. 0._r8)then + if(leafn(p) .ne. 0)then leafn_to_litter(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iout_phn,leafn_to_litter(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) leafn_to_retransn(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iretransn_phn,leafn_to_retransn(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) end if else ! NOTE: The non matrix version of this is in CNNStateUpdate1::NStateUpdate1 EBK (11/26/2019) - ! calculate the leaf N litterfall and retranslocation - leafn_to_litter(p) = leafc_to_litter(p) / lflitcn(ivt(p)) - leafn_to_retransn(p) = (leafc_to_litter(p) / leafcn(ivt(p))) - leafn_to_litter(p) end if !use_matrixcn end if ! calculate fine root N litterfall (no retranslocation of fine root N) frootn_to_litter(p) = frootc_to_litter(p) / frootcn(ivt(p)) - if (CNratio_floating) then - if (.not. use_matrixcn) then - if (leafc(p) == 0.0_r8) then - ntovr_leaf = 0.0_r8 - else - ntovr_leaf = leafc_to_litter(p) * (leafn(p) / leafc(p)) - end if + if (CNratio_floating .eqv. .true.) then + if (leafc(p) == 0.0_r8) then + ntovr_leaf = 0.0_r8 + else + ntovr_leaf = leafc_to_litter(p) * (leafn(p) / leafc(p)) + end if - leafn_to_litter(p) = fr_leafn_to_litter * ntovr_leaf - leafn_to_retransn(p) = ntovr_leaf - leafn_to_litter(p) - else ! Matrix update for leafn to litter and retrans - if(leafn(p) > 0._r8)then + leafn_to_litter(p) = fr_leafn_to_litter * ntovr_leaf + leafn_to_retransn(p) = ntovr_leaf - leafn_to_litter(p) + if (use_matrixcn) then + if(leafn(p) .gt. 0)then leafn_to_litter(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iout_phn,leafn_to_litter(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) leafn_to_retransn(p) = leafn(p) * matrix_update_phn(p,ileaf_to_iretransn_phn,leafn_to_retransn(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else - leafn_to_litter(p) = 0._r8 - leafn_to_retransn(p) = 0._r8 + leafn_to_litter(p) = 0 + leafn_to_retransn(p) = 0 end if - end if ! .not. use_matrixcn + else + ! NOTE: The non matrix version of this is in CNNStateUpdate1::NStateUpdate1 EBK (11/26/2019) + end if !use_matrixcn if (frootc(p) == 0.0_r8) then frootn_to_litter(p) = 0.0_r8 else @@ -3620,9 +3612,8 @@ subroutine CNBackgroundLitterfall (num_soilp, filter_soilp, & endif end if - ! Matrix update for frootn to litter if (use_matrixcn) then - if(frootn(p) /= 0._r8)then + if(frootn(p) .ne. 0)then frootn_to_litter(p) = frootn(p) * matrix_update_phn(p,ifroot_to_iout_phn,frootn_to_litter(p) / frootn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) end if else @@ -3682,7 +3673,7 @@ subroutine CNLivewoodTurnover (num_soilp, filter_soilp, & livestemn_to_retransn => cnveg_nitrogenflux_inst%livestemn_to_retransn_patch , & ! Output: [real(r8) (:) ] livecrootn_to_deadcrootn => cnveg_nitrogenflux_inst%livecrootn_to_deadcrootn_patch , & ! Output: [real(r8) (:) ] livecrootn_to_retransn => cnveg_nitrogenflux_inst%livecrootn_to_retransn_patch , & ! Output: [real(r8) (:) ] - free_retransn_to_npool => cnveg_nitrogenflux_inst%free_retransn_to_npool_patch , & ! Input: [real(r8) (:) ] free leaf N to retranslocated N pool (gN/m2/s) + free_retransn_to_npool => cnveg_nitrogenflux_inst%free_retransn_to_npool_patch , & ! Input: [real(r8) (:) ] free leaf N to retranslocated N pool (gN/m2/s) ileafst_to_ileafxf_phc => cnveg_carbonflux_inst%ileafst_to_ileafxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf storage pool to leaf transfer pool ileafxf_to_ileaf_phc => cnveg_carbonflux_inst%ileafxf_to_ileaf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from leaf transfer pool to leaf pool ifrootst_to_ifrootxf_phc => cnveg_carbonflux_inst%ifrootst_to_ifrootxf_ph , & ! Input: [integer (:)] Index of phenology related C transfer from fine root storage pool to fine root transfer pool @@ -3736,38 +3727,40 @@ subroutine CNLivewoodTurnover (num_soilp, filter_soilp, & ! live stem to dead stem turnover - ! Matrix update for livestemc to deadstem + ctovr = livestemc(p) * lwtop + ntovr = ctovr / livewdcn(ivt(p)) + livestemc_to_deadstemc(p) = ctovr + livestemn_to_deadstemn(p) = ctovr / deadwdcn(ivt(p)) if( use_matrixcn)then livestemc_to_deadstemc(p) = livestemc(p) * matrix_update_phc(p,ilivestem_to_ideadstem_phc,lwtop,dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) if (livestemn(p) .gt. 0.0_r8) then livestemn_to_deadstemn(p) = livestemn(p) * matrix_update_phn(p,ilivestem_to_ideadstem_phn,livestemn_to_deadstemn(p)/livestemn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else - livestemn_to_deadstemn(p) = 0._r8 + livestemn_to_deadstemn(p) = 0 end if else ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) ! and CNNStateUpdate1::NStateUpdate1 - ctovr = livestemc(p) * lwtop - ntovr = ctovr / livewdcn(ivt(p)) - livestemc_to_deadstemc(p) = ctovr - livestemn_to_deadstemn(p) = ctovr / deadwdcn(ivt(p)) end if - if (CNratio_floating) then + if (CNratio_floating .eqv. .true.) then if (livestemc(p) == 0.0_r8) then ntovr = 0.0_r8 livestemn_to_deadstemn(p) = 0.0_r8 - else + else ntovr = ctovr * (livestemn(p) / livestemc(p)) livestemn_to_deadstemn(p) = ctovr / deadwdcn(ivt(p)) - end if - if (use_matrixcn)then ! Matrix update for livestemn to deadstem + end if + + if (use_matrixcn)then if (livestemn(p) .gt. 0.0_r8) then livestemn_to_deadstemn(p) = livestemn(p) * matrix_update_phn(p,ilivestem_to_ideadstem_phn,& livestemn_to_deadstemn(p) / livestemn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else livestemn_to_deadstemn(p) = 0 end if - end if ! use_matrixcn + else + ! NOTE: The non matrix version of this is in CNNStateUpdate1::NStateUpdate1 EBK (11/26/2019) + end if end if livestemn_to_retransn(p) = ntovr - livestemn_to_deadstemn(p) @@ -3777,19 +3770,17 @@ subroutine CNLivewoodTurnover (num_soilp, filter_soilp, & ctovr = livecrootc(p) * lwtop ntovr = ctovr / livewdcn(ivt(p)) - if(.not. use_matrixcn)then ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) ! and CNNStateUpdate1::NStateUpdate1 livecrootc_to_deadcrootc(p) = ctovr livecrootn_to_deadcrootn(p) = ctovr / deadwdcn(ivt(p)) else - ! Matrix update for livecroot to deadcroot livecrootc_to_deadcrootc(p) = livecrootc(p) * matrix_update_phc(p,ilivecroot_to_ideadcroot_phc,lwtop,dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) livecrootn_to_deadcrootn(p) = livecrootn(p) * matrix_update_phn(p,ilivecroot_to_ideadcroot_phn,lwtop/deadwdcn(ivt(p)),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) end if !use_matrixcn - if (CNratio_floating) then + if (CNratio_floating .eqv. .true.) then if (livecrootc(p) == 0.0_r8) then ntovr = 0.0_r8 livecrootn_to_deadcrootn(p) = 0.0_r8 @@ -3797,50 +3788,49 @@ subroutine CNLivewoodTurnover (num_soilp, filter_soilp, & ntovr = ctovr * (livecrootn(p) / livecrootc(p)) livecrootn_to_deadcrootn(p) = ctovr / deadwdcn(ivt(p)) end if - if (use_matrixcn)then ! Matrix update for livecroot to deadcroot + + if (use_matrixcn)then if (livecrootn(p) .ne.0.0_r8 )then livecrootn_to_deadcrootn(p) = matrix_update_phn(p,ilivecroot_to_ideadcroot_phn,& livecrootn_to_deadcrootn(p) / livecrootn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) * livecrootn(p) end if - end if ! use_matrixcn + else + ! NOTE: The non matrix version of this is in CNNStateUpdate1::NStateUpdate1 EBK (11/26/2019) + end if !use_matrixcn end if livecrootn_to_retransn(p) = ntovr - livecrootn_to_deadcrootn(p) - - ! Matrix update for livecrootn and livestemn to retrans as well as free retransn to npool with FUN - if(use_matrixcn)then - if(livecrootn(p) .gt. 0.0_r8) then - livecrootn_to_retransn(p) = matrix_update_phn(p,ilivecroot_to_iretransn_phn,& - livecrootn_to_retransn(p) / livecrootn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) * livecrootn(p) - else - livecrootn_to_retransn(p) = 0 - end if - if(livestemn(p) .gt. 0.0_r8) then - livestemn_to_retransn(p) = matrix_update_phn(p,ilivestem_to_iretransn_phn,& - livestemn_to_retransn(p) / livestemn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) * livestemn(p) - else - livestemn_to_retransn(p) = 0 - end if - ! WW change logic so livestem_retrans goes to npool (via - ! free_retrans flux) - ! this should likely be done more cleanly if it works, i.e. not - ! update fluxes w/ states - ! additional considerations for crop? - ! The non-matrix version of this is in NStateUpdate1 - if (use_fun) then - if (retransn(p) .gt. 0._r8) then - ! The acc matrix check MUST be turned on, or this will - ! fail with Nitrogen balance error EBK 03/11/2021 - free_retransn_to_npool(p) = free_retransn_to_npool(p) + retransn(p) * matrix_update_phn(p,iretransn_to_iout, & - (livestemn_to_retransn(p) + livecrootn_to_retransn(p)) / retransn(p),dt, & - cnveg_nitrogenflux_inst, matrixcheck_ph, acc=.true.) + if(use_matrixcn)then + if(livecrootn(p) .gt. 0.0_r8) then + livecrootn_to_retransn(p) = matrix_update_phn(p,ilivecroot_to_iretransn_phn,& + livecrootn_to_retransn(p) / livecrootn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) * livecrootn(p) else - free_retransn_to_npool(p) = 0._r8 + livecrootn_to_retransn(p) = 0 end if - end if - else - ! The non-matrix version of this is in NStateUpdate1 - end if !use_matrixcn + if(livestemn(p) .gt. 0.0_r8) then + livestemn_to_retransn(p) = matrix_update_phn(p,ilivestem_to_iretransn_phn,& + livestemn_to_retransn(p) / livestemn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) * livestemn(p) + else + livestemn_to_retransn(p) = 0 + end if + ! WW change logic so livestem_retrans goes to npool (via + ! free_retrans flux) + ! this should likely be done more cleanly if it works, i.e. not + ! update fluxes w/ states + ! additional considerations for crop? + ! The non-matrix version of this is in NStateUpdate1 + if (use_fun) then + if (retransn(p) .gt. 0._r8) then + ! The acc matrix check MUST be turned on, or this will + ! fail with Nitrogen balance error EBK 03/11/2021 + free_retransn_to_npool(p) = free_retransn_to_npool(p) + retransn(p) * matrix_update_phn(p,iretransn_to_iout, & + (livestemn_to_retransn(p) + livecrootn_to_retransn(p)) / retransn(p),dt, & + cnveg_nitrogenflux_inst, matrixcheck_ph, acc=.true.) + else + free_retransn_to_npool(p) = 0._r8 + end if + end if + end if !use_matrixcn end if diff --git a/src/soilbiogeochem/SoilBiogeochemNStateUpdate1Mod.F90 b/src/soilbiogeochem/SoilBiogeochemNStateUpdate1Mod.F90 index d7b3c01fc1..4f221c6910 100644 --- a/src/soilbiogeochem/SoilBiogeochemNStateUpdate1Mod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemNStateUpdate1Mod.F90 @@ -9,11 +9,12 @@ module SoilBiogeochemNStateUpdate1Mod use clm_time_manager , only : get_step_size_real use clm_varpar , only : nlevdecomp, ndecomp_cascade_transitions use clm_varctl , only : iulog, use_nitrif_denitrif, use_crop + use SoilBiogeochemDecompCascadeConType , only : use_soil_matrixcn use clm_varcon , only : nitrif_n2o_loss_frac use SoilBiogeochemStateType , only : soilbiogeochem_state_type use SoilBiogeochemNitrogenStateType , only : soilbiogeochem_nitrogenstate_type use SoilBiogeochemNitrogenfluxType , only : soilbiogeochem_nitrogenflux_type - use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con, use_soil_matrixcn + use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con use CNSharedParamsMod , only : use_fun use ColumnType , only : col ! @@ -118,50 +119,47 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & end if ! decomposition fluxes - if (.not. use_soil_matrixcn) then - do k = 1, ndecomp_cascade_transitions + if (.not. use_soil_matrixcn) then + do k = 1, ndecomp_cascade_transitions + do j = 1, nlevdecomp + ! column loop + do fc = 1,num_soilc + c = filter_soilc(fc) + + nf%decomp_npools_sourcesink_col(c,j,cascade_donor_pool(k)) = & + nf%decomp_npools_sourcesink_col(c,j,cascade_donor_pool(k)) - & + nf%decomp_cascade_ntransfer_vr_col(c,j,k) * dt + end do + end do + end do + + + do k = 1, ndecomp_cascade_transitions + if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions do j = 1, nlevdecomp ! column loop do fc = 1,num_soilc c = filter_soilc(fc) + nf%decomp_npools_sourcesink_col(c,j,cascade_receiver_pool(k)) = & + nf%decomp_npools_sourcesink_col(c,j,cascade_receiver_pool(k)) + & + (nf%decomp_cascade_ntransfer_vr_col(c,j,k) + & + nf%decomp_cascade_sminn_flux_vr_col(c,j,k)) * dt + end do + end do + else ! terminal transitions + do j = 1, nlevdecomp + ! column loop + do fc = 1,num_soilc + c = filter_soilc(fc) nf%decomp_npools_sourcesink_col(c,j,cascade_donor_pool(k)) = & nf%decomp_npools_sourcesink_col(c,j,cascade_donor_pool(k)) - & - nf%decomp_cascade_ntransfer_vr_col(c,j,k) * dt + nf%decomp_cascade_sminn_flux_vr_col(c,j,k) * dt end do end do - end do - - - do k = 1, ndecomp_cascade_transitions - if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions - do j = 1, nlevdecomp - ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) - - nf%decomp_npools_sourcesink_col(c,j,cascade_receiver_pool(k)) = & - nf%decomp_npools_sourcesink_col(c,j,cascade_receiver_pool(k)) + & - (nf%decomp_cascade_ntransfer_vr_col(c,j,k) + & - nf%decomp_cascade_sminn_flux_vr_col(c,j,k)) * dt - end do - end do - else ! terminal transitions - do j = 1, nlevdecomp - ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) - nf%decomp_npools_sourcesink_col(c,j,cascade_donor_pool(k)) = & - nf%decomp_npools_sourcesink_col(c,j,cascade_donor_pool(k)) - & - nf%decomp_cascade_sminn_flux_vr_col(c,j,k) * dt - end do - end do - end if - end do - else - ! Matrix solution equvalent to above is in CNSoilMatrixMod.F90? - ! TODO check on this - end if ! + end if + end do + end if ! if (.not. use_nitrif_denitrif) then From 42af57b7f6584610e5127874f55044fe16da2ccb Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 28 Dec 2023 13:18:15 -0700 Subject: [PATCH 009/444] Matrixcn updates pertaining to GULU (gross unrep. landuse chg) --- src/biogeochem/CNBalanceCheckMod.F90 | 1 - src/biogeochem/CNCStateUpdate2Mod.F90 | 132 ++++++++++------- src/biogeochem/CNNStateUpdate2Mod.F90 | 129 +++++++++------- src/biogeochem/dynGrossUnrepMod.F90 | 205 +++++++++++++++++++------- src/dyn_subgrid/dynHarvestMod.F90 | 19 +-- 5 files changed, 313 insertions(+), 173 deletions(-) diff --git a/src/biogeochem/CNBalanceCheckMod.F90 b/src/biogeochem/CNBalanceCheckMod.F90 index fbf30e9549..5b253fdd00 100644 --- a/src/biogeochem/CNBalanceCheckMod.F90 +++ b/src/biogeochem/CNBalanceCheckMod.F90 @@ -60,7 +60,6 @@ module CNBalanceCheckMod !----------------------------------------------------------------------- subroutine Init(this, bounds) - use CNSharedParamsMod, only : use_matrixcn class(cn_balance_type) :: this type(bounds_type) , intent(in) :: bounds diff --git a/src/biogeochem/CNCStateUpdate2Mod.F90 b/src/biogeochem/CNCStateUpdate2Mod.F90 index 76fcc340b6..2890c7d1fd 100644 --- a/src/biogeochem/CNCStateUpdate2Mod.F90 +++ b/src/biogeochem/CNCStateUpdate2Mod.F90 @@ -370,15 +370,27 @@ subroutine CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & do fc = 1,num_soilc c = filter_soilc(fc) - ! column gross unrepresented landcover change fluxes - do i = i_litr_min, i_litr_max - cs_soil%decomp_cpools_vr_col(c,j,i) = & - cs_soil%decomp_cpools_vr_col(c,j,i) + cf_veg%gru_c_to_litr_c_col(c,j,i) * dt - end do - cs_soil%decomp_cpools_vr_col(c,j,i_cwd) = & - cs_soil%decomp_cpools_vr_col(c,j,i_cwd) + cf_veg%gru_c_to_cwdc_col(c,j) * dt + if (.not. use_soil_matrixcn)then + ! column gross unrepresented landcover change fluxes + do i = i_litr_min, i_litr_max + cs_soil%decomp_cpools_vr_col(c,j,i) = & + cs_soil%decomp_cpools_vr_col(c,j,i) + cf_veg%gru_c_to_litr_c_col(c,j,i) * dt + end do + cs_soil%decomp_cpools_vr_col(c,j,i_cwd) = & + cs_soil%decomp_cpools_vr_col(c,j,i_cwd) + cf_veg%gru_c_to_cwdc_col(c,j) * dt - ! wood to product pools - states updated in CNProducts + ! wood to product pools - states updated in CNProducts + else + ! Match above for soil-matrix + do i = i_litr_min, i_litr_max + cf_soil%matrix_Cinput%V(c,j+(i-1)*nlevdecomp) = & + cf_soil%matrix_Cinput%V(c,j+(i-1)*nlevdecomp) + cf_veg%gru_c_to_litr_c_col(c,j,i) * dt + end do + ! Currently i_cwd .ne. i_litr_max + 1 if .not. fates and + ! i_cwd = 0 if fates, so not including in the i-loop + cf_soil%matrix_Cinput%V(c,j+(i_cwd-1)*nlevdecomp) = & + cf_soil%matrix_Cinput%V(c,j+(i_cwd-1)*nlevdecomp) + cf_veg%gru_c_to_cwdc_col(c,j) * dt + end if !soil_matrix end do end do @@ -387,58 +399,66 @@ subroutine CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & p = filter_soilp(fp) ! patch-level carbon fluxes from gross unrepresented landcover change mortality - ! displayed pools - cs_veg%leafc_patch(p) = cs_veg%leafc_patch(p) & - - cf_veg%gru_leafc_to_litter_patch(p) * dt - cs_veg%frootc_patch(p) = cs_veg%frootc_patch(p) & - - cf_veg%gru_frootc_to_litter_patch(p) * dt - cs_veg%livestemc_patch(p) = cs_veg%livestemc_patch(p) & - - cf_veg%gru_livestemc_to_atm_patch(p) * dt - cs_veg%deadstemc_patch(p) = cs_veg%deadstemc_patch(p) & - - cf_veg%gru_deadstemc_to_atm_patch(p) * dt - cs_veg%deadstemc_patch(p) = cs_veg%deadstemc_patch(p) & - - cf_veg%gru_wood_productc_gain_patch(p) * dt - cs_veg%livecrootc_patch(p) = cs_veg%livecrootc_patch(p) & - - cf_veg%gru_livecrootc_to_litter_patch(p) * dt - cs_veg%deadcrootc_patch(p) = cs_veg%deadcrootc_patch(p) & - - cf_veg%gru_deadcrootc_to_litter_patch(p) * dt + ! + ! State update without the matrix solution + ! + if(.not. use_matrixcn)then + ! displayed pools + cs_veg%leafc_patch(p) = cs_veg%leafc_patch(p) & + - cf_veg%gru_leafc_to_litter_patch(p) * dt + cs_veg%frootc_patch(p) = cs_veg%frootc_patch(p) & + - cf_veg%gru_frootc_to_litter_patch(p) * dt + cs_veg%livestemc_patch(p) = cs_veg%livestemc_patch(p) & + - cf_veg%gru_livestemc_to_atm_patch(p) * dt + cs_veg%deadstemc_patch(p) = cs_veg%deadstemc_patch(p) & + - cf_veg%gru_deadstemc_to_atm_patch(p) * dt + cs_veg%deadstemc_patch(p) = cs_veg%deadstemc_patch(p) & + - cf_veg%gru_wood_productc_gain_patch(p) * dt + cs_veg%livecrootc_patch(p) = cs_veg%livecrootc_patch(p) & + - cf_veg%gru_livecrootc_to_litter_patch(p) * dt + cs_veg%deadcrootc_patch(p) = cs_veg%deadcrootc_patch(p) & + - cf_veg%gru_deadcrootc_to_litter_patch(p) * dt - ! xsmrpool - cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) & - - cf_veg%gru_xsmrpool_to_atm_patch(p) * dt + ! xsmrpool + cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) & + - cf_veg%gru_xsmrpool_to_atm_patch(p) * dt - ! storage pools - cs_veg%leafc_storage_patch(p) = cs_veg%leafc_storage_patch(p) & - - cf_veg%gru_leafc_storage_to_atm_patch(p) * dt - cs_veg%frootc_storage_patch(p) = cs_veg%frootc_storage_patch(p) & - - cf_veg%gru_frootc_storage_to_atm_patch(p) * dt - cs_veg%livestemc_storage_patch(p) = cs_veg%livestemc_storage_patch(p) & - - cf_veg%gru_livestemc_storage_to_atm_patch(p) * dt - cs_veg%deadstemc_storage_patch(p) = cs_veg%deadstemc_storage_patch(p) & - - cf_veg%gru_deadstemc_storage_to_atm_patch(p) * dt - cs_veg%livecrootc_storage_patch(p) = cs_veg%livecrootc_storage_patch(p) & - - cf_veg%gru_livecrootc_storage_to_atm_patch(p) * dt - cs_veg%deadcrootc_storage_patch(p) = cs_veg%deadcrootc_storage_patch(p) & - - cf_veg%gru_deadcrootc_storage_to_atm_patch(p) * dt - cs_veg%gresp_storage_patch(p) = cs_veg%gresp_storage_patch(p) & - - cf_veg%gru_gresp_storage_to_atm_patch(p) * dt + ! storage pools + cs_veg%leafc_storage_patch(p) = cs_veg%leafc_storage_patch(p) & + - cf_veg%gru_leafc_storage_to_atm_patch(p) * dt + cs_veg%frootc_storage_patch(p) = cs_veg%frootc_storage_patch(p) & + - cf_veg%gru_frootc_storage_to_atm_patch(p) * dt + cs_veg%livestemc_storage_patch(p) = cs_veg%livestemc_storage_patch(p) & + - cf_veg%gru_livestemc_storage_to_atm_patch(p) * dt + cs_veg%deadstemc_storage_patch(p) = cs_veg%deadstemc_storage_patch(p) & + - cf_veg%gru_deadstemc_storage_to_atm_patch(p) * dt + cs_veg%livecrootc_storage_patch(p) = cs_veg%livecrootc_storage_patch(p) & + - cf_veg%gru_livecrootc_storage_to_atm_patch(p) * dt + cs_veg%deadcrootc_storage_patch(p) = cs_veg%deadcrootc_storage_patch(p) & + - cf_veg%gru_deadcrootc_storage_to_atm_patch(p) * dt + cs_veg%gresp_storage_patch(p) = cs_veg%gresp_storage_patch(p) & + - cf_veg%gru_gresp_storage_to_atm_patch(p) * dt - ! transfer pools - cs_veg%leafc_xfer_patch(p) = cs_veg%leafc_xfer_patch(p) & - - cf_veg%gru_leafc_xfer_to_atm_patch(p) * dt - cs_veg%frootc_xfer_patch(p) = cs_veg%frootc_xfer_patch(p) & - - cf_veg%gru_frootc_xfer_to_atm_patch(p) * dt - cs_veg%livestemc_xfer_patch(p) = cs_veg%livestemc_xfer_patch(p) & - - cf_veg%gru_livestemc_xfer_to_atm_patch(p) * dt - cs_veg%deadstemc_xfer_patch(p) = cs_veg%deadstemc_xfer_patch(p) & - - cf_veg%gru_deadstemc_xfer_to_atm_patch(p) * dt - cs_veg%livecrootc_xfer_patch(p) = cs_veg%livecrootc_xfer_patch(p) & - - cf_veg%gru_livecrootc_xfer_to_atm_patch(p) * dt - cs_veg%deadcrootc_xfer_patch(p) = cs_veg%deadcrootc_xfer_patch(p) & - - cf_veg%gru_deadcrootc_xfer_to_atm_patch(p) * dt - cs_veg%gresp_xfer_patch(p) = cs_veg%gresp_xfer_patch(p) & - - cf_veg%gru_gresp_xfer_to_atm_patch(p) * dt + ! transfer pools + cs_veg%leafc_xfer_patch(p) = cs_veg%leafc_xfer_patch(p) & + - cf_veg%gru_leafc_xfer_to_atm_patch(p) * dt + cs_veg%frootc_xfer_patch(p) = cs_veg%frootc_xfer_patch(p) & + - cf_veg%gru_frootc_xfer_to_atm_patch(p) * dt + cs_veg%livestemc_xfer_patch(p) = cs_veg%livestemc_xfer_patch(p) & + - cf_veg%gru_livestemc_xfer_to_atm_patch(p) * dt + cs_veg%deadstemc_xfer_patch(p) = cs_veg%deadstemc_xfer_patch(p) & + - cf_veg%gru_deadstemc_xfer_to_atm_patch(p) * dt + cs_veg%livecrootc_xfer_patch(p) = cs_veg%livecrootc_xfer_patch(p) & + - cf_veg%gru_livecrootc_xfer_to_atm_patch(p) * dt + cs_veg%deadcrootc_xfer_patch(p) = cs_veg%deadcrootc_xfer_patch(p) & + - cf_veg%gru_deadcrootc_xfer_to_atm_patch(p) * dt + cs_veg%gresp_xfer_patch(p) = cs_veg%gresp_xfer_patch(p) & + - cf_veg%gru_gresp_xfer_to_atm_patch(p) * dt + else + ! NB (slevis) The matrix equivalent of the above is in + ! dynGrossUnrepMod::CNGrossUnrep* + end if end do ! end of patch loop end associate diff --git a/src/biogeochem/CNNStateUpdate2Mod.F90 b/src/biogeochem/CNNStateUpdate2Mod.F90 index 2702b80de5..2dbba68b82 100644 --- a/src/biogeochem/CNNStateUpdate2Mod.F90 +++ b/src/biogeochem/CNNStateUpdate2Mod.F90 @@ -358,14 +358,29 @@ subroutine NStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & do j = 1,nlevdecomp do fc = 1,num_soilc c = filter_soilc(fc) - do i = i_litr_min, i_litr_max - ns_soil%decomp_npools_vr_col(c,j,i) = & - ns_soil%decomp_npools_vr_col(c,j,i) + nf_veg%gru_n_to_litr_n_col(c,j,i) * dt - end do - ! Currently i_cwd .ne. i_litr_max + 1 if .not. fates and - ! i_cwd = 0 if fates, so not including in the i-loop - ns_soil%decomp_npools_vr_col(c,j,i_cwd) = & - ns_soil%decomp_npools_vr_col(c,j,i_cwd) + nf_veg%gru_n_to_cwdn_col(c,j) * dt + ! + ! State update without the matrix solution + ! + if (.not. use_soil_matrixcn)then + do i = i_litr_min, i_litr_max + ns_soil%decomp_npools_vr_col(c,j,i) = & + ns_soil%decomp_npools_vr_col(c,j,i) + nf_veg%gru_n_to_litr_n_col(c,j,i) * dt + end do + ! Currently i_cwd .ne. i_litr_max + 1 if .not. fates and + ! i_cwd = 0 if fates, so not including in the i-loop + ns_soil%decomp_npools_vr_col(c,j,i_cwd) = & + ns_soil%decomp_npools_vr_col(c,j,i_cwd) + nf_veg%gru_n_to_cwdn_col(c,j) * dt + else + ! Do above for the matrix solution + do i = i_litr_min, i_litr_max + nf_soil%matrix_Ninput%V(c,j+(i-1)*nlevdecomp) = & + nf_soil%matrix_Ninput%V(c,j+(i-1)*nlevdecomp) + nf_veg%gru_n_to_litr_n_col(c,j,i) * dt + end do + ! Currently i_cwd .ne. i_litr_max + 1 if .not. fates and + ! i_cwd = 0 if fates, so not including in the i-loop + nf_soil%matrix_Ninput%V(c,j+(i_cwd-1)*nlevdecomp) = & + nf_soil%matrix_Ninput%V(c,j+(i_cwd-1)*nlevdecomp) + nf_veg%gru_n_to_cwdn_col(c,j) * dt + end if !not use_soil_matrixcn end do end do @@ -374,51 +389,59 @@ subroutine NStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & do fp = 1,num_soilp p = filter_soilp(fp) - ! displayed pools - ns_veg%leafn_patch(p) = ns_veg%leafn_patch(p) & - - nf_veg%gru_leafn_to_litter_patch(p) * dt - ns_veg%frootn_patch(p) = ns_veg%frootn_patch(p) & - - nf_veg%gru_frootn_to_litter_patch(p) * dt - ns_veg%livestemn_patch(p) = ns_veg%livestemn_patch(p) & - - nf_veg%gru_livestemn_to_atm_patch(p) * dt - ns_veg%deadstemn_patch(p) = ns_veg%deadstemn_patch(p) & - - nf_veg%gru_deadstemn_to_atm_patch(p) * dt - ns_veg%deadstemn_patch(p) = ns_veg%deadstemn_patch(p) & - - nf_veg%gru_wood_productn_gain_patch(p) * dt - ns_veg%livecrootn_patch(p) = ns_veg%livecrootn_patch(p) & - - nf_veg%gru_livecrootn_to_litter_patch(p) * dt - ns_veg%deadcrootn_patch(p) = ns_veg%deadcrootn_patch(p) & - - nf_veg%gru_deadcrootn_to_litter_patch(p) * dt - ns_veg%retransn_patch(p) = ns_veg%retransn_patch(p) & - - nf_veg%gru_retransn_to_litter_patch(p) * dt - - ! storage pools - ns_veg%leafn_storage_patch(p) = ns_veg%leafn_storage_patch(p) & - - nf_veg%gru_leafn_storage_to_atm_patch(p) * dt - ns_veg%frootn_storage_patch(p) = ns_veg%frootn_storage_patch(p) & - - nf_veg%gru_frootn_storage_to_atm_patch(p) * dt - ns_veg%livestemn_storage_patch(p) = ns_veg%livestemn_storage_patch(p) & - - nf_veg%gru_livestemn_storage_to_atm_patch(p) * dt - ns_veg%deadstemn_storage_patch(p) = ns_veg%deadstemn_storage_patch(p) & - - nf_veg%gru_deadstemn_storage_to_atm_patch(p) * dt - ns_veg%livecrootn_storage_patch(p) = ns_veg%livecrootn_storage_patch(p) & - - nf_veg%gru_livecrootn_storage_to_atm_patch(p) * dt - ns_veg%deadcrootn_storage_patch(p) = ns_veg%deadcrootn_storage_patch(p) & - - nf_veg%gru_deadcrootn_storage_to_atm_patch(p) * dt - - ! transfer pools - ns_veg%leafn_xfer_patch(p) = ns_veg%leafn_xfer_patch(p) & - - nf_veg%gru_leafn_xfer_to_atm_patch(p) *dt - ns_veg%frootn_xfer_patch(p) = ns_veg%frootn_xfer_patch(p) & - - nf_veg%gru_frootn_xfer_to_atm_patch(p) *dt - ns_veg%livestemn_xfer_patch(p) = ns_veg%livestemn_xfer_patch(p) & - - nf_veg%gru_livestemn_xfer_to_atm_patch(p) *dt - ns_veg%deadstemn_xfer_patch(p) = ns_veg%deadstemn_xfer_patch(p) & - - nf_veg%gru_deadstemn_xfer_to_atm_patch(p) *dt - ns_veg%livecrootn_xfer_patch(p) = ns_veg%livecrootn_xfer_patch(p) & - - nf_veg%gru_livecrootn_xfer_to_atm_patch(p) *dt - ns_veg%deadcrootn_xfer_patch(p) = ns_veg%deadcrootn_xfer_patch(p) & - - nf_veg%gru_deadcrootn_xfer_to_atm_patch(p) *dt + ! + ! State update without the matrix solution + ! + if(.not. use_matrixcn)then + ! displayed pools + ns_veg%leafn_patch(p) = ns_veg%leafn_patch(p) & + - nf_veg%gru_leafn_to_litter_patch(p) * dt + ns_veg%frootn_patch(p) = ns_veg%frootn_patch(p) & + - nf_veg%gru_frootn_to_litter_patch(p) * dt + ns_veg%livestemn_patch(p) = ns_veg%livestemn_patch(p) & + - nf_veg%gru_livestemn_to_atm_patch(p) * dt + ns_veg%deadstemn_patch(p) = ns_veg%deadstemn_patch(p) & + - nf_veg%gru_deadstemn_to_atm_patch(p) * dt + ns_veg%deadstemn_patch(p) = ns_veg%deadstemn_patch(p) & + - nf_veg%gru_wood_productn_gain_patch(p) * dt + ns_veg%livecrootn_patch(p) = ns_veg%livecrootn_patch(p) & + - nf_veg%gru_livecrootn_to_litter_patch(p) * dt + ns_veg%deadcrootn_patch(p) = ns_veg%deadcrootn_patch(p) & + - nf_veg%gru_deadcrootn_to_litter_patch(p) * dt + ns_veg%retransn_patch(p) = ns_veg%retransn_patch(p) & + - nf_veg%gru_retransn_to_litter_patch(p) * dt + + ! storage pools + ns_veg%leafn_storage_patch(p) = ns_veg%leafn_storage_patch(p) & + - nf_veg%gru_leafn_storage_to_atm_patch(p) * dt + ns_veg%frootn_storage_patch(p) = ns_veg%frootn_storage_patch(p) & + - nf_veg%gru_frootn_storage_to_atm_patch(p) * dt + ns_veg%livestemn_storage_patch(p) = ns_veg%livestemn_storage_patch(p) & + - nf_veg%gru_livestemn_storage_to_atm_patch(p) * dt + ns_veg%deadstemn_storage_patch(p) = ns_veg%deadstemn_storage_patch(p) & + - nf_veg%gru_deadstemn_storage_to_atm_patch(p) * dt + ns_veg%livecrootn_storage_patch(p) = ns_veg%livecrootn_storage_patch(p) & + - nf_veg%gru_livecrootn_storage_to_atm_patch(p) * dt + ns_veg%deadcrootn_storage_patch(p) = ns_veg%deadcrootn_storage_patch(p) & + - nf_veg%gru_deadcrootn_storage_to_atm_patch(p) * dt + + ! transfer pools + ns_veg%leafn_xfer_patch(p) = ns_veg%leafn_xfer_patch(p) & + - nf_veg%gru_leafn_xfer_to_atm_patch(p) *dt + ns_veg%frootn_xfer_patch(p) = ns_veg%frootn_xfer_patch(p) & + - nf_veg%gru_frootn_xfer_to_atm_patch(p) *dt + ns_veg%livestemn_xfer_patch(p) = ns_veg%livestemn_xfer_patch(p) & + - nf_veg%gru_livestemn_xfer_to_atm_patch(p) *dt + ns_veg%deadstemn_xfer_patch(p) = ns_veg%deadstemn_xfer_patch(p) & + - nf_veg%gru_deadstemn_xfer_to_atm_patch(p) *dt + ns_veg%livecrootn_xfer_patch(p) = ns_veg%livecrootn_xfer_patch(p) & + - nf_veg%gru_livecrootn_xfer_to_atm_patch(p) *dt + ns_veg%deadcrootn_xfer_patch(p) = ns_veg%deadcrootn_xfer_patch(p) & + - nf_veg%gru_deadcrootn_xfer_to_atm_patch(p) *dt + else + ! NB (slevis) The equivalent changes for matrix code are in + ! dynGrossUnrepMod::CNGrossUnrep* + end if !not use_matrixcn end do diff --git a/src/biogeochem/dynGrossUnrepMod.F90 b/src/biogeochem/dynGrossUnrepMod.F90 index bc49e72f4c..b354744b61 100644 --- a/src/biogeochem/dynGrossUnrepMod.F90 +++ b/src/biogeochem/dynGrossUnrepMod.F90 @@ -24,6 +24,7 @@ module dynGrossUnrepMod use clm_varpar , only : natpft_size, i_litr_min, i_litr_max, i_met_lit use ColumnType , only : col use PatchType , only : patch + use CNSharedParamsMod , only : use_matrixcn ! ! !PUBLIC MEMBER FUNCTIONS: implicit none @@ -296,61 +297,157 @@ subroutine CNGrossUnrep (num_soilc, filter_soilc, num_soilp, filter_soilp, & m = 0._r8 end if - ! patch-level gross unrepresented landcover change carbon fluxes - ! displayed pools - gru_leafc_to_litter(p) = leafc(p) * m - gru_frootc_to_litter(p) = frootc(p) * m - gru_livestemc_to_atm(p) = livestemc(p) * m - gru_deadstemc_to_atm(p) = deadstemc(p) * m * convfrac(ivt(p)) - gru_wood_productc_gain(p) = deadstemc(p) * m * (1._r8 - convfrac(ivt(p))) - gru_livecrootc_to_litter(p) = livecrootc(p) * m - gru_deadcrootc_to_litter(p) = deadcrootc(p) * m - gru_xsmrpool_to_atm(p) = xsmrpool(p) * m - - ! storage pools - gru_leafc_storage_to_atm(p) = leafc_storage(p) * m - gru_frootc_storage_to_atm(p) = frootc_storage(p) * m - gru_livestemc_storage_to_atm(p) = livestemc_storage(p) * m - gru_deadstemc_storage_to_atm(p) = deadstemc_storage(p) * m - gru_livecrootc_storage_to_atm(p) = livecrootc_storage(p) * m - gru_deadcrootc_storage_to_atm(p) = deadcrootc_storage(p) * m - gru_gresp_storage_to_atm(p) = gresp_storage(p) * m - - ! transfer pools - gru_leafc_xfer_to_atm(p) = leafc_xfer(p) * m - gru_frootc_xfer_to_atm(p) = frootc_xfer(p) * m - gru_livestemc_xfer_to_atm(p) = livestemc_xfer(p) * m - gru_deadstemc_xfer_to_atm(p) = deadstemc_xfer(p) * m - gru_livecrootc_xfer_to_atm(p) = livecrootc_xfer(p) * m - gru_deadcrootc_xfer_to_atm(p) = deadcrootc_xfer(p) * m - gru_gresp_xfer_to_atm(p) = gresp_xfer(p) * m + if(.not. use_matrixcn)then + ! patch-level gross unrepresented landcover change carbon fluxes + ! displayed pools + gru_leafc_to_litter(p) = leafc(p) * m + gru_frootc_to_litter(p) = frootc(p) * m + gru_livestemc_to_atm(p) = livestemc(p) * m + gru_deadstemc_to_atm(p) = deadstemc(p) * m * convfrac(ivt(p)) + gru_wood_productc_gain(p) = deadstemc(p) * m * (1._r8 - convfrac(ivt(p))) + gru_livecrootc_to_litter(p) = livecrootc(p) * m + gru_deadcrootc_to_litter(p) = deadcrootc(p) * m + gru_xsmrpool_to_atm(p) = xsmrpool(p) * m + + ! storage pools + gru_leafc_storage_to_atm(p) = leafc_storage(p) * m + gru_frootc_storage_to_atm(p) = frootc_storage(p) * m + gru_livestemc_storage_to_atm(p) = livestemc_storage(p) * m + gru_deadstemc_storage_to_atm(p) = deadstemc_storage(p) * m + gru_livecrootc_storage_to_atm(p) = livecrootc_storage(p) * m + gru_deadcrootc_storage_to_atm(p) = deadcrootc_storage(p) * m + gru_gresp_storage_to_atm(p) = gresp_storage(p) * m + + ! transfer pools + gru_leafc_xfer_to_atm(p) = leafc_xfer(p) * m + gru_frootc_xfer_to_atm(p) = frootc_xfer(p) * m + gru_livestemc_xfer_to_atm(p) = livestemc_xfer(p) * m + gru_deadstemc_xfer_to_atm(p) = deadstemc_xfer(p) * m + gru_livecrootc_xfer_to_atm(p) = livecrootc_xfer(p) * m + gru_deadcrootc_xfer_to_atm(p) = deadcrootc_xfer(p) * m + gru_gresp_xfer_to_atm(p) = gresp_xfer(p) * m - ! patch-level gross unrepresented landcover change mortality nitrogen fluxes - ! displayed pools - gru_leafn_to_litter(p) = leafn(p) * m - gru_frootn_to_litter(p) = frootn(p) * m - gru_livestemn_to_atm(p) = livestemn(p) * m - gru_deadstemn_to_atm(p) = deadstemn(p) * m * convfrac(ivt(p)) - gru_wood_productn_gain(p) = deadstemn(p) * m * (1._r8 - convfrac(ivt(p))) - gru_livecrootn_to_litter(p) = livecrootn(p) * m - gru_deadcrootn_to_litter(p) = deadcrootn(p) * m - gru_retransn_to_litter(p) = retransn(p) * m - - ! storage pools - gru_leafn_storage_to_atm(p) = leafn_storage(p) * m - gru_frootn_storage_to_atm(p) = frootn_storage(p) * m - gru_livestemn_storage_to_atm(p) = livestemn_storage(p) * m - gru_deadstemn_storage_to_atm(p) = deadstemn_storage(p) * m - gru_livecrootn_storage_to_atm(p) = livecrootn_storage(p) * m - gru_deadcrootn_storage_to_atm(p) = deadcrootn_storage(p) * m - - ! transfer pools - gru_leafn_xfer_to_atm(p) = leafn_xfer(p) * m - gru_frootn_xfer_to_atm(p) = frootn_xfer(p) * m - gru_livestemn_xfer_to_atm(p) = livestemn_xfer(p) * m - gru_deadstemn_xfer_to_atm(p) = deadstemn_xfer(p) * m - gru_livecrootn_xfer_to_atm(p) = livecrootn_xfer(p) * m - gru_deadcrootn_xfer_to_atm(p) = deadcrootn_xfer(p) * m + ! patch-level gross unrepresented landcover change mortality nitrogen fluxes + ! displayed pools + gru_leafn_to_litter(p) = leafn(p) * m + gru_frootn_to_litter(p) = frootn(p) * m + gru_livestemn_to_atm(p) = livestemn(p) * m + gru_deadstemn_to_atm(p) = deadstemn(p) * m * convfrac(ivt(p)) + gru_wood_productn_gain(p) = deadstemn(p) * m * (1._r8 - convfrac(ivt(p))) + gru_livecrootn_to_litter(p) = livecrootn(p) * m + gru_deadcrootn_to_litter(p) = deadcrootn(p) * m + gru_retransn_to_litter(p) = retransn(p) * m + + ! storage pools + gru_leafn_storage_to_atm(p) = leafn_storage(p) * m + gru_frootn_storage_to_atm(p) = frootn_storage(p) * m + gru_livestemn_storage_to_atm(p) = livestemn_storage(p) * m + gru_deadstemn_storage_to_atm(p) = deadstemn_storage(p) * m + gru_livecrootn_storage_to_atm(p) = livecrootn_storage(p) * m + gru_deadcrootn_storage_to_atm(p) = deadcrootn_storage(p) * m + + ! transfer pools + gru_leafn_xfer_to_atm(p) = leafn_xfer(p) * m + gru_frootn_xfer_to_atm(p) = frootn_xfer(p) * m + gru_livestemn_xfer_to_atm(p) = livestemn_xfer(p) * m + gru_deadstemn_xfer_to_atm(p) = deadstemn_xfer(p) * m + gru_livecrootn_xfer_to_atm(p) = livecrootn_xfer(p) * m + gru_deadcrootn_xfer_to_atm(p) = deadcrootn_xfer(p) * m + else ! matrixcn solution + ! patch-level gross unrepresented landcover change carbon fluxes + ! displayed pools + gru_leafc_to_litter(p) = matrix_update_gmc(p,ileaf_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + leafc(p) + gru_frootc_to_litter(p) = matrix_update_gmc(p,ifroot_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + frootc(p) + gru_livestemc_to_atm(p) = matrix_update_gmc(p,ilivestem_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + livestemc(p) + gru_deadstemc_to_atm(p) = matrix_update_gmc(p,ideadstem_to_iout_gmc,m * convfrac(ivt(p)),dtime,cnveg_carbonflux_inst,.True.,.True.) * & + deadstemc(p) + gru_wood_productc_gain(p) = matrix_update_gmc(p,ideadstem_to_iout_gmc,m * (1._r8 - convfrac(ivt(p))),dtime,cnveg_carbonflux_inst,.True.,.True.) * & + deadstemc(p) + gru_livecrootc_to_litter(p) = matrix_update_gmc(p,ilivecroot_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + livecrootc(p) + gru_deadcrootc_to_litter(p) = matrix_update_gmc(p,ideadcroot_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + deadcrootc(p) + gru_xsmrpool_to_atm(p) = xsmrpool(p) * m + + ! storage pools + gru_leafc_storage_to_atm(p) = matrix_update_gmc(p,ileafst_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + leafc_storage(p) + gru_frootc_storage_to_atm(p) = matrix_update_gmc(p,ifrootst_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + frootc_storage(p) + gru_livestemc_storage_to_atm(p) = matrix_update_gmc(p,ilivestemst_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + livestemc_storage(p) + gru_deadstemc_storage_to_atm(p) = matrix_update_gmc(p,ideadstemst_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + deadstemc_storage(p) + gru_livecrootc_storage_to_atm(p) = matrix_update_gmc(p,ilivecrootst_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + livecrootc_storage(p) + gru_deadcrootc_storage_to_atm(p) = matrix_update_gmc(p,ideadcrootst_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + deadcrootc_storage(p) + gru_gresp_storage_to_atm(p) = gresp_storage(p) * m + + ! transfer pools + gru_leafc_xfer_to_atm(p) = matrix_update_gmc(p,ileafxf_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + leafc_xfer(p) + gru_frootc_xfer_to_atm(p) = matrix_update_gmc(p,ifrootxf_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + frootc_xfer(p) + gru_livestemc_xfer_to_atm(p) = matrix_update_gmc(p,ilivestemxf_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + livestemc_xfer(p) + gru_deadstemc_xfer_to_atm(p) = matrix_update_gmc(p,ideadstemxf_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + deadstemc_xfer(p) + gru_livecrootc_xfer_to_atm(p) = matrix_update_gmc(p,ilivecrootxf_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + livecrootc_xfer(p) + gru_deadcrootc_xfer_to_atm(p) = matrix_update_gmc(p,ideadcrootxf_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & + deadcrootc_xfer(p) + gru_gresp_xfer_to_atm(p) = gresp_xfer(p) * m + + ! patch-level gross unrepresented landcover change mortality nitrogen fluxes + ! displayed pools + gru_leafn_to_litter(p) = matrix_update_gmn(p,ileaf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + leafn(p) + gru_frootn_to_litter(p) = matrix_update_gmn(p,ifroot_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + frootn(p) + gru_livestemn_to_atm(p) = matrix_update_gmn(p,ilivestem_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + livestemn(p) + gru_deadstemn_to_atm(p) = matrix_update_gmn(p,ideadstem_to_iout_gmn,m * convfrac(ivt(p)),dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + deadstemn(p) + gru_wood_productn_gain(p) = matrix_update_gmn(p,ideadstem_to_iout_gmn,m * (1._r8 - convfrac(ivt(p))),dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + deadstemn(p) + gru_livecrootn_to_litter(p) = matrix_update_gmn(p,ilivecroot_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + livecrootn(p) + gru_deadcrootn_to_litter(p) = matrix_update_gmn(p,ideadcroot_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + deadcrootn(p) + gru_retransn_to_litter(p) = matrix_update_gmn(p,iretransn_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + retransn(p) + + ! storage pools + gru_leafn_storage_to_atm(p) = matrix_update_gmn(p,ileafst_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + leafn_storage(p) + gru_frootn_storage_to_atm(p) = matrix_update_gmn(p,ifrootst_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + frootn_storage(p) + gru_livestemn_storage_to_atm(p) = matrix_update_gmn(p,ilivestemst_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + livestemn_storage(p) + gru_deadstemn_storage_to_atm(p) = matrix_update_gmn(p,ideadstemst_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + deadstemn_storage(p) + gru_livecrootn_storage_to_atm(p) = matrix_update_gmn(p,ilivecrootst_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.)* & + livecrootn_storage(p) + gru_deadcrootn_storage_to_atm(p) = matrix_update_gmn(p,ideadcrootst_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.)* & + deadcrootn_storage(p) + ! transfer pools + gru_leafn_xfer_to_atm(p) = matrix_update_gmn(p,ileafxf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + leafn_xfer(p) + gru_frootn_xfer_to_atm(p) = matrix_update_gmn(p,ifrootxf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + frootn_xfer(p) + gru_livestemn_xfer_to_atm(p) = matrix_update_gmn(p,ilivestemxf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + livestemn_xfer(p) + gru_deadstemn_xfer_to_atm(p) = matrix_update_gmn(p,ideadstemxf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + deadstemn_xfer(p) + gru_livecrootn_xfer_to_atm(p) = matrix_update_gmn(p,ilivecrootxf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + livecrootn_xfer(p) + gru_deadcrootn_xfer_to_atm(p) = matrix_update_gmn(p,ideadcrootxf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & + deadcrootn_xfer(p) + end if end if ! end tree block diff --git a/src/dyn_subgrid/dynHarvestMod.F90 b/src/dyn_subgrid/dynHarvestMod.F90 index b662d67d73..609ba6679b 100644 --- a/src/dyn_subgrid/dynHarvestMod.F90 +++ b/src/dyn_subgrid/dynHarvestMod.F90 @@ -434,9 +434,9 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & m = 0._r8 end if - ! patch-level harvest carbon fluxes - ! displayed pools if(.not. use_matrixcn)then + ! patch-level harvest carbon fluxes + ! displayed pools hrv_leafc_to_litter(p) = leafc(p) * m hrv_frootc_to_litter(p) = frootc(p) * m hrv_livestemc_to_litter(p) = livestemc(p) * m @@ -492,6 +492,8 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & ! NOTE: The non-matrix part of this update is in CNCStatUpdate2 CStateUpdate2h (EBK 11/25/2019) ! and for Nitrogen The non-matrix part of this update is in CNNStatUpdate2 NStateUpdate2h (EBK 11/25/2019) else + ! patch-level harvest carbon fluxes + ! displayed pools hrv_leafc_to_litter(p) = matrix_update_gmc(p,ileaf_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & leafc(p) hrv_frootc_to_litter(p) = matrix_update_gmc(p,ifroot_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & @@ -506,7 +508,7 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & deadcrootc(p) hrv_xsmrpool_to_atm(p) = xsmrpool(p) * m - ! storage pools + ! storage pools hrv_leafc_storage_to_litter(p) = matrix_update_gmc(p,ileafst_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & leafc_storage(p) hrv_frootc_storage_to_litter(p) = matrix_update_gmc(p,ifrootst_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & @@ -521,8 +523,7 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & deadcrootc_storage(p) hrv_gresp_storage_to_litter(p) = gresp_storage(p) * m - - ! transfer pools + ! transfer pools hrv_leafc_xfer_to_litter(p) = matrix_update_gmc(p,ileafxf_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & leafc_xfer(p) hrv_frootc_xfer_to_litter(p) = matrix_update_gmc(p,ifrootxf_to_iout_gmc,m,dtime,cnveg_carbonflux_inst,.True.,.True.) * & @@ -537,6 +538,8 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & deadcrootc_xfer(p) hrv_gresp_xfer_to_litter(p) = gresp_xfer(p) * m + ! patch-level harvest mortality nitrogen fluxes + ! displayed pools hrv_leafn_to_litter(p) = matrix_update_gmn(p,ileaf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & leafn(p) hrv_frootn_to_litter(p) = matrix_update_gmn(p,ifroot_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & @@ -552,7 +555,7 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & hrv_retransn_to_litter(p) = matrix_update_gmn(p,iretransn_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & retransn(p) - ! storage pools + ! storage pools hrv_leafn_storage_to_litter(p) = matrix_update_gmn(p,ileafst_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) *& leafn_storage(p) hrv_frootn_storage_to_litter(p) = matrix_update_gmn(p,ifrootst_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) *& @@ -565,7 +568,7 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & livecrootn_storage(p) hrv_deadcrootn_storage_to_litter(p) = matrix_update_gmn(p,ideadcrootst_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.)*& deadcrootn_storage(p) - ! transfer pools + ! transfer pools hrv_leafn_xfer_to_litter(p) = matrix_update_gmn(p,ileafxf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & leafn_xfer(p) hrv_frootn_xfer_to_litter(p) = matrix_update_gmn(p,ifrootxf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & @@ -578,9 +581,7 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & livecrootn_xfer(p) hrv_deadcrootn_xfer_to_litter(p) = matrix_update_gmn(p,ideadcrootxf_to_iout_gmn,m,dtime,cnveg_nitrogenflux_inst,.True.,.True.) * & deadcrootn_xfer(p) - end if - end if ! end tree block end do ! end of pft loop From 57aa176ae3f28dbea9a9a20c3953fe4c6c1bae12 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 28 Dec 2023 15:55:12 -0700 Subject: [PATCH 010/444] Additional updates for matrixcn to work with GULU --- src/biogeochem/CNCStateUpdate2Mod.F90 | 5 +++- src/biogeochem/CNDriverMod.F90 | 12 +++++--- src/biogeochem/CNNStateUpdate2Mod.F90 | 5 +++- src/biogeochem/dynGrossUnrepMod.F90 | 40 ++++++++++++++++++++++++++- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/biogeochem/CNCStateUpdate2Mod.F90 b/src/biogeochem/CNCStateUpdate2Mod.F90 index 2890c7d1fd..c59d7d47f1 100644 --- a/src/biogeochem/CNCStateUpdate2Mod.F90 +++ b/src/biogeochem/CNCStateUpdate2Mod.F90 @@ -335,7 +335,8 @@ end subroutine CStateUpdate2h !----------------------------------------------------------------------- subroutine CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, soilbiogeochem_carbonstate_inst) + cnveg_carbonflux_inst, cnveg_carbonstate_inst, & + soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst) ! ! !DESCRIPTION: ! Update all the prognostic carbon state @@ -348,6 +349,7 @@ subroutine CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & integer , intent(in) :: filter_soilp(:) ! filter for soil patches type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst + type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst ! ! !LOCAL VARIABLES: @@ -359,6 +361,7 @@ subroutine CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & associate( & cf_veg => cnveg_carbonflux_inst , & cs_veg => cnveg_carbonstate_inst , & + cf_soil => soilbiogeochem_carbonflux_inst, & cs_soil => soilbiogeochem_carbonstate_inst & ) diff --git a/src/biogeochem/CNDriverMod.F90 b/src/biogeochem/CNDriverMod.F90 index 3d75ee51f0..d7eb964f1d 100644 --- a/src/biogeochem/CNDriverMod.F90 +++ b/src/biogeochem/CNDriverMod.F90 @@ -799,18 +799,22 @@ subroutine CNDriverNoLeaching(bounds, end if call CStateUpdate2g( num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, soilbiogeochem_carbonstate_inst) + cnveg_carbonflux_inst, cnveg_carbonstate_inst, & + soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst) if ( use_c13 ) then call CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst) + c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, & + c13_soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonflux_inst) end if if ( use_c14 ) then call CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst) + c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, & + c14_soilbiogeochem_carbonstate_inst, c14_soilbiogeochem_carbonflux_inst) end if call NStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenstate_inst) + cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, & + soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) call t_stopf('CNUpdate2') diff --git a/src/biogeochem/CNNStateUpdate2Mod.F90 b/src/biogeochem/CNNStateUpdate2Mod.F90 index 2dbba68b82..4b6174195e 100644 --- a/src/biogeochem/CNNStateUpdate2Mod.F90 +++ b/src/biogeochem/CNNStateUpdate2Mod.F90 @@ -321,7 +321,8 @@ end subroutine NStateUpdate2h !----------------------------------------------------------------------- subroutine NStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenstate_inst) + cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, & + soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) ! ! !DESCRIPTION: ! Update all the prognostic nitrogen state @@ -337,6 +338,7 @@ subroutine NStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & type(cnveg_nitrogenflux_type) , intent(in) :: cnveg_nitrogenflux_inst type(cnveg_nitrogenstate_type) , intent(inout) :: cnveg_nitrogenstate_inst type(soilbiogeochem_nitrogenstate_type) , intent(inout) :: soilbiogeochem_nitrogenstate_inst + type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst ! ! !LOCAL VARIABLES: integer :: c,p,j,l,i ! indices @@ -347,6 +349,7 @@ subroutine NStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & associate( & nf_veg => cnveg_nitrogenflux_inst , & ns_veg => cnveg_nitrogenstate_inst , & + nf_soil => soilbiogeochem_nitrogenflux_inst, & ns_soil => soilbiogeochem_nitrogenstate_inst & ) diff --git a/src/biogeochem/dynGrossUnrepMod.F90 b/src/biogeochem/dynGrossUnrepMod.F90 index b354744b61..0c9b1e2c53 100644 --- a/src/biogeochem/dynGrossUnrepMod.F90 +++ b/src/biogeochem/dynGrossUnrepMod.F90 @@ -158,6 +158,7 @@ subroutine CNGrossUnrep (num_soilc, filter_soilc, num_soilp, filter_soilp, & use pftconMod , only : noveg, nbrdlf_evr_shrub, nc4_grass use clm_varcon , only : secspday use clm_time_manager, only : get_step_size_real, is_beg_curr_year + use CNVegMatrixMod , only : matrix_update_gmc, matrix_update_gmn ! ! !ARGUMENTS: integer , intent(in) :: num_soilc ! number of soil columns in filter @@ -269,7 +270,44 @@ subroutine CNGrossUnrep (num_soilc, filter_soilc, num_soilp, filter_soilp, & gru_livestemn_xfer_to_atm => cnveg_nitrogenflux_inst%gru_livestemn_xfer_to_atm_patch , & ! Output: [real(r8) (:)] gru_deadstemn_xfer_to_atm => cnveg_nitrogenflux_inst%gru_deadstemn_xfer_to_atm_patch , & ! Output: [real(r8) (:)] gru_livecrootn_xfer_to_atm => cnveg_nitrogenflux_inst%gru_livecrootn_xfer_to_atm_patch , & ! Output: [real(r8) (:)] - gru_deadcrootn_xfer_to_atm => cnveg_nitrogenflux_inst%gru_deadcrootn_xfer_to_atm_patch & ! Output: [real(r8) (:)] + gru_deadcrootn_xfer_to_atm => cnveg_nitrogenflux_inst%gru_deadcrootn_xfer_to_atm_patch , & ! Output: [real(r8) (:)] + ileaf_to_iout_gmc => cnveg_carbonflux_inst%ileaf_to_iout_gm , & + ileafst_to_iout_gmc => cnveg_carbonflux_inst%ileafst_to_iout_gm , & + ileafxf_to_iout_gmc => cnveg_carbonflux_inst%ileafxf_to_iout_gm , & + ifroot_to_iout_gmc => cnveg_carbonflux_inst%ifroot_to_iout_gm , & + ifrootst_to_iout_gmc => cnveg_carbonflux_inst%ifrootst_to_iout_gm , & + ifrootxf_to_iout_gmc => cnveg_carbonflux_inst%ifrootxf_to_iout_gm , & + ilivestem_to_iout_gmc => cnveg_carbonflux_inst%ilivestem_to_iout_gm , & + ilivestemst_to_iout_gmc => cnveg_carbonflux_inst%ilivestemst_to_iout_gm , & + ilivestemxf_to_iout_gmc => cnveg_carbonflux_inst%ilivestemxf_to_iout_gm , & + ideadstem_to_iout_gmc => cnveg_carbonflux_inst%ideadstem_to_iout_gm , & + ideadstemst_to_iout_gmc => cnveg_carbonflux_inst%ideadstemst_to_iout_gm , & + ideadstemxf_to_iout_gmc => cnveg_carbonflux_inst%ideadstemxf_to_iout_gm , & + ilivecroot_to_iout_gmc => cnveg_carbonflux_inst%ilivecroot_to_iout_gm , & + ilivecrootst_to_iout_gmc => cnveg_carbonflux_inst%ilivecrootst_to_iout_gm , & + ilivecrootxf_to_iout_gmc => cnveg_carbonflux_inst%ilivecrootxf_to_iout_gm , & + ideadcroot_to_iout_gmc => cnveg_carbonflux_inst%ideadcroot_to_iout_gm , & + ideadcrootst_to_iout_gmc => cnveg_carbonflux_inst%ideadcrootst_to_iout_gm , & + ideadcrootxf_to_iout_gmc => cnveg_carbonflux_inst%ideadcrootxf_to_iout_gm , & + ileaf_to_iout_gmn => cnveg_nitrogenflux_inst%ileaf_to_iout_gm , & + ileafst_to_iout_gmn => cnveg_nitrogenflux_inst%ileafst_to_iout_gm , & + ileafxf_to_iout_gmn => cnveg_nitrogenflux_inst%ileafxf_to_iout_gm , & + ifroot_to_iout_gmn => cnveg_nitrogenflux_inst%ifroot_to_iout_gm , & + ifrootst_to_iout_gmn => cnveg_nitrogenflux_inst%ifrootst_to_iout_gm , & + ifrootxf_to_iout_gmn => cnveg_nitrogenflux_inst%ifrootxf_to_iout_gm , & + ilivestem_to_iout_gmn => cnveg_nitrogenflux_inst%ilivestem_to_iout_gm , & + ilivestemst_to_iout_gmn => cnveg_nitrogenflux_inst%ilivestemst_to_iout_gm , & + ilivestemxf_to_iout_gmn => cnveg_nitrogenflux_inst%ilivestemxf_to_iout_gm , & + ideadstem_to_iout_gmn => cnveg_nitrogenflux_inst%ideadstem_to_iout_gm , & + ideadstemst_to_iout_gmn => cnveg_nitrogenflux_inst%ideadstemst_to_iout_gm , & + ideadstemxf_to_iout_gmn => cnveg_nitrogenflux_inst%ideadstemxf_to_iout_gm , & + ilivecroot_to_iout_gmn => cnveg_nitrogenflux_inst%ilivecroot_to_iout_gm , & + ilivecrootst_to_iout_gmn => cnveg_nitrogenflux_inst%ilivecrootst_to_iout_gm , & + ilivecrootxf_to_iout_gmn => cnveg_nitrogenflux_inst%ilivecrootxf_to_iout_gm , & + ideadcroot_to_iout_gmn => cnveg_nitrogenflux_inst%ideadcroot_to_iout_gm , & + ideadcrootst_to_iout_gmn => cnveg_nitrogenflux_inst%ideadcrootst_to_iout_gm , & + ideadcrootxf_to_iout_gmn => cnveg_nitrogenflux_inst%ideadcrootxf_to_iout_gm , & + iretransn_to_iout_gmn => cnveg_nitrogenflux_inst%iretransn_to_iout_gm & ) dtime = get_step_size_real() From 1242be2f5b74d65729682322c4c8228a0b6e07aa Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 28 Dec 2023 20:44:17 -0700 Subject: [PATCH 011/444] Cheyenne GULU test now passes with these additional updates --- src/biogeochem/CNCStateUpdate2Mod.F90 | 18 ++++++++++-------- src/biogeochem/CNGapMortalityMod.F90 | 5 ----- src/biogeochem/dynGrossUnrepMod.F90 | 2 +- src/dyn_subgrid/dynHarvestMod.F90 | 5 ----- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/biogeochem/CNCStateUpdate2Mod.F90 b/src/biogeochem/CNCStateUpdate2Mod.F90 index c59d7d47f1..5fb7a283e9 100644 --- a/src/biogeochem/CNCStateUpdate2Mod.F90 +++ b/src/biogeochem/CNCStateUpdate2Mod.F90 @@ -401,6 +401,16 @@ subroutine CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & do fp = 1,num_soilp p = filter_soilp(fp) + ! xsmrpool + cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) & + - cf_veg%gru_xsmrpool_to_atm_patch(p) * dt + ! gresp storage pool + cs_veg%gresp_storage_patch(p) = cs_veg%gresp_storage_patch(p) & + - cf_veg%gru_gresp_storage_to_atm_patch(p) * dt + ! gresp transfer pool + cs_veg%gresp_xfer_patch(p) = cs_veg%gresp_xfer_patch(p) & + - cf_veg%gru_gresp_xfer_to_atm_patch(p) * dt + ! patch-level carbon fluxes from gross unrepresented landcover change mortality ! ! State update without the matrix solution @@ -422,10 +432,6 @@ subroutine CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%deadcrootc_patch(p) = cs_veg%deadcrootc_patch(p) & - cf_veg%gru_deadcrootc_to_litter_patch(p) * dt - ! xsmrpool - cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) & - - cf_veg%gru_xsmrpool_to_atm_patch(p) * dt - ! storage pools cs_veg%leafc_storage_patch(p) = cs_veg%leafc_storage_patch(p) & - cf_veg%gru_leafc_storage_to_atm_patch(p) * dt @@ -439,8 +445,6 @@ subroutine CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cf_veg%gru_livecrootc_storage_to_atm_patch(p) * dt cs_veg%deadcrootc_storage_patch(p) = cs_veg%deadcrootc_storage_patch(p) & - cf_veg%gru_deadcrootc_storage_to_atm_patch(p) * dt - cs_veg%gresp_storage_patch(p) = cs_veg%gresp_storage_patch(p) & - - cf_veg%gru_gresp_storage_to_atm_patch(p) * dt ! transfer pools cs_veg%leafc_xfer_patch(p) = cs_veg%leafc_xfer_patch(p) & @@ -455,8 +459,6 @@ subroutine CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cf_veg%gru_livecrootc_xfer_to_atm_patch(p) * dt cs_veg%deadcrootc_xfer_patch(p) = cs_veg%deadcrootc_xfer_patch(p) & - cf_veg%gru_deadcrootc_xfer_to_atm_patch(p) * dt - cs_veg%gresp_xfer_patch(p) = cs_veg%gresp_xfer_patch(p) & - - cf_veg%gru_gresp_xfer_to_atm_patch(p) * dt else ! NB (slevis) The matrix equivalent of the above is in diff --git a/src/biogeochem/CNGapMortalityMod.F90 b/src/biogeochem/CNGapMortalityMod.F90 index e9013e03b1..c99660e3c6 100644 --- a/src/biogeochem/CNGapMortalityMod.F90 +++ b/src/biogeochem/CNGapMortalityMod.F90 @@ -24,11 +24,6 @@ module CNGapMortalityMod use PatchType , only : patch use GridcellType , only : grc use CNSharedParamsMod , only : use_matrixcn - use clm_varpar , only : ileaf,ileaf_st,ileaf_xf,ifroot,ifroot_st,ifroot_xf,& - ilivestem,ilivestem_st,ilivestem_xf,& - ideadstem,ideadstem_st,ideadstem_xf,& - ilivecroot,ilivecroot_st,ilivecroot_xf,& - ideadcroot,ideadcroot_st,ideadcroot_xf,iretransn,ioutc,ioutn use CNVegMatrixMod , only : matrix_update_gmc, matrix_update_gmn ! implicit none diff --git a/src/biogeochem/dynGrossUnrepMod.F90 b/src/biogeochem/dynGrossUnrepMod.F90 index 0c9b1e2c53..1da39a0b64 100644 --- a/src/biogeochem/dynGrossUnrepMod.F90 +++ b/src/biogeochem/dynGrossUnrepMod.F90 @@ -364,7 +364,7 @@ subroutine CNGrossUnrep (num_soilc, filter_soilc, num_soilp, filter_soilp, & gru_livecrootc_xfer_to_atm(p) = livecrootc_xfer(p) * m gru_deadcrootc_xfer_to_atm(p) = deadcrootc_xfer(p) * m gru_gresp_xfer_to_atm(p) = gresp_xfer(p) * m - + ! patch-level gross unrepresented landcover change mortality nitrogen fluxes ! displayed pools gru_leafn_to_litter(p) = leafn(p) * m diff --git a/src/dyn_subgrid/dynHarvestMod.F90 b/src/dyn_subgrid/dynHarvestMod.F90 index 609ba6679b..2936a41545 100644 --- a/src/dyn_subgrid/dynHarvestMod.F90 +++ b/src/dyn_subgrid/dynHarvestMod.F90 @@ -25,11 +25,6 @@ module dynHarvestMod use PatchType , only : patch use CNSharedParamsMod , only : use_matrixcn use clm_varctl , only : use_fates - use clm_varpar , only : ileaf,ileaf_st,ileaf_xf,ifroot,ifroot_st,ifroot_xf,& - ilivestem,ilivestem_st,ilivestem_xf,& - ideadstem,ideadstem_st,ideadstem_xf,& - ilivecroot,ilivecroot_st,ilivecroot_xf,& - ideadcroot,ideadcroot_st,ideadcroot_xf,ioutc,ioutn ! ! !PUBLIC MEMBER FUNCTIONS: implicit none From 46cbf4b3e67b1b55260b6b5b6d57778c1cc54db7 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 29 Dec 2023 16:04:20 -0700 Subject: [PATCH 012/444] Remove PS from SMS_Ld3_PS test for it to work with matrixcn --- cime_config/testdefs/testlist_clm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index e1f26f0703..3551d34b1a 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -536,7 +536,7 @@ - + From 2287bb6b7b4fdb66a97dc462d37173b72a46ec73 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 29 Dec 2023 19:04:24 -0700 Subject: [PATCH 013/444] Corrections for model to build and a test to pass Used this one for testing: SMS_D.1x1_brazil.I1850Clm51BgcCrop.cheyenne_gnu.clm-mimics_matrixcn --- src/biogeochem/CNCStateUpdate1Mod.F90 | 61 ++++--------------- src/biogeochem/CNDriverMod.F90 | 8 +-- .../SoilBiogeochemNitrogenStateType.F90 | 1 + 3 files changed, 17 insertions(+), 53 deletions(-) diff --git a/src/biogeochem/CNCStateUpdate1Mod.F90 b/src/biogeochem/CNCStateUpdate1Mod.F90 index c342e36a22..e839136e11 100644 --- a/src/biogeochem/CNCStateUpdate1Mod.F90 +++ b/src/biogeochem/CNCStateUpdate1Mod.F90 @@ -215,6 +215,18 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & ! terms have been moved to CStateUpdateDynPatch. I think this is zeroed every ! time step, but to be safe, I'm explicitly setting it to zero here. cf_soil%decomp_cpools_sourcesink_col(c,j,i_cwd) = 0._r8 + + ! litter and SOM HR fluxes + do k = 1, ndecomp_cascade_transitions + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) = & + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) & + - ( cf_soil%decomp_cascade_hr_vr_col(c,j,k) + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)) * dt + if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) = & + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) & + + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k) * dt + end if + end do else ! ! For the matrix solution the actual state update comes after the matrix @@ -233,55 +245,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & end if fates_if end do fc_loop - - - ! litter and SOM HR fluxes - do k = 1, ndecomp_cascade_transitions - do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) - ! - ! State update without the matrix solution - ! - if (.not. use_soil_matrixcn) then - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) = & - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) & - - ( cf_soil%decomp_cascade_hr_vr_col(c,j,k) + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)) *dt - end if !not use_soil_matrixcn - end do - end do - end do - do k = 1, ndecomp_cascade_transitions - if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions - do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) - if (.not. use_soil_matrixcn) then - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) = & - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) & - - ( cf_soil%decomp_cascade_hr_vr_col(c,j,k) + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)) *dt - end if !not use_soil_matrixcn - end do - end do - end do - do k = 1, ndecomp_cascade_transitions - if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions - do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) - ! - ! State update without the matrix solution - ! - if (.not. use_soil_matrixcn) then - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) = & - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) & - + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)*dt - end if !not use_soil_matrixcn - end do - end do - end do - end if - end do soilpatch_loop: do fp = 1,num_soilp p = filter_soilp(fp) diff --git a/src/biogeochem/CNDriverMod.F90 b/src/biogeochem/CNDriverMod.F90 index be341477a5..67eaba1013 100644 --- a/src/biogeochem/CNDriverMod.F90 +++ b/src/biogeochem/CNDriverMod.F90 @@ -1097,10 +1097,10 @@ subroutine CNDriverLeaching(bounds, & if ( use_matrixcn ) then call t_startf('CNVMatrix') - call CNVegMatrix(bounds,num_bgc_soilp,filter_bgc_soilp(1:num_bgc_soilp),num_actfirep,filter_actfirep,cnveg_carbonstate_inst,cnveg_nitrogenstate_inst,& - cnveg_carbonflux_inst, cnveg_nitrogenflux_inst,cnveg_state_inst,soilbiogeochem_nitrogenflux_inst,& - c13_cnveg_carbonstate_inst,c14_cnveg_carbonstate_inst,c13_cnveg_carbonflux_inst,& - c14_cnveg_carbonflux_inst) + call CNVegMatrix(bounds, num_bgc_vegp, filter_bgc_vegp(1:num_bgc_vegp), & + num_actfirep, filter_actfirep, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & + cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, cnveg_state_inst,soilbiogeochem_nitrogenflux_inst, & + c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst) call t_stopf('CNVMatrix') end if diff --git a/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 b/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 index e97ed3e6eb..a0cbc81a9e 100644 --- a/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 @@ -15,6 +15,7 @@ module SoilBiogeochemNitrogenStateType use clm_varctl , only : iulog, override_bgc_restart_mismatch_dump, spinup_state use landunit_varcon , only : istcrop, istsoil use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con, use_soil_matrixcn + use SoilBiogeochemDecompCascadeConType , only : mimics_decomp, century_decomp, decomp_method use LandunitType , only : lun use ColumnType , only : col use GridcellType , only : grc From 107f854c89a237b2d1d99ad36b78ce2ef2ad2544 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Sat, 30 Dec 2023 21:42:36 -0700 Subject: [PATCH 014/444] Fix for FatesCold simulations to pass --- src/biogeochem/CNCStateUpdate1Mod.F90 | 30 +++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/biogeochem/CNCStateUpdate1Mod.F90 b/src/biogeochem/CNCStateUpdate1Mod.F90 index e839136e11..4eb52d9c10 100644 --- a/src/biogeochem/CNCStateUpdate1Mod.F90 +++ b/src/biogeochem/CNCStateUpdate1Mod.F90 @@ -216,17 +216,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & ! time step, but to be safe, I'm explicitly setting it to zero here. cf_soil%decomp_cpools_sourcesink_col(c,j,i_cwd) = 0._r8 - ! litter and SOM HR fluxes - do k = 1, ndecomp_cascade_transitions - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) = & - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) & - - ( cf_soil%decomp_cascade_hr_vr_col(c,j,k) + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)) * dt - if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) = & - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) & - + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k) * dt - end if - end do else ! ! For the matrix solution the actual state update comes after the matrix @@ -243,6 +232,25 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & end do end if fates_if + + do j = 1,nlevdecomp + ! + ! State update without the matrix solution + ! + if (.not. use_soil_matrixcn) then + ! litter and SOM HR fluxes + do k = 1, ndecomp_cascade_transitions + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) = & + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) & + - ( cf_soil%decomp_cascade_hr_vr_col(c,j,k) + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)) * dt + if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) = & + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) & + + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k) * dt + end if + end do + end if + end do end do fc_loop From 3af4aedfbb8bc7a8b0076184197141c463e6c8fd Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 2 Jan 2024 18:39:00 -0700 Subject: [PATCH 015/444] Corrections from comparing model versions --- src/biogeochem/CNPhenologyMod.F90 | 40 +++++++++---------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index e1b7b2edb6..2d9ab51473 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -3506,17 +3506,8 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & t1 = 1.0_r8 / dt frootc_to_litter(p) = t1 * frootc(p) + cpool_to_frootc(p) - ! TODO slevis: This line didn't appear in dev159. Remove? - ! biofuel_harvfrac is only non-zero for prognostic crops. - leafc_to_litter(p) = t1 * leafc(p) * (1._r8 - biofuel_harvfrac(ivt(p))) + cpool_to_leafc(p) - - ! leafc_litter and frootc_to_litter for matrix + ! frootc_to_litter for matrix if (use_matrixcn) then - if(leafc(p) .gt. 0)then - leafc_to_litter(p) = leafc(p) * matrix_update_phc(p,ileaf_to_iout_phc,leafc_to_litter(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) - else - leafc_to_litter(p) = 0 - end if if(frootc(p) .gt. 0)then frootc_to_litter(p) = frootc(p) * matrix_update_phc(p,ifroot_to_iout_phc,frootc_to_litter(p) / frootc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else @@ -3618,6 +3609,7 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & ! as well as leaf C:N ratio (unaffected by biofuel harvest). It thus does not ! need to be updated here. + ! Matrix for grain, livestem to litter, leaf to litter, and biofuel if(use_matrixcn)then if(reproductivec(p,1) .gt. 0)then grainc_to_out = reproductivec(p,1) * matrix_update_phc(p,igrain_to_iout_phc,(repr_grainc_to_seed(p,1) + repr_grainc_to_food(p,1)) / reproductivec(p,1),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) @@ -3633,13 +3625,17 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & end if if(livestemc(p) .gt. 0)then livestemc_to_litter(p) = livestemc(p) * matrix_update_phc(p,ilivestem_to_iout_phc,livestemc_to_litter(p) / livestemc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) + livestemc_to_biofuelc(p) = livestemc(p) * matrix_update_gmc(p,ilivestem_to_iout_gmc,livestemc_to_biofuelc(p) / livestemc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) else livestemc_to_litter(p) = 0 + livestemc_to_biofuelc(p) = 0 end if if(livestemn(p) .gt. 0)then livestemn_to_biofueln(p) = livestemn(p) * matrix_update_gmn(p,ilivestem_to_iout_gmn,livestemn_to_biofueln(p) / livestemn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,.True.) + livestemn_to_litter(p) = livestemn(p) * matrix_update_phn(p,ilivestem_to_iout_phn, (1._r8- biofuel_harvfrac(ivt(p)))/dt, dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else livestemn_to_biofueln(p) = 0 + livestemn_to_litter(p) = 0 end if if(leafn(p) > 0)then leafn_to_biofueln(p) = leafn(p) * matrix_update_gmn(p,ileaf_to_iout_gmn,leafn_to_biofueln(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,.True.) @@ -3647,14 +3643,11 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & leafn_to_biofueln(p) = 0 end if if (leafc(p) > 0)then - leafc_to_biofuelc(p) = leafc(p) * matrix_update_gmc(p,ileaf_to_iout_gmc,leafc_to_biofuelc(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) - else - leafc_to_biofuelc(p) = 0 - end if - if(livestemc(p) .gt. 0)then - livestemc_to_biofuelc(p) = livestemc(p) * matrix_update_gmc(p,ilivestem_to_iout_gmc,livestemc_to_biofuelc(p) / livestemc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) + leafc_to_biofuelc(p) = leafc(p) * matrix_update_gmc(p,ileaf_to_iout_gmc,leafc_to_biofuelc(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) + leafc_to_litter(p) = leafc(p) * matrix_update_phc(p,ileaf_to_iout_phc,leafc_to_litter(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - livestemc_to_biofuelc(p) = 0 + leafc_to_biofuelc(p) = 0 + leafc_to_litter(p) = 0 end if else ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) @@ -3675,7 +3668,7 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & if(frootc(p) .gt. 0)then frootc_to_litter(p) = frootc(p) * matrix_update_phc(p,ifroot_to_iout_phc,frootc_to_litter(p) / frootc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - frootc_to_litter(p) = 0 + frootc_to_litter(p) = 0 ! TODO slevis here and elsewhere end if else ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) @@ -3824,17 +3817,6 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & endif end if - ! TODO slevis: This paragraph didn't appear in dev159. Remove? - if (ivt(p) >= npcropmin) then - ! NOTE(slevis, 2014-12) results in -ve livestemn and -ve totpftn - !X! livestemn_to_litter(p) = livestemc_to_litter(p) / livewdcn(ivt(p)) - ! NOTE(slevis, 2014-12) Beth Drewniak suggested this instead - livestemn_to_litter(p) = livestemn(p) / dt * (1._r8 - biofuel_harvfrac(ivt(p))) - if(use_matrixcn)then - livestemn_to_litter(p) = livestemn(p) * matrix_update_phn(p,ilivestem_to_iout_phn, (1._r8- biofuel_harvfrac(ivt(p)))/dt, dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) - end if - end if - ! save the current litterfall fluxes prev_leafc_to_litter(p) = leafc_to_litter(p) prev_frootc_to_litter(p) = frootc_to_litter(p) From 2ea1cecedd3a00cd98d962f9de1eaac2159ace05 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 2 Jan 2024 18:46:58 -0700 Subject: [PATCH 016/444] Corrections to lists of tests and expected failures --- cime_config/testdefs/ExpectedTestFails.xml | 4 ++-- cime_config/testdefs/testlist_clm.xml | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 6be036c485..b0f7fa860b 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -50,13 +50,13 @@ #1733 - + FAIL #640, same test with clm-ciso_soil_matrixcn_only works - + FAIL #640, same test with clm-ciso_soil_matrixcn_only works diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 114e3781a0..5ec791b7d4 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -373,7 +373,7 @@ - + @@ -632,7 +632,7 @@ - + @@ -641,7 +641,7 @@ - + @@ -729,7 +729,7 @@ - + @@ -808,7 +808,7 @@ - + @@ -1005,7 +1005,7 @@ - + @@ -1014,7 +1014,7 @@ - + @@ -2383,7 +2383,7 @@ - + @@ -2603,7 +2603,7 @@ - + From 3b4d882878204b3dcda3a651375d12a9a074940f Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 12 Mar 2024 15:51:13 -0600 Subject: [PATCH 017/444] Add matrixcn code for residue removal variables --- src/biogeochem/CNPhenologyMod.F90 | 42 ++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index 619b28801b..b53c195418 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -3605,43 +3605,51 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & ! Matrix for grain, livestem to litter, leaf to litter, and biofuel if(use_matrixcn)then - if(reproductivec(p,1) .gt. 0)then + if(reproductivec(p,1) > 0._r8)then grainc_to_out = reproductivec(p,1) * matrix_update_phc(p,igrain_to_iout_phc,(repr_grainc_to_seed(p,1) + repr_grainc_to_food(p,1)) / reproductivec(p,1),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - repr_grainc_to_seed(p,1) = 0 - repr_grainc_to_food(p,1) = 0 + repr_grainc_to_seed(p,1) = 0._r8 + repr_grainc_to_food(p,1) = 0._r8 end if - if(reproductiven(p,1) .gt. 0)then + if(reproductiven(p,1) > 0._r8)then grainn_to_out = reproductiven(p,1) * matrix_update_phn(p,igrain_to_iout_phn,(repr_grainn_to_seed(p,1) + repr_grainn_to_food(p,1)) / reproductiven(p,1),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else - repr_grainn_to_seed(p,1) = 0 - repr_grainn_to_food(p,1) = 0 + repr_grainn_to_seed(p,1) = 0._r8 + repr_grainn_to_food(p,1) = 0._r8 end if - if(livestemc(p) .gt. 0)then + if(livestemc(p) > 0._r8)then livestemc_to_litter(p) = livestemc(p) * matrix_update_phc(p,ilivestem_to_iout_phc,livestemc_to_litter(p) / livestemc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) + livestemc_to_removedresiduec(p) = livestemc(p) * matrix_update_gmc(p,ilivestem_to_iout_gmc,livestemc_to_removedresiduec(p) / livestemc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) livestemc_to_biofuelc(p) = livestemc(p) * matrix_update_gmc(p,ilivestem_to_iout_gmc,livestemc_to_biofuelc(p) / livestemc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) else - livestemc_to_litter(p) = 0 - livestemc_to_biofuelc(p) = 0 + livestemc_to_litter(p) = 0._r8 + livestemc_to_removedresiduec(p) = 0._r8 + livestemc_to_biofuelc(p) = 0._r8 end if - if(livestemn(p) .gt. 0)then + if(livestemn(p) > 0._r8)then livestemn_to_biofueln(p) = livestemn(p) * matrix_update_gmn(p,ilivestem_to_iout_gmn,livestemn_to_biofueln(p) / livestemn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,.True.) + livestemn_to_removedresiduen(p) = livestemn(p) * matrix_update_gmn(p,ilivestem_to_iout_gmn,livestemn_to_removedresiduen(p) / livestemn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,.True.) livestemn_to_litter(p) = livestemn(p) * matrix_update_phn(p,ilivestem_to_iout_phn, (1._r8- biofuel_harvfrac(ivt(p)))/dt, dt,cnveg_nitrogenflux_inst,matrixcheck_ph,acc_ph) else - livestemn_to_biofueln(p) = 0 - livestemn_to_litter(p) = 0 + livestemn_to_biofueln(p) = 0._r8 + livestemn_to_removedresiduen(p) = 0._r8 + livestemn_to_litter(p) = 0._r8 end if - if(leafn(p) > 0)then + if(leafn(p) > 0._r8)then leafn_to_biofueln(p) = leafn(p) * matrix_update_gmn(p,ileaf_to_iout_gmn,leafn_to_biofueln(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,.True.) + leafn_to_removedresiduen(p) = leafn(p) * matrix_update_gmn(p,ileaf_to_iout_gmn,leafn_to_removedresiduen(p) / leafn(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,.True.) else - leafn_to_biofueln(p) = 0 + leafn_to_biofueln(p) = 0._r8 + leafn_to_removedresiduen(p) = 0._r8 end if - if (leafc(p) > 0)then + if (leafc(p) > 0._r8)then leafc_to_biofuelc(p) = leafc(p) * matrix_update_gmc(p,ileaf_to_iout_gmc,leafc_to_biofuelc(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) + leafc_to_removedresiduec(p) = leafc(p) * matrix_update_gmc(p,ileaf_to_iout_gmc,leafc_to_removedresiduec(p) / leafc(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,.True.) leafc_to_litter(p) = leafc(p) * matrix_update_phc(p,ileaf_to_iout_phc,leafc_to_litter(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else - leafc_to_biofuelc(p) = 0 - leafc_to_litter(p) = 0 + leafc_to_biofuelc(p) = 0._r8 + leafc_to_removedresiduec(p) = 0._r8 + leafc_to_litter(p) = 0._r8 end if else ! NOTE: The non matrix version of this is in CNCStateUpdate1::CStateUpdate1 EBK (11/26/2019) From fe50ce16c03446c86b7018d1c655ca9a71b61982 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 12 Mar 2024 16:08:18 -0600 Subject: [PATCH 018/444] Update comment based on most recent code changes --- src/biogeochem/CNPhenologyMod.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index b53c195418..c6e6cf3635 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -3603,7 +3603,8 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & ! as well as leaf C:N ratio (unaffected by biofuel harvest). It thus does not ! need to be updated here. - ! Matrix for grain, livestem to litter, leaf to litter, and biofuel + ! Matrix for grain + ! Matrix for livestem/leaf to litter, biofuel, and removed residue if(use_matrixcn)then if(reproductivec(p,1) > 0._r8)then grainc_to_out = reproductivec(p,1) * matrix_update_phc(p,igrain_to_iout_phc,(repr_grainc_to_seed(p,1) + repr_grainc_to_food(p,1)) / reproductivec(p,1),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) From acd1413ef75868c873e72c17810704049495c00f Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 12 Mar 2024 16:25:36 -0600 Subject: [PATCH 019/444] Correction to latest code mods --- src/biogeochem/CNPhenologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index c6e6cf3635..c81dd4215d 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -3645,7 +3645,7 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & end if if (leafc(p) > 0._r8)then leafc_to_biofuelc(p) = leafc(p) * matrix_update_gmc(p,ileaf_to_iout_gmc,leafc_to_biofuelc(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) - leafc_to_removedresiduec(p) = leafc(p) * matrix_update_gmc(p,ileaf_to_iout_gmc,leafc_to_removedresiduec(p) / leafc(p),dt,cnveg_nitrogenflux_inst,matrixcheck_ph,.True.) + leafc_to_removedresiduec(p) = leafc(p) * matrix_update_gmc(p,ileaf_to_iout_gmc,leafc_to_removedresiduec(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,.True.) leafc_to_litter(p) = leafc(p) * matrix_update_phc(p,ileaf_to_iout_phc,leafc_to_litter(p) / leafc(p),dt,cnveg_carbonflux_inst,matrixcheck_ph,acc_ph) else leafc_to_biofuelc(p) = 0._r8 From 82c1903287d254dc5b8ed5084c38118029eab90c Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 19 Mar 2024 11:23:05 -0600 Subject: [PATCH 020/444] Corrections for PEM...till test to PASS --- .../SoilBiogeochemDecompCascadeBGCMod.F90 | 21 +++++---------- .../SoilBiogeochemDecompCascadeMIMICSMod.F90 | 26 +++++++++++++++++-- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 b/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 index 139cdbba32..49fc95d6f5 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 @@ -911,23 +911,16 @@ subroutine decomp_rate_constants_bgc(bounds, num_bgc_soilc, filter_bgc_soilc, & ! Above into soil matrix if(use_soil_matrixcn)then - Ksoil%DM(c,j+nlevdecomp*(i_met_lit-1)) = k_l1 * t_scalar(c,j) * w_scalar(c,j) * & - depth_scalar(c,j) * o_scalar(c,j) * spinup_geogterm_l1(c) * dt - Ksoil%DM(c,j+nlevdecomp*(i_cel_lit-1)) = k_l2_l3 * t_scalar(c,j) * w_scalar(c,j) * & - depth_scalar(c,j) * o_scalar(c,j) * spinup_geogterm_l23(c) * dt - Ksoil%DM(c,j+nlevdecomp*(i_lig_lit-1)) = k_l2_l3 * t_scalar(c,j) * w_scalar(c,j) * & - depth_scalar(c,j) * o_scalar(c,j) * spinup_geogterm_l23(c) * dt - Ksoil%DM(c,j+nlevdecomp*(i_act_som-1)) = k_s1 * t_scalar(c,j) * w_scalar(c,j) * & - depth_scalar(c,j) * o_scalar(c,j) * spinup_geogterm_s1(c) * dt - Ksoil%DM(c,j+nlevdecomp*(i_slo_som-1)) = k_s2 * t_scalar(c,j) * w_scalar(c,j) * & - depth_scalar(c,j) * o_scalar(c,j) * spinup_geogterm_s2(c) * dt - Ksoil%DM(c,j+nlevdecomp*(i_pas_som-1)) = k_s3 * t_scalar(c,j) * w_scalar(c,j) * & - depth_scalar(c,j) * o_scalar(c,j) * spinup_geogterm_s3(c) * dt + Ksoil%DM(c,j+nlevdecomp*(i_met_lit-1)) = decomp_k(c,j,i_met_lit) * dt + Ksoil%DM(c,j+nlevdecomp*(i_cel_lit-1)) = decomp_k(c,j,i_cel_lit) * dt + Ksoil%DM(c,j+nlevdecomp*(i_lig_lit-1)) = decomp_k(c,j,i_lig_lit) * dt + Ksoil%DM(c,j+nlevdecomp*(i_act_som-1)) = decomp_k(c,j,i_act_som) * dt + Ksoil%DM(c,j+nlevdecomp*(i_slo_som-1)) = decomp_k(c,j,i_slo_som) * dt + Ksoil%DM(c,j+nlevdecomp*(i_pas_som-1)) = decomp_k(c,j,i_pas_som) * dt ! same for cwd but only if fates is not enabled; fates handles CWD ! on its own structure if (.not. use_fates) then - Ksoil%DM(c,j+nlevdecomp*(i_cwd-1)) = k_frag * t_scalar(c,j) * w_scalar(c,j) * depth_scalar(c,j) * & - o_scalar(c,j) * spinup_geogterm_cwd(c) * dt + Ksoil%DM(c,j+nlevdecomp*(i_cwd-1)) = decomp_k(c,j,i_cwd) * dt end if end if !use_soil_matrixcn end do diff --git a/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 b/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 index 65091755f5..e9bb60bcec 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 @@ -18,7 +18,7 @@ module SoilBiogeochemDecompCascadeMIMICSMod use spmdMod , only : masterproc use abortutils , only : endrun use CNSharedParamsMod , only : CNParamsShareInst, nlev_soildecomp_standard - use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con + use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con, InitSoilTransfer, use_soil_matrixcn use SoilBiogeochemStateType , only : soilbiogeochem_state_type use SoilBiogeochemCarbonFluxType , only : soilbiogeochem_carbonflux_type use SoilBiogeochemCarbonStateType , only : soilbiogeochem_carbonstate_type @@ -734,6 +734,8 @@ subroutine init_decompcascade_mimics(bounds, soilbiogeochem_state_inst, soilstat nue_decomp_cascade(i_cwdl2) = 1.0_r8 end if + if (use_soil_matrixcn) call InitSoilTransfer() + deallocate(params_inst%mimics_mge) deallocate(params_inst%mimics_vmod) deallocate(params_inst%mimics_vint) @@ -763,7 +765,7 @@ subroutine decomp_rates_mimics(bounds, num_bgc_soilc, filter_bgc_soilc, & ! decomposition cascade model ! ! !USES: - use clm_time_manager , only : get_average_days_per_year + use clm_time_manager , only : get_average_days_per_year, get_step_size use clm_varcon , only : secspday, secsphr, tfrz use clm_varcon , only : g_to_mg, cm3_to_m3 use subgridAveMod , only : p2c @@ -822,6 +824,7 @@ subroutine decomp_rates_mimics(bounds, num_bgc_soilc, filter_bgc_soilc, & integer :: p, fp, c, fc, j, k, l, s ! indices integer :: pf ! fates patch index integer :: nc ! clump index + real(r8):: dt ! decomposition time step real(r8):: days_per_year ! days per year real(r8):: depth_scalar(bounds%begc:bounds%endc,1:nlevdecomp) real(r8):: w_d_o_scalars ! product of w_scalar * depth_scalar * o_scalar @@ -882,6 +885,7 @@ subroutine decomp_rates_mimics(bounds, num_bgc_soilc, filter_bgc_soilc, & cn_col => soilbiogeochem_carbonflux_inst%cn_col , & ! Output: [real(r8) (:,:) ] C:N ratio ligninNratioAvg => soilbiogeochem_carbonflux_inst%litr_lig_c_to_n_col, & ! Input: [real(r8) (:) ] C:N ratio of litter lignin decomp_k => soilbiogeochem_carbonflux_inst%decomp_k_col , & ! Output: [real(r8) (:,:,:) ] rate for decomposition (1./sec) + Ksoil => soilbiogeochem_carbonflux_inst%Ksoil , & ! Output: [real(r8) (:,:,:) ] rate constant for decomposition (1./sec) spinup_factor => decomp_cascade_con%spinup_factor & ! Input: [real(r8) (:) ] factor for AD spinup associated with each pool ) @@ -892,6 +896,7 @@ subroutine decomp_rates_mimics(bounds, num_bgc_soilc, filter_bgc_soilc, & mino2lim = CNParamsShareInst%mino2lim days_per_year = get_average_days_per_year() + dt = real( get_step_size(), r8 ) ! ! Set "decomp_depth_efolding" parameter ! decomp_depth_efolding = CNParamsShareInst%decomp_depth_efolding @@ -1311,6 +1316,23 @@ subroutine decomp_rates_mimics(bounds, num_bgc_soilc, filter_bgc_soilc, & if (get_do_tillage()) then call get_apply_tillage_multipliers(idop, c, j, decomp_k(c,j,:)) end if + +! Above into soil matrix + if(use_soil_matrixcn)then + Ksoil%DM(c,j+nlevdecomp*(i_met_lit-1)) = decomp_k(c,j,i_met_lit) * dt + Ksoil%DM(c,j+nlevdecomp*(i_str_lit-1)) = decomp_k(c,j,i_str_lit) * dt + Ksoil%DM(c,j+nlevdecomp*(i_avl_som-1)) = decomp_k(c,j,i_avl_som) * dt + Ksoil%DM(c,j+nlevdecomp*(i_phys_som-1)) = decomp_k(c,j,i_phys_som) * dt + Ksoil%DM(c,j+nlevdecomp*(i_chem_som-1)) = decomp_k(c,j,i_chem_som) * dt + Ksoil%DM(c,j+nlevdecomp*(i_cop_mic-1)) = decomp_k(c,j,i_cop_mic) * dt + Ksoil%DM(c,j+nlevdecomp*(i_oli_mic-1)) = decomp_k(c,j,i_oli_mic) * dt + ! same for cwd but only if fates is not enabled; fates handles + ! CWD + ! on its own structure + if (.not. use_fates) then + Ksoil%DM(c,j+nlevdecomp*(i_cwd-1)) = decomp_k(c,j,i_cwd) * dt + end if + end if !use_soil_matrixcn end do end do From 64870fa5b51fef1f93a4d05488c0a18e2d65d7d4 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Mon, 25 Mar 2024 09:53:37 -0600 Subject: [PATCH 021/444] Getting around "file not found" error for /run directory --- cime_config/SystemTests/sspmatrixcn.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cime_config/SystemTests/sspmatrixcn.py b/cime_config/SystemTests/sspmatrixcn.py index bd41d84651..5f2d3e065e 100644 --- a/cime_config/SystemTests/sspmatrixcn.py +++ b/cime_config/SystemTests/sspmatrixcn.py @@ -207,7 +207,9 @@ def run_phase(self): linkfile = os.path.join(rundir, os.path.basename(item)) if os.path.exists(linkfile): os.remove( linkfile ) - os.symlink(item, linkfile ) + self._case.flush() + if os.path.exists(rundir): + os.symlink(item, linkfile ) for item in glob.glob("{}/*rpointer*".format(rest_path)): shutil.copy(item, rundir) @@ -215,7 +217,8 @@ def run_phase(self): # # Run the case (Archiving on) # - self._case.flush() + if not os.path.exists(rundir): + self._case.flush() self.run_indv(suffix="step{}".format(self.steps[n]), st_archive=True) # From 25f0236576b01044df8509e865dbce35587983ca Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 26 Mar 2024 09:49:24 -0600 Subject: [PATCH 022/444] Getting around "file not found" error for rundir (this time test passes) --- cime_config/SystemTests/sspmatrixcn.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cime_config/SystemTests/sspmatrixcn.py b/cime_config/SystemTests/sspmatrixcn.py index 5f2d3e065e..eec462e72c 100644 --- a/cime_config/SystemTests/sspmatrixcn.py +++ b/cime_config/SystemTests/sspmatrixcn.py @@ -207,9 +207,9 @@ def run_phase(self): linkfile = os.path.join(rundir, os.path.basename(item)) if os.path.exists(linkfile): os.remove( linkfile ) - self._case.flush() - if os.path.exists(rundir): - os.symlink(item, linkfile ) + if not os.path.isdir(rundir): + os.makedirs(rundir) + os.symlink(item, linkfile ) for item in glob.glob("{}/*rpointer*".format(rest_path)): shutil.copy(item, rundir) @@ -217,8 +217,7 @@ def run_phase(self): # # Run the case (Archiving on) # - if not os.path.exists(rundir): - self._case.flush() + self._case.flush() self.run_indv(suffix="step{}".format(self.steps[n]), st_archive=True) # From d4cbc8c58570b027adbc155b7f39d0c2faaf3f38 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 26 Mar 2024 13:03:46 -0600 Subject: [PATCH 023/444] Bug-fix discovered by izumi_nag test --- src/main/surfrdUtilsMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/surfrdUtilsMod.F90 b/src/main/surfrdUtilsMod.F90 index 97f5b7d80f..ac7c1304b8 100644 --- a/src/main/surfrdUtilsMod.F90 +++ b/src/main/surfrdUtilsMod.F90 @@ -282,8 +282,8 @@ subroutine collapse_to_dominant(weight, lower_bound, upper_bound, begg, endg, n_ ! original sum of all the weights wt_sum(g) = sum(weight(g,:)) - if (present(do_not_collapse) .and. do_not_collapse(g)) then - cycle + if (present(do_not_collapse)) then + if (do_not_collapse(g)) cycle end if max_indices = 0 ! initialize From f06ceb8c8e3b47d96f363a7d2c681c7a68c1432e Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 26 Mar 2024 13:15:26 -0600 Subject: [PATCH 024/444] Update derecho test from failing P64x2 to passing P24x2 --- cime_config/testdefs/testlist_clm.xml | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 3d713e98ec..04200b7271 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2835,19 +2835,7 @@ - - - - - - - - - - - - - + From 0ebb7e0415809c49250ecbc1bbd355227068ae35 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Wed, 27 Mar 2024 13:22:13 -0600 Subject: [PATCH 025/444] Rename isspinup -> spinup_matrixcn, is_outmatrix -> hist_wrt_matrixcn_diag Ran aux_clm on derecho and got expected results --- bld/CLMBuildNamelist.pm | 28 +++++++++---------- bld/namelist_files/namelist_defaults_ctsm.xml | 16 +++++------ .../namelist_definition_ctsm.xml | 6 ++-- bld/unit_testers/build-namelist_test.pl | 18 ++++++------ cime_config/SystemTests/sspmatrixcn.py | 2 +- .../clm/ciso_monthly_matrixcn/user_nl_clm | 2 +- src/biogeochem/CNVegMatrixMod.F90 | 14 +++++----- src/main/clm_varctl.F90 | 4 +-- src/main/controlMod.F90 | 10 +++---- src/soilbiogeochem/CNSoilMatrixMod.F90 | 16 +++++------ 10 files changed, 58 insertions(+), 58 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 67b8bd3b5c..ca0221277f 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -114,7 +114,7 @@ OPTIONS off : run in normal mode (spinup_state = 0) To spinup using the CN soil matrix method use "sasu" SemiAnalytic Spin-Up (SASU) - sasu: Turn on matrix spinup (isspinup=T) + sasu: Turn on matrix spinup (spinup_matrixcn=T) Normal spinup sequence is: on, sasu, off Default is set by clm_accelerated_spinup mode. @@ -1234,21 +1234,21 @@ sub setup_cmdl_spinup { } $nl_flags->{$var} = $val; if ( &value_is_true($nl_flags->{'use_soil_matrixcn'}) ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "isspinup", + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "spinup_matrixcn", , 'use_fates'=>$nl_flags->{'use_fates'}, 'bgc_mode'=>$nl_flags->{'bgc_mode'} , 'phys'=>$nl_flags->{'phys'}, 'use_soil_matrixcn'=>$nl_flags->{'use_soil_matrixcn'}, , clm_accelerated_spinup=>$nl_flags->{'clm_accelerated_spinup'} ); my $spinup; - if ( &value_is_true($nl->get_value("isspinup") ) ) { + if ( &value_is_true($nl->get_value("spinup_matrixcn") ) ) { $spinup = ".true."; } else { $spinup = ".false."; } - $nl_flags->{'isspinup'} = $spinup; - if ( &value_is_true($nl_flags->{'isspinup'}) ) { + $nl_flags->{'spinup_matrixcn'} = $spinup; + if ( &value_is_true($nl_flags->{'spinup_matrixcn'}) ) { $nl_flags->{'bgc_spinup'} = "on"; if ( $nl_flags->{'clm_accelerated_spinup'} eq "off" ) { - $log->fatal_error("matrix spinup (isspinup) is True, but clm_accelerated_spinup is off, change one or the other"); + $log->fatal_error("matrix spinup (spinup_matrixcn) is True, but clm_accelerated_spinup is off, change one or the other"); } } else { $nl_flags->{'bgc_spinup'} = "off"; @@ -4569,14 +4569,14 @@ sub setup_logic_cnmatrix { # my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; - my @matrixlist = ( "use_matrixcn", "is_outmatrix" ); + my @matrixlist = ( "use_matrixcn", "hist_wrt_matrixcn_diag" ); foreach my $var ( @matrixlist ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var , 'use_fates'=>$nl_flags->{'use_fates'}, 'bgc_mode'=>$nl_flags->{'bgc_mode'} , 'phys'=>$nl_flags->{'phys'}, 'use_soil_matrixcn'=>$nl_flags->{'use_soil_matrixcn'}, - , 'isspinup'=>$nl_flags->{'isspinup'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} ); + , 'spinup_matrixcn'=>$nl_flags->{'spinup_matrixcn'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} ); } - @matrixlist = ( "use_matrixcn", "use_soil_matrixcn", "is_outmatrix", "isspinup" ); + @matrixlist = ( "use_matrixcn", "use_soil_matrixcn", "hist_wrt_matrixcn_diag", "spinup_matrixcn" ); # Matrix items can't be on for SP mode if ( $nl_flags->{'bgc_mode'} eq "sp" ) { foreach my $var ( @matrixlist ) { @@ -4607,14 +4607,14 @@ sub setup_logic_cnmatrix { } # If both matrixcn and soil_matrix are off outmatrix can't be on if ( ! &value_is_true($nl->get_value("use_matrixcn")) && ! &value_is_true($nl_flags->{"use_soil_matrixcn"}) ) { - my $var = "is_outmatrix"; + my $var = "hist_wrt_matrixcn_diag"; if ( &value_is_true($nl->get_value($var)) ) { $log->fatal_error("$var can NOT be on when both use_matrixcn and use_soil_matrixcn are off" ); } } # If soil_matrix is off ispspinup can't be on if ( ! &value_is_true($nl_flags->{"use_soil_matrixcn"}) ) { - my $var = "isspinup"; + my $var = "spinup_matrixcn"; if ( &value_is_true($nl->get_value($var)) ) { $log->fatal_error("$var can NOT be on when use_soil_matrixcn is off" ); } @@ -4623,10 +4623,10 @@ sub setup_logic_cnmatrix { # if soil matrix is on and spinup is on, set spinup specific variables my @spinup_vars = ( "nyr_forcing", "nyr_sasu", "iloop_avg" ); foreach my $var ( @spinup_vars ) { - if ( &value_is_true($nl_flags->{"use_soil_matrixcn"}) && &value_is_true($nl_flags->{'isspinup'}) ) { + if ( &value_is_true($nl_flags->{"use_soil_matrixcn"}) && &value_is_true($nl_flags->{'spinup_matrixcn'}) ) { if ( $var ne "nyr_sasu" ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - , 'phys'=>$nl_flags->{'phys'}, 'isspinup'=>$nl_flags->{'isspinup'} ); + , 'phys'=>$nl_flags->{'phys'}, 'spinup_matrixcn'=>$nl_flags->{'spinup_matrixcn'} ); } else { # Set SASU spinup period to nyr_forcing (slow mode) by default add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, @@ -4644,7 +4644,7 @@ sub setup_logic_cnmatrix { } } } - if ( &value_is_true($nl_flags->{"use_soil_matrixcn"}) && &value_is_true($nl_flags->{'isspinup'}) ) { + if ( &value_is_true($nl_flags->{"use_soil_matrixcn"}) && &value_is_true($nl_flags->{'spinup_matrixcn'}) ) { my $nyr_forcing = $nl->get_value('nyr_forcing'); my $nyr_sasu = $nl->get_value('nyr_sasu'); if ( $nyr_sasu > $nyr_forcing ) { diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index f2e42dd6e0..1455bbf873 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -661,18 +661,18 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. .false. -.false. -.false. -.false. -.true. -.true. -.false. +.false. +.false. +.false. +.true. +.true. +.false. 1 -20 +20 1 -999 --999 +-999 diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 5214c20942..4cf8b8ad7d 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1149,12 +1149,12 @@ Turn on the Matrix solution for above ground biogeochemistry, requires CN to be Turn on the Matrix solution for soil biogeochemistry - Turn on extra output for the matrix solution - Turn on semi-analytic spinup solution for the CN/Soil matrix, requires soil matrix to be on This will drive the solution to equilibrium @@ -1162,7 +1162,7 @@ This will drive the solution to equilibrium -Number of years to average the storage capacitance over for the soil Matrix solution during semi-analytic spinup (isspinup=T) +Number of years to average the storage capacitance over for the soil Matrix solution during semi-analytic spinup (spinup_matrixcn=T) Normally should be the same as the number of years the atmospheric forcing is run over diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 3c3a42abc9..83429d2f18 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -326,8 +326,8 @@ sub cat_and_create_namelistinfile { "-res 0.9x1.25 -use_case 1850_control", "-res 1x1pt_US-UMB -clm_usr_name 1x1pt_US-UMB -namelist '&a fsurdat=\"/dev/null\"/'", "-res 1x1_brazil", - "-namelist '&a use_matrixcn=F,use_soil_matrixcn=F,is_outmatrix=F,isspinup=F/' -bgc sp", - "-namelist '&a use_matrixcn=T,use_soil_matrixcn=T,is_outmatrix=T,isspinup=T/' -bgc bgc -crop -clm_accelerated_spinup on", + "-namelist '&a use_matrixcn=F,use_soil_matrixcn=F,hist_wrt_matrixcn_diag=F,spinup_matrixcn=F/' -bgc sp", + "-namelist '&a use_matrixcn=T,use_soil_matrixcn=T,hist_wrt_matrixcn_diag=T,spinup_matrixcn=T/' -bgc bgc -crop -clm_accelerated_spinup on", "-namelist \"&a soil_decomp_method='MIMICSWieder2015',use_matrixcn=F/\" -bgc bgc -crop", "-namelist \"&a soil_decomp_method='MIMICSWieder2015',use_matrixcn=T/\" -bgc bgc -crop", "-bgc bgc -crop -clm_accelerated_spinup sasu", @@ -970,12 +970,12 @@ sub cat_and_create_namelistinfile { phys=>"clm5_0", }, "outmatrixWOmatrix" =>{ options=>"-envxml_dir . -bgc bgc", - namelst=>"use_soil_matrixcn=.false.,use_matrixcn=F,is_outmatrix=T", + namelst=>"use_soil_matrixcn=.false.,use_matrixcn=F,hist_wrt_matrixcn_diag=T", GLC_TWO_WAY_COUPLING=>"TRUE", phys=>"clm5_0", }, "spinupWOsoilmatrix" =>{ options=>"-envxml_dir . -bgc bgc", - namelst=>"use_soil_matrixcn=F,use_matrixcn=T,isspinup=T", + namelst=>"use_soil_matrixcn=F,use_matrixcn=T,spinup_matrixcn=T", GLC_TWO_WAY_COUPLING=>"TRUE", phys=>"clm5_0", }, @@ -990,27 +990,27 @@ sub cat_and_create_namelistinfile { phys=>"clm5_1", }, "nyrforceWOspinup" =>{ options=>"-envxml_dir . -bgc bgc -clm_accelerated_spinup sasu", - namelst=>"use_matrixcn=.false.,isspinup=F,nyr_forcing=20", + namelst=>"use_matrixcn=.false.,spinup_matrixcn=F,nyr_forcing=20", GLC_TWO_WAY_COUPLING=>"TRUE", phys=>"clm5_0", }, "nyrsasuGTnyrforce" =>{ options=>"-envxml_dir . -bgc bgc -clm_accelerated_spinup sasu", - namelst=>"use_matrixcn=.false.,isspinup=T,nyr_forcing=20,nyr_sasu=21", + namelst=>"use_matrixcn=.false.,spinup_matrixcn=T,nyr_forcing=20,nyr_sasu=21", GLC_TWO_WAY_COUPLING=>"TRUE", phys=>"clm5_0", }, "iloopZero" =>{ options=>"-envxml_dir . -bgc bgc -clm_accelerated_spinup sasu", - namelst=>"use_matrixcn=.false.,isspinup=T,iloop_avg=0", + namelst=>"use_matrixcn=.false.,spinup_matrixcn=T,iloop_avg=0", GLC_TWO_WAY_COUPLING=>"TRUE", phys=>"clm5_0", }, "matrixspinupWADmode" =>{ options=>"-envxml_dir . -bgc bgc -clm_accelerated_spinup sasu", - namelst=>"isspinup=T,spinup_state=2", + namelst=>"spinup_matrixcn=T,spinup_state=2", GLC_TWO_WAY_COUPLING=>"TRUE", phys=>"clm5_0", }, "matrixspinupWclmaccell" =>{ options=>"-envxml_dir . -bgc bgc -clm_accelerated_spinup off", - namelst=>"use_soil_matrixcn=T,isspinup=T", + namelst=>"use_soil_matrixcn=T,spinup_matrixcn=T", GLC_TWO_WAY_COUPLING=>"TRUE", phys=>"clm5_0", }, diff --git a/cime_config/SystemTests/sspmatrixcn.py b/cime_config/SystemTests/sspmatrixcn.py index eec462e72c..0e0d57e6c2 100644 --- a/cime_config/SystemTests/sspmatrixcn.py +++ b/cime_config/SystemTests/sspmatrixcn.py @@ -130,7 +130,7 @@ def append_user_nl(self, caseroot, n=0): # For all but last step turn extra matrix output to off b4last = self.n_steps() - 1 if ( n < b4last ): - contents_to_append = contents_to_append + ", is_outmatrix = .False." + contents_to_append = contents_to_append + ", hist_wrt_matrixcn_diag = .False." # For matrix spinup steps, set the matrix spinup and other variables associated with it if ( self.spin[n] == "sasu" ): contents_to_append = contents_to_append + ", nyr_forcing = "+str(self.nyr_forcing) diff --git a/cime_config/testdefs/testmods_dirs/clm/ciso_monthly_matrixcn/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/ciso_monthly_matrixcn/user_nl_clm index 56d4261a45..6b7eb4347d 100644 --- a/cime_config/testdefs/testmods_dirs/clm/ciso_monthly_matrixcn/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/ciso_monthly_matrixcn/user_nl_clm @@ -1,3 +1,3 @@ use_matrixcn = .true. use_soil_matrixcn = .true. - is_outmatrix = .true. + hist_wrt_matrixcn_diag = .true. diff --git a/src/biogeochem/CNVegMatrixMod.F90 b/src/biogeochem/CNVegMatrixMod.F90 index c171490bf0..bf7527bc71 100644 --- a/src/biogeochem/CNVegMatrixMod.F90 +++ b/src/biogeochem/CNVegMatrixMod.F90 @@ -41,7 +41,7 @@ module CNVegMatrixMod use CNVegNitrogenFluxType , only : cnveg_nitrogenflux_type use CNVegStateType , only : cnveg_state_type use SoilBiogeochemNitrogenFluxType , only : soilbiogeochem_nitrogenflux_type - use clm_varctl , only : isspinup, is_outmatrix, nyr_forcing, nyr_SASU, iloop_avg + use clm_varctl , only : spinup_matrixcn, hist_wrt_matrixcn_diag, nyr_forcing, nyr_SASU, iloop_avg use clm_varctl , only : use_c13, use_c14 use SparseMatrixMultiplyMod , only : sparse_matrix_type,diag_matrix_type,vector_type use MatrixMod , only : inverse @@ -1253,7 +1253,7 @@ subroutine CNVegMatrix(bounds,num_soilp,filter_soilp,num_actfirep,filter_actfire if(mod(iyr-1,nyr_forcing) .eq. 0)then iloop = iloop + 1 end if - if(.not. isspinup .or. isspinup .and. mod(iyr-1,nyr_SASU) .eq. 0)then + if(.not. spinup_matrixcn .or. spinup_matrixcn .and. mod(iyr-1,nyr_SASU) .eq. 0)then do fp = 1,num_soilp p = filter_soilp(fp) leafc0(p) = max(leafc(p), epsi) @@ -1683,7 +1683,7 @@ subroutine CNVegMatrix(bounds,num_soilp,filter_soilp,num_actfirep,filter_actfire ! Accumulate transfers during the whole calendar year call t_startf('CN veg matrix-accum. trans.') - if(isspinup .or. is_outmatrix)then + if(spinup_matrixcn .or. hist_wrt_matrixcn_diag)then do fp = 1,num_soilp p = filter_soilp(fp) matrix_calloc_leaf_acc(p) = matrix_calloc_leaf_acc(p) + vegmatrixc_input%V(p,ileaf) @@ -2439,8 +2439,8 @@ subroutine CNVegMatrix(bounds,num_soilp,filter_soilp,num_actfirep,filter_actfire call t_stopf('CN veg matrix-assign new value') ! Calculate C storage capacity. 2D matrix instead of sparse matrix is still used when calculating the inverse - if(isspinup .or. is_outmatrix)then - if((.not. isspinup .and. is_end_curr_year()) .or. (isspinup .and. is_end_curr_year() .and. mod(iyr,nyr_SASU) .eq. 0))then + if(spinup_matrixcn .or. hist_wrt_matrixcn_diag)then + if((.not. spinup_matrixcn .and. is_end_curr_year()) .or. (spinup_matrixcn .and. is_end_curr_year() .and. mod(iyr,nyr_SASU) .eq. 0))then do fp = 1,num_soilp call t_startf('CN veg matrix-prepare AK^-1') p = filter_soilp(fp) @@ -2881,7 +2881,7 @@ subroutine CNVegMatrix(bounds,num_soilp,filter_soilp,num_actfirep,filter_actfire call t_startf('CN veg matrix-finalize spinup') - if(isspinup .and. .not. is_first_step_of_this_run_segment())then + if(spinup_matrixcn .and. .not. is_first_step_of_this_run_segment())then deadstemc(p) = vegmatrixc_rt(ideadstem) deadstemc_storage(p) = vegmatrixc_rt(ideadstem_st) deadcrootc(p) = vegmatrixc_rt(ideadcroot) @@ -3184,7 +3184,7 @@ subroutine CNVegMatrix(bounds,num_soilp,filter_soilp,num_actfirep,filter_actfire end if ! Save C storage capacity from temporary variables to module variables - if(is_outmatrix)then + if(hist_wrt_matrixcn_diag)then matrix_cap_leafc(p) = vegmatrixc_rt(ileaf) matrix_cap_leafc_storage(p) = vegmatrixc_rt(ileaf_st) matrix_cap_leafc_xfer(p) = vegmatrixc_rt(ileaf_xf) diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index ffc43b4200..faead44399 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -280,8 +280,8 @@ module clm_varctl !---------------------------------------------------------- ! CN matrix !---------------------------------------------------------- - logical, public :: isspinup = .false. !.false. ! true => use acc spinup - logical, public :: is_outmatrix = .false.!.false. ! true => use acc spinup + logical, public :: spinup_matrixcn = .false. !.false. ! true => use acc spinup + logical, public :: hist_wrt_matrixcn_diag = .false.!.false. ! true => use acc spinup ! SASU integer, public :: nyr_forcing = 10 ! length of forcing years for the spin up. eg. if DATM_CLMNCEP_YR_START=1901;DATM_CLMNCEP_YR_END=1920, then nyr_forcing = 20 integer, public :: nyr_SASU = 1 ! length of each semi-analytic solution. eg. nyr_SASU=5, analytic solutions will be calculated every five years. diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index ef006bcc42..acb4d6491b 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -189,7 +189,7 @@ subroutine control_init(dtime) ! CN Matrix solution namelist /clm_inparm / & - use_matrixcn, use_soil_matrixcn, is_outmatrix, isspinup, nyr_forcing, nyr_sasu, iloop_avg + use_matrixcn, use_soil_matrixcn, hist_wrt_matrixcn_diag, spinup_matrixcn, nyr_forcing, nyr_sasu, iloop_avg ! lake_melt_icealb is of dimension numrad @@ -325,8 +325,8 @@ subroutine control_init(dtime) if(use_fates)then use_matrixcn = .false. use_soil_matrixcn = .false. - is_outmatrix = .false. - isspinup = .false. + hist_wrt_matrixcn_diag = .false. + spinup_matrixcn = .false. end if nyr_forcing = 10 @@ -850,8 +850,8 @@ subroutine control_spmd() call mpi_bcast (use_dynroot, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_matrixcn, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_soil_matrixcn, 1, MPI_LOGICAL, 0, mpicom, ier) - call mpi_bcast (is_outmatrix, 1, MPI_LOGICAL, 0, mpicom, ier) - call mpi_bcast (isspinup, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (hist_wrt_matrixcn_diag, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (spinup_matrixcn, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (nyr_forcing, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (nyr_sasu, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (iloop_avg, 1, MPI_INTEGER, 0, mpicom, ier) diff --git a/src/soilbiogeochem/CNSoilMatrixMod.F90 b/src/soilbiogeochem/CNSoilMatrixMod.F90 index 1248c5e1d6..56c1f11b5c 100644 --- a/src/soilbiogeochem/CNSoilMatrixMod.F90 +++ b/src/soilbiogeochem/CNSoilMatrixMod.F90 @@ -34,7 +34,7 @@ module CNSoilMatrixMod use SoilBiogeochemNitrogenFluxType , only : soilbiogeochem_nitrogenflux_type use CNSharedParamsMod , only : CNParamsShareInst use SoilStateType , only : soilstate_type - use clm_varctl , only : isspinup, is_outmatrix, nyr_forcing, nyr_SASU, iloop_avg + use clm_varctl , only : spinup_matrixcn, hist_wrt_matrixcn_diag, nyr_forcing, nyr_SASU, iloop_avg use ColumnType , only : col use GridcellType , only : grc use clm_varctl , only : use_c13, use_c14, iulog @@ -67,14 +67,14 @@ subroutine CNSoilMatrixInit( ) if ( use_soil_matrixcn ) then write(iulog,*) 'CN Soil matrix solution is on' write(iulog,*) '*****************************' - if ( isspinup ) then + if ( spinup_matrixcn ) then write(iulog,*) ' Matrix spinup is on' write(iulog,*) ' *******************' write(iulog,*) ' nyr_forcing = ', nyr_forcing write(iulog,*) ' nyr_SASU = ', nyr_SASU write(iulog,*) ' iloop_avg = ', iloop_avg end if - if ( is_outmatrix )then + if ( hist_wrt_matrixcn_diag )then write(iulog,*) ' Extra matrix solution tracability output is turned on' else write(iulog,*) ' no extra matrix solution tracability output' @@ -343,7 +343,7 @@ subroutine CNSoilMatrix(bounds,num_soilc, filter_soilc, num_actfirec, filter_act if(mod(iyr-1,nyr_forcing) .eq. 0)then iloop = iloop + 1 end if - if(.not. isspinup .or. isspinup .and. mod(iyr-1,nyr_SASU) .eq. 0)then + if(.not. spinup_matrixcn .or. spinup_matrixcn .and. mod(iyr-1,nyr_SASU) .eq. 0)then do i = 1,ndecomp_pools do j = 1, nlevdecomp do fc = 1,num_soilc @@ -550,7 +550,7 @@ subroutine CNSoilMatrix(bounds,num_soilc, filter_soilc, num_actfirec, filter_act call t_stopf('CN Soil matrix-assign back') - if(use_soil_matrixcn .and. (is_outmatrix .or. isspinup))then + if(use_soil_matrixcn .and. (hist_wrt_matrixcn_diag .or. spinup_matrixcn))then ! Accumulate C transfers during a whole calendar year to calculate the C and N capacity do j=1,ndecomp_pools*nlevdecomp @@ -665,7 +665,7 @@ subroutine CNSoilMatrix(bounds,num_soilc, filter_soilc, num_actfirec, filter_act end if call t_startf('CN Soil matrix-calc. C capacity') - if((.not. isspinup .and. is_end_curr_year()) .or. (isspinup .and. is_end_curr_year() .and. mod(iyr,nyr_SASU) .eq. 0))then + if((.not. spinup_matrixcn .and. is_end_curr_year()) .or. (spinup_matrixcn .and. is_end_curr_year() .and. mod(iyr,nyr_SASU) .eq. 0))then ! Copy C transfers from sparse matrix to 2D temporary variables tran_acc and tran_nacc ! Calculate the C and N transfer rate by dividing CN transfer by base value saved at begin of each year. do fc = 1,num_soilc @@ -816,7 +816,7 @@ subroutine CNSoilMatrix(bounds,num_soilc, filter_soilc, num_actfirec, filter_act do j = 1,nlevdecomp do fc = 1,num_soilc c = filter_soilc(fc) - if(isspinup .and. .not. is_first_step_of_this_run_segment())then + if(spinup_matrixcn .and. .not. is_first_step_of_this_run_segment())then cs_soil%decomp_cpools_vr_col(c,j,i) = soilmatrixc_cap(c,j+(i-1)*nlevdecomp,1) if(use_c13)then cs13_soil%decomp_cpools_vr_col(c,j,i) = soilmatrixc13_cap(c,j+(i-1)*nlevdecomp,1) @@ -871,7 +871,7 @@ subroutine CNSoilMatrix(bounds,num_soilc, filter_soilc, num_actfirec, filter_act end do end do - if(isspinup)call update_DA_nstep() + if(spinup_matrixcn)call update_DA_nstep() if(iloop .eq. iloop_avg .and. iyr .eq. nyr_forcing)iloop = 0 if(iyr .eq. nyr_forcing)iyr = 0 From 1a2ddffdffbae8b3140b0e751b530f21db9c5afb Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Wed, 27 Mar 2024 13:24:58 -0600 Subject: [PATCH 026/444] Replace 1.e+36 with spval in cnmatrix code --- src/biogeochem/CNVegMatrixMod.F90 | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/biogeochem/CNVegMatrixMod.F90 b/src/biogeochem/CNVegMatrixMod.F90 index bf7527bc71..5582afeffe 100644 --- a/src/biogeochem/CNVegMatrixMod.F90 +++ b/src/biogeochem/CNVegMatrixMod.F90 @@ -23,6 +23,7 @@ module CNVegMatrixMod use clm_time_manager , only : get_step_size,is_end_curr_year,is_first_step_of_this_run_segment,& is_beg_curr_year,update_DA_nstep use decompMod , only : bounds_type + use clm_varcon , only : spval use clm_varpar , only : nlevdecomp, nvegcpool, nvegnpool use clm_varpar , only : ileaf,ileaf_st,ileaf_xf,ifroot,ifroot_st,ifroot_xf,& ilivestem,ilivestem_st,ilivestem_xf,& @@ -2711,27 +2712,27 @@ subroutine CNVegMatrix(bounds,num_soilp,filter_soilp,num_actfirep,filter_actfire matrix_ntransfer_acc(iretransn,iretransn) = -matrix_nturnover_retransn_acc(p) do i=1,nvegcpool - if(matrix_ctransfer_acc(i,i) .eq. 0)then - matrix_ctransfer_acc(i,i) = 1.e+36 + if(matrix_ctransfer_acc(i,i) == 0)then + matrix_ctransfer_acc(i,i) = spval end if end do if(use_c13)then do i=1,nvegcpool - if(matrix_c13transfer_acc(i,i) .eq. 0)then - matrix_c13transfer_acc(i,i) = 1.e+36 + if(matrix_c13transfer_acc(i,i) == 0)then + matrix_c13transfer_acc(i,i) = spval end if end do end if if(use_c14)then do i=1,nvegcpool - if(matrix_c14transfer_acc(i,i) .eq. 0)then - matrix_c14transfer_acc(i,i) = 1.e+36 + if(matrix_c14transfer_acc(i,i) == 0)then + matrix_c14transfer_acc(i,i) = spval end if end do end if do i=1,nvegnpool - if(matrix_ntransfer_acc(i,i) .eq. 0)then - matrix_ntransfer_acc(i,i) = 1.e+36 + if(matrix_ntransfer_acc(i,i) == 0)then + matrix_ntransfer_acc(i,i) = spval end if end do From 47839a77229c61555e3b8932927bb54cdc511b27 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Wed, 27 Mar 2024 14:39:43 -0600 Subject: [PATCH 027/444] Black reformatting of two files --- cime_config/SystemTests/sspmatrixcn.py | 455 ++++++++++++++----------- cime_config/buildnml | 72 ++-- 2 files changed, 295 insertions(+), 232 deletions(-) diff --git a/cime_config/SystemTests/sspmatrixcn.py b/cime_config/SystemTests/sspmatrixcn.py index 0e0d57e6c2..37d4154121 100644 --- a/cime_config/SystemTests/sspmatrixcn.py +++ b/cime_config/SystemTests/sspmatrixcn.py @@ -14,15 +14,15 @@ """ import shutil, glob, os, sys -if __name__ == '__main__': - CIMEROOT = os.environ.get("CIMEROOT") - if CIMEROOT is None: - CIMEROOT = "../../cime"; +if __name__ == "__main__": + CIMEROOT = os.environ.get("CIMEROOT") + if CIMEROOT is None: + CIMEROOT = "../../cime" - sys.path.append(os.path.join( CIMEROOT, "scripts", "lib")) - sys.path.append(os.path.join( CIMEROOT, "scripts" ) ) + sys.path.append(os.path.join(CIMEROOT, "scripts", "lib")) + sys.path.append(os.path.join(CIMEROOT, "scripts")) else: - from CIME.utils import append_testlog + from CIME.utils import append_testlog from CIME.XML.standard_module_setup import * from CIME.SystemTests.system_tests_common import SystemTestsCommon @@ -31,123 +31,170 @@ logger = logging.getLogger(__name__) + class SSPMATRIXCN(SystemTestsCommon): # Class data nyr_forcing = 2 # Get different integer multiples of the number of forcing years - full = nyr_forcing - twice = 2 * nyr_forcing + full = nyr_forcing + twice = 2 * nyr_forcing thrice = 3 * nyr_forcing # Define the settings that will be used for each step - steps = ["0-AD", "1-SASU", "2-norm" ] - desc = ["Accell-Decomp(AD)-coldstart", "slow-mode Semi-Analytic SpinUp(SASU)", "normal" ] - runtyp = ["startup", "hybrid", "branch" ] - spin = ["on", "sasu", "off" ] - stop_n = [5, thrice, thrice ] - cold = [True, False, False ] - iloop = [-999, -999, -999 ] - sasu = [-999, -999, -999 ] + steps = ["0-AD", "1-SASU", "2-norm"] + desc = [ + "Accell-Decomp(AD)-coldstart", + "slow-mode Semi-Analytic SpinUp(SASU)", + "normal", + ] + runtyp = ["startup", "hybrid", "branch"] + spin = ["on", "sasu", "off"] + stop_n = [5, thrice, thrice] + cold = [True, False, False] + iloop = [-999, -999, -999] + sasu = [-999, -999, -999] def __init__(self, case=None): """ initialize an object interface to the SSPMATRIXCN system test """ - expect ( len(self.steps) == len(self.sasu), "length of steps must be the same as sasu" ) - expect ( len(self.steps) == len(self.spin), "length of steps must be the same as spin" ) - expect ( len(self.steps) == len(self.desc), "length of steps must be the same as desc" ) - expect ( len(self.steps) == len(self.cold), "length of steps must be the same as cold" ) - expect ( len(self.steps) == len(self.runtyp), "length of steps must be the same as runtyp" ) - expect ( len(self.steps) == len(self.iloop), "length of steps must be the same as iloop" ) - expect ( len(self.steps) == len(self.stop_n), "length of steps must be the same as stop_n" ) - - if __name__ != '__main__': - SystemTestsCommon.__init__(self, case) - ystart = int(self._case.get_value("DATM_YR_START")) - yend = int(self._case.get_value("DATM_YR_END")) - self.comp = self._case.get_value("COMP_LND") + expect( + len(self.steps) == len(self.sasu), + "length of steps must be the same as sasu", + ) + expect( + len(self.steps) == len(self.spin), + "length of steps must be the same as spin", + ) + expect( + len(self.steps) == len(self.desc), + "length of steps must be the same as desc", + ) + expect( + len(self.steps) == len(self.cold), + "length of steps must be the same as cold", + ) + expect( + len(self.steps) == len(self.runtyp), + "length of steps must be the same as runtyp", + ) + expect( + len(self.steps) == len(self.iloop), + "length of steps must be the same as iloop", + ) + expect( + len(self.steps) == len(self.stop_n), + "length of steps must be the same as stop_n", + ) + + if __name__ != "__main__": + SystemTestsCommon.__init__(self, case) + ystart = int(self._case.get_value("DATM_YR_START")) + yend = int(self._case.get_value("DATM_YR_END")) + self.comp = self._case.get_value("COMP_LND") else: - self._case = None - self.comp = "clm" - ystart = 2000 - yend = 2001 + self._case = None + self.comp = "clm" + ystart = 2000 + yend = 2001 for n in range(len(self.steps)): - if ( n == 0 ): - expect( self.cold[n] == True, "First step MUST be a cold-start" ) - expect( self.runtyp[n] == "startup", "First step MUST be a startup" ) - else: - expect( self.cold[n] == False, "Other steps must NOT be a cold-start" ) - expect( self.runtyp[n] != "startup", "Other steps MUST NOT be a startup" ) - - if ( self.spin[n] == "sasu" ): - expect( self.cold[n] == False, "SASU step should NOT be a cold-start" ) - if ( self.sasu[n] != -999 ): - expect( self.sasu[n] > 0, "SASU steps must set SASU cycle" ) - expect( self.sasu[n] <= self.nyr_forcing, "SASU cycles can't be greater than a full forcing cycle" ) - - expect( yend-ystart+1 == self.nyr_forcing, "Number of years run over MUST correspond to nyr_forcing" ) + if n == 0: + expect(self.cold[n] == True, "First step MUST be a cold-start") + expect(self.runtyp[n] == "startup", "First step MUST be a startup") + else: + expect(self.cold[n] == False, "Other steps must NOT be a cold-start") + expect(self.runtyp[n] != "startup", "Other steps MUST NOT be a startup") + + if self.spin[n] == "sasu": + expect(self.cold[n] == False, "SASU step should NOT be a cold-start") + if self.sasu[n] != -999: + expect(self.sasu[n] > 0, "SASU steps must set SASU cycle") + expect( + self.sasu[n] <= self.nyr_forcing, + "SASU cycles can't be greater than a full forcing cycle", + ) + + expect( + yend - ystart + 1 == self.nyr_forcing, + "Number of years run over MUST correspond to nyr_forcing", + ) self._testname = "SSPMATRIX" - def check_n( self, n): + def check_n(self, n): "Check if n is within range" - expect( ( (n >= 0) and (n < self.n_steps()) ), "Step number is out of range = " + str(n) ) + expect( + ((n >= 0) and (n < self.n_steps())), + "Step number is out of range = " + str(n), + ) def __logger__(self, n=0): "Log info on this step" - self.check_n( n ) - msg = "Step {}: {}: doing a {} run for {} years".format( self.steps[n], self.runtyp[n], self.desc[n], self.stop_n[n] ) + self.check_n(n) + msg = "Step {}: {}: doing a {} run for {} years".format( + self.steps[n], self.runtyp[n], self.desc[n], self.stop_n[n] + ) logger.info(msg) - logger.info(" spinup type: {}".format( self.spin[n] ) ) - if __name__ != '__main__': - append_testlog(msg) - if ( n+1 < self.n_steps() ): - logger.info(" writing restarts at end of run") - logger.info(" short term archiving is on ") + logger.info(" spinup type: {}".format(self.spin[n])) + if __name__ != "__main__": + append_testlog(msg) + if n + 1 < self.n_steps(): + logger.info(" writing restarts at end of run") + logger.info(" short term archiving is on ") def n_steps(self): "Total number of steps" - return( len(self.steps) ) + return len(self.steps) def total_years(self): "Total number of years needed to do the full spinup" ysum = 0 for nyr in self.stop_n: - ysum = ysum + nyr + ysum = ysum + nyr - return( ysum ) + return ysum def append_user_nl(self, caseroot, n=0): "Append needed settings to the user_nl files" - self.check_n( n ) + self.check_n(n) # For all set output to yearly contents_to_append = "hist_nhtfrq = -8760" - contents_to_append = contents_to_append + ", hist_mfilt = "+str(self.nyr_forcing) + contents_to_append = ( + contents_to_append + ", hist_mfilt = " + str(self.nyr_forcing) + ) # For all but last step turn extra matrix output to off b4last = self.n_steps() - 1 - if ( n < b4last ): - contents_to_append = contents_to_append + ", hist_wrt_matrixcn_diag = .False." + if n < b4last: + contents_to_append = ( + contents_to_append + ", hist_wrt_matrixcn_diag = .False." + ) # For matrix spinup steps, set the matrix spinup and other variables associated with it - if ( self.spin[n] == "sasu" ): - contents_to_append = contents_to_append + ", nyr_forcing = "+str(self.nyr_forcing) - if ( self.sasu[n] != -999 ): - contents_to_append = contents_to_append + ", nyr_sasu = " + str(self.sasu[n]) - if ( self.iloop[n] != -999 ): - contents_to_append = contents_to_append + ", iloop_avg = " + str(self.iloop[n]) + if self.spin[n] == "sasu": + contents_to_append = ( + contents_to_append + ", nyr_forcing = " + str(self.nyr_forcing) + ) + if self.sasu[n] != -999: + contents_to_append = ( + contents_to_append + ", nyr_sasu = " + str(self.sasu[n]) + ) + if self.iloop[n] != -999: + contents_to_append = ( + contents_to_append + ", iloop_avg = " + str(self.iloop[n]) + ) # For cold start, run with matrix off - if ( self.cold[n] ): + if self.cold[n]: contents_to_append = contents_to_append + ", use_matrixcn = .False." contents_to_append = contents_to_append + ", use_soil_matrixcn = .False." # Always append to the end - user_nl_utils.append_to_user_nl_files(caseroot = caseroot, - component = self.comp, - contents = contents_to_append) + user_nl_utils.append_to_user_nl_files( + caseroot=caseroot, component=self.comp, contents=contents_to_append + ) def run_phase(self): "Run phase" @@ -156,77 +203,80 @@ def run_phase(self): orig_case = self._case orig_casevar = self._case.get_value("CASE") - # Get a clone of each step except the last one b4last = self.n_steps() - 1 for n in range(b4last): - # - # Clone the main case, and get it setup for the next step - # - clone_path = "{}.step{}".format(caseroot,self.steps[n]) - if os.path.exists(clone_path): - shutil.rmtree(clone_path) - if ( n > 0 ): - del clone - self._set_active_case(orig_case) - clone = self._case.create_clone(clone_path, keepexe=True) - os.chdir(clone_path) - self._set_active_case(clone) - - self.__logger__(n) - - with clone: - clone.set_value("RUN_TYPE", self.runtyp[n] ) - clone.set_value("STOP_N", self.stop_n[n] ) - - clone.set_value("CLM_ACCELERATED_SPINUP", self.spin[n] ) - - if ( self.cold[n] ): - clone.set_value("CLM_FORCE_COLDSTART", "on" ) - else: - clone.set_value("CLM_FORCE_COLDSTART", "off" ) - - self.append_user_nl( clone_path, n ) - - dout_sr = clone.get_value("DOUT_S_ROOT") - - self._skip_pnl = False - # - # Start up from the previous case - # - rundir = clone.get_value("RUNDIR") - with clone: - if ( n > 0 ): - clone.set_value("GET_REFCASE", False) - expect( "refcase" in locals(), "refcase was NOT previously set" ) - clone.set_value("RUN_REFCASE", refcase ) - expect( "refdate" in locals(), "refdate was NOT previously set" ) - clone.set_value("RUN_STARTDATE", refdate ) - clone.set_value("RUN_REFDATE", refdate ) - for item in glob.glob("{}/*{}*".format(rest_path, refdate)): - linkfile = os.path.join(rundir, os.path.basename(item)) - if os.path.exists(linkfile): - os.remove( linkfile ) - if not os.path.isdir(rundir): - os.makedirs(rundir) - os.symlink(item, linkfile ) - - for item in glob.glob("{}/*rpointer*".format(rest_path)): - shutil.copy(item, rundir) - - # - # Run the case (Archiving on) - # - self._case.flush() - self.run_indv(suffix="step{}".format(self.steps[n]), st_archive=True) - - # - # Get the reference case from this step for the next step - # - refcase = clone.get_value("CASE") - refdate = run_cmd_no_fail(r'ls -1dt {}/rest/*-00000* | head -1 | sed "s/-00000.*//" | sed "s/^.*rest\///"'.format(dout_sr)) - refsec = "00000" - rest_path = os.path.join(dout_sr, "rest", "{}-{}".format(refdate, refsec)) + # + # Clone the main case, and get it setup for the next step + # + clone_path = "{}.step{}".format(caseroot, self.steps[n]) + if os.path.exists(clone_path): + shutil.rmtree(clone_path) + if n > 0: + del clone + self._set_active_case(orig_case) + clone = self._case.create_clone(clone_path, keepexe=True) + os.chdir(clone_path) + self._set_active_case(clone) + + self.__logger__(n) + + with clone: + clone.set_value("RUN_TYPE", self.runtyp[n]) + clone.set_value("STOP_N", self.stop_n[n]) + + clone.set_value("CLM_ACCELERATED_SPINUP", self.spin[n]) + + if self.cold[n]: + clone.set_value("CLM_FORCE_COLDSTART", "on") + else: + clone.set_value("CLM_FORCE_COLDSTART", "off") + + self.append_user_nl(clone_path, n) + + dout_sr = clone.get_value("DOUT_S_ROOT") + + self._skip_pnl = False + # + # Start up from the previous case + # + rundir = clone.get_value("RUNDIR") + with clone: + if n > 0: + clone.set_value("GET_REFCASE", False) + expect("refcase" in locals(), "refcase was NOT previously set") + clone.set_value("RUN_REFCASE", refcase) + expect("refdate" in locals(), "refdate was NOT previously set") + clone.set_value("RUN_STARTDATE", refdate) + clone.set_value("RUN_REFDATE", refdate) + for item in glob.glob("{}/*{}*".format(rest_path, refdate)): + linkfile = os.path.join(rundir, os.path.basename(item)) + if os.path.exists(linkfile): + os.remove(linkfile) + if not os.path.isdir(rundir): + os.makedirs(rundir) + os.symlink(item, linkfile) + + for item in glob.glob("{}/*rpointer*".format(rest_path)): + shutil.copy(item, rundir) + + # + # Run the case (Archiving on) + # + self._case.flush() + self.run_indv(suffix="step{}".format(self.steps[n]), st_archive=True) + + # + # Get the reference case from this step for the next step + # + refcase = clone.get_value("CASE") + refdate = run_cmd_no_fail( + r'ls -1dt {}/rest/*-00000* | head -1 | sed "s/-00000.*//" | sed "s/^.*rest\///"'.format( + dout_sr + ) + ) + refsec = "00000" + rest_path = os.path.join(dout_sr, "rest", "{}-{}".format(refdate, refsec)) # # Last step in original case @@ -239,25 +289,25 @@ def run_phase(self): self._set_active_case(orig_case) self.__logger__(n) self._case.set_value("DOUT_S", False) - self._case.set_value("RUN_TYPE", self.runtyp[n] ) - self._case.set_value("STOP_N", self.stop_n[n] ) + self._case.set_value("RUN_TYPE", self.runtyp[n]) + self._case.set_value("STOP_N", self.stop_n[n]) rundir = self._case.get_value("RUNDIR") self._case.set_value("GET_REFCASE", False) - expect( "refcase" in locals(), "refcase was NOT previously set" ) + expect("refcase" in locals(), "refcase was NOT previously set") self._case.set_value("RUN_REFCASE", refcase) - expect( "refdate" in locals(), "refdate was NOT previously set" ) + expect("refdate" in locals(), "refdate was NOT previously set") self._case.set_value("RUN_REFDATE", refdate) - self._case.set_value("RUN_STARTDATE", refdate ) + self._case.set_value("RUN_STARTDATE", refdate) for item in glob.glob("{}/*{}*".format(rest_path, refdate)): linkfile = os.path.join(rundir, os.path.basename(item)) if os.path.exists(linkfile): - os.remove( linkfile ) - os.symlink(item, linkfile ) + os.remove(linkfile) + os.symlink(item, linkfile) for item in glob.glob("{}/*rpointer*".format(rest_path)): shutil.copy(item, rundir) - self.append_user_nl( clone_path, n ) + self.append_user_nl(clone_path, n) # # Don't need to set COLDSTART or ACCEL_SPINUP # @@ -266,7 +316,8 @@ def run_phase(self): # Run the case (short term archiving is off) # self._case.flush() - self.run_indv( suffix="step{}".format(self.steps[n]), st_archive=False ) + self.run_indv(suffix="step{}".format(self.steps[n]), st_archive=False) + # # Unit testing for above @@ -274,59 +325,57 @@ def run_phase(self): import unittest from CIME.case import Case from CIME.utils import _LessThanFilter -from argparse import RawTextHelpFormatter +from argparse import RawTextHelpFormatter + class test_ssp_matrixcn(unittest.TestCase): + def setUp(self): + self.ssp = SSPMATRIXCN() + + def test_logger(self): + # Test the logger + stream_handler = logging.StreamHandler(sys.stdout) + logger.addHandler(stream_handler) + logger.level = logging.DEBUG + logger.info("nyr_forcing = {}".format(self.ssp.nyr_forcing)) + for n in range(self.ssp.n_steps()): + self.ssp.__logger__(n) + if self.ssp.spin[n] == "sasu": + logger.info(" SASU spinup is .true.") + if self.ssp.sasu[n] != -999: + logger.info(" nyr_sasu = {}".format(self.ssp.sasu[n])) + if self.ssp.iloop[n] != -999: + logger.info(" iloop_avg = {}".format(self.ssp.iloop[n])) + + logger.info("Total number of years {}".format(self.ssp.total_years())) + logger.removeHandler(stream_handler) + + def test_n_steps(self): + self.assertTrue(self.ssp.n_steps() == 3) + + def test_valid_n(self): + for n in range(self.ssp.n_steps()): + self.ssp.check_n(n) + + def test_negative_n(self): + self.assertRaises(SystemExit, self.ssp.check_n, -1) + + def test_n_too_big(self): + self.assertRaises(SystemExit, self.ssp.check_n, self.ssp.n_steps()) + + def test_append_user_nl_step2(self): + ufile = "user_nl_clm" + if not os.path.exists(ufile): + os.mknod(ufile) + else: + expect(0, ufile + " file already exists, not overwritting it") - def setUp( self ): - self.ssp = SSPMATRIXCN() - - def test_logger( self ): - # Test the logger - stream_handler = logging.StreamHandler(sys.stdout) - logger.addHandler(stream_handler) - logger.level = logging.DEBUG - logger.info( "nyr_forcing = {}".format(self.ssp.nyr_forcing) ) - for n in range(self.ssp.n_steps()): - self.ssp.__logger__(n) - if ( self.ssp.spin[n] == "sasu" ): - logger.info( " SASU spinup is .true." ) - if ( self.ssp.sasu[n] != -999 ): - logger.info( " nyr_sasu = {}".format(self.ssp.sasu[n]) ) - if ( self.ssp.iloop[n] != -999 ): - logger.info( " iloop_avg = {}".format(self.ssp.iloop[n]) ) - - logger.info( "Total number of years {}".format( self.ssp.total_years() ) ) - logger.removeHandler(stream_handler) - - def test_n_steps( self ): - self.assertTrue( self.ssp.n_steps() == 3) - - def test_valid_n( self ): - for n in range(self.ssp.n_steps()): - self.ssp.check_n(n) - - def test_negative_n( self ): - self.assertRaises(SystemExit, self.ssp.check_n, -1 ) - - def test_n_too_big( self ): - self.assertRaises(SystemExit, self.ssp.check_n, self.ssp.n_steps() ) - - def test_append_user_nl_step2( self ): - ufile = "user_nl_clm" - if not os.path.exists(ufile): - os.mknod(ufile) - else: - expect( 0, ufile+" file already exists, not overwritting it" ) - - self.ssp.append_user_nl( caseroot=".", n=2) - print( ufile+" for step 2" ) - log = open(ufile, "r").read() - print( log ) - os.remove(ufile) - - -if __name__ == '__main__': - unittest.main() + self.ssp.append_user_nl(caseroot=".", n=2) + print(ufile + " for step 2") + log = open(ufile, "r").read() + print(log) + os.remove(ufile) +if __name__ == "__main__": + unittest.main() diff --git a/cime_config/buildnml b/cime_config/buildnml index 11112b81f0..2f27473732 100755 --- a/cime_config/buildnml +++ b/cime_config/buildnml @@ -51,24 +51,24 @@ def buildnml(case, caseroot, compname): clm_accelerated_spinup = case.get_value("CLM_ACCELERATED_SPINUP") comp_interface = case.get_value("COMP_INTERFACE") lilac_mode = case.get_value("LILAC_MODE") - if ( comp_interface == "nuopc" ): - yr_start = case.get_value("DATM_YR_START") - yr_end = case.get_value("DATM_YR_END") + if comp_interface == "nuopc": + yr_start = case.get_value("DATM_YR_START") + yr_end = case.get_value("DATM_YR_END") else: - yr_start = case.get_value("DATM_CLMNCEP_YR_START") - yr_end = case.get_value("DATM_CLMNCEP_YR_END") + yr_start = case.get_value("DATM_CLMNCEP_YR_START") + yr_end = case.get_value("DATM_CLMNCEP_YR_END") - if ( yr_start != None and yr_start < 0 ): - yr_start = case.get_value("DATM_CPLHIST_YR_START") - yr_end = case.get_value("DATM_CPLHIST_YR_END") + if yr_start != None and yr_start < 0: + yr_start = case.get_value("DATM_CPLHIST_YR_START") + yr_end = case.get_value("DATM_CPLHIST_YR_END") # For LILAC - if ( yr_start == None or lilac_mode == "on" ): - yr_start = "0" - yr_end = "0" + if yr_start == None or lilac_mode == "on": + yr_start = "0" + yr_end = "0" yr_start = int(yr_start) - yr_end = int(yr_end) + yr_end = int(yr_end) comp_atm = case.get_value("COMP_ATM") lnd_grid = case.get_value("LND_GRID") @@ -117,7 +117,9 @@ def buildnml(case, caseroot, compname): clm_phys = case.get_value("CLM_PHYSICS_VERSION") config_cache_text = _config_cache_template.format(clm_phys=clm_phys) - config_cache_path = os.path.join(caseroot, "Buildconf", compname + "conf", "config_cache.xml") + config_cache_path = os.path.join( + caseroot, "Buildconf", compname + "conf", "config_cache.xml" + ) with open(config_cache_path, "w") as config_cache_file: config_cache_file.write(config_cache_text) @@ -206,22 +208,28 @@ def buildnml(case, caseroot, compname): else: ignore = "-ignore_ic_date" - tuning = "-lnd_tuning_mode %s "%lnd_tuning_mode - + tuning = "-lnd_tuning_mode %s " % lnd_tuning_mode + # # Spinup settings and specifics for SASU spinup # - spinup = "-clm_accelerated_spinup %s "%clm_accelerated_spinup - if ( clm_accelerated_spinup == "sasu" ): - if ( (yr_start != None) and (yr_end != None) ): - nyr = yr_end - yr_start + 1 - if ( (yr_end <= 0) or (yr_start <= 0) ): - logger.error( "ERROR: Year start and end are both negative and should not be" ) - clm_namelist_opts = "nyr_forcing={} {}".format(nyr, clm_namelist_opts) - else: - logger.warning( "WARNING: It does not make sense to do a SASU spinup with a prognostic atmosphere model" ) - logger.warning( " as it expects regular atmosphere forcing that is cycled over" ) - + spinup = "-clm_accelerated_spinup %s " % clm_accelerated_spinup + if clm_accelerated_spinup == "sasu": + if (yr_start != None) and (yr_end != None): + nyr = yr_end - yr_start + 1 + if (yr_end <= 0) or (yr_start <= 0): + logger.error( + "ERROR: Year start and end are both negative and should not be" + ) + clm_namelist_opts = "nyr_forcing={} {}".format(nyr, clm_namelist_opts) + else: + logger.warning( + "WARNING: It does not make sense to do a SASU spinup with a prognostic atmosphere model" + ) + logger.warning( + " as it expects regular atmosphere forcing that is cycled over" + ) + infile = os.path.join(ctsmconf, "namelist") inputdata_file = os.path.join(caseroot, "Buildconf", "ctsm.input_data_list") @@ -234,7 +242,9 @@ def buildnml(case, caseroot, compname): lndfrac_file = os.path.join(lnd_domain_path, lnd_domain_file) lndfrac_setting = "-lnd_frac " + lndfrac_file - config_cache_file = os.path.join(caseroot, "Buildconf", compname + "conf", "config_cache.xml") + config_cache_file = os.path.join( + caseroot, "Buildconf", compname + "conf", "config_cache.xml" + ) # ----------------------------------------------------- # Clear out old data @@ -297,7 +307,9 @@ def buildnml(case, caseroot, compname): break if not os.path.exists(os.path.join(rundir, clm_startfile)): - logger.warning("WARNING: Could NOT find a start file to use using" + clm_startfile) + logger.warning( + "WARNING: Could NOT find a start file to use using" + clm_startfile + ) clm_icfile = "%s = '%s'" % (startfile_type, clm_startfile) else: clm_icfile = "" @@ -308,7 +320,9 @@ def buildnml(case, caseroot, compname): user_nl_file = os.path.join(caseroot, "user_nl_clm" + inst_string) namelist_infile = os.path.join(ctsmconf, "namelist") - create_namelist_infile(case, user_nl_file, namelist_infile, "\n".join(infile_lines)) + create_namelist_infile( + case, user_nl_file, namelist_infile, "\n".join(infile_lines) + ) cmd = os.path.join(lnd_root, "bld", "build-namelist") From 4cef2cc63b6282c1792ef45803cfad33f2dc3737 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Wed, 27 Mar 2024 14:45:05 -0600 Subject: [PATCH 028/444] Update .git-blame-ignore-revs --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 4798c37853..2c92251e93 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -32,3 +32,4 @@ d866510188d26d51bcd6d37239283db690af7e82 6fccf682eaf718615407d9bacdd3903b8786a03d 2500534eb0a83cc3aff94b30fb62e915054030bf 78d05967c2b027dc9776a884716597db6ef7f57c +47839a77229c61555e3b8932927bb54cdc511b27 From e79364382b7f6a555a60070c6f84f52366c9c663 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 2 Apr 2024 18:08:20 -0600 Subject: [PATCH 029/444] testlist updates for LGRAIN2 and LREPRSTRUCT tests --- cime_config/testdefs/testlist_clm.xml | 67 ++------------------------- 1 file changed, 4 insertions(+), 63 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 04200b7271..f44a8e84ab 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3377,9 +3377,9 @@ - + - + @@ -3387,19 +3387,9 @@ - - - - - - - - - - - + - + @@ -3407,26 +3397,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -3436,16 +3406,6 @@ - - - - - - - - - - @@ -3455,16 +3415,6 @@ - - - - - - - - - - @@ -3474,15 +3424,6 @@ - - - - - - - - - From 306d11a6dcb9c16f29fbc3937b1110110a5d436c Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Wed, 3 Apr 2024 14:15:58 -0600 Subject: [PATCH 030/444] testlist updates for already existing matrixcn tests --- cime_config/testdefs/testlist_clm.xml | 30 ++++++--------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index f44a8e84ab..a47d74de5d 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -530,7 +530,7 @@ - + @@ -540,7 +540,7 @@ - + @@ -548,27 +548,9 @@ - - - - - - - - - - - - - - - - - - - + @@ -578,7 +560,7 @@ - + @@ -587,7 +569,7 @@ - + @@ -804,7 +786,7 @@ - + From 99ba6ced5d9fbfcfb42d3b4c4cd253ccc7d72c9c Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 4 Apr 2024 18:05:23 -0600 Subject: [PATCH 031/444] Removed testmod directory not in use --- .../clm/ciso_decStart_monthly_matrixcn_spinup/include_user_mods | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/ciso_decStart_monthly_matrixcn_spinup/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/ciso_decStart_monthly_matrixcn_spinup/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/ciso_decStart_monthly_matrixcn_spinup/include_user_mods deleted file mode 100644 index 442d7afb24..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/ciso_decStart_monthly_matrixcn_spinup/include_user_mods +++ /dev/null @@ -1,2 +0,0 @@ -../decStart -../ciso_monthly_matrixcn_spinup From 45dbe6247da94965e4c37593ca38592f3e25da9e Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 4 Apr 2024 18:16:10 -0600 Subject: [PATCH 032/444] Adding matrixcnOn testmods --- .../testdefs/testmods_dirs/clm/matrixcnOn/include_user_mods | 1 + cime_config/testdefs/testmods_dirs/clm/matrixcnOn/user_nl_clm | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/matrixcnOn/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/matrixcnOn/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/matrixcnOn/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn/include_user_mods new file mode 100644 index 0000000000..fe0e18cf88 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn/include_user_mods @@ -0,0 +1 @@ +../default diff --git a/cime_config/testdefs/testmods_dirs/clm/matrixcnOn/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn/user_nl_clm new file mode 100644 index 0000000000..185d6a2410 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn/user_nl_clm @@ -0,0 +1,3 @@ +hist_wrt_matrixcn_diag = .true. +use_matrixcn = .true. +use_soil_matrixcn = .true. From 0d07eb28518db409863bab811dbc3b7919f967c7 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Mon, 8 Apr 2024 16:46:20 -0600 Subject: [PATCH 033/444] 45 new tests with matrixcnOn testmods --- cime_config/testdefs/testlist_clm.xml | 456 +++++++++++++++++++------- 1 file changed, 343 insertions(+), 113 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index a47d74de5d..6056439278 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2,17 +2,23 @@ - + + + + + + + + + - - @@ -21,6 +27,16 @@ + + + + + + + + + + @@ -139,13 +155,21 @@ - + + + + + + + + + @@ -350,13 +374,21 @@ - + + + + + + + + + @@ -378,13 +410,21 @@ - + + + + + + + + + @@ -396,8 +436,6 @@ - - @@ -405,6 +443,15 @@ + + + + + + + + + @@ -501,7 +548,6 @@ - @@ -509,9 +555,17 @@ + + + + + + + + + - @@ -519,15 +573,32 @@ + + + + + + + + + - + + + + + + + + + @@ -675,13 +746,13 @@ - + - + - - + + @@ -693,13 +764,13 @@ - + - + - + @@ -711,9 +782,17 @@ + + + + + + + + + - @@ -721,6 +800,15 @@ + + + + + + + + + @@ -759,12 +847,14 @@ - + - + + + @@ -775,13 +865,13 @@ - + - + - + @@ -820,36 +910,38 @@ - + - + - + + - + - + - + + @@ -961,6 +1053,16 @@ + + + + + + + + + + @@ -972,8 +1074,6 @@ - - @@ -981,6 +1081,15 @@ + + + + + + + + + @@ -1007,6 +1116,15 @@ + + + + + + + + + @@ -1035,6 +1153,15 @@ + + + + + + + + + @@ -1043,6 +1170,15 @@ + + + + + + + + + @@ -1051,27 +1187,26 @@ - + - + - + - + - @@ -1117,14 +1252,6 @@ - - - - - - - - @@ -1133,13 +1260,13 @@ - + - + - + @@ -1238,16 +1365,6 @@ - - - - - - - - - - @@ -1258,14 +1375,14 @@ - + - - + - - + + + @@ -1278,16 +1395,6 @@ - - - - - - - - - - @@ -1446,13 +1553,21 @@ - + + + + + + + + + @@ -1531,10 +1646,6 @@ - - - - @@ -1544,6 +1655,16 @@ + + + + + + + + + + @@ -1619,6 +1740,15 @@ + + + + + + + + + @@ -1647,6 +1777,16 @@ + + + + + + + + + + @@ -1666,15 +1806,6 @@ - - - - - - - - - @@ -1684,13 +1815,13 @@ - + - + - + @@ -1702,13 +1833,13 @@ - + - + - - + + @@ -1762,6 +1893,16 @@ + + + + + + + + + + @@ -1774,7 +1915,6 @@ - @@ -1782,13 +1922,13 @@ - + - + - + @@ -1800,6 +1940,15 @@ + + + + + + + + + @@ -1812,8 +1961,6 @@ - - @@ -1822,6 +1969,16 @@ + + + + + + + + + + @@ -1853,14 +2010,14 @@ - + - + + - - + @@ -1873,6 +2030,16 @@ + + + + + + + + + + @@ -1896,8 +2063,6 @@ - - @@ -1905,6 +2070,16 @@ + + + + + + + + + + @@ -2091,10 +2266,6 @@ - - - - @@ -2104,6 +2275,18 @@ + + + + + + + + + + + + @@ -2170,6 +2353,17 @@ + + + + + + + + + + + @@ -2255,7 +2449,6 @@ - @@ -2263,6 +2456,15 @@ + + + + + + + + + @@ -2427,6 +2629,15 @@ + + + + + + + + + @@ -2756,7 +2967,6 @@ - @@ -2765,6 +2975,16 @@ + + + + + + + + + + @@ -3312,7 +3532,6 @@ - @@ -3322,6 +3541,17 @@ + + + + + + + + + + + From a2fc12b8be573434ef95e23e00efecffc87a6c18 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 11 Apr 2024 12:44:38 -0600 Subject: [PATCH 034/444] Change matrixcnOn tests to Clm51 and remove redundant tests --- cime_config/testdefs/testlist_clm.xml | 95 ++++++++------------------- 1 file changed, 29 insertions(+), 66 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 6056439278..c3bda24655 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -27,7 +27,7 @@ - + @@ -161,7 +161,7 @@ - + @@ -380,7 +380,7 @@ - + @@ -555,7 +555,7 @@ - + @@ -573,7 +573,7 @@ - + @@ -590,7 +590,7 @@ - + @@ -800,7 +800,7 @@ - + @@ -847,10 +847,10 @@ - + - - + + @@ -918,7 +918,7 @@ - + @@ -935,7 +935,7 @@ - + @@ -1081,15 +1081,6 @@ - - - - - - - - - @@ -1116,15 +1107,6 @@ - - - - - - - - - @@ -1153,7 +1135,7 @@ - + @@ -1170,7 +1152,7 @@ - + @@ -1196,7 +1178,7 @@ - + @@ -1260,7 +1242,7 @@ - + @@ -1559,7 +1541,7 @@ - + @@ -1655,16 +1637,6 @@ - - - - - - - - - - @@ -1740,7 +1712,7 @@ - + @@ -1777,7 +1749,7 @@ - + @@ -1815,15 +1787,6 @@ - - - - - - - - - @@ -1893,7 +1856,7 @@ - + @@ -1922,7 +1885,7 @@ - + @@ -1940,7 +1903,7 @@ - + @@ -2030,7 +1993,7 @@ - + @@ -2070,7 +2033,7 @@ - + @@ -2275,7 +2238,7 @@ - + @@ -2456,7 +2419,7 @@ - + @@ -2629,7 +2592,7 @@ - + @@ -2975,7 +2938,7 @@ - + @@ -3541,7 +3504,7 @@ - + From bd7d031760665a5cdc920ef61c2a519bb5116b6e Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 11 Apr 2024 14:51:17 -0600 Subject: [PATCH 035/444] Rename failing Clm51 tests back to Clm50 due to missing compsets --- cime_config/testdefs/testlist_clm.xml | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index b730b62720..54c9d0fb62 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -27,7 +27,7 @@ - + @@ -199,7 +199,7 @@ - + @@ -418,7 +418,7 @@ - + @@ -611,7 +611,7 @@ - + @@ -628,7 +628,7 @@ - + @@ -956,7 +956,7 @@ - + @@ -973,7 +973,7 @@ - + @@ -1173,7 +1173,7 @@ - + @@ -1190,7 +1190,7 @@ - + @@ -1750,7 +1750,7 @@ - + @@ -1787,7 +1787,7 @@ - + @@ -1894,7 +1894,7 @@ - + @@ -2071,7 +2071,7 @@ - + @@ -2457,7 +2457,7 @@ - + From 5d0a037a71c8e97e6f7e4c12535715bfbc16722d Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 11 Apr 2024 19:45:40 -0600 Subject: [PATCH 036/444] Remove a clm/FatesCold--clm/matrixcnOn test as invalid --- cime_config/testdefs/testlist_clm.xml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 54c9d0fb62..aea06d7f1e 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2976,16 +2976,6 @@ - - - - - - - - - - From 48b52dc5179a4ba3388a911a8aea7f1c682ce62c Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 17 Apr 2024 17:08:50 -0600 Subject: [PATCH 037/444] Point FATES external at Charlie's LUH2 branch. --- Externals_CLM.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Externals_CLM.cfg b/Externals_CLM.cfg index dc1bc3f0e7..1494217277 100644 --- a/Externals_CLM.cfg +++ b/Externals_CLM.cfg @@ -1,8 +1,8 @@ [fates] local_path = src/fates protocol = git -repo_url = https://github.com/NGEET/fates -tag = sci.1.70.0_api.32.0.0 +repo_url = https://github.com/ckoven/fates +hash = d37d9733b5970dfe67a required = True [externals_description] From 66c100482afdb26bb431d5c1e71deda28e3cdb69 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Fri, 26 Apr 2024 13:56:24 -0600 Subject: [PATCH 038/444] Update cmeps to the branch --- Externals.cfg | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Externals.cfg b/Externals.cfg index 185f412cab..1aa8991883 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -48,9 +48,12 @@ tag = cime6.0.217_httpsbranch03 required = True [cmeps] -tag = cmeps0.14.50 +#tag = cmeps0.14.50 +#branch = dust_emis_mod +hash = d79e34f67df825f9265bdaaf3091f8995d5df1a2 protocol = git -repo_url = https://github.com/ESCOMP/CMEPS.git +#repo_url = https://github.com/ESCOMP/CMEPS.git +repo_url = https://github.com/ekluzek/CMEPS.git local_path = components/cmeps required = True From f8aa6eac32a00c821824478860c06a26fbdb9010 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Fri, 26 Apr 2024 15:02:04 -0600 Subject: [PATCH 039/444] Add shr_dust_emis_mod.F90 to the files needed for unit testing, fails, because ESMF is currently needed and not available --- src/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 568b53cd15..9d2e6041b5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,9 +20,11 @@ add_subdirectory(${CLM_ROOT}/share/src csm_share) add_subdirectory(${CLM_ROOT}/share/unit_test_stubs/util csm_share_stubs) add_subdirectory(${CLM_ROOT}/share/src/esmf_wrf_timemgr esmf_wrf_timemgr) -# Add the single file we need from CMEPS -set (drv_sources_needed - ${CLM_ROOT}/components/cmeps/cesm/nuopc_cap_share/glc_elevclass_mod.F90) +# Add files needed from CMEPS +list ( APPEND drv_sources_needed + ${CLM_ROOT}/components/cmeps/cesm/nuopc_cap_share/glc_elevclass_mod.F90 + ${CLM_ROOT}/components/cmeps/cesm/nuopc_cap_share/shr_dust_emis_mod.F90 + ) # Add CLM source directories add_subdirectory(${CLM_ROOT}/src/utils clm_utils) From 526bc19b068546e4d92828cf44c86596010e9482 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 17 Apr 2024 15:39:56 -0600 Subject: [PATCH 040/444] Update CTSM to work with FATES LUH2. Some issues remain. --- bld/CLMBuildNamelist.pm | 26 +- bld/namelist_files/namelist_defaults_ctsm.xml | 10 +- .../namelist_definition_ctsm.xml | 26 +- bld/unit_testers/build-namelist_test.pl | 1 + .../testmods_dirs/clm/Fates/user_nl_clm | 2 +- .../clm/FatesColdLogging/user_nl_clm | 1 + .../usermods_dirs/fates_sp/user_nl_clm | 2 +- src/dyn_subgrid/dynFATESLandUseChangeMod.F90 | 80 +++++- src/main/clm_instMod.F90 | 3 +- src/main/clm_varctl.F90 | 4 +- src/main/controlMod.F90 | 14 +- src/utils/clmfates_interfaceMod.F90 | 227 ++++++++++++++++-- 12 files changed, 351 insertions(+), 45 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 4df42d5e74..bcf68a8d61 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -783,7 +783,7 @@ sub setup_cmdl_fates_mode { # dis-allow fates specific namelist items with non-fates runs my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys", "use_fates_cohort_age_tracking","use_fates_inventory_init","use_fates_fixed_biogeog", - "use_fates_nocomp","use_fates_sp","fates_inventory_ctrl_filename","use_fates_logging", + "use_fates_nocomp","use_fates_sp","fates_inventory_ctrl_filename","fates_harvest_mode", "fates_parteh_mode","use_fates_tree_damage","fates_seeddisp_cadence","use_fates_luh","fluh_timeseries" ); # dis-allow fates specific namelist items with non-fates runs foreach my $var ( @list ) { @@ -4370,7 +4370,7 @@ sub setup_logic_fates { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_paramfile', 'phys'=>$nl_flags->{'phys'}); my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys", "use_fates_inventory_init","use_fates_fixed_biogeog","use_fates_nocomp","fates_seeddisp_cadence", - "use_fates_logging","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage","use_fates_luh" ); + "fates_harvest_mode","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage","use_fates_luh" ); foreach my $var ( @list ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); @@ -4426,6 +4426,28 @@ sub setup_logic_fates { } } } + + # Check fates_harvest_mode compatibility + my $var = "fates_harvest_mode"; + if ( defined($nl->get_value($var)) ) { + # using fates_harvest_mode with CLM landuse driver data - for user convienence + # if ( $nl->get_value($var) == 2) { + # # Make sure that do_harvest is set to true + # if ( ! &value_is_true($nl->get_value('do_harvest')) ) { + # fatal_error("do_harvest must be true when $var is equal to 2" ); + # } + # using fates_harvest mode with raw luh2 harvest data + if ( $nl->get_value($var) > 2) { + # Make sure that use_fates_luh is true when using raw fates luh2 harvest data + if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { + fatal_error("use_fates_luh is required to be true when $var is greater than 2" ); + } + # do_harvest can not be on if we are using the raw fates luh2 harvest data + if ( &value_is_true($nl->get_value('do_harvest')) ) { + fatal_error("do_harvest can not be true when $var is greater than 2" ); + } + } + } } } diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 7891361238..bc962d1b0f 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1572,11 +1572,14 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 lnd/clm2/surfdata_map/release-clm5.0.18/landuse.timeseries_10x15_SSP5-3.4_16pfts_Irrig_CMIP6_simyr1850-2100_c190228.nc - + lnd/clm2/surfdata_map/fates-sci.1.68.3_api.31.0.0_tools.1.0.1/LUH2_states_transitions_management.timeseries_4x5_hist_simyr1850-2015_c231101.nc + +lnd/clm2/surfdata_map/fates-sci.1.73.0_api.33.0.0/fates_landuse_pft_map_4x5_240206.nc + lnd/clm2/surfdata_map/fates-sci.1.68.3_api.31.0.0_tools.1.0.1/LUH2_states_transitions_management.timeseries_4x5_hist_simyr1850-2015_c231101.nc @@ -2756,14 +2759,17 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 0 +0 .false. .false. .false. .false. .false. -.false. .false. .false. +.false. +.true. +.true. .false. 1 0 diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index b672b43125..fa2d83a3c9 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -734,10 +734,15 @@ Toggle to turn on no competition mode (only relevant if FATES is being used). Toggle to turn on FATES satellite phenology mode (only relevant if FATES is being used). - -Toggle to turn on the logging module -(Only relevant if FATES is on) + +Set FATES harvesting mode by setting fates_harvest_mode > 0. +Allowed values are: + 0 : no fates harvesting of any kind + 1 : fates logging via fates logging event codes (see fates parameter file) only + 2 : fates harvest driven by CLM landuse timeseries data (dynHarvestMod) + 3 : fates harvest driven by LUH2 raw harvest data, area-based (dynFATESLandUseChangeMod) + 4 : fates harvest driven by LUH2 raw harvest data, mass-based (dynFATESLandUseChangeMod) If TRUE, enable use of land use harmonization (LUH) state and transition data from luh_timeseries file. +This is enabled by default if fates_harvest_mode is set to use the raw LUH2 harvest +data (fates_harvest_mode >= 3) (Also, only valid for use_fates = true and is incompatible with transient runs currently.) + +If TRUE, ignore the land-use state vector and transitions, and assert that all lands +are primary, and that there is no harvest. + + @@ -793,6 +806,11 @@ types to vary over time. (Only relevant if FATES is on). + +Full pathname of fates landuse x pft data map. + + Toggle to turn on the LUNA model, to effect Photosynthesis by leaf Nitrogen diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 9b579dd9ce..899bd10b9c 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -1046,6 +1046,7 @@ sub cat_and_create_namelistinfile { GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, + # TODO SSR: Replace this with fates_harvest_mode "useloggingButNOTFATES" =>{ options=>"-envxml_dir . -no-megan", namelst=>"use_fates_logging=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", diff --git a/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm index 406fb598f6..91df3e2e61 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm @@ -16,7 +16,7 @@ hist_fincl1 = 'FATES_NCOHORTS', 'FATES_TRIMMING', 'FATES_AREA_PLANTS', 'FATES_SAPWOODC', 'FATES_LEAFC', 'FATES_FROOTC', 'FATES_REPROC', 'FATES_STRUCTC', 'FATES_NONSTRUCTC', 'FATES_VEGC_ABOVEGROUND', 'FATES_CANOPY_VEGC', 'FATES_USTORY_VEGC', 'FATES_PRIMARY_PATCHFUSION_ERR', -'FATES_HARVEST_CARBON_FLUX', 'FATES_DISTURBANCE_RATE_FIRE', +'FATES_HARVEST_WOODPROD_C_FLUX', 'FATES_DISTURBANCE_RATE_FIRE', 'FATES_DISTURBANCE_RATE_LOGGING', 'FATES_DISTURBANCE_RATE_TREEFALL', 'FATES_STOMATAL_COND', 'FATES_LBLAYER_COND', 'FATES_NPP', 'FATES_GPP', 'FATES_AUTORESP', 'FATES_GROWTH_RESP', 'FATES_MAINT_RESP', 'FATES_GPP_CANOPY', diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLogging/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLogging/user_nl_clm index 3b74a4fd37..5f457f3f1c 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLogging/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLogging/user_nl_clm @@ -1 +1,2 @@ +! TODO SSR: Replace this with fates_harvest_mode use_fates_logging= .true. diff --git a/cime_config/usermods_dirs/fates_sp/user_nl_clm b/cime_config/usermods_dirs/fates_sp/user_nl_clm index 093ecd7eda..37da8d1c67 100644 --- a/cime_config/usermods_dirs/fates_sp/user_nl_clm +++ b/cime_config/usermods_dirs/fates_sp/user_nl_clm @@ -22,7 +22,7 @@ hist_fexcl1 = 'FATES_TRIMMING', 'FATES_COLD_STATUS', 'FATES_GDD', 'FATES_NCHILLD 'FATES_SAPWOODC', 'FATES_FROOTC', 'FATES_REPROC', 'FATES_STRUCTC', 'FATES_NONSTRUCTC', 'FATES_VEGC_ABOVEGROUND', 'FATES_CANOPY_VEGC', 'FATES_USTORY_VEGC', 'FATES_PRIMARY_PATCHFUSION_ERR', 'FATES_DISTURBANCE_RATE_FIRE', 'FATES_DISTURBANCE_RATE_LOGGING', 'FATES_DISTURBANCE_RATE_TREEFALL', - 'FATES_HARVEST_CARBON_FLUX', 'FATES_GPP_CANOPY', 'FATES_AUTORESP_CANOPY', + 'FATES_HARVEST_WOODPROD_C_FLUX', 'FATES_GPP_CANOPY', 'FATES_AUTORESP_CANOPY', 'FATES_GPP_USTORY', 'FATES_AUTORESP_USTORY', 'FATES_CROWNAREA_CL', 'FATES_DEMOTION_CARBONFLUX', 'FATES_PROMOTION_CARBONFLUX', 'FATES_MORTALITY_CFLUX_CANOPY', 'FATES_MORTALITY_CFLUX_USTORY', 'FATES_DDBH_CANOPY_SZ', 'FATES_DDBH_USTORY_SZ', 'FATES_BASALAREA_SZ', diff --git a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 index 45f4340d6a..4f326d82a5 100644 --- a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 +++ b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 @@ -26,13 +26,39 @@ module dynFATESLandUseChangeMod ! Landuse state at beginning of year (fraction of gridcell), landuse state name x gridcell real(r8), allocatable, public :: landuse_states(:,:) + ! TODO SSR: Ask Charlie for description to go here + real(r8), allocatable, public :: landuse_harvest(:,:) + ! Number of landuse transition and state names integer, public, parameter :: num_landuse_transition_vars = 108 integer, public, parameter :: num_landuse_state_vars = 12 + integer, public, parameter :: num_landuse_harvest_vars = 5 + + ! Define the fates landuse namelist mode switch values + integer, public, parameter :: fates_harvest_no_logging = 0 + integer, public, parameter :: fates_harvest_logging_only = 1 + integer, public, parameter :: fates_harvest_clmlanduse = 2 + integer, public, parameter :: fates_harvest_luh_area = 3 + integer, public, parameter :: fates_harvest_luh_mass = 4 + + ! Define landuse harvest unit integer representation + integer, public, parameter :: landuse_harvest_area_units = 1 + integer, public, parameter :: landuse_harvest_mass_units = 2 + integer, public :: landuse_harvest_units ! landuse filename type(dyn_file_type), target :: dynFatesLandUse_file + ! LUH2 raw wood harvest area fraction + character(len=10), target :: landuse_harvest_area_varnames(num_landuse_harvest_vars) = & + [character(len=10) :: 'primf_harv', 'primn_harv', 'secmf_harv', 'secyf_harv', 'secnf_harv'] + + ! LUH2 raw wood harvest biomass carbon + character(len=10), target :: landuse_harvest_mass_varnames(num_landuse_harvest_vars) = & + [character(len=10) :: 'primf_bioh', 'primn_bioh', 'secmf_bioh', 'secyf_bioh', 'secnf_bioh'] + + character(len=10), public, pointer :: landuse_harvest_varnames(:) => null() + ! Land use name arrays character(len=5), public, parameter :: landuse_state_varnames(num_landuse_state_vars) = & [character(len=5) :: 'primf','primn','secdf','secdn','pastr','range', & @@ -64,8 +90,9 @@ module dynFATESLandUseChangeMod 'c3nfx_to_c3ann','c3nfx_to_c4ann','c3nfx_to_c3per','c3nfx_to_c4per', & 'c3nfx_to_secdf','c3nfx_to_secdn','c3nfx_to_pastr','c3nfx_to_range','c3nfx_to_urban'] - type(dyn_var_time_uninterp_type) :: landuse_transition_vars(num_landuse_transition_vars) ! value of each landuse variable - type(dyn_var_time_uninterp_type) :: landuse_state_vars(num_landuse_state_vars) ! value of each landuse variable + type(dyn_var_time_uninterp_type) :: landuse_transition_vars(num_landuse_transition_vars) ! value of each transitions variable + type(dyn_var_time_uninterp_type) :: landuse_state_vars(num_landuse_state_vars) ! value of each state variable + type(dyn_var_time_uninterp_type) :: landuse_harvest_vars(num_landuse_harvest_vars) ! value of each harvest variable public :: dynFatesLandUseInit public :: dynFatesLandUseInterp @@ -79,14 +106,14 @@ subroutine dynFatesLandUseInit(bounds, landuse_filename) ! Initialize data structures for land use information. ! !USES: - use clm_varctl , only : use_cn, use_fates_luh + use clm_varctl , only : use_cn, use_fates_luh, fates_harvest_mode use dynVarTimeUninterpMod , only : dyn_var_time_uninterp_type use dynTimeInfoMod , only : YEAR_POSITION_START_OF_TIMESTEP use dynTimeInfoMod , only : YEAR_POSITION_END_OF_TIMESTEP ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds ! proc-level bounds - character(len=*) , intent(in) :: landuse_filename ! name of file containing land use information + character(len=*) , intent(in) :: landuse_filename ! name of file containing landuse timeseries information (fates luh2) ! !LOCAL VARIABLES integer :: varnum, i ! counter for harvest variables @@ -111,17 +138,23 @@ subroutine dynFatesLandUseInit(bounds, landuse_filename) if (ier /= 0) then call endrun(msg=' allocation error for landuse_transitions'//errMsg(__FILE__, __LINE__)) end if + allocate(landuse_harvest(num_landuse_harvest_vars,bounds%begg:bounds%endg),stat=ier) + if (ier /= 0) then + call endrun(msg=' allocation error for landuse_harvest'//errMsg(__FILE__, __LINE__)) + end if + ! Initialize the states, transitions and harvest mapping percentages as zero by default landuse_states = 0._r8 landuse_transitions = 0._r8 + landuse_harvest = 0._r8 if (use_fates_luh) then - ! Generate the dyn_file_type object. Note that the land use data being read in is for the - ! transitions occuring within the current year + ! Generate the dyn_file_type object. + ! Start calls get_prev_date, whereas end calls get_curr_date dynFatesLandUse_file = dyn_file_type(landuse_filename, YEAR_POSITION_END_OF_TIMESTEP) - ! Get initial land use data + ! Get initial land use data from the fates luh2 timeseries dataset num_points = (bounds%endg - bounds%begg + 1) landuse_shape(1) = num_points ! Does this need an explicit array shape to be passed to the constructor? do varnum = 1, num_landuse_transition_vars @@ -136,6 +169,28 @@ subroutine dynFatesLandUseInit(bounds, landuse_filename) dim1name=grlnd, conversion_factor=1.0_r8, & do_check_sums_equal_1=.false., data_shape=landuse_shape) end do + + ! Get the harvest rate data from the fates luh2 timeseries dataset if enabled + if (fates_harvest_mode .ge. fates_harvest_luh_area ) then + + ! change the harvest varnames being used depending on the mode selected + if (fates_harvest_mode .eq. fates_harvest_luh_area ) then + landuse_harvest_varnames => landuse_harvest_area_varnames + landuse_harvest_units = landuse_harvest_area_units + elseif (fates_harvest_mode .eq. fates_harvest_luh_mass ) then + landuse_harvest_varnames => landuse_harvest_mass_varnames + landuse_harvest_units = landuse_harvest_mass_units + else + call endrun(msg=' undefined fates harvest mode selected'//errMsg(__FILE__, __LINE__)) + end if + + do varnum = 1, num_landuse_harvest_vars + landuse_harvest_vars(varnum) = dyn_var_time_uninterp_type( & + dyn_file=dynFatesLandUse_file, varname=landuse_harvest_varnames(varnum), & + dim1name=grlnd, conversion_factor=1.0_r8, & + do_check_sums_equal_1=.false., data_shape=landuse_shape) + end do + end if end if ! Since fates needs state data during initialization, make sure to call @@ -159,7 +214,7 @@ subroutine dynFatesLandUseInterp(bounds, init_state) ! !USES: use dynTimeInfoMod , only : time_info_type - use clm_varctl , only : use_cn + use clm_varctl , only : use_cn, fates_harvest_mode ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds ! proc-level bounds @@ -181,13 +236,14 @@ subroutine dynFatesLandUseInterp(bounds, init_state) init_flag = init_state end if - ! Get the current year + ! Get the data for the current year call dynFatesLandUse_file%time_info%set_current_year() if (dynFatesLandUse_file%time_info%is_before_time_series() .and. .not.(init_flag)) then ! Reset the land use transitions to zero for safety landuse_transitions(1:num_landuse_transition_vars,bounds%begg:bounds%endg) = 0._r8 landuse_states(1:num_landuse_state_vars,bounds%begg:bounds%endg) = 0._r8 + landuse_harvest(1:num_landuse_harvest_vars,bounds%begg:bounds%endg) = 0._r8 else ! Loop through all variables on the data file and put data into the temporary array ! then update the global state and transitions array. @@ -200,6 +256,12 @@ subroutine dynFatesLandUseInterp(bounds, init_state) call landuse_state_vars(varnum)%get_current_data(this_data) landuse_states(varnum,bounds%begg:bounds%endg) = this_data(bounds%begg:bounds%endg) end do + if (fates_harvest_mode .ge. fates_harvest_luh_area ) then + do varnum = 1, num_landuse_harvest_vars + call landuse_harvest_vars(varnum)%get_current_data(this_data) + landuse_harvest(varnum,bounds%begg:bounds%endg) = this_data(bounds%begg:bounds%endg) + end do + end if deallocate(this_data) end if diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 1ca450b48d..830dcfcca7 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -200,6 +200,7 @@ subroutine clm_instInit(bounds) use SoilWaterRetentionCurveFactoryMod , only : create_soil_water_retention_curve use decompMod , only : get_proc_bounds use BalanceCheckMod , only : GetBalanceCheckSkipSteps + use clm_varctl , only : flandusepftdat ! ! !ARGUMENTS type(bounds_type), intent(in) :: bounds ! processor bounds @@ -436,7 +437,7 @@ subroutine clm_instInit(bounds) ! Initialize the Functionaly Assembled Terrestrial Ecosystem Simulator (FATES) ! if (use_fates) then - call clm_fates%Init(bounds) + call clm_fates%Init(bounds, flandusepftdat) end if deallocate (h2osno_col) diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index e0d142bffd..9ab6c631c7 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -302,7 +302,7 @@ module clm_varctl ! > 1 for external data (lightning and/or anthropogenic ignitions) ! see bld/namelist_files/namelist_definition_clm4_5.xml for details logical, public :: use_fates_tree_damage = .false. ! true => turn on tree damage module - logical, public :: use_fates_logging = .false. ! true => turn on logging module + integer, public :: fates_harvest_mode = 0 ! 0 for no harvest/logging; 1-4 for harvest mode options logical, public :: use_fates_planthydro = .false. ! true => turn on fates hydro logical, public :: use_fates_cohort_age_tracking = .false. ! true => turn on cohort age tracking logical, public :: use_fates_ed_st3 = .false. ! true => static stand structure @@ -311,7 +311,9 @@ module clm_varctl logical, public :: use_fates_fixed_biogeog = .false. ! true => use fixed biogeography mode logical, public :: use_fates_nocomp = .false. ! true => use no comopetition mode logical, public :: use_fates_luh = .false. ! true => use FATES landuse data mode + logical, public :: use_fates_potentialveg = .false. ! true => FATES potential veg only character(len=256), public :: fluh_timeseries = '' ! filename for fates landuse timeseries data + character(len=256), public :: flandusepftdat = '' ! filename for fates landuse x pft data character(len=256), public :: fates_inventory_ctrl_filename = '' ! filename for inventory control ! FATES SP AND FATES BGC are MUTUTALLY EXCLUSIVE, THEY CAN'T BOTH BE ON diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 44efec4eeb..196bc141ff 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -222,7 +222,7 @@ subroutine control_init(dtime) ! FATES Flags namelist /clm_inparm/ fates_paramfile, use_fates, & - fates_spitfire_mode, use_fates_logging, & + fates_spitfire_mode, fates_harvest_mode, & use_fates_planthydro, use_fates_ed_st3, & use_fates_cohort_age_tracking, & use_fates_ed_prescribed_phys, & @@ -231,7 +231,9 @@ subroutine control_init(dtime) use_fates_nocomp, & use_fates_sp, & use_fates_luh, & + use_fates_potentialveg, & fluh_timeseries, & + flandusepftdat, & fates_inventory_ctrl_filename, & fates_parteh_mode, & fates_seeddisp_cadence, & @@ -772,7 +774,7 @@ subroutine control_spmd() call mpi_bcast (for_testing_allow_interp_non_ciso_to_ciso, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (fates_spitfire_mode, 1, MPI_INTEGER, 0, mpicom, ier) - call mpi_bcast (use_fates_logging, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (fates_harvest_mode, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (use_fates_planthydro, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_tree_damage, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_cohort_age_tracking, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -783,10 +785,12 @@ subroutine control_spmd() call mpi_bcast (use_fates_nocomp, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_sp, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_luh, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_fates_potentialveg, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_bgc, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (fates_inventory_ctrl_filename, len(fates_inventory_ctrl_filename), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (fates_paramfile, len(fates_paramfile) , MPI_CHARACTER, 0, mpicom, ier) - call mpi_bcast (fluh_timeseries, len(fates_paramfile) , MPI_CHARACTER, 0, mpicom, ier) + call mpi_bcast (fluh_timeseries, len(fluh_timeseries) , MPI_CHARACTER, 0, mpicom, ier) + call mpi_bcast (flandusepftdat, len(flandusepftdat) , MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (fates_parteh_mode, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (fates_seeddisp_cadence, 1, MPI_INTEGER, 0, mpicom, ier) @@ -1144,7 +1148,7 @@ subroutine control_print () write(iulog, *) ' use_fates = ', use_fates if (use_fates) then write(iulog, *) ' fates_spitfire_mode = ', fates_spitfire_mode - write(iulog, *) ' use_fates_logging = ', use_fates_logging + write(iulog, *) ' fates_harvest_mode = ', fates_harvest_mode write(iulog, *) ' fates_paramfile = ', fates_paramfile write(iulog, *) ' fates_parteh_mode = ', fates_parteh_mode write(iulog, *) ' use_fates_planthydro = ', use_fates_planthydro @@ -1157,7 +1161,9 @@ subroutine control_print () write(iulog, *) ' use_fates_nocomp = ', use_fates_nocomp write(iulog, *) ' use_fates_sp = ', use_fates_sp write(iulog, *) ' use_fates_luh= ', use_fates_luh + write(iulog, *) ' use_fates_potentialveg = ', use_fates_potentialveg write(iulog, *) ' fluh_timeseries = ', trim(fluh_timeseries) + write(iulog, *) ' flandusepftdat = ', trim(flandusepftdat) write(iulog, *) ' fates_seeddisp_cadence = ', fates_seeddisp_cadence write(iulog, *) ' fates_seeddisp_cadence: 0, 1, 2, 3 => off, daily, monthly, or yearly dispersal' write(iulog, *) ' fates_inventory_ctrl_filename = ', trim(fates_inventory_ctrl_filename) diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index 83d7186021..3f84a28508 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -54,12 +54,14 @@ module CLMFatesInterfaceMod use clm_varctl , only : use_fates_cohort_age_tracking use clm_varctl , only : use_fates_ed_st3 use clm_varctl , only : use_fates_ed_prescribed_phys - use clm_varctl , only : use_fates_logging + use clm_varctl , only : fates_harvest_mode use clm_varctl , only : use_fates_inventory_init use clm_varctl , only : use_fates_fixed_biogeog use clm_varctl , only : use_fates_nocomp use clm_varctl , only : use_fates_sp use clm_varctl , only : use_fates_luh + use clm_varctl , only : use_fates_potentialveg + use clm_varctl , only : flandusepftdat use clm_varctl , only : fates_seeddisp_cadence use clm_varctl , only : fates_inventory_ctrl_filename use clm_varctl , only : use_nitrif_denitrif @@ -180,6 +182,12 @@ module CLMFatesInterfaceMod use dynFATESLandUseChangeMod, only : landuse_transitions, landuse_states use dynFATESLandUseChangeMod, only : landuse_transition_varnames, landuse_state_varnames use dynFATESLandUseChangeMod, only : dynFatesLandUseInterp + use dynFATESLandUseChangeMod, only : num_landuse_harvest_vars + use dynFATESLandUseChangeMod, only : fates_harvest_no_logging + use dynFATESLandUseChangeMod, only : fates_harvest_luh_area + use dynFATESLandUseChangeMod, only : landuse_harvest + use dynFATESLandUseChangeMod, only : landuse_harvest_units + use dynFATESLandUseChangeMod, only : landuse_harvest_varnames implicit none @@ -272,6 +280,8 @@ module CLMFatesInterfaceMod character(len=*), parameter, private :: sourcefile = & __FILE__ + integer, parameter :: num_landuse_pft_vars = 4 + public :: CLMFatesGlobals1 public :: CLMFatesGlobals2 @@ -384,8 +394,10 @@ subroutine CLMFatesGlobals2() integer :: pass_cohort_age_tracking integer :: pass_tree_damage integer :: pass_use_luh + integer :: pass_use_potentialveg integer :: pass_num_luh_states integer :: pass_num_luh_transitions + integer :: pass_lupftdat call t_startf('fates_globals2') @@ -477,7 +489,7 @@ subroutine CLMFatesGlobals2() end if call set_fates_ctrlparms('use_ed_st3',ival=pass_ed_st3) - if(use_fates_logging) then + if (fates_harvest_mode > fates_harvest_no_logging) then pass_logging = 1 else pass_logging = 0 @@ -505,8 +517,8 @@ subroutine CLMFatesGlobals2() end if call set_fates_ctrlparms('use_cohort_age_tracking',ival=pass_cohort_age_tracking) - ! check fates logging namelist value first because hlm harvest overrides it - if(use_fates_logging) then + ! check fates logging namelist value first because hlm harvest can override it + if (fates_harvest_mode > fates_harvest_no_logging) then pass_logging = 1 else pass_logging = 0 @@ -521,23 +533,53 @@ subroutine CLMFatesGlobals2() pass_num_lu_harvest_cats = 0 end if - call set_fates_ctrlparms('use_lu_harvest',ival=pass_lu_harvest) - call set_fates_ctrlparms('num_lu_harvest_cats',ival=pass_num_lu_harvest_cats) - call set_fates_ctrlparms('use_logging',ival=pass_logging) - if(use_fates_luh) then pass_use_luh = 1 pass_num_luh_states = num_landuse_state_vars pass_num_luh_transitions = num_landuse_transition_vars + + ! Do not set harvest passing variables to zero not in luh harvest modes + ! as the user may want to use the CLM landuse harvest with luh2 transitions + if(fates_harvest_mode >= fates_harvest_luh_area) then + ! End the run if do_harvest is true with this run mode. + ! This should be caught be the build namelist. + if(get_do_harvest()) then + call endrun(msg="do_harvest and fates_harvest_mode using luh2 harvest data are incompatible"//& + errmsg(sourcefile, __LINE__)) + else + pass_lu_harvest = 1 + end if + end if else pass_use_luh = 0 pass_num_luh_states = 0 pass_num_luh_transitions = 0 end if + call set_fates_ctrlparms('use_luh2',ival=pass_use_luh) call set_fates_ctrlparms('num_luh2_states',ival=pass_num_luh_states) call set_fates_ctrlparms('num_luh2_transitions',ival=pass_num_luh_transitions) + if ( use_fates_potentialveg ) then + pass_use_potentialveg = 1 + else + pass_use_potentialveg = 0 + end if + call set_fates_ctrlparms('use_fates_potentialveg',ival=pass_use_potentialveg) + + if(flandusepftdat /= '') then + pass_lupftdat = 1 + else + pass_lupftdat = 0 + end if + call set_fates_ctrlparms('use_landusepft_data',ival=pass_lupftdat) + + ! Wait to set the harvest and logging variables after checking get_do_harvest + ! and fates_harvest_modes + call set_fates_ctrlparms('use_lu_harvest',ival=pass_lu_harvest) + call set_fates_ctrlparms('num_lu_harvest_cats',ival=pass_num_lu_harvest_cats) + call set_fates_ctrlparms('use_logging',ival=pass_logging) + if(use_fates_inventory_init) then pass_inventory_init = 1 else @@ -585,7 +627,7 @@ end subroutine CLMFatesTimesteps ! ==================================================================================== - subroutine init(this, bounds_proc ) + subroutine init(this, bounds_proc, flandusepftdat) ! --------------------------------------------------------------------------------- ! This initializes the hlm_fates_interface_type @@ -614,6 +656,7 @@ subroutine init(this, bounds_proc ) ! Input Arguments class(hlm_fates_interface_type), intent(inout) :: this type(bounds_type),intent(in) :: bounds_proc + character(len=*), intent(in) :: flandusepftdat ! local variables integer :: nclumps ! Number of threads @@ -631,6 +674,9 @@ subroutine init(this, bounds_proc ) integer :: ndecomp integer :: numg + real(r8), allocatable :: landuse_pft_map(:,:,:) + real(r8), allocatable :: landuse_bareground(:) + ! Initialize the FATES communicators with the HLM ! This involves to stages ! 1) allocate the vectors @@ -663,6 +709,13 @@ subroutine init(this, bounds_proc ) write(iulog,*) 'clm_fates%init(): allocating for ',nclumps,' threads' end if + ! Retrieve the landuse x pft static data if the file is present + if (flandusepftdat /= '') then + call GetLandusePFTData(bounds_proc, flandusepftdat, landuse_pft_map, landuse_bareground) + end if + + nclumps = get_proc_clumps() + allocate(copy_fates_var(bounds_proc%begc:bounds_proc%endc)) copy_fates_var(:) = .false. @@ -767,18 +820,26 @@ subroutine init(this, bounds_proc ) this%fates(nc)%sites(s)%lat = grc%latdeg(g) this%fates(nc)%sites(s)%lon = grc%londeg(g) - this%fates(nc)%bc_in(s)%pft_areafrac(:)=0._r8 - ! initialize static layers for reduced complexity FATES versions from HLM - ! maybe make this into a subroutine of it's own later. - do m = surfpft_lb,surfpft_ub - ft = m - surfpft_lb - this%fates(nc)%bc_in(s)%pft_areafrac(ft)=wt_nat_patch(g,m) - end do + ! Transfer the landuse x pft data to fates via bc_in if file is given + if (flandusepftdat /= '') then + this%fates(nc)%bc_in(s)%pft_areafrac_lu(:,1:num_landuse_pft_vars) = landuse_pft_map(g,:,1:num_landuse_pft_vars) + this%fates(nc)%bc_in(s)%baregroundfrac = landuse_bareground(g) + end if - if (abs(sum(this%fates(nc)%bc_in(s)%pft_areafrac(surfpft_lb:surfpft_ub)) - 1.0_r8) > sum_to_1_tol) then - write(iulog,*) 'pft_area error in interfc ', s, sum(this%fates(nc)%bc_in(s)%pft_areafrac(:)) - 1.0_r8 - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + if (flandusepftdat == '') then + ! initialize static layers for reduced complexity FATES versions from HLM + ! maybe make this into a subroutine of it's own later. + this%fates(nc)%bc_in(s)%pft_areafrac(:)=0._r8 + do m = surfpft_lb,surfpft_ub + ft = m - surfpft_lb + this%fates(nc)%bc_in(s)%pft_areafrac(ft)=wt_nat_patch(g,m) + end do + + if (abs(sum(this%fates(nc)%bc_in(s)%pft_areafrac(surfpft_lb:surfpft_ub)) - 1.0_r8) > sum_to_1_tol) then + write(iulog,*) 'pft_area error in interfc ', s, sum(this%fates(nc)%bc_in(s) %pft_areafrac(:)) - 1.0_r8 + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if end do !site ! Initialize site-level static quantities dictated by the HLM @@ -820,6 +881,12 @@ subroutine init(this, bounds_proc ) ! Fire data to send to FATES call create_fates_fire_data_method( this%fates_fire_data_method ) + ! deallocate the local landuse x pft array + if (flandusepftdat /= '') then + deallocate(landuse_pft_map) + deallocate(landuse_bareground) + end if + call t_stopf('fates_init') end subroutine init @@ -1087,6 +1154,12 @@ subroutine dynamics_driv(this, nc, bounds_clump, & this%fates(nc)%bc_in(s)%hlm_luh_state_names = landuse_state_varnames this%fates(nc)%bc_in(s)%hlm_luh_transitions = landuse_transitions(:,g) this%fates(nc)%bc_in(s)%hlm_luh_transition_names = landuse_transition_varnames + + if (fates_harvest_mode >= fates_harvest_luh_area) then + this%fates(nc)%bc_in(s)%hlm_harvest_rates = landuse_harvest(:,g) + this%fates(nc)%bc_in(s)%hlm_harvest_catnames = landuse_harvest_varnames + this%fates(nc)%bc_in(s)%hlm_harvest_units = landuse_harvest_units + end if end if end do @@ -2033,6 +2106,12 @@ subroutine init_coldstart(this, waterstatebulk_inst, waterdiagnosticbulk_inst, & this%fates(nc)%bc_in(s)%hlm_luh_state_names = landuse_state_varnames this%fates(nc)%bc_in(s)%hlm_luh_transitions = landuse_transitions(:,g) this%fates(nc)%bc_in(s)%hlm_luh_transition_names = landuse_transition_varnames + + if (fates_harvest_mode >= fates_harvest_luh_area ) then + this%fates(nc)%bc_in(s)%hlm_harvest_rates = landuse_harvest(:,g) + this%fates(nc)%bc_in(s)%hlm_harvest_catnames = landuse_harvest_varnames + this%fates(nc)%bc_in(s)%hlm_harvest_units = landuse_harvest_units + end if end if end do @@ -3646,6 +3725,114 @@ subroutine GetAndSetTime() end subroutine GetAndSetTime + ! ====================================================================================== + + subroutine GetLandusePFTData(bounds, landuse_pft_file, landuse_pft_map, landuse_bareground) + + ! !DESCRIPTION: + ! Read in static landuse x pft file + + ! !USES: + use fileutils , only : getfil + use ncdio_pio , only : file_desc_t, ncd_io, ncd_inqdlen + use ncdio_pio , only : ncd_pio_openfile, ncd_pio_closefile + use decompMod , only : BOUNDS_LEVEL_PROC + use clm_varcon, only : grlnd + use FatesConstantsMod, only : fates_unset_r8 + + + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds ! proc-level bounds + character(len=*) , intent(in) :: landuse_pft_file ! name of file containing static landuse x pft information + real(r8), allocatable, intent(inout) :: landuse_pft_map(:,:,:) + real(r8), allocatable, intent(inout) :: landuse_bareground(:) + + ! !LOCAL VARIABLES + integer :: varnum ! variable number + integer :: dimid, dimlen ! dimension id number and length + integer :: ier ! error id + character(len=256) :: locfn ! local file name + type(file_desc_t) :: ncid ! netcdf id + real(r8), pointer :: arraylocal(:,:) ! local array for reading fraction data + real(r8), pointer :: arraylocal_bareground(:) ! local array for reading bareground data + logical :: readvar ! true => variable is on dataset + !character(len=16), parameter :: grlnd = 'lndgrid' ! name of lndgrid + + integer, parameter :: dim_landuse_pft = 14 + + ! Land use name arrays + character(len=10), parameter :: landuse_pft_map_varnames(num_landuse_pft_vars) = & + [character(len=10) :: 'frac_primr','frac_secnd','frac_pastr','frac_range'] !need to move 'frac_surf' to a different variable + + character(len=*), parameter :: subname = 'GetLandusePFTData' + + !----------------------------------------------------------------------- + + ! Check to see if the landuse file name has been provided + ! Note: getfile checks this as well + if (masterproc) then + write(iulog,*) 'Attempting to read landuse x pft data .....' + if (landuse_pft_file == ' ') then + write(iulog,*)'landuse_pft_file must be specified' + call endrun(msg=errMsg(__FILE__, __LINE__)) + endif + endif + + ! Initialize the landuse x pft arrays and initialize to unset + allocate(landuse_pft_map(bounds%begg:bounds%endg,dim_landuse_pft,num_landuse_pft_vars),stat=ier) + if (ier /= 0) then + call endrun(msg=' allocation error for landuse_pft_map'//errMsg(__FILE__, __LINE__)) + end if + landuse_pft_map = fates_unset_r8 + + allocate(landuse_bareground(bounds%begg:bounds%endg),stat=ier) + if (ier /= 0) then + call endrun(msg=' allocation error for landuse_bareground'//errMsg(__FILE__, __LINE__)) + end if + landuse_bareground = fates_unset_r8 + + + ! Get the local filename and open the file + call getfil(landuse_pft_file, locfn, 0) + call ncd_pio_openfile (ncid, trim(locfn), 0) + + ! Check that natpft dimension on the file matches the target array dimensions + call ncd_inqdlen(ncid, dimid, dimlen, 'natpft') + if (dimlen /= dim_landuse_pft) then + write(iulog,*) 'natpft dimensions on the landuse x pft file do not match target array size' + call endrun(msg=errMsg(__FILE__, __LINE__)) + end if + + ! Allocate a temporary array since ncdio expects a pointer + allocate(arraylocal(bounds%begg:bounds%endg,dim_landuse_pft)) + allocate(arraylocal_bareground(bounds%begg:bounds%endg)) + + ! Read the landuse x pft data from file + do varnum = 1, num_landuse_pft_vars + call ncd_io(ncid=ncid, varname=landuse_pft_map_varnames(varnum), flag='read', & + data=arraylocal, dim1name=grlnd, readvar=readvar) + if (.not. readvar) & + call endrun(msg='ERROR: '//trim(landuse_pft_map_varnames(varnum))// & + ' NOT on landuse x pft file'//errMsg(__FILE__, __LINE__)) + landuse_pft_map(bounds%begg:bounds%endg,:,varnum) = arraylocal(bounds%begg:bounds%endg,:) + end do + + ! Read the bareground data from file. This is per gridcell only. + call ncd_io(ncid=ncid, varname='frac_brgnd', flag='read', & + data=arraylocal_bareground, dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun(msg='ERROR: frac_brgnd NOT on landuse x pft file'//errMsg(__FILE__, __LINE__)) + landuse_bareground(bounds%begg:bounds%endg) = arraylocal_bareground(bounds%begg:bounds%endg) + + ! Deallocate the temporary local array point and close the file + deallocate(arraylocal) + deallocate(arraylocal_bareground) + call ncd_pio_closefile(ncid) + + ! Check that sums equal to unity + + end subroutine GetLandusePFTData + + !----------------------------------------------------------------------- end module CLMFatesInterfaceMod From 46420cfb64f4ebb2b092daef9071a3f070b403bf Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Apr 2024 09:40:21 -0600 Subject: [PATCH 041/444] Add fates_landuse_v2 test suite. --- cime_config/testdefs/testlist_clm.xml | 36 +++++++++++++++++++ .../clm/FatesColdLUH2Mode1/include_user_mods | 1 + .../clm/FatesColdLUH2Mode1/user_nl_clm | 1 + .../clm/FatesColdLUH2Mode2/include_user_mods | 1 + .../clm/FatesColdLUH2Mode2/user_nl_clm | 1 + .../clm/FatesColdLUH2Mode3/include_user_mods | 1 + .../clm/FatesColdLUH2Mode3/user_nl_clm | 1 + .../clm/FatesColdLUH2Mode4/include_user_mods | 1 + .../clm/FatesColdLUH2Mode4/user_nl_clm | 1 + 9 files changed, 44 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/user_nl_clm diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index dec8cf49d8..4184cc7e1f 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2910,6 +2910,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/include_user_mods new file mode 100644 index 0000000000..7eb8bb1579 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/include_user_mods @@ -0,0 +1 @@ +../FatesColdLUH2 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/user_nl_clm new file mode 100644 index 0000000000..dea75b71e7 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/user_nl_clm @@ -0,0 +1 @@ +fates_harvest_mode = 1 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/include_user_mods new file mode 100644 index 0000000000..7eb8bb1579 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/include_user_mods @@ -0,0 +1 @@ +../FatesColdLUH2 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/user_nl_clm new file mode 100644 index 0000000000..fd4c74fe57 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/user_nl_clm @@ -0,0 +1 @@ +fates_harvest_mode = 2 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/include_user_mods new file mode 100644 index 0000000000..7eb8bb1579 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/include_user_mods @@ -0,0 +1 @@ +../FatesColdLUH2 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/user_nl_clm new file mode 100644 index 0000000000..3332e9e526 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/user_nl_clm @@ -0,0 +1 @@ +fates_harvest_mode = 3 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/include_user_mods new file mode 100644 index 0000000000..7eb8bb1579 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/include_user_mods @@ -0,0 +1 @@ +../FatesColdLUH2 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/user_nl_clm new file mode 100644 index 0000000000..13dae9efee --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/user_nl_clm @@ -0,0 +1 @@ +fates_harvest_mode = 4 From e4c8b6a0f1dfd0392fc956cf5d3f41e197508ba5 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Apr 2024 11:32:05 -0600 Subject: [PATCH 042/444] Point FATES external to my repo: Nag array index fix. --- Externals_CLM.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Externals_CLM.cfg b/Externals_CLM.cfg index 1494217277..ef4406545e 100644 --- a/Externals_CLM.cfg +++ b/Externals_CLM.cfg @@ -1,8 +1,8 @@ [fates] local_path = src/fates protocol = git -repo_url = https://github.com/ckoven/fates -hash = d37d9733b5970dfe67a +repo_url = https://github.com/samsrabin/fates +hash = c03a4ba64a7e59817658f1c3357ffff681d8b958 required = True [externals_description] From 7216006b1c2400d1ca2932899671f9bcec85b6af Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Apr 2024 16:48:41 -0600 Subject: [PATCH 043/444] Apply relevant changes from rgknox/fates-auto-params. --- .../testdefs/testmods_dirs/clm/Fates/shell_commands | 5 +++++ .../testdefs/testmods_dirs/clm/Fates/user_nl_clm | 1 + .../testdefs/testmods_dirs/clm/_scripts/README | 2 ++ .../clm/_scripts/get_fates_shell_commands_vars.sh | 11 +++++++++++ 4 files changed, 19 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/_scripts/README create mode 100755 cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh diff --git a/cime_config/testdefs/testmods_dirs/clm/Fates/shell_commands b/cime_config/testdefs/testmods_dirs/clm/Fates/shell_commands index 41a2342a51..3443bacef0 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Fates/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/Fates/shell_commands @@ -1,2 +1,7 @@ ./xmlchange CLM_BLDNML_OPTS="-no-megan" --append ./xmlchange BFBFLAG="TRUE" + +SRCROOT=`./xmlquery SRCROOT --value` +. "${SRCROOT}"/cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh + +ncgen -o $FATESPARAMFILE $FATESDIR/parameter_files/fates_params_default.cdl diff --git a/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm index 91df3e2e61..57adea1ff6 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm @@ -4,6 +4,7 @@ hist_nhtfrq = -24 hist_empty_htapes = .true. hist_ndens = 1 fates_spitfire_mode = 1 +fates_paramfile='${SRCROOT}/src/fates/parameter_files/binaries/${CASE}-params.nc' hist_fincl1 = 'FATES_NCOHORTS', 'FATES_TRIMMING', 'FATES_AREA_PLANTS', 'FATES_AREA_TREES', 'FATES_COLD_STATUS', 'FATES_GDD', 'FATES_NCHILLDAYS', 'FATES_NCOLDDAYS', 'FATES_DAYSINCE_COLDLEAFOFF','FATES_DAYSINCE_COLDLEAFON', diff --git a/cime_config/testdefs/testmods_dirs/clm/_scripts/README b/cime_config/testdefs/testmods_dirs/clm/_scripts/README new file mode 100644 index 0000000000..66eb22a375 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/_scripts/README @@ -0,0 +1,2 @@ +This directory contains scripts that can be called in +shell_commands of multiple testmods. diff --git a/cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh b/cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh new file mode 100755 index 0000000000..382fb4e53e --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh @@ -0,0 +1,11 @@ +# This script should be called in shell_commands with +# . "${SRCROOT}"/cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh +# where the leading period ensures it's run in the same shell. + +CASE=`./xmlquery CASE --value` +FATESDIR="${SRCROOT}/src/fates" +FATESPARAMDIR="${SRCROOT}/src/fates/parameter_files/binaries" +mkdir -p "${FATESPARAMDIR}" +FATESPARAMFILE="${FATESPARAMDIR}/${CASE}-params.nc" + +# No exit status because it should be called in the same shell. From a7c21a752224c09361b4280a730e5c61273244fa Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Tue, 23 Apr 2024 12:26:35 -0600 Subject: [PATCH 044/444] Don't allow flandusepftdat to be set in non-FATES runs. --- bld/CLMBuildNamelist.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index bcf68a8d61..e3ceedeccc 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -784,7 +784,7 @@ sub setup_cmdl_fates_mode { my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys", "use_fates_cohort_age_tracking","use_fates_inventory_init","use_fates_fixed_biogeog", "use_fates_nocomp","use_fates_sp","fates_inventory_ctrl_filename","fates_harvest_mode", - "fates_parteh_mode","use_fates_tree_damage","fates_seeddisp_cadence","use_fates_luh","fluh_timeseries" ); + "fates_parteh_mode","use_fates_tree_damage","fates_seeddisp_cadence","use_fates_luh","fluh_timeseries","flandusepftdat"); # dis-allow fates specific namelist items with non-fates runs foreach my $var ( @list ) { if ( defined($nl->get_value($var)) ) { From 90a40281134953f3d371a6454642773035efe137 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Tue, 23 Apr 2024 12:27:16 -0600 Subject: [PATCH 045/444] Actually set flandusepftdat in CLMBuildNamelist.pm. --- bld/CLMBuildNamelist.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index e3ceedeccc..0f7f6891c5 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4424,6 +4424,9 @@ sub setup_logic_fates { } elsif ( ! -f "$fname" ) { $log->fatal_error("$fname does NOT point to a valid filename" ); } + + $var = "flandusepftdat"; + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, nofail=>1 ); } } From d88fda01ba5904e80cf432f609cc10d4392f2767 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Tue, 23 Apr 2024 12:27:43 -0600 Subject: [PATCH 046/444] Update path for default flandusepftdat. --- bld/namelist_files/namelist_defaults_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index bc962d1b0f..66c0f837e0 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1578,7 +1578,7 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 >lnd/clm2/surfdata_map/fates-sci.1.68.3_api.31.0.0_tools.1.0.1/LUH2_states_transitions_management.timeseries_4x5_hist_simyr1850-2015_c231101.nc -lnd/clm2/surfdata_map/fates-sci.1.73.0_api.33.0.0/fates_landuse_pft_map_4x5_240206.nc +lnd/clm2/surfdata_map/fates-sci.1.73.0_api.36.0.0/fates_landuse_pft_map_4x5_240206.nc Date: Sun, 28 Apr 2024 13:45:50 -0600 Subject: [PATCH 047/444] Point FATES external back at Charlie's branch. --- Externals_CLM.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Externals_CLM.cfg b/Externals_CLM.cfg index ef4406545e..b689141aaf 100644 --- a/Externals_CLM.cfg +++ b/Externals_CLM.cfg @@ -1,8 +1,8 @@ [fates] local_path = src/fates protocol = git -repo_url = https://github.com/samsrabin/fates -hash = c03a4ba64a7e59817658f1c3357ffff681d8b958 +repo_url = https://github.com/ckoven/fates +hash = c1a7453c8331277a156a0ee158a870c1b8598a9f required = True [externals_description] From 0191278f95a35f90c76b7922fb51d8e42d68b24e Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sun, 28 Apr 2024 13:48:21 -0600 Subject: [PATCH 048/444] Add missing potential veg to build list. Manually cherry-picked from Greg Lemieux's b33a722. --- bld/CLMBuildNamelist.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 0f7f6891c5..7e2e4294af 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -784,7 +784,8 @@ sub setup_cmdl_fates_mode { my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys", "use_fates_cohort_age_tracking","use_fates_inventory_init","use_fates_fixed_biogeog", "use_fates_nocomp","use_fates_sp","fates_inventory_ctrl_filename","fates_harvest_mode", - "fates_parteh_mode","use_fates_tree_damage","fates_seeddisp_cadence","use_fates_luh","fluh_timeseries","flandusepftdat"); + "fates_parteh_mode","use_fates_tree_damage","fates_seeddisp_cadence","use_fates_luh","fluh_timeseries","flandusepftdat", + "use_fates_potentialveg"); # dis-allow fates specific namelist items with non-fates runs foreach my $var ( @list ) { if ( defined($nl->get_value($var)) ) { From b767a82b5eb448817e2e36609bde1633e105e358 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Mon, 29 Apr 2024 18:59:30 -0600 Subject: [PATCH 049/444] Start adding the unit testing for dust emission in cmeps --- Externals.cfg | 2 +- src/CMakeLists.txt | 4 ++ src/drv_test/CMakeLists.txt | 1 + .../shr_dust_emis_test/CMakeLists.txt | 3 ++ .../shr_dust_emis_test/test_shr_dust_emis.pf | 50 +++++++++++++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/drv_test/CMakeLists.txt create mode 100644 src/drv_test/shr_dust_emis_test/CMakeLists.txt create mode 100644 src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf diff --git a/Externals.cfg b/Externals.cfg index 1aa8991883..70c0bd6124 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -50,7 +50,7 @@ required = True [cmeps] #tag = cmeps0.14.50 #branch = dust_emis_mod -hash = d79e34f67df825f9265bdaaf3091f8995d5df1a2 +hash = 492faf0014ad9d91c22bb92e2570e558a76093fe protocol = git #repo_url = https://github.com/ESCOMP/CMEPS.git repo_url = https://github.com/ekluzek/CMEPS.git diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9d2e6041b5..9388e65bc2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -105,3 +105,7 @@ add_subdirectory(${CLM_ROOT}/src/dyn_subgrid/test clm_dyn_subgrid_test) add_subdirectory(${CLM_ROOT}/src/main/test clm_main_test) add_subdirectory(${CLM_ROOT}/src/init_interp/test clm_init_interp_test) add_subdirectory(${CLM_ROOT}/src/self_tests/test clm_self_tests_test) + +# Add driver unit test directories +add_subdirectory(${CLM_ROOT}/src/drv_test drv_test) + diff --git a/src/drv_test/CMakeLists.txt b/src/drv_test/CMakeLists.txt new file mode 100644 index 0000000000..adf66b8b92 --- /dev/null +++ b/src/drv_test/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(shr_dust_emis_test) diff --git a/src/drv_test/shr_dust_emis_test/CMakeLists.txt b/src/drv_test/shr_dust_emis_test/CMakeLists.txt new file mode 100644 index 0000000000..21fb9c8d47 --- /dev/null +++ b/src/drv_test/shr_dust_emis_test/CMakeLists.txt @@ -0,0 +1,3 @@ +add_pfunit_ctest(dust_emis + TEST_SOURCES "test_shr_dust_emis.pf" + LINK_LIBRARIES clm csm_share) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf new file mode 100644 index 0000000000..aa60427eac --- /dev/null +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -0,0 +1,50 @@ +module test_shr_dust_emis + + ! Tests of shr_dust_emis_mod.F90 from CMEPS nuopc_cap_share + + use funit + use shr_dust_emis_mod, only : check_if_initialized + use unittestUtils, only : endrun_msg + + implicit none + + @TestCase + type, extends(TestCase) :: TestDustEmis + contains + procedure :: setUp + procedure :: tearDown + end type TestDustEmis + +contains + + ! ======================================================================== + ! Helper routines + ! ======================================================================== + + subroutine setUp(this) + class(TestDustEmis), intent(inout) :: this + end subroutine setUp + + subroutine tearDown(this) + class(TestDustEmis), intent(inout) :: this + + end subroutine tearDown + + + + ! ======================================================================== + ! Begin tests + ! ======================================================================== + + @Test + subroutine check_if_initialized_aborts(this) + ! Test that the check_if_initialized check aborts when called initially + class(TestDustEmis), intent(inout) :: this + + call check_if_initialized() + @assertExceptionRaised(endrun_msg('ERROR: dust emission namelist has NOT been read in yet, shr_dust_emis_mod is NOT initialized') ) + + end subroutine check_if_initialized_aborts + + +end module test_shr_dust_emis From 82704fe7e86aa68f2bd7254d83bb62c53f4aabeb Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Apr 2024 09:21:16 -0600 Subject: [PATCH 050/444] Change call to is_NOT_initialized function, unit test works --- src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf index aa60427eac..a619618e1d 100644 --- a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -3,7 +3,7 @@ module test_shr_dust_emis ! Tests of shr_dust_emis_mod.F90 from CMEPS nuopc_cap_share use funit - use shr_dust_emis_mod, only : check_if_initialized + use shr_dust_emis_mod, only : is_NOT_initialized use unittestUtils, only : endrun_msg implicit none @@ -40,9 +40,11 @@ contains subroutine check_if_initialized_aborts(this) ! Test that the check_if_initialized check aborts when called initially class(TestDustEmis), intent(inout) :: this + logical :: not_init - call check_if_initialized() + not_init = is_NOT_initialized() @assertExceptionRaised(endrun_msg('ERROR: dust emission namelist has NOT been read in yet, shr_dust_emis_mod is NOT initialized') ) + @assertTrue(not_init) end subroutine check_if_initialized_aborts From 118010da9524fa08401ba6af3c2b6be560b0d2c7 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Apr 2024 10:51:45 -0600 Subject: [PATCH 051/444] add a test that is expected to fail --- .../shr_dust_emis_test/test_shr_dust_emis.pf | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf index a619618e1d..646b3cfce1 100644 --- a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -3,8 +3,8 @@ module test_shr_dust_emis ! Tests of shr_dust_emis_mod.F90 from CMEPS nuopc_cap_share use funit - use shr_dust_emis_mod, only : is_NOT_initialized - use unittestUtils, only : endrun_msg + use shr_dust_emis_mod + use unittestUtils , only : endrun_msg implicit none @@ -48,5 +48,16 @@ contains end subroutine check_if_initialized_aborts + @Test + subroutine check_when_initialized_runs(this) + ! Test that the initializiation check runs when it is initialized + class(TestDustEmis), intent(inout) :: this + logical :: not_init + + call dust_emis_set_options( 'Zender_2003', 'lnd') + not_init = is_NOT_initialized() + @assertFalse(not_init) + + end subroutine check_when_initialized_runs end module test_shr_dust_emis From 516d14721ae3f29c40316c6fb7fbd4fd7d9970d2 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Apr 2024 11:10:03 -0600 Subject: [PATCH 052/444] Update cmeps version so will work --- Externals.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals.cfg b/Externals.cfg index 70c0bd6124..3753aac874 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -50,7 +50,7 @@ required = True [cmeps] #tag = cmeps0.14.50 #branch = dust_emis_mod -hash = 492faf0014ad9d91c22bb92e2570e558a76093fe +hash = ecb6d45aa00a4960564ea963b00754fb4c3b7d2c protocol = git #repo_url = https://github.com/ESCOMP/CMEPS.git repo_url = https://github.com/ekluzek/CMEPS.git From 5cf5dc04734ff81fc77b43e8a003af826e9553a4 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Apr 2024 14:31:23 -0600 Subject: [PATCH 053/444] Add more tests that pass --- .../shr_dust_emis_test/test_shr_dust_emis.pf | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf index 646b3cfce1..efe6a5c2a8 100644 --- a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -60,4 +60,35 @@ contains end subroutine check_when_initialized_runs + @Test + subroutine check_dust_emis(this) + ! Test that the dust_emis logical functions work as expected + class(TestDustEmis), intent(inout) :: this + logical :: not_init + + call dust_emis_set_options( 'Zender_2003', 'lnd') + @assertTrue( is_dust_emis_zender() ) + @assertFalse( is_dust_emis_leung() ) + call dust_emis_set_options( 'Leung_2023', 'lnd') + @assertFalse( is_dust_emis_zender() ) + @assertTrue( is_dust_emis_leung() ) + + end subroutine check_dust_emis + + + @Test + subroutine check_zender_soil(this) + ! Test that the dust_emis_Zender logical functions work as expected + class(TestDustEmis), intent(inout) :: this + logical :: not_init + + call dust_emis_set_options( 'Zender_2003', 'lnd') + @assertTrue( is_zender_soil_erod_from_land() ) + @assertFalse( is_zender_soil_erod_from_atm() ) + call dust_emis_set_options( 'Zender_2003', 'atm') + @assertFalse( is_zender_soil_erod_from_land() ) + @assertTrue( is_zender_soil_erod_from_atm() ) + + end subroutine check_zender_soil + end module test_shr_dust_emis From c2d226c20c1ae3cbbf5f3e2b91a7bee67fd0e5aa Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 1 May 2024 13:50:29 -0600 Subject: [PATCH 054/444] Add new tests and get working again --- .../shr_dust_emis_test/test_shr_dust_emis.pf | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf index efe6a5c2a8..467d00de59 100644 --- a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -69,7 +69,7 @@ contains call dust_emis_set_options( 'Zender_2003', 'lnd') @assertTrue( is_dust_emis_zender() ) @assertFalse( is_dust_emis_leung() ) - call dust_emis_set_options( 'Leung_2023', 'lnd') + call dust_emis_set_options( 'Leung_2023', 'none') @assertFalse( is_dust_emis_zender() ) @assertTrue( is_dust_emis_leung() ) @@ -90,5 +90,25 @@ contains @assertTrue( is_zender_soil_erod_from_atm() ) end subroutine check_zender_soil + + + @Test + subroutine check_options(this) + ! Test that the check_options subroutine catches errors that should die + class(TestDustEmis), intent(inout) :: this + logical :: not_init + + call dust_emis_set_options( 'zztop', 'zztop') + @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: dust_emis_method namelist item is not valid')) + call dust_emis_set_options( 'Leung_2023', 'lnd') + @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: zender_soil_erod_source should NOT be set, when dust_emis_method=Leung_2023')) + call dust_emis_set_options( 'Leung_2023', 'atm') + @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: zender_soil_erod_source should NOT be set, when dust_emis_method=Leung_2023')) + call dust_emis_set_options( 'Zender_2003', 'none') + @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: zender_soil_erod_source can only be lnd or atm')) + call dust_emis_set_options( 'Zender_2003', 'zztop') + @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: zender_soil_erod_source can only be lnd or atm')) + + end subroutine check_options end module test_shr_dust_emis From 0ff68d77dc824f6dbb0c8f6cac0a9ec3773e0b8c Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 1 May 2024 14:05:25 -0600 Subject: [PATCH 055/444] Update cmeps with unit-testing completed --- Externals.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals.cfg b/Externals.cfg index 3753aac874..39818b0fdc 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -50,7 +50,7 @@ required = True [cmeps] #tag = cmeps0.14.50 #branch = dust_emis_mod -hash = ecb6d45aa00a4960564ea963b00754fb4c3b7d2c +hash = 0285eeb59605df44bc3abf38a61e8436361e7e8c protocol = git #repo_url = https://github.com/ESCOMP/CMEPS.git repo_url = https://github.com/ekluzek/CMEPS.git From fffb79409b29ed741c119d9fb37496898a689cd9 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 1 May 2024 15:46:26 -0700 Subject: [PATCH 056/444] add use_fates_lupft switch --- bld/CLMBuildNamelist.pm | 25 +++++++++++++++++++ bld/namelist_files/namelist_defaults_ctsm.xml | 18 +++++++------ .../namelist_definition_ctsm.xml | 6 +++++ src/main/clm_varctl.F90 | 1 + src/main/controlMod.F90 | 3 +++ src/utils/clmfates_interfaceMod.F90 | 16 ++++-------- 6 files changed, 51 insertions(+), 18 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 7e2e4294af..021381a18e 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4414,6 +4414,31 @@ sub setup_logic_fates { } } } + # make sure that fates landuse x pft mode has the necessary run mode configurations + # and add the necessary landuse x pft static mapping data default if not defined + my $var = "use_fates_lupft"; + if ( defined($nl->get_value($var)) ) { + if ( &value_is_true($nl->get_value($var)) ) { + $var = "flandusepftdat"; + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, + 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); + my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); + if ( ! defined($nl->get_value($var)) ) { + fatal_error("$var is required when use_fates_lupft is set" ); + } elsif ( ! -f "$fname" ) { + fatal_error("$fname does NOT point to a valid filename" ); + } + } + # make sure that nocomp and fbg mode are enabled as well as use_fates_luh + my @list = ( "use_fates_nocomp", "use_fates_fixed_biogeog, use_fates_luh" ); + foreach my $var ( @list ) { + if ( ! &value_is_true($nl->get_value($var)) ) { + fatal_error("$var is required when use_fates_lupft is true" ); + } + } + } + # check that fates landuse change mode has the necessary luh2 landuse timeseries data + # and add the default if not defined my $var = "use_fates_luh"; if ( defined($nl->get_value($var)) ) { if ( &value_is_true($nl->get_value($var)) ) { diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 66c0f837e0..49109c6591 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2767,17 +2767,21 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 .false. .false. .false. +.false. .false. -.true. -.true. -.false. +.true. +.true. +.true. +.false. 1 0 -.true. -.false. -.true. -.false. +.true. +.true. +.false. +.true. +.true. +.false. diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index fa2d83a3c9..a2df9b1d1e 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -791,6 +791,12 @@ data (fates_harvest_mode >= 3) (Also, only valid for use_fates = true and is incompatible with transient runs currently.) + +If TRUE, enable use of fates land use x pft mapping data file. +(Only valid for use_fates = true and is incompatible with transient runs currently.) + + If TRUE, ignore the land-use state vector and transitions, and assert that all lands diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 9ab6c631c7..64d6e15747 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -311,6 +311,7 @@ module clm_varctl logical, public :: use_fates_fixed_biogeog = .false. ! true => use fixed biogeography mode logical, public :: use_fates_nocomp = .false. ! true => use no comopetition mode logical, public :: use_fates_luh = .false. ! true => use FATES landuse data mode + logical, public :: use_fates_lupft = .false. ! true => use FATES landuse x pft static mapping mode logical, public :: use_fates_potentialveg = .false. ! true => FATES potential veg only character(len=256), public :: fluh_timeseries = '' ! filename for fates landuse timeseries data character(len=256), public :: flandusepftdat = '' ! filename for fates landuse x pft data diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 196bc141ff..55dd92305d 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -231,6 +231,7 @@ subroutine control_init(dtime) use_fates_nocomp, & use_fates_sp, & use_fates_luh, & + use_fates_lupft, & use_fates_potentialveg, & fluh_timeseries, & flandusepftdat, & @@ -785,6 +786,7 @@ subroutine control_spmd() call mpi_bcast (use_fates_nocomp, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_sp, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_luh, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_fates_lupft, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_potentialveg, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_bgc, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (fates_inventory_ctrl_filename, len(fates_inventory_ctrl_filename), MPI_CHARACTER, 0, mpicom, ier) @@ -1161,6 +1163,7 @@ subroutine control_print () write(iulog, *) ' use_fates_nocomp = ', use_fates_nocomp write(iulog, *) ' use_fates_sp = ', use_fates_sp write(iulog, *) ' use_fates_luh= ', use_fates_luh + write(iulog, *) ' use_fates_lupft= ', use_fates_lupft write(iulog, *) ' use_fates_potentialveg = ', use_fates_potentialveg write(iulog, *) ' fluh_timeseries = ', trim(fluh_timeseries) write(iulog, *) ' flandusepftdat = ', trim(flandusepftdat) diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index 3f84a28508..b0ae0044f3 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -60,6 +60,7 @@ module CLMFatesInterfaceMod use clm_varctl , only : use_fates_nocomp use clm_varctl , only : use_fates_sp use clm_varctl , only : use_fates_luh + use clm_varctl , only : use_fates_lupft use clm_varctl , only : use_fates_potentialveg use clm_varctl , only : flandusepftdat use clm_varctl , only : fates_seeddisp_cadence @@ -567,13 +568,6 @@ subroutine CLMFatesGlobals2() end if call set_fates_ctrlparms('use_fates_potentialveg',ival=pass_use_potentialveg) - if(flandusepftdat /= '') then - pass_lupftdat = 1 - else - pass_lupftdat = 0 - end if - call set_fates_ctrlparms('use_landusepft_data',ival=pass_lupftdat) - ! Wait to set the harvest and logging variables after checking get_do_harvest ! and fates_harvest_modes call set_fates_ctrlparms('use_lu_harvest',ival=pass_lu_harvest) @@ -710,7 +704,7 @@ subroutine init(this, bounds_proc, flandusepftdat) end if ! Retrieve the landuse x pft static data if the file is present - if (flandusepftdat /= '') then + if (use_fates_lupft) then call GetLandusePFTData(bounds_proc, flandusepftdat, landuse_pft_map, landuse_bareground) end if @@ -821,12 +815,12 @@ subroutine init(this, bounds_proc, flandusepftdat) this%fates(nc)%sites(s)%lon = grc%londeg(g) ! Transfer the landuse x pft data to fates via bc_in if file is given - if (flandusepftdat /= '') then + if (use_fates_lupft) then this%fates(nc)%bc_in(s)%pft_areafrac_lu(:,1:num_landuse_pft_vars) = landuse_pft_map(g,:,1:num_landuse_pft_vars) this%fates(nc)%bc_in(s)%baregroundfrac = landuse_bareground(g) end if - if (flandusepftdat == '') then + if (.not. use_fates_lupft) then ! initialize static layers for reduced complexity FATES versions from HLM ! maybe make this into a subroutine of it's own later. this%fates(nc)%bc_in(s)%pft_areafrac(:)=0._r8 @@ -882,7 +876,7 @@ subroutine init(this, bounds_proc, flandusepftdat) call create_fates_fire_data_method( this%fates_fire_data_method ) ! deallocate the local landuse x pft array - if (flandusepftdat /= '') then + if (use_fates_lupft) then deallocate(landuse_pft_map) deallocate(landuse_bareground) end if From 5d11bcf5c1ad64bb8898e54f15852315439c5d57 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 1 May 2024 15:52:27 -0700 Subject: [PATCH 057/444] add fates use_potentialveg namelist defaults settings and checks --- bld/CLMBuildNamelist.pm | 13 ++++++++++++- bld/namelist_files/namelist_defaults_ctsm.xml | 9 +++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 021381a18e..7999e9a31d 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4455,7 +4455,18 @@ sub setup_logic_fates { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, nofail=>1 ); } } - + # check that fates landuse is on and harvest mode is off when potential veg switch is true + my $var = "use_potentialveg"; + if ( defined($nl->get_value($var)) ) { + if ( &value_is_true($nl->get_value($var)) ) { + if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { + fatal_error("use_fates_luh must be true when $var is true" ); + } + if ( $nl->get_value('fates_harvest_mode') > 0) { + fatal_error("fates_harvest_mode must be off (i.e. set to zero) when $var is true" ); + } + } + } # Check fates_harvest_mode compatibility my $var = "fates_harvest_mode"; if ( defined($nl->get_value($var)) ) { diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 49109c6591..68a122e9bc 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2769,10 +2769,11 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 .false. .false. .false. -.true. -.true. -.true. -.false. +.true. +.true. +.true. +.true. +.false. 1 0 From f0f2b9e17c17cc095832e4439313192fdea28a75 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Wed, 1 May 2024 16:58:18 -0600 Subject: [PATCH 058/444] Additional conflict resolution in testlist_clm.xml --- cime_config/testdefs/testlist_clm.xml | 35 +-------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index d3ee1eae35..ff3d113c53 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -955,14 +955,6 @@ - - - - - - - - @@ -981,14 +973,6 @@ - - - - - - - - @@ -1062,15 +1046,6 @@ - - - - - - - - - @@ -1088,14 +1063,6 @@ - - - - - - - - @@ -2875,7 +2842,7 @@ - + From 3cc33e59813be988d983cfca47f2e9ef99819f1d Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 2 May 2024 12:24:55 -0600 Subject: [PATCH 059/444] Update test to use a valid compset --- cime_config/testdefs/testlist_clm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index ff3d113c53..cfd81a5a2b 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -830,7 +830,7 @@ - + From 6bd7d37a956edb0fc2bb20f7d593c64e4fa6eb0c Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 2 May 2024 11:49:28 -0700 Subject: [PATCH 060/444] add use_fates_lupft to default namelist --- bld/CLMBuildNamelist.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 7999e9a31d..23505492bd 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -785,7 +785,7 @@ sub setup_cmdl_fates_mode { "use_fates_cohort_age_tracking","use_fates_inventory_init","use_fates_fixed_biogeog", "use_fates_nocomp","use_fates_sp","fates_inventory_ctrl_filename","fates_harvest_mode", "fates_parteh_mode","use_fates_tree_damage","fates_seeddisp_cadence","use_fates_luh","fluh_timeseries","flandusepftdat", - "use_fates_potentialveg"); + "use_fates_potentialveg","use_fates_lupft"); # dis-allow fates specific namelist items with non-fates runs foreach my $var ( @list ) { if ( defined($nl->get_value($var)) ) { @@ -4371,7 +4371,8 @@ sub setup_logic_fates { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_paramfile', 'phys'=>$nl_flags->{'phys'}); my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys", "use_fates_inventory_init","use_fates_fixed_biogeog","use_fates_nocomp","fates_seeddisp_cadence", - "fates_harvest_mode","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage","use_fates_luh" ); + "fates_harvest_mode","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage", + "use_fates_luh","use_fates_lupft" ); foreach my $var ( @list ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); From bbfe2b4542fc56b08cfeeffefc1b4e54f9572181 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 2 May 2024 15:07:50 -0600 Subject: [PATCH 061/444] Correction to last commit (1850 should have been 2000) --- cime_config/testdefs/testlist_clm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index cfd81a5a2b..bf20c1241a 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -830,7 +830,7 @@ - + From 57004d92e39e6f83393f6f7c74cf3e21062e18c3 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 3 May 2024 17:34:08 -0600 Subject: [PATCH 062/444] New conflict resolution in testlist_clm.xml, this time for an izumi test --- cime_config/testdefs/testlist_clm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index bf20c1241a..c2bb819572 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -1652,7 +1652,7 @@ - + From f65de8fc0968316fe7e9a4c99bbc6e897dee5a92 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sat, 4 May 2024 11:08:24 -0600 Subject: [PATCH 063/444] Add LND_SETS_DUST_EMIS_DRV_FLDS which will be used to NOT set dust_emis drv_flds_in settings when CAM is going to set them --- cime_config/config_component.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cime_config/config_component.xml b/cime_config/config_component.xml index f7adab268f..c474b7e0c1 100644 --- a/cime_config/config_component.xml +++ b/cime_config/config_component.xml @@ -162,6 +162,20 @@ This is typically set by the compset. + + logical + TRUE,FALSE + TRUE + + + + run_component_cpl + env_run.xml + If CTSM will set the dust settings in drv_flds_in (TRUE), or if ATM (i.e. CAM) will - DO NOT EDIT (set by compset name) + + char clm,nwp From 89f08710f61275cb0ac1dea22b5de849787682b2 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sat, 4 May 2024 11:17:34 -0600 Subject: [PATCH 064/444] Move dust_emis and soil_erod namelist items to the drv_fld_in namelist file in CMEPS --- bld/CLMBuildNamelist.pm | 13 ++++++++----- bld/namelist_files/namelist_defaults_ctsm.xml | 2 -- bld/namelist_files/namelist_definition_ctsm.xml | 14 -------------- .../namelist_definition_drv_flds.xml | 13 +++++++++++++ bld/unit_testers/build-namelist_test.pl | 14 +++++++++++++- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index fb44023cd5..ce2c2a81d2 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -517,6 +517,7 @@ sub read_namelist_defaults { "$cfgdir/namelist_files/namelist_defaults_ctsm.xml", "$cfgdir/namelist_files/namelist_defaults_drv.xml", "$cfgdir/namelist_files/namelist_defaults_fire_emis.xml", + "$cfgdir/namelist_files/namelist_defaults_dust_emis.xml", "$cfgdir/namelist_files/namelist_defaults_drydep.xml" ); # Add the location of the use case defaults files to the options hash @@ -3988,7 +3989,7 @@ sub setup_logic_fire_emis { #------------------------------------------------------------------------------- sub setup_logic_dust_emis { - # Logic to handle the dust emissions + # Logic to handle the dust emissions namelists, both drv_flds_in and lnd_in files my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; # First get the dust emission method @@ -4011,14 +4012,16 @@ sub setup_logic_dust_emis { 'dust_emis_method'=>$dust_emis_method, 'zender_soil_erod_source'=>$zender_source, 'hgrid'=>$nl_flags->{'res'}, 'lnd_tuning_mod'=>$nl_flags->{'lnd_tuning_mode'} ); } - } else { + } elsif ( $zender_source eq "atm" ) { foreach my $option ( @zender_files_in_lnd_opts ) { if ( defined($nl->get_value($option)) ) { - $log->fatal_error("zender_soil_erod_source is NOT lnd, but the file option $option is being set" . - " and should NOT be unless you want it handled here in the LAND model, " . + $log->fatal_error("zender_soil_erod_source is atm, and the file option $option is being set" . + " which should NOT be unless you want it handled here in the LAND model, " . "otherwise the equivalent option is set in CAM" ); } } + } elsif ( $zender_source eq "none" ) { + $log->fatal_error("zender_soil_erod_source is set to none and only atm or lnd should be used when $var is Zender_2002" ); } } else { # Verify that NONE of the Zender options are being set if Zender is NOT being used @@ -4736,7 +4739,7 @@ sub write_output_files { $log->verbose_message("Writing clm namelist to $outfile"); # Drydep, fire-emission or MEGAN namelist for driver - @groups = qw(drydep_inparm megan_emis_nl fire_emis_nl carma_inparm); + @groups = qw(drydep_inparm megan_emis_nl fire_emis_nl carma_inparm dust_emis_inparm); $outfile = "$opts->{'dir'}/drv_flds_in"; $nl->write($outfile, 'groups'=>\@groups, 'note'=>"$note" ); $log->verbose_message("Writing @groups namelists to $outfile"); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 147a23f49a..6fde63ee02 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1991,8 +1991,6 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c -Zender_2003 -atm bilinear lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 37c457141c..e730082e90 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1612,20 +1612,6 @@ Mapping method from Nitrogen deposition input file to the model resolution - -Which dust emission method is going to be used. Either the Zender 2003 scheme or the Leung 2023 -scheme. -(NOTE: The Leung 2023 method is NOT currently available) - - - -Option only applying for the Zender_2003 method for whether the soil erodibility file is handled -here in CTSM, or in the ATM model. -(only used when dust_emis_method is Zender_2003) - - Option only applying for the Zender_2003 method for whether the soil erodibility file is handled diff --git a/bld/namelist_files/namelist_definition_drv_flds.xml b/bld/namelist_files/namelist_definition_drv_flds.xml index 088f5c5fa9..89bab07f4f 100644 --- a/bld/namelist_files/namelist_definition_drv_flds.xml +++ b/bld/namelist_files/namelist_definition_drv_flds.xml @@ -123,4 +123,17 @@ List of fluxes needed by the CARMA model, from CLM to CAM. + + Which dust emission method is going to be used. Either the Zender 2003 scheme or the Leung 2023 scheme. + (NOTE: The Leung 2023 method is NOT currently available) + + + + Option only applying for the Zender_2003 method for whether the soil erodibility file is handled + in the active LAND model or in the ATM model. + (only used when dust_emis_method is Zender_2003) + + diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 7b654337af..114fb0c36c 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 2513; +my $ntests = 2515; if ( defined($opts{'compare'}) ) { $ntests += 1545; @@ -1255,6 +1255,18 @@ sub cat_and_create_namelistinfile { GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_1", }, + "soil_erod_none_w_Zender" =>{ options=>"--envxml_dir .", + namelst=>"dust_emis_method='Zender_2003', " . + "zender_soil_erod_source='none'", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_1", + }, + "soil_erod_bad_w_Zender" =>{ options=>"--envxml_dir .", + namelst=>"dust_emis_method='Zender_2003', " . + "zender_soil_erod_source='zztop'", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_1", + }, ); foreach my $key ( keys(%failtest) ) { print( "$key\n" ); From edae95a1013439e234e7d56d57c01efc74ce063f Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Sat, 4 May 2024 13:08:16 -0600 Subject: [PATCH 065/444] manually revert defaults for use_fates_lupft and fix calls to fatal_error --- bld/CLMBuildNamelist.pm | 25 +++++++++++-------- bld/namelist_files/namelist_defaults_ctsm.xml | 7 ++---- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 23505492bd..01d583eb16 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4371,12 +4371,16 @@ sub setup_logic_fates { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_paramfile', 'phys'=>$nl_flags->{'phys'}); my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys", "use_fates_inventory_init","use_fates_fixed_biogeog","use_fates_nocomp","fates_seeddisp_cadence", - "fates_harvest_mode","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage", - "use_fates_luh","use_fates_lupft" ); + "fates_harvest_mode","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage"); foreach my $var ( @list ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); } + + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_lupft', 'use_fates'=>$nl_flags->{'use_fates'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_luh', 'use_fates'=>$nl_flags->{'use_fates'}, + 'use_fates_lupft'=>$nl_flags->{'use_fates_lupft'} ); + my $suplnitro = $nl->get_value('suplnitro'); my $parteh_mode = $nl->get_value('fates_parteh_mode'); if ( ($parteh_mode == 1) && ($suplnitro !~ /ALL/) && not &value_is_true( $nl_flags->{'use_fates_sp'}) ) { @@ -4384,6 +4388,7 @@ sub setup_logic_fates { "but and FATES-SP is not active, but fates_parteh_mode is 1, so Nitrogen is not active" . "Change suplnitro back to ALL"); } + # # For FATES SP mode make sure no-competetiion, and fixed-biogeography are also set # And also check for other settings that can't be trigged on as well @@ -4425,16 +4430,16 @@ sub setup_logic_fates { 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); if ( ! defined($nl->get_value($var)) ) { - fatal_error("$var is required when use_fates_lupft is set" ); + $log->fatal_error("$var is required when use_fates_lupft is set" ); } elsif ( ! -f "$fname" ) { - fatal_error("$fname does NOT point to a valid filename" ); + $log->fatal_error("$fname does NOT point to a valid filename" ); } } # make sure that nocomp and fbg mode are enabled as well as use_fates_luh my @list = ( "use_fates_nocomp", "use_fates_fixed_biogeog, use_fates_luh" ); foreach my $var ( @list ) { if ( ! &value_is_true($nl->get_value($var)) ) { - fatal_error("$var is required when use_fates_lupft is true" ); + $log->fatal_error("$var is required when use_fates_lupft is true" ); } } } @@ -4461,10 +4466,10 @@ sub setup_logic_fates { if ( defined($nl->get_value($var)) ) { if ( &value_is_true($nl->get_value($var)) ) { if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { - fatal_error("use_fates_luh must be true when $var is true" ); + $log->fatal_error("use_fates_luh must be true when $var is true" ); } if ( $nl->get_value('fates_harvest_mode') > 0) { - fatal_error("fates_harvest_mode must be off (i.e. set to zero) when $var is true" ); + $log->fatal_error("fates_harvest_mode must be off (i.e. set to zero) when $var is true" ); } } } @@ -4475,17 +4480,17 @@ sub setup_logic_fates { # if ( $nl->get_value($var) == 2) { # # Make sure that do_harvest is set to true # if ( ! &value_is_true($nl->get_value('do_harvest')) ) { - # fatal_error("do_harvest must be true when $var is equal to 2" ); + # $log->fatal_error("do_harvest must be true when $var is equal to 2" ); # } # using fates_harvest mode with raw luh2 harvest data if ( $nl->get_value($var) > 2) { # Make sure that use_fates_luh is true when using raw fates luh2 harvest data if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { - fatal_error("use_fates_luh is required to be true when $var is greater than 2" ); + $log->fatal_error("use_fates_luh is required to be true when $var is greater than 2" ); } # do_harvest can not be on if we are using the raw fates luh2 harvest data if ( &value_is_true($nl->get_value('do_harvest')) ) { - fatal_error("do_harvest can not be true when $var is greater than 2" ); + $log->fatal_error("do_harvest can not be true when $var is greater than 2" ); } } } diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 68a122e9bc..1195ba5329 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2769,19 +2769,16 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 .false. .false. .false. -.true. -.true. + .true. -.true. .false. + 1 0 .true. -.true. .false. .true. -.true. .false. From af6a1c0e87a4f3d03e3fe6976b00af3ac94398f1 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Sat, 4 May 2024 13:37:22 -0600 Subject: [PATCH 066/444] remove old flandusepftdat add_default and fix use_fates_lupft check this also temporarily removes the use_fates_lupft check for the use_fates_luh namelist defaults --- bld/CLMBuildNamelist.pm | 17 +++++++---------- bld/namelist_files/namelist_defaults_ctsm.xml | 6 +----- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 01d583eb16..1cb14878e7 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4389,7 +4389,6 @@ sub setup_logic_fates { "Change suplnitro back to ALL"); } - # # For FATES SP mode make sure no-competetiion, and fixed-biogeography are also set # And also check for other settings that can't be trigged on as well # @@ -4434,12 +4433,13 @@ sub setup_logic_fates { } elsif ( ! -f "$fname" ) { $log->fatal_error("$fname does NOT point to a valid filename" ); } - } - # make sure that nocomp and fbg mode are enabled as well as use_fates_luh - my @list = ( "use_fates_nocomp", "use_fates_fixed_biogeog, use_fates_luh" ); - foreach my $var ( @list ) { - if ( ! &value_is_true($nl->get_value($var)) ) { - $log->fatal_error("$var is required when use_fates_lupft is true" ); + + # make sure that nocomp and fbg mode are enabled as well as use_fates_luh + my @list = ( "use_fates_nocomp", "use_fates_fixed_biogeog, use_fates_luh" ); + foreach my $var ( @list ) { + if ( ! &value_is_true($nl->get_value($var)) ) { + $log->fatal_error("$var is required when use_fates_lupft is true" ); + } } } } @@ -4456,9 +4456,6 @@ sub setup_logic_fates { } elsif ( ! -f "$fname" ) { $log->fatal_error("$fname does NOT point to a valid filename" ); } - - $var = "flandusepftdat"; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, nofail=>1 ); } } # check that fates landuse is on and harvest mode is off when potential veg switch is true diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 1195ba5329..e6f6b736a6 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2769,13 +2769,9 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 .false. .false. .false. - -.true. -.false. - +.false. 1 0 - .true. .false. .true. From d5575d5c31e0013b8e303b3bc6966f6c8e405f55 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Sat, 4 May 2024 14:42:15 -0600 Subject: [PATCH 067/444] correct call to add_default for use_fates_lupft dependency with use_fates_luh --- bld/CLMBuildNamelist.pm | 2 +- bld/namelist_files/namelist_defaults_ctsm.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 1cb14878e7..7ad35584aa 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4379,7 +4379,7 @@ sub setup_logic_fates { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_lupft', 'use_fates'=>$nl_flags->{'use_fates'}); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_luh', 'use_fates'=>$nl_flags->{'use_fates'}, - 'use_fates_lupft'=>$nl_flags->{'use_fates_lupft'} ); + 'use_fates_lupft'=>$nl->get_value('use_fates_lupft') ); my $suplnitro = $nl->get_value('suplnitro'); my $parteh_mode = $nl->get_value('fates_parteh_mode'); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index e6f6b736a6..38a0fe6493 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2769,7 +2769,8 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 .false. .false. .false. -.false. +.true. +.false. 1 0 .true. From ea773e451b78b3b7011a534a73352693600be95e Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Sat, 4 May 2024 14:53:16 -0600 Subject: [PATCH 068/444] add use_fates_lupft dependencies for nocomp and fbg --- bld/CLMBuildNamelist.pm | 10 ++++++++-- bld/namelist_files/namelist_defaults_ctsm.xml | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 7ad35584aa..261c775fbd 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4370,7 +4370,7 @@ sub setup_logic_fates { if (&value_is_true( $nl_flags->{'use_fates'}) ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_paramfile', 'phys'=>$nl_flags->{'phys'}); my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys", - "use_fates_inventory_init","use_fates_fixed_biogeog","use_fates_nocomp","fates_seeddisp_cadence", + "use_fates_inventory_init","fates_seeddisp_cadence", "fates_harvest_mode","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage"); foreach my $var ( @list ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, @@ -4380,6 +4380,12 @@ sub setup_logic_fates { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_lupft', 'use_fates'=>$nl_flags->{'use_fates'}); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_luh', 'use_fates'=>$nl_flags->{'use_fates'}, 'use_fates_lupft'=>$nl->get_value('use_fates_lupft') ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_nocomp', 'use_fates'=>$nl_flags->{'use_fates'}, + 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), + 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_fixed_biogeog', 'use_fates'=>$nl_flags->{'use_fates'}, + 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), + 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); my $suplnitro = $nl->get_value('suplnitro'); my $parteh_mode = $nl->get_value('fates_parteh_mode'); @@ -4435,7 +4441,7 @@ sub setup_logic_fates { } # make sure that nocomp and fbg mode are enabled as well as use_fates_luh - my @list = ( "use_fates_nocomp", "use_fates_fixed_biogeog, use_fates_luh" ); + my @list = ( "use_fates_luh", "use_fates_nocomp", "use_fates_fixed_biogeog" ); foreach my $var ( @list ) { if ( ! &value_is_true($nl->get_value($var)) ) { $log->fatal_error("$var is required when use_fates_lupft is true" ); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 38a0fe6493..216ad74ca1 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2774,8 +2774,10 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 1 0 .true. +.true. .false. .true. +.true. .false. From a21181f1b3e4a89f426e4b9bdce52e76b06ffc39 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Sun, 5 May 2024 12:24:05 -0600 Subject: [PATCH 069/444] add fates_harvest_mode to use_fates_luh check --- bld/CLMBuildNamelist.pm | 3 ++- bld/namelist_files/namelist_defaults_ctsm.xml | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 261c775fbd..8af5f035e9 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4379,7 +4379,8 @@ sub setup_logic_fates { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_lupft', 'use_fates'=>$nl_flags->{'use_fates'}); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_luh', 'use_fates'=>$nl_flags->{'use_fates'}, - 'use_fates_lupft'=>$nl->get_value('use_fates_lupft') ); + 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), + 'fates_harvest_mode'=>$nl->get_value('fates_harvest_mode') ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_nocomp', 'use_fates'=>$nl_flags->{'use_fates'}, 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 216ad74ca1..206ab7cd1b 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2769,6 +2769,8 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 .false. .false. .false. +.true. +.true. .true. .false. 1 From d8178e415a399f2f0fd61b15f92b4c43f9dd4484 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Sun, 5 May 2024 12:54:52 -0600 Subject: [PATCH 070/444] add use_fates_potentialveg to use_fates_luh check --- bld/CLMBuildNamelist.pm | 4 +++- bld/namelist_files/namelist_defaults_ctsm.xml | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 8af5f035e9..b450060736 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4377,9 +4377,11 @@ sub setup_logic_fates { 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); } + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_potentialveg', 'use_fates'=>$nl_flags->{'use_fates'}); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_lupft', 'use_fates'=>$nl_flags->{'use_fates'}); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_luh', 'use_fates'=>$nl_flags->{'use_fates'}, 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), + 'use_fates_potentialveg'=>$nl->get_value('use_fates_potentialveg'), 'fates_harvest_mode'=>$nl->get_value('fates_harvest_mode') ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_nocomp', 'use_fates'=>$nl_flags->{'use_fates'}, 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), @@ -4466,7 +4468,7 @@ sub setup_logic_fates { } } # check that fates landuse is on and harvest mode is off when potential veg switch is true - my $var = "use_potentialveg"; + my $var = "use_fates_potentialveg"; if ( defined($nl->get_value($var)) ) { if ( &value_is_true($nl->get_value($var)) ) { if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 206ab7cd1b..9d2a34b7bf 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2769,10 +2769,11 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 .false. .false. .false. -.true. -.true. +.true. +.true. .true. -.false. +.true. +.false. 1 0 .true. From 9751fb68174903134e301472087edc263bc4822e Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Sun, 5 May 2024 13:01:20 -0600 Subject: [PATCH 071/444] add check to fates sp mode to make sure landuse isn't enabled --- bld/CLMBuildNamelist.pm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index b450060736..54f0c0c997 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4414,6 +4414,10 @@ sub setup_logic_fates { if ( $nl->get_value('fates_spitfire_mode') > 0 ) { $log->fatal_error('fates_spitfire_mode can NOT be set to greater than 0 when use_fates_sp is true'); } + # fates landuse can't be on with FATES SP mode is active + if ( &value_is_true($nl->get_value('use_fates_luh')) ) { + $log->fatal_error('use_fates_luh can NOT be true when use_fates_sp is true'); + } } } my $var = "use_fates_inventory_init"; From 75f9cc54227f39f7baabc430de7a12506b892192 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 6 May 2024 15:35:56 -0700 Subject: [PATCH 072/444] rename luh unit test that matched old test --- bld/unit_testers/build-namelist_test.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 899bd10b9c..0bf0ea5390 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -1062,7 +1062,7 @@ sub cat_and_create_namelistinfile { GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, - "useinventorybutnotfile" =>{ options=>"--res 0.9x1.25 --bgc fates --envxml_dir . --no-megan", + "useLUH2butnotfile" =>{ options=>"--res 0.9x1.25 --bgc fates --envxml_dir . --no-megan", namelst=>"use_fates_luh=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", From ff3af55931b98e9cb7b9553717d10f2388954197 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 6 May 2024 16:24:30 -0700 Subject: [PATCH 073/444] add build namelist unit tests for fates landuse v2 --- bld/unit_testers/build-namelist_test.pl | 41 +++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 0bf0ea5390..70243c5843 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,10 +163,10 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 1999; +my $ntests = 2006; if ( defined($opts{'compare'}) ) { - $ntests += 1353; + $ntests += 1360; } plan( tests=>$ntests ); @@ -1062,11 +1062,16 @@ sub cat_and_create_namelistinfile { GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, - "useLUH2butnotfile" =>{ options=>"--res 0.9x1.25 --bgc fates --envxml_dir . --no-megan", + "useFATESLUH2butnotfile" =>{ options=>"--res 0.9x1.25 --bgc fates --envxml_dir . --no-megan", namelst=>"use_fates_luh=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, + "useFATESLUPFTbutnotfile" =>{ options=>"--res 0.9x1.25 --bgc fates --envxml_dir . --no-megan", + namelst=>"use_fates_lupft=.true.", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm4_5", + }, "inventoryfileDNE" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_fates_luh=.true., fluh_timeseries='zztop'", GLC_TWO_WAY_COUPLING=>"FALSE", @@ -1092,6 +1097,36 @@ sub cat_and_create_namelistinfile { GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, + "useFATESSPwithLUH" =>{ options=>"-bgc fates -envxml_dir . -no-megan", + namelst=>"use_fates_sp=T,use_fates_luh=T", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "useFATESPOTVEGwithHARVEST" =>{ options=>"-bgc fates -envxml_dir . -no-megan", + namelst=>"use_fates_potentialveg=T,fates_harvest_mode=1", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "useFATESHARVEST3WOLUH" =>{ options=>"-bgc fates -envxml_dir . -no-megan", + namelst=>"use_fates_luh=F,fates_harvest_mode=3", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "useFATESLUPFTWOLUH" =>{ options=>"-bgc fates -envxml_dir . -no-megan", + namelst=>"use_fates_lupft=T,use_fates_luh=F", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "useFATESLUPFTWONOCOMP" =>{ options=>"-bgc fates -envxml_dir . -no-megan", + namelst=>"use_fates_lupft=T,use_fates_nocomp=F", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "useFATESLUPFTWOFBG" =>{ options=>"-bgc fates -envxml_dir . -no-megan", + namelst=>"use_fates_lupft=T,use_fates_fixedbiogeog=F", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, "useFATESTRANSWdynPFT" =>{ options=>"-bgc fates -envxml_dir . -use_case 20thC_transient -no-megan", namelst=>"do_transient_pfts=T", GLC_TWO_WAY_COUPLING=>"FALSE", From 69154dab7b33706491bdabc634d9a80142bf0b35 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 6 May 2024 16:37:07 -0700 Subject: [PATCH 074/444] update fates logging unit test to use new fates harvest mode --- bld/namelist_files/namelist_definition_ctsm.xml | 2 +- bld/unit_testers/build-namelist_test.pl | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index a2df9b1d1e..edcfa36d27 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -814,7 +814,7 @@ types to vary over time. -Full pathname of fates landuse x pft data map. +Full pathname of fates landuse x pft static data map. "FALSE", phys=>"clm4_5", }, - # TODO SSR: Replace this with fates_harvest_mode "useloggingButNOTFATES" =>{ options=>"-envxml_dir . -no-megan", - namelst=>"use_fates_logging=.true.", + namelst=>"fates_harvest_mode=1", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, From 5c5ca6f8e40cc6fe69d9b9a7edf32ce5242a7629 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 6 May 2024 17:49:34 -0600 Subject: [PATCH 075/444] minor update --- bld/unit_testers/build-namelist_test.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 3b2dabd057..f674849b6f 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 2006; +my $ntests = 2007; if ( defined($opts{'compare'}) ) { $ntests += 1360; From 6f8021cb9be81521f4f905b27b353ce9de1980be Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 7 May 2024 03:30:20 -0600 Subject: [PATCH 076/444] Start adding reference for LND_SETS_DUST_EMIS_DRV_FLDS in unit tester --- bld/unit_testers/build-namelist_test.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 114fb0c36c..30110d92f7 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -42,7 +42,7 @@ sub make_env_run { my %settings = @_; # Set default settings - my %env_vars = ( DIN_LOC_ROOT=>"MYDINLOCROOT", GLC_TWO_WAY_COUPLING=>"FALSE", NEONSITE=>"" ); + my %env_vars = ( DIN_LOC_ROOT=>"MYDINLOCROOT", GLC_TWO_WAY_COUPLING=>"FALSE", LND_SETS_DUST_EMIS_DRV_FLDS=>"TRUE", NEONSITE=>"" ); # Set any settings that came in from function call foreach my $item ( keys(%settings) ) { $env_vars{$item} = $settings{$item}; From f52f76fc0c71f3521a0680207141b1545dd6098a Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 7 May 2024 03:31:04 -0600 Subject: [PATCH 077/444] Add dust emis namelist default for drv_flds_in --- .../namelist_defaults_dust_emis.xml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 bld/namelist_files/namelist_defaults_dust_emis.xml diff --git a/bld/namelist_files/namelist_defaults_dust_emis.xml b/bld/namelist_files/namelist_defaults_dust_emis.xml new file mode 100644 index 0000000000..40bf3d9078 --- /dev/null +++ b/bld/namelist_files/namelist_defaults_dust_emis.xml @@ -0,0 +1,21 @@ + + + + + + + + + +Zender_2003 + +atm + + From 2a88002ea1a916d21da69b05c6621774cca74b39 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 7 May 2024 10:26:16 -0700 Subject: [PATCH 078/444] change lupft check to fbg + luh check to mirror fates-side logic --- src/utils/clmfates_interfaceMod.F90 | 37 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index b0ae0044f3..048824a83a 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -398,7 +398,6 @@ subroutine CLMFatesGlobals2() integer :: pass_use_potentialveg integer :: pass_num_luh_states integer :: pass_num_luh_transitions - integer :: pass_lupftdat call t_startf('fates_globals2') @@ -704,7 +703,7 @@ subroutine init(this, bounds_proc, flandusepftdat) end if ! Retrieve the landuse x pft static data if the file is present - if (use_fates_lupft) then + if (use_fates_fixed_biogeog .and. use_fates_luh) then call GetLandusePFTData(bounds_proc, flandusepftdat, landuse_pft_map, landuse_bareground) end if @@ -815,23 +814,23 @@ subroutine init(this, bounds_proc, flandusepftdat) this%fates(nc)%sites(s)%lon = grc%londeg(g) ! Transfer the landuse x pft data to fates via bc_in if file is given - if (use_fates_lupft) then - this%fates(nc)%bc_in(s)%pft_areafrac_lu(:,1:num_landuse_pft_vars) = landuse_pft_map(g,:,1:num_landuse_pft_vars) - this%fates(nc)%bc_in(s)%baregroundfrac = landuse_bareground(g) - end if - - if (.not. use_fates_lupft) then - ! initialize static layers for reduced complexity FATES versions from HLM - ! maybe make this into a subroutine of it's own later. - this%fates(nc)%bc_in(s)%pft_areafrac(:)=0._r8 - do m = surfpft_lb,surfpft_ub - ft = m - surfpft_lb - this%fates(nc)%bc_in(s)%pft_areafrac(ft)=wt_nat_patch(g,m) - end do + if (use_fates_fixed_biogeog) then + if (use_fates_luh) then + this%fates(nc)%bc_in(s)%pft_areafrac_lu(:,1:num_landuse_pft_vars) = landuse_pft_map(g,:,1:num_landuse_pft_vars) + this%fates(nc)%bc_in(s)%baregroundfrac = landuse_bareground(g) + else + ! initialize static layers for reduced complexity FATES versions from HLM + ! maybe make this into a subroutine of it's own later. + this%fates(nc)%bc_in(s)%pft_areafrac(:)=0._r8 + do m = surfpft_lb,surfpft_ub + ft = m - surfpft_lb + this%fates(nc)%bc_in(s)%pft_areafrac(ft)=wt_nat_patch(g,m) + end do - if (abs(sum(this%fates(nc)%bc_in(s)%pft_areafrac(surfpft_lb:surfpft_ub)) - 1.0_r8) > sum_to_1_tol) then - write(iulog,*) 'pft_area error in interfc ', s, sum(this%fates(nc)%bc_in(s) %pft_areafrac(:)) - 1.0_r8 - call endrun(msg=errMsg(sourcefile, __LINE__)) + if (abs(sum(this%fates(nc)%bc_in(s)%pft_areafrac(surfpft_lb:surfpft_ub)) - 1.0_r8) > sum_to_1_tol) then + write(iulog,*) 'pft_area error in interfc ', s, sum(this%fates(nc)%bc_in(s) %pft_areafrac(:)) - 1.0_r8 + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if end if end if end do !site @@ -876,7 +875,7 @@ subroutine init(this, bounds_proc, flandusepftdat) call create_fates_fire_data_method( this%fates_fire_data_method ) ! deallocate the local landuse x pft array - if (use_fates_lupft) then + if (use_fates_fixed_biogeog .and. use_fates_luh) then deallocate(landuse_pft_map) deallocate(landuse_bareground) end if From 0bcf80acea865f2df37d13911aa6b9d167622a66 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 1 May 2024 16:37:32 -0600 Subject: [PATCH 079/444] FatesColdLUH2 tests now use use_fates_nocomp false. --- cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm | 1 + 1 file changed, 1 insertion(+) diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm index 854c21407f..917ba314b3 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm @@ -1 +1,2 @@ use_fates_luh = .true. +use_fates_nocomp = .false. From 0edcb1b5b118c7029807a05e1ce3773396c6ec7f Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 8 May 2024 10:22:47 -0600 Subject: [PATCH 080/444] Update FATES external to latest ckoven/luh2_nocomp_merge. --- Externals_CLM.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals_CLM.cfg b/Externals_CLM.cfg index b689141aaf..e1bc1696af 100644 --- a/Externals_CLM.cfg +++ b/Externals_CLM.cfg @@ -2,7 +2,7 @@ local_path = src/fates protocol = git repo_url = https://github.com/ckoven/fates -hash = c1a7453c8331277a156a0ee158a870c1b8598a9f +hash = 153b0bda9c96f18e8d2a93887a082bc7a31b574b required = True [externals_description] From 92fb80687f707c1799cacea85bc64bc9c1cd9f89 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 8 May 2024 13:25:19 -0600 Subject: [PATCH 081/444] Update FatesColdLUH2 testdef. --- .../testmods_dirs/clm/FatesColdLUH2/user_nl_clm | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm index 917ba314b3..970e7df7cd 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm @@ -1,2 +1,11 @@ + +! Run a transient case, with vegetation starting from bare ground, but land use starting from LUH state vector on starting date, in a nocomp configuration. +! From Charlie's list of valid FATES configurations: +! https://docs.google.com/spreadsheets/d/1eE3sRMYxfocZKbT8uIQhXpjjtfM2feXPRSWXJNoo4jM/edit#gid=0 +flandusepftdat = '$DIN_LOC_ROOT/lnd/clm2/surfdata_map/fates-sci.1.73.0_api.36.0.0/fates_landuse_pft_map_4x5_240206.nc' use_fates_luh = .true. -use_fates_nocomp = .false. +use_fates_nocomp = .true. +use_fates_fixed_biogeog = .true. +use_fates_sp = .false. +use_fates_potentialveg = .false. +fluh_timeseries = '$DIN_LOC_ROOT/lnd/clm2/surfdata_map/fates-sci.1.68.3_api.31.0.0_tools.1.0.1/LUH2_states_transitions_management.timeseries_4x5_hist_simyr1850-2015_c231101.nc' From f6728017c7726f947492179f88031cccfa81181f Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 8 May 2024 13:26:56 -0600 Subject: [PATCH 082/444] Add FatesColdLUH2Mode0 testdef. --- cime_config/testdefs/testlist_clm.xml | 9 +++++++++ .../clm/FatesColdLUH2Mode0/include_user_mods | 1 + .../testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm | 1 + 3 files changed, 11 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 4184cc7e1f..022bb9ad73 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2910,6 +2910,15 @@ + + + + + + + + + diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/include_user_mods new file mode 100644 index 0000000000..7eb8bb1579 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/include_user_mods @@ -0,0 +1 @@ +../FatesColdLUH2 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm new file mode 100644 index 0000000000..929a8e6e14 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm @@ -0,0 +1 @@ +fates_harvest_mode = 0 From 05332fb117e7ed94abcc09c5c66f5db8d8885638 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 9 May 2024 10:53:59 -0700 Subject: [PATCH 083/444] Remove get_do_harvest dependency for fates harvest modes --- src/dyn_subgrid/dynSubgridDriverMod.F90 | 7 ++- src/utils/clmfates_interfaceMod.F90 | 71 +++++++++---------------- 2 files changed, 32 insertions(+), 46 deletions(-) diff --git a/src/dyn_subgrid/dynSubgridDriverMod.F90 b/src/dyn_subgrid/dynSubgridDriverMod.F90 index e5ca3f002e..b12b135b59 100644 --- a/src/dyn_subgrid/dynSubgridDriverMod.F90 +++ b/src/dyn_subgrid/dynSubgridDriverMod.F90 @@ -89,6 +89,11 @@ subroutine dynSubgrid_init(bounds_proc, glc_behavior, crop_inst) ! Note that dynpft_init needs to be called from outside any loops over clumps - so ! this routine needs to be called from outside any loops over clumps. ! + ! + ! !USES: + use clm_varctl , only : fates_harvest_mode + use dynFATESLandUseChangeMod , only : fates_harvest_clmlanduse + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds_proc ! processor-level bounds type(glc_behavior_type) , intent(in) :: glc_behavior @@ -123,7 +128,7 @@ subroutine dynSubgrid_init(bounds_proc, glc_behavior, crop_inst) ! flanduse_timeseries file. However, this could theoretically be changed so that the ! harvest data were separated from the pftdyn data, allowing them to differ in the ! years over which they apply. - if (get_do_harvest()) then + if (get_do_harvest() .or. fates_harvest_mode >= fates_harvest_clmlanduse) then call dynHarvest_init(bounds_proc, harvest_filename=get_flanduse_timeseries()) end if diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index 048824a83a..308d5cee8e 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -169,7 +169,6 @@ module CLMFatesInterfaceMod use FATESFireBase , only : fates_fire_base_type use FATESFireFactoryMod , only : no_fire, scalar_lightning, successful_ignitions,& anthro_ignitions, anthro_suppression - use dynSubgridControlMod , only : get_do_harvest use dynHarvestMod , only : num_harvest_inst, harvest_varnames use dynHarvestMod , only : harvest_units, mass_units, unitless_units use dynHarvestMod , only : dynHarvest_interp_resolve_harvesttypes @@ -185,6 +184,7 @@ module CLMFatesInterfaceMod use dynFATESLandUseChangeMod, only : dynFatesLandUseInterp use dynFATESLandUseChangeMod, only : num_landuse_harvest_vars use dynFATESLandUseChangeMod, only : fates_harvest_no_logging + use dynFATESLandUseChangeMod, only : fates_harvest_clmlanduse use dynFATESLandUseChangeMod, only : fates_harvest_luh_area use dynFATESLandUseChangeMod, only : landuse_harvest use dynFATESLandUseChangeMod, only : landuse_harvest_units @@ -489,13 +489,6 @@ subroutine CLMFatesGlobals2() end if call set_fates_ctrlparms('use_ed_st3',ival=pass_ed_st3) - if (fates_harvest_mode > fates_harvest_no_logging) then - pass_logging = 1 - else - pass_logging = 0 - end if - call set_fates_ctrlparms('use_logging',ival=pass_logging) - if(use_fates_ed_prescribed_phys) then pass_ed_prescribed_phys = 1 else @@ -517,39 +510,28 @@ subroutine CLMFatesGlobals2() end if call set_fates_ctrlparms('use_cohort_age_tracking',ival=pass_cohort_age_tracking) - ! check fates logging namelist value first because hlm harvest can override it + ! FATES logging and harvest modes if (fates_harvest_mode > fates_harvest_no_logging) then - pass_logging = 1 - else - pass_logging = 0 - end if - - if(get_do_harvest()) then - pass_logging = 1 - pass_num_lu_harvest_cats = num_harvest_inst - pass_lu_harvest = 1 - else - pass_lu_harvest = 0 - pass_num_lu_harvest_cats = 0 - end if + pass_logging = 1 ! Time driven logging, without landuse harvest + ! CLM landuse timeseries driven harvest rates + if (fates_harvest_mode == fates_harvest_clmlanduse) + pass_num_lu_harvest_cats = num_harvest_inst + pass_lu_harvest = 1 + + ! LUH2 landuse timeseries driven harvest rates + else if (fates_harvest_mode >= fates_harvest_luh_area) then + pass_lu_harvest = 1 + pass_num_lu_harvest_types = num_landuse_harvest_vars + else + pass_lu_harvest = 0 + pass_num_lu_harvest_cats = 0 + end if + ! FATES landuse modes if(use_fates_luh) then pass_use_luh = 1 pass_num_luh_states = num_landuse_state_vars pass_num_luh_transitions = num_landuse_transition_vars - - ! Do not set harvest passing variables to zero not in luh harvest modes - ! as the user may want to use the CLM landuse harvest with luh2 transitions - if(fates_harvest_mode >= fates_harvest_luh_area) then - ! End the run if do_harvest is true with this run mode. - ! This should be caught be the build namelist. - if(get_do_harvest()) then - call endrun(msg="do_harvest and fates_harvest_mode using luh2 harvest data are incompatible"//& - errmsg(sourcefile, __LINE__)) - else - pass_lu_harvest = 1 - end if - end if else pass_use_luh = 0 pass_num_luh_states = 0 @@ -567,8 +549,7 @@ subroutine CLMFatesGlobals2() end if call set_fates_ctrlparms('use_fates_potentialveg',ival=pass_use_potentialveg) - ! Wait to set the harvest and logging variables after checking get_do_harvest - ! and fates_harvest_modes + ! Wait to set the harvest and logging variables after checking fates_harvest_modes call set_fates_ctrlparms('use_lu_harvest',ival=pass_lu_harvest) call set_fates_ctrlparms('num_lu_harvest_cats',ival=pass_num_lu_harvest_cats) call set_fates_ctrlparms('use_logging',ival=pass_logging) @@ -996,7 +977,8 @@ subroutine dynamics_driv(this, nc, bounds_clump, & ! Set the FATES global time and date variables call GetAndSetTime - if (get_do_harvest()) then + ! Get harvest rates for CLM landuse timeseries driven rates + if (fates_harvest_mode == fates_harvest_clmlanduse) call dynHarvest_interp_resolve_harvesttypes(bounds_clump, & harvest_rates=harvest_rates(begg:endg,1:num_harvest_inst), & after_start_of_harvest_ts=after_start_of_harvest_ts) @@ -1122,7 +1104,7 @@ subroutine dynamics_driv(this, nc, bounds_clump, & ! for now there is one veg column per gridcell, so store all harvest data in each site ! this will eventually change ! today's hlm harvest flag needs to be set no matter what - if (get_do_harvest()) then + if (fates_harvest_mode == fates_harvest_clmlanduse) if (after_start_of_harvest_ts) then this%fates(nc)%bc_in(s)%hlm_harvest_rates(1:num_harvest_inst) = harvest_rates(g,1:num_harvest_inst) else @@ -1140,6 +1122,11 @@ subroutine dynamics_driv(this, nc, bounds_clump, & write(iulog,*) harvest_units call endrun(msg=errMsg(sourcefile, __LINE__)) end if + + else if (fates_harvest_mode >= fates_harvest_luh_area) then + this%fates(nc)%bc_in(s)%hlm_harvest_rates = landuse_harvest(:,g) + this%fates(nc)%bc_in(s)%hlm_harvest_catnames = landuse_harvest_varnames + this%fates(nc)%bc_in(s)%hlm_harvest_units = landuse_harvest_units endif if (use_fates_luh) then @@ -1147,12 +1134,6 @@ subroutine dynamics_driv(this, nc, bounds_clump, & this%fates(nc)%bc_in(s)%hlm_luh_state_names = landuse_state_varnames this%fates(nc)%bc_in(s)%hlm_luh_transitions = landuse_transitions(:,g) this%fates(nc)%bc_in(s)%hlm_luh_transition_names = landuse_transition_varnames - - if (fates_harvest_mode >= fates_harvest_luh_area) then - this%fates(nc)%bc_in(s)%hlm_harvest_rates = landuse_harvest(:,g) - this%fates(nc)%bc_in(s)%hlm_harvest_catnames = landuse_harvest_varnames - this%fates(nc)%bc_in(s)%hlm_harvest_units = landuse_harvest_units - end if end if end do From a35f91d53444c2ac7af2ee1434ae0f85431208b4 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 9 May 2024 11:15:18 -0700 Subject: [PATCH 084/444] fix check to be only during use of clm landuse timeseries for fates --- src/dyn_subgrid/dynSubgridDriverMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dyn_subgrid/dynSubgridDriverMod.F90 b/src/dyn_subgrid/dynSubgridDriverMod.F90 index b12b135b59..162247a0ff 100644 --- a/src/dyn_subgrid/dynSubgridDriverMod.F90 +++ b/src/dyn_subgrid/dynSubgridDriverMod.F90 @@ -128,7 +128,7 @@ subroutine dynSubgrid_init(bounds_proc, glc_behavior, crop_inst) ! flanduse_timeseries file. However, this could theoretically be changed so that the ! harvest data were separated from the pftdyn data, allowing them to differ in the ! years over which they apply. - if (get_do_harvest() .or. fates_harvest_mode >= fates_harvest_clmlanduse) then + if (get_do_harvest() .or. fates_harvest_mode == fates_harvest_clmlanduse) then call dynHarvest_init(bounds_proc, harvest_filename=get_flanduse_timeseries()) end if From 74e86669d21c18043a057d955f55e17bd5e7913e Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 9 May 2024 11:48:57 -0700 Subject: [PATCH 085/444] fix passing num landuse harvest vars to the fates landuse harvest categories --- src/utils/clmfates_interfaceMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index 308d5cee8e..cd94b6a15c 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -521,7 +521,7 @@ subroutine CLMFatesGlobals2() ! LUH2 landuse timeseries driven harvest rates else if (fates_harvest_mode >= fates_harvest_luh_area) then pass_lu_harvest = 1 - pass_num_lu_harvest_types = num_landuse_harvest_vars + pass_num_lu_harvest_cats = num_landuse_harvest_vars else pass_lu_harvest = 0 pass_num_lu_harvest_cats = 0 From fd07890223b3e92d91caa1a034055d1184bcff2e Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 9 May 2024 11:51:20 -0700 Subject: [PATCH 086/444] fix missing end if --- src/utils/clmfates_interfaceMod.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index cd94b6a15c..b9e9bf3031 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -526,6 +526,7 @@ subroutine CLMFatesGlobals2() pass_lu_harvest = 0 pass_num_lu_harvest_cats = 0 end if + end if ! FATES landuse modes if(use_fates_luh) then From 72ed62381b8312b0f0355b938d30c8b1a852cb31 Mon Sep 17 00:00:00 2001 From: loaner Date: Thu, 9 May 2024 16:25:53 -0700 Subject: [PATCH 087/444] update do_harvest to not be compatible with fates --- bld/CLMBuildNamelist.pm | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 54f0c0c997..e422109078 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -2932,7 +2932,7 @@ sub setup_logic_do_harvest { $cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)"; } - elsif (!&value_is_true($nl->get_value('use_cn')) && !&value_is_true($nl->get_value('use_fates'))) { + elsif (!&value_is_true($nl->get_value('use_cn')) && &value_is_true($nl->get_value('use_fates'))) { $cannot_be_true = "$var can only be set to true when running with either CN or FATES"; } @@ -4486,22 +4486,12 @@ sub setup_logic_fates { # Check fates_harvest_mode compatibility my $var = "fates_harvest_mode"; if ( defined($nl->get_value($var)) ) { - # using fates_harvest_mode with CLM landuse driver data - for user convienence - # if ( $nl->get_value($var) == 2) { - # # Make sure that do_harvest is set to true - # if ( ! &value_is_true($nl->get_value('do_harvest')) ) { - # $log->fatal_error("do_harvest must be true when $var is equal to 2" ); - # } # using fates_harvest mode with raw luh2 harvest data if ( $nl->get_value($var) > 2) { # Make sure that use_fates_luh is true when using raw fates luh2 harvest data if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { $log->fatal_error("use_fates_luh is required to be true when $var is greater than 2" ); } - # do_harvest can not be on if we are using the raw fates luh2 harvest data - if ( &value_is_true($nl->get_value('do_harvest')) ) { - $log->fatal_error("do_harvest can not be true when $var is greater than 2" ); - } } } } From f00ba49d552a3dc3578012f1cf32e6925ac224f9 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 9 May 2024 17:58:07 -0600 Subject: [PATCH 088/444] remove fates from the do_harvest section altogether --- bld/CLMBuildNamelist.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index e422109078..aafc7739a3 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -2932,8 +2932,8 @@ sub setup_logic_do_harvest { $cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)"; } - elsif (!&value_is_true($nl->get_value('use_cn')) && &value_is_true($nl->get_value('use_fates'))) { - $cannot_be_true = "$var can only be set to true when running with either CN or FATES"; + elsif (!&value_is_true($nl->get_value('use_cn'))) { + $cannot_be_true = "$var can only be set to true when running with CN. Please set use_cn to true."; } if ($cannot_be_true) { From 278a901fc4821e0c6abef4e0c5ed9bbf41f64516 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 10 May 2024 10:43:41 -0700 Subject: [PATCH 089/444] fix if statements --- src/utils/clmfates_interfaceMod.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index b9e9bf3031..5c23f1c1dc 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -514,7 +514,7 @@ subroutine CLMFatesGlobals2() if (fates_harvest_mode > fates_harvest_no_logging) then pass_logging = 1 ! Time driven logging, without landuse harvest ! CLM landuse timeseries driven harvest rates - if (fates_harvest_mode == fates_harvest_clmlanduse) + if (fates_harvest_mode == fates_harvest_clmlanduse) then pass_num_lu_harvest_cats = num_harvest_inst pass_lu_harvest = 1 @@ -979,7 +979,7 @@ subroutine dynamics_driv(this, nc, bounds_clump, & call GetAndSetTime ! Get harvest rates for CLM landuse timeseries driven rates - if (fates_harvest_mode == fates_harvest_clmlanduse) + if (fates_harvest_mode == fates_harvest_clmlanduse) then call dynHarvest_interp_resolve_harvesttypes(bounds_clump, & harvest_rates=harvest_rates(begg:endg,1:num_harvest_inst), & after_start_of_harvest_ts=after_start_of_harvest_ts) @@ -1105,7 +1105,7 @@ subroutine dynamics_driv(this, nc, bounds_clump, & ! for now there is one veg column per gridcell, so store all harvest data in each site ! this will eventually change ! today's hlm harvest flag needs to be set no matter what - if (fates_harvest_mode == fates_harvest_clmlanduse) + if (fates_harvest_mode == fates_harvest_clmlanduse) then if (after_start_of_harvest_ts) then this%fates(nc)%bc_in(s)%hlm_harvest_rates(1:num_harvest_inst) = harvest_rates(g,1:num_harvest_inst) else From d66ddff54439bd192b9ed8b07419a17cd3282656 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 13 May 2024 11:21:08 -0700 Subject: [PATCH 090/444] update fates_harvest_mode to use chars to set namelist options initial commit --- src/dyn_subgrid/dynFATESLandUseChangeMod.F90 | 10 ++++++---- src/main/clm_varctl.F90 | 2 +- src/main/controlMod.F90 | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 index 4f326d82a5..d9bd0352ca 100644 --- a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 +++ b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 @@ -171,13 +171,14 @@ subroutine dynFatesLandUseInit(bounds, landuse_filename) end do ! Get the harvest rate data from the fates luh2 timeseries dataset if enabled - if (fates_harvest_mode .ge. fates_harvest_luh_area ) then + if (trim(fates_harvest_mode) .eq. fates_harvest_luh_area .or. & + trim(fates_harvest_mode) .eq. fates_harvest_luh_mass) then ! change the harvest varnames being used depending on the mode selected - if (fates_harvest_mode .eq. fates_harvest_luh_area ) then + if (trim(fates_harvest_mode) .eq. fates_harvest_luh_area ) then landuse_harvest_varnames => landuse_harvest_area_varnames landuse_harvest_units = landuse_harvest_area_units - elseif (fates_harvest_mode .eq. fates_harvest_luh_mass ) then + elseif (trim(fates_harvest_mode) .eq. fates_harvest_luh_mass ) then landuse_harvest_varnames => landuse_harvest_mass_varnames landuse_harvest_units = landuse_harvest_mass_units else @@ -256,7 +257,8 @@ subroutine dynFatesLandUseInterp(bounds, init_state) call landuse_state_vars(varnum)%get_current_data(this_data) landuse_states(varnum,bounds%begg:bounds%endg) = this_data(bounds%begg:bounds%endg) end do - if (fates_harvest_mode .ge. fates_harvest_luh_area ) then + if (trim(fates_harvest_mode) .eq. fates_harvest_luh_area .or. & + trim(fates_harvest_mode) .eq. fates_harvest_luh_mass) then do varnum = 1, num_landuse_harvest_vars call landuse_harvest_vars(varnum)%get_current_data(this_data) landuse_harvest(varnum,bounds%begg:bounds%endg) = this_data(bounds%begg:bounds%endg) diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 64d6e15747..59b72c8e74 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -302,7 +302,7 @@ module clm_varctl ! > 1 for external data (lightning and/or anthropogenic ignitions) ! see bld/namelist_files/namelist_definition_clm4_5.xml for details logical, public :: use_fates_tree_damage = .false. ! true => turn on tree damage module - integer, public :: fates_harvest_mode = 0 ! 0 for no harvest/logging; 1-4 for harvest mode options + character(len=256), public :: fates_harvest_mode = '' ! five different harvest modes; see namelist definition logical, public :: use_fates_planthydro = .false. ! true => turn on fates hydro logical, public :: use_fates_cohort_age_tracking = .false. ! true => turn on cohort age tracking logical, public :: use_fates_ed_st3 = .false. ! true => static stand structure diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 55dd92305d..1dd432bb7e 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -775,7 +775,7 @@ subroutine control_spmd() call mpi_bcast (for_testing_allow_interp_non_ciso_to_ciso, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (fates_spitfire_mode, 1, MPI_INTEGER, 0, mpicom, ier) - call mpi_bcast (fates_harvest_mode, 1, MPI_INTEGER, 0, mpicom, ier) + call mpi_bcast (fates_harvest_mode, len(fates_harvest_mode) , MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (use_fates_planthydro, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_tree_damage, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_cohort_age_tracking, 1, MPI_LOGICAL, 0, mpicom, ier) From 458c788eb6b7ca8b6351a5c3e4ebfae7d8364e21 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 13 May 2024 15:07:05 -0700 Subject: [PATCH 091/444] add default pass values for logging and harvest --- src/utils/clmfates_interfaceMod.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index 5c23f1c1dc..ba6c59143f 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -511,6 +511,9 @@ subroutine CLMFatesGlobals2() call set_fates_ctrlparms('use_cohort_age_tracking',ival=pass_cohort_age_tracking) ! FATES logging and harvest modes + pass_logging = 0 + pass_lu_harvest = 0 + pass_num_lu_harvest_cats = 0 if (fates_harvest_mode > fates_harvest_no_logging) then pass_logging = 1 ! Time driven logging, without landuse harvest ! CLM landuse timeseries driven harvest rates @@ -522,9 +525,6 @@ subroutine CLMFatesGlobals2() else if (fates_harvest_mode >= fates_harvest_luh_area) then pass_lu_harvest = 1 pass_num_lu_harvest_cats = num_landuse_harvest_vars - else - pass_lu_harvest = 0 - pass_num_lu_harvest_cats = 0 end if end if From 28f5bc36108af5281f3fdfd286b43bac5a849786 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 13 May 2024 15:25:00 -0700 Subject: [PATCH 092/444] update fates_harvest_mode to accept strings --- bld/CLMBuildNamelist.pm | 4 +-- bld/namelist_files/namelist_defaults_ctsm.xml | 6 ++--- .../namelist_definition_ctsm.xml | 17 ++++++------ bld/unit_testers/build-namelist_test.pl | 6 ++--- .../clm/FatesColdLUH2Mode0/user_nl_clm | 2 +- .../clm/FatesColdLUH2Mode1/user_nl_clm | 2 +- .../clm/FatesColdLUH2Mode2/user_nl_clm | 2 +- .../clm/FatesColdLUH2Mode3/user_nl_clm | 2 +- .../clm/FatesColdLUH2Mode4/user_nl_clm | 2 +- src/dyn_subgrid/dynSubgridDriverMod.F90 | 2 +- src/utils/clmfates_interfaceMod.F90 | 27 ++++++++++--------- 11 files changed, 37 insertions(+), 35 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index aafc7739a3..456447925c 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4478,7 +4478,7 @@ sub setup_logic_fates { if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { $log->fatal_error("use_fates_luh must be true when $var is true" ); } - if ( $nl->get_value('fates_harvest_mode') > 0) { + if ( $nl->get_value('fates_harvest_mode') ne 'no_harvest') { $log->fatal_error("fates_harvest_mode must be off (i.e. set to zero) when $var is true" ); } } @@ -4487,7 +4487,7 @@ sub setup_logic_fates { my $var = "fates_harvest_mode"; if ( defined($nl->get_value($var)) ) { # using fates_harvest mode with raw luh2 harvest data - if ( $nl->get_value($var) > 2) { + if ( $nl->get_value($var) eq 'luhdata_area' || $nl->get_value($var) eq 'luhdata_mass' ) { # Make sure that use_fates_luh is true when using raw fates luh2 harvest data if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { $log->fatal_error("use_fates_luh is required to be true when $var is greater than 2" ); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 9d2a34b7bf..5da9cb22bf 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2759,7 +2759,7 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 0 -0 +no_harvest .false. .false. .false. @@ -2769,8 +2769,8 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 .false. .false. .false. -.true. -.true. +.true. +.true. .true. .true. .false. diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index edcfa36d27..03b1e9e64d 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -735,14 +735,14 @@ Toggle to turn on FATES satellite phenology mode (only relevant if FATES is bein -Set FATES harvesting mode by setting fates_harvest_mode > 0. + group="clm_inparm" valid_values="no_harvest_event_code,surfdata_file,luhdata_area,luhdata_mass"> +Set FATES harvesting mode by setting fates_harvest_mode to a valid string option. Allowed values are: - 0 : no fates harvesting of any kind - 1 : fates logging via fates logging event codes (see fates parameter file) only - 2 : fates harvest driven by CLM landuse timeseries data (dynHarvestMod) - 3 : fates harvest driven by LUH2 raw harvest data, area-based (dynFATESLandUseChangeMod) - 4 : fates harvest driven by LUH2 raw harvest data, mass-based (dynFATESLandUseChangeMod) + no_harvest: no fates harvesting of any kind + event_code: fates logging via fates logging event codes (see fates parameter file) only + surfdata_file: fates harvest driven by CLM landuse timeseries data (dynHarvestMod) + luhdata_area: fates harvest driven by LUH2 raw harvest data, area-based (dynFATESLandUseChangeMod) + luhdata_mass: fates harvest driven by LUH2 raw harvest data, mass-based (dynFATESLandUseChangeMod) If TRUE, enable use of land use harmonization (LUH) state and transition data from luh_timeseries file. -This is enabled by default if fates_harvest_mode is set to use the raw LUH2 harvest -data (fates_harvest_mode >= 3) +This is enabled by default if fates_harvest_mode is set to use the raw LUH2 harvest data (Also, only valid for use_fates = true and is incompatible with transient runs currently.) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index f674849b6f..973fdffd16 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -1047,7 +1047,7 @@ sub cat_and_create_namelistinfile { phys=>"clm4_5", }, "useloggingButNOTFATES" =>{ options=>"-envxml_dir . -no-megan", - namelst=>"fates_harvest_mode=1", + namelst=>"fates_harvest_mode=event_code", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, @@ -1102,12 +1102,12 @@ sub cat_and_create_namelistinfile { phys=>"clm5_0", }, "useFATESPOTVEGwithHARVEST" =>{ options=>"-bgc fates -envxml_dir . -no-megan", - namelst=>"use_fates_potentialveg=T,fates_harvest_mode=1", + namelst=>"use_fates_potentialveg=T,fates_harvest_mode=event_code", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "useFATESHARVEST3WOLUH" =>{ options=>"-bgc fates -envxml_dir . -no-megan", - namelst=>"use_fates_luh=F,fates_harvest_mode=3", + namelst=>"use_fates_luh=F,fates_harvest_mode=luhdata_area", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm index 929a8e6e14..b3b338e232 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm @@ -1 +1 @@ -fates_harvest_mode = 0 +fates_harvest_mode = no_harvest diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/user_nl_clm index dea75b71e7..c0e1c476be 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/user_nl_clm @@ -1 +1 @@ -fates_harvest_mode = 1 +fates_harvest_mode = event_code diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/user_nl_clm index fd4c74fe57..61e1daaa93 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/user_nl_clm @@ -1 +1 @@ -fates_harvest_mode = 2 +fates_harvest_mode = surfdata_file diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/user_nl_clm index 3332e9e526..d760105e68 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/user_nl_clm @@ -1 +1 @@ -fates_harvest_mode = 3 +fates_harvest_mode = luhdata_area diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/user_nl_clm index 13dae9efee..bb5f30f75d 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/user_nl_clm @@ -1 +1 @@ -fates_harvest_mode = 4 +fates_harvest_mode = luhdata_mass diff --git a/src/dyn_subgrid/dynSubgridDriverMod.F90 b/src/dyn_subgrid/dynSubgridDriverMod.F90 index 162247a0ff..faef029b40 100644 --- a/src/dyn_subgrid/dynSubgridDriverMod.F90 +++ b/src/dyn_subgrid/dynSubgridDriverMod.F90 @@ -128,7 +128,7 @@ subroutine dynSubgrid_init(bounds_proc, glc_behavior, crop_inst) ! flanduse_timeseries file. However, this could theoretically be changed so that the ! harvest data were separated from the pftdyn data, allowing them to differ in the ! years over which they apply. - if (get_do_harvest() .or. fates_harvest_mode == fates_harvest_clmlanduse) then + if (get_do_harvest() .or. trim(fates_harvest_mode) == fates_harvest_clmlanduse) then call dynHarvest_init(bounds_proc, harvest_filename=get_flanduse_timeseries()) end if diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index ba6c59143f..4205802088 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -186,6 +186,7 @@ module CLMFatesInterfaceMod use dynFATESLandUseChangeMod, only : fates_harvest_no_logging use dynFATESLandUseChangeMod, only : fates_harvest_clmlanduse use dynFATESLandUseChangeMod, only : fates_harvest_luh_area + use dynFATESLandUseChangeMod, only : fates_harvest_luh_mass use dynFATESLandUseChangeMod, only : landuse_harvest use dynFATESLandUseChangeMod, only : landuse_harvest_units use dynFATESLandUseChangeMod, only : landuse_harvest_varnames @@ -514,20 +515,25 @@ subroutine CLMFatesGlobals2() pass_logging = 0 pass_lu_harvest = 0 pass_num_lu_harvest_cats = 0 - if (fates_harvest_mode > fates_harvest_no_logging) then + if (trim(fates_harvest_mode) /= fates_harvest_no_logging) then pass_logging = 1 ! Time driven logging, without landuse harvest ! CLM landuse timeseries driven harvest rates - if (fates_harvest_mode == fates_harvest_clmlanduse) then + if (trim(fates_harvest_mode) == fates_harvest_clmlanduse) then pass_num_lu_harvest_cats = num_harvest_inst pass_lu_harvest = 1 ! LUH2 landuse timeseries driven harvest rates - else if (fates_harvest_mode >= fates_harvest_luh_area) then + else if (trim(fates_harvest_mode)== fates_harvest_luh_area .or. & + trim(fates_harvest_mode)== fates_harvest_luh_mass) then pass_lu_harvest = 1 pass_num_lu_harvest_cats = num_landuse_harvest_vars end if end if + call set_fates_ctrlparms('use_lu_harvest',ival=pass_lu_harvest) + call set_fates_ctrlparms('num_lu_harvest_cats',ival=pass_num_lu_harvest_cats) + call set_fates_ctrlparms('use_logging',ival=pass_logging) + ! FATES landuse modes if(use_fates_luh) then pass_use_luh = 1 @@ -550,11 +556,6 @@ subroutine CLMFatesGlobals2() end if call set_fates_ctrlparms('use_fates_potentialveg',ival=pass_use_potentialveg) - ! Wait to set the harvest and logging variables after checking fates_harvest_modes - call set_fates_ctrlparms('use_lu_harvest',ival=pass_lu_harvest) - call set_fates_ctrlparms('num_lu_harvest_cats',ival=pass_num_lu_harvest_cats) - call set_fates_ctrlparms('use_logging',ival=pass_logging) - if(use_fates_inventory_init) then pass_inventory_init = 1 else @@ -979,7 +980,7 @@ subroutine dynamics_driv(this, nc, bounds_clump, & call GetAndSetTime ! Get harvest rates for CLM landuse timeseries driven rates - if (fates_harvest_mode == fates_harvest_clmlanduse) then + if (trim(fates_harvest_mode) == fates_harvest_clmlanduse) then call dynHarvest_interp_resolve_harvesttypes(bounds_clump, & harvest_rates=harvest_rates(begg:endg,1:num_harvest_inst), & after_start_of_harvest_ts=after_start_of_harvest_ts) @@ -1105,7 +1106,7 @@ subroutine dynamics_driv(this, nc, bounds_clump, & ! for now there is one veg column per gridcell, so store all harvest data in each site ! this will eventually change ! today's hlm harvest flag needs to be set no matter what - if (fates_harvest_mode == fates_harvest_clmlanduse) then + if (trim(fates_harvest_mode) == fates_harvest_clmlanduse) then if (after_start_of_harvest_ts) then this%fates(nc)%bc_in(s)%hlm_harvest_rates(1:num_harvest_inst) = harvest_rates(g,1:num_harvest_inst) else @@ -1124,7 +1125,8 @@ subroutine dynamics_driv(this, nc, bounds_clump, & call endrun(msg=errMsg(sourcefile, __LINE__)) end if - else if (fates_harvest_mode >= fates_harvest_luh_area) then + else if (trim(fates_harvest_mode) == fates_harvest_luh_area .or. & + trim(fates_harvest_mode) == fates_harvest_luh_mass) then this%fates(nc)%bc_in(s)%hlm_harvest_rates = landuse_harvest(:,g) this%fates(nc)%bc_in(s)%hlm_harvest_catnames = landuse_harvest_varnames this%fates(nc)%bc_in(s)%hlm_harvest_units = landuse_harvest_units @@ -2082,7 +2084,8 @@ subroutine init_coldstart(this, waterstatebulk_inst, waterdiagnosticbulk_inst, & this%fates(nc)%bc_in(s)%hlm_luh_transitions = landuse_transitions(:,g) this%fates(nc)%bc_in(s)%hlm_luh_transition_names = landuse_transition_varnames - if (fates_harvest_mode >= fates_harvest_luh_area ) then + if (trim(fates_harvest_mode) == fates_harvest_luh_area .or. & + trim(fates_harvest_mode) == fates_harvest_luh_mass) then this%fates(nc)%bc_in(s)%hlm_harvest_rates = landuse_harvest(:,g) this%fates(nc)%bc_in(s)%hlm_harvest_catnames = landuse_harvest_varnames this%fates(nc)%bc_in(s)%hlm_harvest_units = landuse_harvest_units From 8aa0a708ca8751aa770ccc40a66fb962d26f5acc Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Fri, 26 Apr 2024 13:56:24 -0600 Subject: [PATCH 093/444] Update cmeps to the branch --- Externals.cfg | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Externals.cfg b/Externals.cfg index 185f412cab..1aa8991883 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -48,9 +48,12 @@ tag = cime6.0.217_httpsbranch03 required = True [cmeps] -tag = cmeps0.14.50 +#tag = cmeps0.14.50 +#branch = dust_emis_mod +hash = d79e34f67df825f9265bdaaf3091f8995d5df1a2 protocol = git -repo_url = https://github.com/ESCOMP/CMEPS.git +#repo_url = https://github.com/ESCOMP/CMEPS.git +repo_url = https://github.com/ekluzek/CMEPS.git local_path = components/cmeps required = True From 603d2677f85eff3a15a284ded3d89722371b81be Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Fri, 26 Apr 2024 15:02:04 -0600 Subject: [PATCH 094/444] Add shr_dust_emis_mod.F90 to the files needed for unit testing, fails, because ESMF is currently needed and not available --- src/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 568b53cd15..9d2e6041b5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,9 +20,11 @@ add_subdirectory(${CLM_ROOT}/share/src csm_share) add_subdirectory(${CLM_ROOT}/share/unit_test_stubs/util csm_share_stubs) add_subdirectory(${CLM_ROOT}/share/src/esmf_wrf_timemgr esmf_wrf_timemgr) -# Add the single file we need from CMEPS -set (drv_sources_needed - ${CLM_ROOT}/components/cmeps/cesm/nuopc_cap_share/glc_elevclass_mod.F90) +# Add files needed from CMEPS +list ( APPEND drv_sources_needed + ${CLM_ROOT}/components/cmeps/cesm/nuopc_cap_share/glc_elevclass_mod.F90 + ${CLM_ROOT}/components/cmeps/cesm/nuopc_cap_share/shr_dust_emis_mod.F90 + ) # Add CLM source directories add_subdirectory(${CLM_ROOT}/src/utils clm_utils) From 0b48097c502c98521b8014171a2d4f3cdaa5dec2 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Mon, 29 Apr 2024 18:59:30 -0600 Subject: [PATCH 095/444] Start adding the unit testing for dust emission in cmeps --- Externals.cfg | 2 +- src/CMakeLists.txt | 4 ++ src/drv_test/CMakeLists.txt | 1 + .../shr_dust_emis_test/CMakeLists.txt | 3 ++ .../shr_dust_emis_test/test_shr_dust_emis.pf | 50 +++++++++++++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/drv_test/CMakeLists.txt create mode 100644 src/drv_test/shr_dust_emis_test/CMakeLists.txt create mode 100644 src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf diff --git a/Externals.cfg b/Externals.cfg index 1aa8991883..70c0bd6124 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -50,7 +50,7 @@ required = True [cmeps] #tag = cmeps0.14.50 #branch = dust_emis_mod -hash = d79e34f67df825f9265bdaaf3091f8995d5df1a2 +hash = 492faf0014ad9d91c22bb92e2570e558a76093fe protocol = git #repo_url = https://github.com/ESCOMP/CMEPS.git repo_url = https://github.com/ekluzek/CMEPS.git diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9d2e6041b5..9388e65bc2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -105,3 +105,7 @@ add_subdirectory(${CLM_ROOT}/src/dyn_subgrid/test clm_dyn_subgrid_test) add_subdirectory(${CLM_ROOT}/src/main/test clm_main_test) add_subdirectory(${CLM_ROOT}/src/init_interp/test clm_init_interp_test) add_subdirectory(${CLM_ROOT}/src/self_tests/test clm_self_tests_test) + +# Add driver unit test directories +add_subdirectory(${CLM_ROOT}/src/drv_test drv_test) + diff --git a/src/drv_test/CMakeLists.txt b/src/drv_test/CMakeLists.txt new file mode 100644 index 0000000000..adf66b8b92 --- /dev/null +++ b/src/drv_test/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(shr_dust_emis_test) diff --git a/src/drv_test/shr_dust_emis_test/CMakeLists.txt b/src/drv_test/shr_dust_emis_test/CMakeLists.txt new file mode 100644 index 0000000000..21fb9c8d47 --- /dev/null +++ b/src/drv_test/shr_dust_emis_test/CMakeLists.txt @@ -0,0 +1,3 @@ +add_pfunit_ctest(dust_emis + TEST_SOURCES "test_shr_dust_emis.pf" + LINK_LIBRARIES clm csm_share) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf new file mode 100644 index 0000000000..aa60427eac --- /dev/null +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -0,0 +1,50 @@ +module test_shr_dust_emis + + ! Tests of shr_dust_emis_mod.F90 from CMEPS nuopc_cap_share + + use funit + use shr_dust_emis_mod, only : check_if_initialized + use unittestUtils, only : endrun_msg + + implicit none + + @TestCase + type, extends(TestCase) :: TestDustEmis + contains + procedure :: setUp + procedure :: tearDown + end type TestDustEmis + +contains + + ! ======================================================================== + ! Helper routines + ! ======================================================================== + + subroutine setUp(this) + class(TestDustEmis), intent(inout) :: this + end subroutine setUp + + subroutine tearDown(this) + class(TestDustEmis), intent(inout) :: this + + end subroutine tearDown + + + + ! ======================================================================== + ! Begin tests + ! ======================================================================== + + @Test + subroutine check_if_initialized_aborts(this) + ! Test that the check_if_initialized check aborts when called initially + class(TestDustEmis), intent(inout) :: this + + call check_if_initialized() + @assertExceptionRaised(endrun_msg('ERROR: dust emission namelist has NOT been read in yet, shr_dust_emis_mod is NOT initialized') ) + + end subroutine check_if_initialized_aborts + + +end module test_shr_dust_emis From d2d2da45ec2662c404424096b03a9b32debd9e01 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Apr 2024 09:21:16 -0600 Subject: [PATCH 096/444] Change call to is_NOT_initialized function, unit test works --- src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf index aa60427eac..a619618e1d 100644 --- a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -3,7 +3,7 @@ module test_shr_dust_emis ! Tests of shr_dust_emis_mod.F90 from CMEPS nuopc_cap_share use funit - use shr_dust_emis_mod, only : check_if_initialized + use shr_dust_emis_mod, only : is_NOT_initialized use unittestUtils, only : endrun_msg implicit none @@ -40,9 +40,11 @@ contains subroutine check_if_initialized_aborts(this) ! Test that the check_if_initialized check aborts when called initially class(TestDustEmis), intent(inout) :: this + logical :: not_init - call check_if_initialized() + not_init = is_NOT_initialized() @assertExceptionRaised(endrun_msg('ERROR: dust emission namelist has NOT been read in yet, shr_dust_emis_mod is NOT initialized') ) + @assertTrue(not_init) end subroutine check_if_initialized_aborts From 66578f0efd1f575b3adfe49bf1682e9c6fe703cb Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Apr 2024 10:51:45 -0600 Subject: [PATCH 097/444] add a test that is expected to fail --- .../shr_dust_emis_test/test_shr_dust_emis.pf | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf index a619618e1d..646b3cfce1 100644 --- a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -3,8 +3,8 @@ module test_shr_dust_emis ! Tests of shr_dust_emis_mod.F90 from CMEPS nuopc_cap_share use funit - use shr_dust_emis_mod, only : is_NOT_initialized - use unittestUtils, only : endrun_msg + use shr_dust_emis_mod + use unittestUtils , only : endrun_msg implicit none @@ -48,5 +48,16 @@ contains end subroutine check_if_initialized_aborts + @Test + subroutine check_when_initialized_runs(this) + ! Test that the initializiation check runs when it is initialized + class(TestDustEmis), intent(inout) :: this + logical :: not_init + + call dust_emis_set_options( 'Zender_2003', 'lnd') + not_init = is_NOT_initialized() + @assertFalse(not_init) + + end subroutine check_when_initialized_runs end module test_shr_dust_emis From a6927691757bdb91dc4d911461446a4e0746c3aa Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Apr 2024 11:10:03 -0600 Subject: [PATCH 098/444] Update cmeps version so will work --- Externals.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals.cfg b/Externals.cfg index 70c0bd6124..3753aac874 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -50,7 +50,7 @@ required = True [cmeps] #tag = cmeps0.14.50 #branch = dust_emis_mod -hash = 492faf0014ad9d91c22bb92e2570e558a76093fe +hash = ecb6d45aa00a4960564ea963b00754fb4c3b7d2c protocol = git #repo_url = https://github.com/ESCOMP/CMEPS.git repo_url = https://github.com/ekluzek/CMEPS.git From a65752d3d1abfc626631390c6b2378a5813e079f Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Apr 2024 14:31:23 -0600 Subject: [PATCH 099/444] Add more tests that pass --- .../shr_dust_emis_test/test_shr_dust_emis.pf | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf index 646b3cfce1..efe6a5c2a8 100644 --- a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -60,4 +60,35 @@ contains end subroutine check_when_initialized_runs + @Test + subroutine check_dust_emis(this) + ! Test that the dust_emis logical functions work as expected + class(TestDustEmis), intent(inout) :: this + logical :: not_init + + call dust_emis_set_options( 'Zender_2003', 'lnd') + @assertTrue( is_dust_emis_zender() ) + @assertFalse( is_dust_emis_leung() ) + call dust_emis_set_options( 'Leung_2023', 'lnd') + @assertFalse( is_dust_emis_zender() ) + @assertTrue( is_dust_emis_leung() ) + + end subroutine check_dust_emis + + + @Test + subroutine check_zender_soil(this) + ! Test that the dust_emis_Zender logical functions work as expected + class(TestDustEmis), intent(inout) :: this + logical :: not_init + + call dust_emis_set_options( 'Zender_2003', 'lnd') + @assertTrue( is_zender_soil_erod_from_land() ) + @assertFalse( is_zender_soil_erod_from_atm() ) + call dust_emis_set_options( 'Zender_2003', 'atm') + @assertFalse( is_zender_soil_erod_from_land() ) + @assertTrue( is_zender_soil_erod_from_atm() ) + + end subroutine check_zender_soil + end module test_shr_dust_emis From dd73ca699a83c80f5d2dc36fb9fa7482b4eec5eb Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 1 May 2024 13:50:29 -0600 Subject: [PATCH 100/444] Add new tests and get working again --- .../shr_dust_emis_test/test_shr_dust_emis.pf | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf index efe6a5c2a8..467d00de59 100644 --- a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -69,7 +69,7 @@ contains call dust_emis_set_options( 'Zender_2003', 'lnd') @assertTrue( is_dust_emis_zender() ) @assertFalse( is_dust_emis_leung() ) - call dust_emis_set_options( 'Leung_2023', 'lnd') + call dust_emis_set_options( 'Leung_2023', 'none') @assertFalse( is_dust_emis_zender() ) @assertTrue( is_dust_emis_leung() ) @@ -90,5 +90,25 @@ contains @assertTrue( is_zender_soil_erod_from_atm() ) end subroutine check_zender_soil + + + @Test + subroutine check_options(this) + ! Test that the check_options subroutine catches errors that should die + class(TestDustEmis), intent(inout) :: this + logical :: not_init + + call dust_emis_set_options( 'zztop', 'zztop') + @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: dust_emis_method namelist item is not valid')) + call dust_emis_set_options( 'Leung_2023', 'lnd') + @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: zender_soil_erod_source should NOT be set, when dust_emis_method=Leung_2023')) + call dust_emis_set_options( 'Leung_2023', 'atm') + @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: zender_soil_erod_source should NOT be set, when dust_emis_method=Leung_2023')) + call dust_emis_set_options( 'Zender_2003', 'none') + @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: zender_soil_erod_source can only be lnd or atm')) + call dust_emis_set_options( 'Zender_2003', 'zztop') + @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: zender_soil_erod_source can only be lnd or atm')) + + end subroutine check_options end module test_shr_dust_emis From ccd976af2ace8896eef72013d80ba3bccd8684af Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 1 May 2024 14:05:25 -0600 Subject: [PATCH 101/444] Update cmeps with unit-testing completed --- Externals.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals.cfg b/Externals.cfg index 3753aac874..39818b0fdc 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -50,7 +50,7 @@ required = True [cmeps] #tag = cmeps0.14.50 #branch = dust_emis_mod -hash = ecb6d45aa00a4960564ea963b00754fb4c3b7d2c +hash = 0285eeb59605df44bc3abf38a61e8436361e7e8c protocol = git #repo_url = https://github.com/ESCOMP/CMEPS.git repo_url = https://github.com/ekluzek/CMEPS.git From 65fc5536bd17b81f3b532ac764e15991b61a1e41 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sat, 4 May 2024 11:08:24 -0600 Subject: [PATCH 102/444] Add LND_SETS_DUST_EMIS_DRV_FLDS which will be used to NOT set dust_emis drv_flds_in settings when CAM is going to set them --- cime_config/config_component.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cime_config/config_component.xml b/cime_config/config_component.xml index f7adab268f..c474b7e0c1 100644 --- a/cime_config/config_component.xml +++ b/cime_config/config_component.xml @@ -162,6 +162,20 @@ This is typically set by the compset. + + logical + TRUE,FALSE + TRUE + + + + run_component_cpl + env_run.xml + If CTSM will set the dust settings in drv_flds_in (TRUE), or if ATM (i.e. CAM) will - DO NOT EDIT (set by compset name) + + char clm,nwp From d9c94eb04ebbf31ef4d5441d26eb59d360b2251d Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sat, 4 May 2024 11:17:34 -0600 Subject: [PATCH 103/444] Move dust_emis and soil_erod namelist items to the drv_fld_in namelist file in CMEPS --- bld/CLMBuildNamelist.pm | 13 ++++++++----- bld/namelist_files/namelist_defaults_ctsm.xml | 2 -- bld/namelist_files/namelist_definition_ctsm.xml | 14 -------------- .../namelist_definition_drv_flds.xml | 13 +++++++++++++ bld/unit_testers/build-namelist_test.pl | 14 +++++++++++++- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index fb44023cd5..ce2c2a81d2 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -517,6 +517,7 @@ sub read_namelist_defaults { "$cfgdir/namelist_files/namelist_defaults_ctsm.xml", "$cfgdir/namelist_files/namelist_defaults_drv.xml", "$cfgdir/namelist_files/namelist_defaults_fire_emis.xml", + "$cfgdir/namelist_files/namelist_defaults_dust_emis.xml", "$cfgdir/namelist_files/namelist_defaults_drydep.xml" ); # Add the location of the use case defaults files to the options hash @@ -3988,7 +3989,7 @@ sub setup_logic_fire_emis { #------------------------------------------------------------------------------- sub setup_logic_dust_emis { - # Logic to handle the dust emissions + # Logic to handle the dust emissions namelists, both drv_flds_in and lnd_in files my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; # First get the dust emission method @@ -4011,14 +4012,16 @@ sub setup_logic_dust_emis { 'dust_emis_method'=>$dust_emis_method, 'zender_soil_erod_source'=>$zender_source, 'hgrid'=>$nl_flags->{'res'}, 'lnd_tuning_mod'=>$nl_flags->{'lnd_tuning_mode'} ); } - } else { + } elsif ( $zender_source eq "atm" ) { foreach my $option ( @zender_files_in_lnd_opts ) { if ( defined($nl->get_value($option)) ) { - $log->fatal_error("zender_soil_erod_source is NOT lnd, but the file option $option is being set" . - " and should NOT be unless you want it handled here in the LAND model, " . + $log->fatal_error("zender_soil_erod_source is atm, and the file option $option is being set" . + " which should NOT be unless you want it handled here in the LAND model, " . "otherwise the equivalent option is set in CAM" ); } } + } elsif ( $zender_source eq "none" ) { + $log->fatal_error("zender_soil_erod_source is set to none and only atm or lnd should be used when $var is Zender_2002" ); } } else { # Verify that NONE of the Zender options are being set if Zender is NOT being used @@ -4736,7 +4739,7 @@ sub write_output_files { $log->verbose_message("Writing clm namelist to $outfile"); # Drydep, fire-emission or MEGAN namelist for driver - @groups = qw(drydep_inparm megan_emis_nl fire_emis_nl carma_inparm); + @groups = qw(drydep_inparm megan_emis_nl fire_emis_nl carma_inparm dust_emis_inparm); $outfile = "$opts->{'dir'}/drv_flds_in"; $nl->write($outfile, 'groups'=>\@groups, 'note'=>"$note" ); $log->verbose_message("Writing @groups namelists to $outfile"); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index cc407961ff..b232c865cb 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1993,8 +1993,6 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c -Zender_2003 -atm bilinear lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 37c457141c..e730082e90 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1612,20 +1612,6 @@ Mapping method from Nitrogen deposition input file to the model resolution - -Which dust emission method is going to be used. Either the Zender 2003 scheme or the Leung 2023 -scheme. -(NOTE: The Leung 2023 method is NOT currently available) - - - -Option only applying for the Zender_2003 method for whether the soil erodibility file is handled -here in CTSM, or in the ATM model. -(only used when dust_emis_method is Zender_2003) - - Option only applying for the Zender_2003 method for whether the soil erodibility file is handled diff --git a/bld/namelist_files/namelist_definition_drv_flds.xml b/bld/namelist_files/namelist_definition_drv_flds.xml index 088f5c5fa9..89bab07f4f 100644 --- a/bld/namelist_files/namelist_definition_drv_flds.xml +++ b/bld/namelist_files/namelist_definition_drv_flds.xml @@ -123,4 +123,17 @@ List of fluxes needed by the CARMA model, from CLM to CAM. + + Which dust emission method is going to be used. Either the Zender 2003 scheme or the Leung 2023 scheme. + (NOTE: The Leung 2023 method is NOT currently available) + + + + Option only applying for the Zender_2003 method for whether the soil erodibility file is handled + in the active LAND model or in the ATM model. + (only used when dust_emis_method is Zender_2003) + + diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 7b654337af..114fb0c36c 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 2513; +my $ntests = 2515; if ( defined($opts{'compare'}) ) { $ntests += 1545; @@ -1255,6 +1255,18 @@ sub cat_and_create_namelistinfile { GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_1", }, + "soil_erod_none_w_Zender" =>{ options=>"--envxml_dir .", + namelst=>"dust_emis_method='Zender_2003', " . + "zender_soil_erod_source='none'", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_1", + }, + "soil_erod_bad_w_Zender" =>{ options=>"--envxml_dir .", + namelst=>"dust_emis_method='Zender_2003', " . + "zender_soil_erod_source='zztop'", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_1", + }, ); foreach my $key ( keys(%failtest) ) { print( "$key\n" ); From 0c23d08c2bad4677b70afe22640e2a8bb5f4543a Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 2 May 2024 14:26:53 -0600 Subject: [PATCH 104/444] Update ChangeLog and ChangeSum. --- doc/ChangeLog | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ doc/ChangeSum | 1 + 2 files changed, 82 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index e5c2466085..e0a5e45cb6 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,85 @@ =============================================================== +Tag name: ctsm5.2.003 +Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) +Date: Thu May 2 14:06:54 MDT 2024 +One-line Summary: Merge b4b-dev + +Purpose and description of changes +---------------------------------- + +Brings in 4 PRs from b4b-dev to master: +- Regional CTSM Simulations and Capability of Creating Mesh Files (ESCOMP/CTSM#1892; Negin Sobhani and Adrianna Foster) +- Add line about documentation in PR template (ESCOMP/CTSM#2488; Sam Rabin) +- CTSM5.2 2000 fsurdat T42 64x128 file (ESCOMP/CTSM#2495; Sam Levis) +- Move plumber2 scripts to python directory (ESCOMP/CTSM#2505; Teagan King) + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- + +List of CTSM issues fixed (include CTSM Issue # and description): +- Resolves ESCOMP/CTSM#1513: Need a process to subset ESMF mesh files from global ones for regional grids +- Resolves ESCOMP/CTSM#1773: High resolution regional simulations +- Resolves ESCOMP/CTSM#2187: Move new PLUMBER2 scripts to python directory to enable python testing +- Resolves ESCOMP/CTSM#2486: Temporarily add back a T42 dataset for CAM + + +Notes of particular relevance for users +--------------------------------------- + +Changes to documentation: +- Adds documentation for making mesh files + + +Notes of particular relevance for developers: +--------------------------------------------- + +Changes to tests or testing: +- Adds testing for mesh-making Python scripts +- Adds testing for plumber2_surf_wrapper + + +Testing summary: +---------------- + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +- ESCOMP/CTSM#2513: Merge b4b-dev 2024-05-02 +- Constituent PRs: + - ESCOMP/CTSM#1892: Regional CTSM Simulations and Capability of Creating Mesh Files (https://github.com/ESCOMP/CTSM/pull/1892) + - ESCOMP/CTSM#2488: Add line about documentation in PR template (https://github.com/ESCOMP/CTSM/pull/2488) + - ESCOMP/CTSM#2495: CTSM5.2 2000 fsurdat T42 64x128 file (https://github.com/ESCOMP/CTSM/pull/2495) + - ESCOMP/CTSM#2505: Move plumber2 scripts to python directory (https://github.com/ESCOMP/CTSM/pull/2505) + +=============================================================== +=============================================================== Tag name: ctsm5.2.002 Originator(s): glemieux (Gregory Lemieux, LBNL, glemieux@lbl.gov) Date: Fri 26 Apr 2024 11:13:46 AM MDT diff --git a/doc/ChangeSum b/doc/ChangeSum index 40033a7d6f..b48e04889d 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,6 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.2.003 samrabin 05/02/2024 Merge b4b-dev ctsm5.2.002 glemieux 04/26/2024 FATES default allometry parameter file update ctsm5.2.001 erik 04/22/2024 Merge b4b-dev ctsm5.2.0 many 04/20/2024 New mksurfdata_esmf tool to create new surface datasets that are in place From 747d104c156733f520008819359612c0b8b1dd83 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 7 May 2024 03:30:20 -0600 Subject: [PATCH 105/444] Start adding reference for LND_SETS_DUST_EMIS_DRV_FLDS in unit tester --- bld/unit_testers/build-namelist_test.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 114fb0c36c..30110d92f7 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -42,7 +42,7 @@ sub make_env_run { my %settings = @_; # Set default settings - my %env_vars = ( DIN_LOC_ROOT=>"MYDINLOCROOT", GLC_TWO_WAY_COUPLING=>"FALSE", NEONSITE=>"" ); + my %env_vars = ( DIN_LOC_ROOT=>"MYDINLOCROOT", GLC_TWO_WAY_COUPLING=>"FALSE", LND_SETS_DUST_EMIS_DRV_FLDS=>"TRUE", NEONSITE=>"" ); # Set any settings that came in from function call foreach my $item ( keys(%settings) ) { $env_vars{$item} = $settings{$item}; From c36f3a9e6aa9e58f8ff05d4db7ee7349690841f5 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 7 May 2024 03:31:04 -0600 Subject: [PATCH 106/444] Add dust emis namelist default for drv_flds_in --- .../namelist_defaults_dust_emis.xml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 bld/namelist_files/namelist_defaults_dust_emis.xml diff --git a/bld/namelist_files/namelist_defaults_dust_emis.xml b/bld/namelist_files/namelist_defaults_dust_emis.xml new file mode 100644 index 0000000000..40bf3d9078 --- /dev/null +++ b/bld/namelist_files/namelist_defaults_dust_emis.xml @@ -0,0 +1,21 @@ + + + + + + + + + +Zender_2003 + +atm + + From 8ab4063d65dff584758d054c05287e49a00d9130 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 15 May 2024 11:14:02 -0600 Subject: [PATCH 107/444] Git rebase didn't correct the change files for some reason, so going back to the b4b-dev version of those --- doc/ChangeLog | 81 --------------------------------------------------- doc/ChangeSum | 1 - 2 files changed, 82 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index e0a5e45cb6..e5c2466085 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,85 +1,4 @@ =============================================================== -Tag name: ctsm5.2.003 -Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) -Date: Thu May 2 14:06:54 MDT 2024 -One-line Summary: Merge b4b-dev - -Purpose and description of changes ----------------------------------- - -Brings in 4 PRs from b4b-dev to master: -- Regional CTSM Simulations and Capability of Creating Mesh Files (ESCOMP/CTSM#1892; Negin Sobhani and Adrianna Foster) -- Add line about documentation in PR template (ESCOMP/CTSM#2488; Sam Rabin) -- CTSM5.2 2000 fsurdat T42 64x128 file (ESCOMP/CTSM#2495; Sam Levis) -- Move plumber2 scripts to python directory (ESCOMP/CTSM#2505; Teagan King) - - -Significant changes to scientifically-supported configurations --------------------------------------------------------------- - -Does this tag change answers significantly for any of the following physics configurations? -(Details of any changes will be given in the "Answer changes" section below.) - - [Put an [X] in the box for any configuration with significant answer changes.] - -[ ] clm6_0 - -[ ] clm5_1 - -[ ] clm5_0 - -[ ] ctsm5_0-nwp - -[ ] clm4_5 - - -Bugs fixed ----------- - -List of CTSM issues fixed (include CTSM Issue # and description): -- Resolves ESCOMP/CTSM#1513: Need a process to subset ESMF mesh files from global ones for regional grids -- Resolves ESCOMP/CTSM#1773: High resolution regional simulations -- Resolves ESCOMP/CTSM#2187: Move new PLUMBER2 scripts to python directory to enable python testing -- Resolves ESCOMP/CTSM#2486: Temporarily add back a T42 dataset for CAM - - -Notes of particular relevance for users ---------------------------------------- - -Changes to documentation: -- Adds documentation for making mesh files - - -Notes of particular relevance for developers: ---------------------------------------------- - -Changes to tests or testing: -- Adds testing for mesh-making Python scripts -- Adds testing for plumber2_surf_wrapper - - -Testing summary: ----------------- - - regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): - - derecho ----- OK - izumi ------- OK - - -Other details -------------- - -Pull Requests that document the changes (include PR ids): -- ESCOMP/CTSM#2513: Merge b4b-dev 2024-05-02 -- Constituent PRs: - - ESCOMP/CTSM#1892: Regional CTSM Simulations and Capability of Creating Mesh Files (https://github.com/ESCOMP/CTSM/pull/1892) - - ESCOMP/CTSM#2488: Add line about documentation in PR template (https://github.com/ESCOMP/CTSM/pull/2488) - - ESCOMP/CTSM#2495: CTSM5.2 2000 fsurdat T42 64x128 file (https://github.com/ESCOMP/CTSM/pull/2495) - - ESCOMP/CTSM#2505: Move plumber2 scripts to python directory (https://github.com/ESCOMP/CTSM/pull/2505) - -=============================================================== -=============================================================== Tag name: ctsm5.2.002 Originator(s): glemieux (Gregory Lemieux, LBNL, glemieux@lbl.gov) Date: Fri 26 Apr 2024 11:13:46 AM MDT diff --git a/doc/ChangeSum b/doc/ChangeSum index b48e04889d..40033a7d6f 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,6 +1,5 @@ Tag Who Date Summary ============================================================================================================================ - ctsm5.2.003 samrabin 05/02/2024 Merge b4b-dev ctsm5.2.002 glemieux 04/26/2024 FATES default allometry parameter file update ctsm5.2.001 erik 04/22/2024 Merge b4b-dev ctsm5.2.0 many 04/20/2024 New mksurfdata_esmf tool to create new surface datasets that are in place From f19a080721f5fffa96b580da51a170cbe80d4244 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 15 May 2024 17:59:34 -0600 Subject: [PATCH 108/444] add more landuse graceful failures If luh + fbg are present fail if flandusepftdat isn't valid. Don't allow fluh_timeseries to be defined if in potential veg mode to avoid confusing users that it is needed. --- bld/CLMBuildNamelist.pm | 71 ++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index aafc7739a3..0d8ca732b4 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4433,21 +4433,9 @@ sub setup_logic_fates { } } # make sure that fates landuse x pft mode has the necessary run mode configurations - # and add the necessary landuse x pft static mapping data default if not defined my $var = "use_fates_lupft"; if ( defined($nl->get_value($var)) ) { if ( &value_is_true($nl->get_value($var)) ) { - $var = "flandusepftdat"; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); - my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); - if ( ! defined($nl->get_value($var)) ) { - $log->fatal_error("$var is required when use_fates_lupft is set" ); - } elsif ( ! -f "$fname" ) { - $log->fatal_error("$fname does NOT point to a valid filename" ); - } - - # make sure that nocomp and fbg mode are enabled as well as use_fates_luh my @list = ( "use_fates_luh", "use_fates_nocomp", "use_fates_fixed_biogeog" ); foreach my $var ( @list ) { if ( ! &value_is_true($nl->get_value($var)) ) { @@ -4457,31 +4445,56 @@ sub setup_logic_fates { } } # check that fates landuse change mode has the necessary luh2 landuse timeseries data - # and add the default if not defined + # and add the default if not defined. Do not add default if use_fates_potentialveg is true. + # If fixed biogeography is on, make sure that flandusepftdat is avilable. my $var = "use_fates_luh"; if ( defined($nl->get_value($var)) ) { if ( &value_is_true($nl->get_value($var)) ) { - $var = "fluh_timeseries"; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, nofail=>1 ); - my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); - if ( ! defined($nl->get_value($var)) ) { - $log->fatal_error("$var is required when use_fates_luh is set" ); - } elsif ( ! -f "$fname" ) { - $log->fatal_error("$fname does NOT point to a valid filename" ); - } + $var = "use_fates_potentialveg"; + if ( defined($nl->get_value($var)) ) { + if ( ! &value_is_true($nl->get_value($var)) ) { + $var = "fluh_timeseries"; + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'phys'=>$nl_flags->{'phys'}, + 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, nofail=>1 ); + my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); + if ( ! defined($nl->get_value($var)) ) { + $log->fatal_error("$var is required when use_fates_luh is set and use_fates_potentialveg is false" ); + } elsif ( ! -f "$fname" ) { + $log->fatal_error("$var does NOT point to a valid filename" ); + } + } + } + $var = "use_fates_fixed_biogeog"; + if ( defined($nl->get_value($var)) ) { + if ( &value_is_true($nl->get_value($var)) ) { + $var = "flandusepftdat"; + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, + 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); + my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); + if ( ! defined($nl->get_value($var)) ) { + $log->fatal_error("$var is required when use_fates_luh and use_fates_fixed_biogeog is set" ); + } elsif ( ! -f "$fname" ) { + $log->fatal_error("$var does NOT point to a valid filename" ); + } + } + } } } # check that fates landuse is on and harvest mode is off when potential veg switch is true my $var = "use_fates_potentialveg"; if ( defined($nl->get_value($var)) ) { - if ( &value_is_true($nl->get_value($var)) ) { - if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { - $log->fatal_error("use_fates_luh must be true when $var is true" ); - } - if ( $nl->get_value('fates_harvest_mode') > 0) { - $log->fatal_error("fates_harvest_mode must be off (i.e. set to zero) when $var is true" ); - } - } + if ( &value_is_true($nl->get_value($var)) ) { + if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { + $log->fatal_error("use_fates_luh must be true when $var is true" ); + } + if ( $nl->get_value('fates_harvest_mode') > 0) { + $log->fatal_error("fates_harvest_mode must be off (i.e. set to zero) when $var is true" ); + } + my $var = "fluh_timeseries"; + if ( defined($nl->get_value($var)) ) { + $log->fatal_error("fluh_timeseries can not be defined when use_fates_potentialveg is true" ); + } + } } # Check fates_harvest_mode compatibility my $var = "fates_harvest_mode"; From 7c5c632f02b54f2285bdfb3902834d78715077f7 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 16 May 2024 15:03:31 -0600 Subject: [PATCH 109/444] fix namelist definition --- bld/namelist_files/namelist_definition_ctsm.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 03b1e9e64d..58e0aca3a6 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -734,8 +734,8 @@ Toggle to turn on no competition mode (only relevant if FATES is being used). Toggle to turn on FATES satellite phenology mode (only relevant if FATES is being used). - + Set FATES harvesting mode by setting fates_harvest_mode to a valid string option. Allowed values are: no_harvest: no fates harvesting of any kind From 5e9bc2e9a40987ff5477d0b3cdc742c3fbcf5f23 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 16 May 2024 15:04:39 -0600 Subject: [PATCH 110/444] Update finidat that previously failing test now picks up by default --- bld/namelist_files/namelist_defaults_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index c62df7d77b..90e397d544 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1097,7 +1097,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). ic_ymd="20110101" sim_year="2000" do_transient_pfts=".false." ic_tod="0" glc_nec="10" use_crop=".true." irrigate=".true." lnd_tuning_mode="clm6_0_GSWP3v1" ->lnd/clm2/initdata_esmf/ctsm5.2/clmi.I2000Clm50BgcCrop.2011-01-01.1.9x2.5_gx1v7_gl4_simyr2000_c240223.nc +>lnd/clm2/initdata_esmf/ctsm5.2/clmi.I2000Clm52BgcCrop.2000-01-01.1.9x2.5_gx1v7_gl4_simyr2000_c240515.nc From 0266a70e98142750e6c34494740a8dd3e600a93c Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 16 May 2024 15:22:10 -0600 Subject: [PATCH 111/444] update landuse parameters from ints to chars --- src/dyn_subgrid/dynFATESLandUseChangeMod.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 index d9bd0352ca..f330ee2b78 100644 --- a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 +++ b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 @@ -35,11 +35,11 @@ module dynFATESLandUseChangeMod integer, public, parameter :: num_landuse_harvest_vars = 5 ! Define the fates landuse namelist mode switch values - integer, public, parameter :: fates_harvest_no_logging = 0 - integer, public, parameter :: fates_harvest_logging_only = 1 - integer, public, parameter :: fates_harvest_clmlanduse = 2 - integer, public, parameter :: fates_harvest_luh_area = 3 - integer, public, parameter :: fates_harvest_luh_mass = 4 + character(len=13), public, parameter :: fates_harvest_no_logging = 'no_harvest' + character(len=13), public, parameter :: fates_harvest_logging_only = 'event_code' + character(len=13), public, parameter :: fates_harvest_clmlanduse = 'surfdata_file' + character(len=13), public, parameter :: fates_harvest_luh_area = 'luhdata_area' + character(len=13), public, parameter :: fates_harvest_luh_mass = 'luhdata_mass' ! Define landuse harvest unit integer representation integer, public, parameter :: landuse_harvest_area_units = 1 From b706c5a717652f24ca30e7dd43285b9e527b0f16 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 16 May 2024 16:22:11 -0600 Subject: [PATCH 112/444] Have build-namelist not do the dust emission namelist settings, when the XML variable is set for CAM to do it, and add a test for this --- bld/CLMBuildNamelist.pm | 120 +++++++++-------- bld/unit_testers/build-namelist_test.pl | 169 ++---------------------- 2 files changed, 80 insertions(+), 209 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index ce2c2a81d2..98fdd861a0 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -97,7 +97,7 @@ OPTIONS CENTURY or MIMICS decomposition This toggles on the namelist variables: use_fates. use_lch4 and use_nitrif_denitrif are optional - + (Only for CLM4.5/CLM5.0) -[no-]chk_res Also check [do NOT check] to make sure the resolution and land-mask is valid. @@ -1012,7 +1012,7 @@ sub setup_cmdl_fire_light_res { if ( ! &value_is_true($nl_flags->{'neon'}) ) { if ( defined($opts->{'clm_usr_name'}) ) { $log->warning("The NEON lightning dataset does NOT cover the entire globe, make sure it covers the region for your grid"); - } else { + } else { $log->fatal_error("The NEON lightning dataset can NOT be used for global grids or regions or points outside of its area as it does NOT cover the entire globe."); } } @@ -1702,7 +1702,7 @@ sub process_namelist_inline_logic { ###################################### # namelist options for dust emissions ###################################### - setup_logic_dust_emis($opts, $nl_flags, $definition, $defaults, $nl); + setup_logic_dust_emis($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref); ################################# # namelist group: megan_emis_nl # @@ -2273,7 +2273,7 @@ sub setup_logic_crop_inparm { } add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "initial_seed_at_planting", 'use_crop'=>$nl->get_value('use_crop') ); - + my $crop_residue_removal_frac = $nl->get_value('crop_residue_removal_frac'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'crop_residue_removal_frac' ); if ( $crop_residue_removal_frac < 0.0 or $crop_residue_removal_frac > 1.0 ) { @@ -2614,8 +2614,8 @@ SIMYR: foreach my $sim_yr ( @sim_years ) { if ( defined($use_init_interp_default) ) { $log->fatal_error($err_msg." but can't find one without $useinitvar being set to true, change it to true in your user_nl_clm file in your case"); } else { - my $set = "Relevent settings: use_cndv = ". $nl_flags->{'use_cndv'} . " phys = " . - $physv->as_string() . " hgrid = " . $nl_flags->{'res'} . " sim_year = " . + my $set = "Relevent settings: use_cndv = ". $nl_flags->{'use_cndv'} . " phys = " . + $physv->as_string() . " hgrid = " . $nl_flags->{'res'} . " sim_year = " . $settings{'sim_year'} . " lnd_tuning_mode = " . $nl_flags->{'lnd_tuning_mode'} . "use_fates = " . $nl_flags->{'use_fates'}; $log->fatal_error($err_msg." but the default setting of $useinitvar is false, so set both $var to a startup file and $useinitvar==TRUE, or developers should modify the namelist_defaults file".$set); @@ -3158,7 +3158,6 @@ sub setup_logic_supplemental_nitrogen { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'suplnitro', 'use_fates'=>$nl_flags->{'use_fates'}); } - # # Error checking for suplnitro # @@ -3683,10 +3682,10 @@ sub setup_logic_nitrogen_deposition { 'use_cn'=>$nl_flags->{'use_cn'}, 'hgrid'=>$nl_flags->{'res'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndep_taxmode', 'phys'=>$nl_flags->{'phys'}, - 'use_cn'=>$nl_flags->{'use_cn'}, + 'use_cn'=>$nl_flags->{'use_cn'}, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'} ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndep_varlist', 'phys'=>$nl_flags->{'phys'}, - 'use_cn'=>$nl_flags->{'use_cn'}, + 'use_cn'=>$nl_flags->{'use_cn'}, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'} ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_ndep', 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, 'sim_year'=>$nl_flags->{'sim_year'}, @@ -3990,51 +3989,64 @@ sub setup_logic_fire_emis { sub setup_logic_dust_emis { # Logic to handle the dust emissions namelists, both drv_flds_in and lnd_in files - my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref) = @_; - # First get the dust emission method - my $var = "dust_emis_method"; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var ); - - my $dust_emis_method = remove_leading_and_trailing_quotes( $nl->get_value($var) ); - - my @zender_files_in_lnd_opts = ( "stream_fldfilename_zendersoilerod", "stream_meshfile_zendersoilerod", - "zendersoilerod_mapalgo" ); - if ( $dust_emis_method eq "Zender_2003" ) { - # get the zender_soil_erod_source - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, - "zender_soil_erod_source", 'dust_emis_method'=>$dust_emis_method ); - - my $zender_source = remove_leading_and_trailing_quotes( $nl->get_value('zender_soil_erod_source') ); - if ( $zender_source eq "lnd" ) { - foreach my $option ( @zender_files_in_lnd_opts ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $option, - 'dust_emis_method'=>$dust_emis_method, 'zender_soil_erod_source'=>$zender_source, - 'hgrid'=>$nl_flags->{'res'}, 'lnd_tuning_mod'=>$nl_flags->{'lnd_tuning_mode'} ); - } - } elsif ( $zender_source eq "atm" ) { - foreach my $option ( @zender_files_in_lnd_opts ) { - if ( defined($nl->get_value($option)) ) { - $log->fatal_error("zender_soil_erod_source is atm, and the file option $option is being set" . - " which should NOT be unless you want it handled here in the LAND model, " . - "otherwise the equivalent option is set in CAM" ); - } - } - } elsif ( $zender_source eq "none" ) { - $log->fatal_error("zender_soil_erod_source is set to none and only atm or lnd should be used when $var is Zender_2002" ); - } + # Only set dust emission settings -- if not connected to CAM + my $lnd_sets_dust = logical_to_fortran($envxml_ref->{'LND_SETS_DUST_EMIS_DRV_FLDS'}); + if ( &value_is_true( $lnd_sets_dust)) { + + # First get the dust emission method + my $var = "dust_emis_method"; + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var ); + my $dust_emis_method = remove_leading_and_trailing_quotes( $nl->get_value($var) ); + + my @zender_files_in_lnd_opts = ( "stream_fldfilename_zendersoilerod", "stream_meshfile_zendersoilerod", + "zendersoilerod_mapalgo" ); + if ( $dust_emis_method eq "Zender_2003" ) { + # get the zender_soil_erod_source + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + "zender_soil_erod_source", 'dust_emis_method'=>$dust_emis_method ); + + my $zender_source = remove_leading_and_trailing_quotes( $nl->get_value('zender_soil_erod_source') ); + if ( $zender_source eq "lnd" ) { + foreach my $option ( @zender_files_in_lnd_opts ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $option, + 'dust_emis_method'=>$dust_emis_method, 'zender_soil_erod_source'=>$zender_source, + 'hgrid'=>$nl_flags->{'res'}, 'lnd_tuning_mod'=>$nl_flags->{'lnd_tuning_mode'} ); + } + } elsif ( $zender_source eq "atm" ) { + foreach my $option ( @zender_files_in_lnd_opts ) { + if ( defined($nl->get_value($option)) ) { + $log->fatal_error("zender_soil_erod_source is atm, and the file option $option is being set" . + " which should NOT be unless you want it handled here in the LAND model, " . + "otherwise the equivalent option is set in CAM" ); + } + } + } elsif ( $zender_source eq "none" ) { + $log->fatal_error("zender_soil_erod_source is set to none and only atm or lnd should be used when $var is Zender_2002" ); + } + } else { + # Verify that NONE of the Zender options are being set if Zender is NOT being used + push @zender_files_in_lnd_opts, "zender_soil_erod_source"; + foreach my $option ( @zender_files_in_lnd_opts ) { + if ( defined($nl->get_value($option)) ) { + $log->fatal_error("dust_emis_method is NOT set to Zender_2003, but one of it's options " . + "$option is being set, need to change one or the other" ); + } + } + if ( $dust_emis_method eq "Leung_2023" ) { + $log->warning("dust_emis_method is Leung_2023 and that option has NOT been brought into CTSM yet"); + } + } + # Otherwise make sure dust settings are NOT being set in CLM } else { - # Verify that NONE of the Zender options are being set if Zender is NOT being used - push @zender_files_in_lnd_opts, "zender_soil_erod_source"; - foreach my $option ( @zender_files_in_lnd_opts ) { - if ( defined($nl->get_value($option)) ) { - $log->fatal_error("dust_emis_method is NOT set to Zender_2003, but one of it's options " . - "$option is being set, need to change one or the other" ); - } - } - if ( $dust_emis_method eq "Leung_2023" ) { - $log->warning("dust_emis_method is Leung_2023 and that option has NOT been brought into CTSM yet"); - } + my @vars = ( "dust_emis_method", "zender_soil_erod_source" ); + foreach my $option ( @vars ) { + if ( defined($nl->get_value($option)) ) { + $log->fatal_error("Dust emission variable is being set in CTSM, which should NOT be done when" . + " connected to CAM as CAM should set them"); + } + } } } @@ -4528,8 +4540,8 @@ sub setup_logic_fates { my $suplnitro = $nl->get_value('suplnitro'); my $parteh_mode = $nl->get_value('fates_parteh_mode'); if ( ($parteh_mode == 1) && ($suplnitro !~ /ALL/) && not &value_is_true( $nl_flags->{'use_fates_sp'}) ) { - $log->fatal_error("supplemental Nitrogen (suplnitro) is NOT set to ALL, FATES is on, " . - "but and FATES-SP is not active, but fates_parteh_mode is 1, so Nitrogen is not active" . + $log->fatal_error("supplemental Nitrogen (suplnitro) is NOT set to ALL, FATES is on, " . + "but and FATES-SP is not active, but fates_parteh_mode is 1, so Nitrogen is not active" . "Change suplnitro back to ALL"); } # diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 30110d92f7..d017997c6a 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 2515; +my $ntests = 2516; if ( defined($opts{'compare'}) ) { $ntests += 1545; @@ -500,447 +500,358 @@ sub cat_and_create_namelistinfile { my %failtest = ( "coldstart but with IC file"=>{ options=>"-clm_start_type cold -envxml_dir .", namelst=>"finidat='$finidat'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "clm_demand on finidat" =>{ options=>"-clm_demand finidat -envxml_dir .", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "blank IC file, not cold" =>{ options=>"-clm_start_type startup -envxml_dir .", namelst=>"finidat=' '", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "startup without interp" =>{ options=>"-clm_start_type startup -envxml_dir . -bgc sp -sim_year 1850", namelst=>"use_init_interp=.false., start_ymd=19200901", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "use_crop without -crop" =>{ options=>" -envxml_dir .", namelst=>"use_crop=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "soilm_stream off w file" =>{ options=>"-res 0.9x1.25 -envxml_dir .", namelst=>"use_soil_moisture_streams = .false.,stream_fldfilename_soilm='file_provided_when_off'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "exice_stream off w file" =>{ options=>"-res 0.9x1.25 -envxml_dir .", namelst=>"use_excess_ice=.true., use_excess_ice_streams = .false.,stream_fldfilename_exice='file_provided_when_off'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "exice_stream off w mesh" =>{ options=>"-res 0.9x1.25 -envxml_dir .", namelst=>"use_excess_ice=.true., use_excess_ice_streams = .false.,stream_meshfile_exice='file_provided_when_off'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "exice off, but stream on" =>{ options=>"-res 0.9x1.25 -envxml_dir .", namelst=>"use_excess_ice=.false., use_excess_ice_streams = .true.,stream_fldfilename_exice='file_provided', stream_meshfile_exice='file_provided'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "exice stream off, but setmap"=>{ options=>"-res 0.9x1.25 -envxml_dir .", namelst=>"use_excess_ice=.true., use_excess_ice_streams = .false.,stream_mapalgo_exice='bilinear'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "exice stream on, but mct" =>{ options=>"--res 0.9x1.25 --envxml_dir . --driver mct --lnd_frac $DOMFILE ", namelst=>"use_excess_ice=.true., use_excess_ice_streams=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "clm50CNDVwtransient" =>{ options=>" -envxml_dir . -use_case 20thC_transient -dynamic_vegetation -res 10x15 -ignore_warnings", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "decomp_without_cn" =>{ options=>" -envxml_dir . -bgc sp", namelst=>"soil_decomp_method='CENTURYKoven2013'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "bgc_with_no_decomp" =>{ options=>" -envxml_dir . -bgc bgc", namelst=>"soil_decomp_method='None'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "reseed without CN" =>{ options=>" -envxml_dir . -bgc sp", namelst=>"reseed_dead_plants=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "onset_threh w SP" =>{ options=>" -envxml_dir . -bgc sp", namelst=>"onset_thresh_depends_on_veg=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "dribble_crphrv w/o CN" =>{ options=>" -envxml_dir . -bgc sp", namelst=>"dribble_crophrv_xsmrpool_2atm=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "dribble_crphrv w/o crop" =>{ options=>" -envxml_dir . -bgc bgc -no-crop", namelst=>"dribble_crophrv_xsmrpool_2atm=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "CNDV with flanduse_timeseries - clm4_5"=>{ options=>"-bgc bgc -dynamic_vegetation -envxml_dir . -ignore_warnings", namelst=>"flanduse_timeseries='my_flanduse_timeseries_file.nc'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "use_cndv=T without bldnml op"=>{ options=>"-bgc bgc -envxml_dir . -ignore_warnings", namelst=>"use_cndv=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "use_cndv=F with dyn_veg op"=>{ options=>"-bgc bgc -dynamic_vegetation -envxml_dir . -ignore_warnings", namelst=>"use_cndv=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "crop with use_crop false" =>{ options=>"-crop -bgc bgc -envxml_dir .", namelst=>"use_crop=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "crop without CN" =>{ options=>"-crop -bgc sp -envxml_dir .", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "toosmall soil w trans" =>{ options=>"-envxml_dir .", namelst=>"toosmall_soil=10, dyn_transient_pfts=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "toosmall lake w trans" =>{ options=>"-envxml_dir .", namelst=>"toosmall_lake=10, dyn_transient_pfts=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "toosmall crop w trans" =>{ options=>"-bgc bgc -crop -envxml_dir .", namelst=>"toosmall_crop=10, dyn_transient_pfts=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "toosmall wetl w trans" =>{ options=>"-bgc bgc -envxml_dir .", namelst=>"toosmall_wetland=10, dyn_transient_pfts=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "toosmall glc w trans" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"toosmall_glacier=10, dyn_transient_pfts=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "toosmall urban w trans" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"toosmall_urban=10, dyn_transient_pfts=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "collapse_urban w trans" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"collapse_urban=T, dyn_transient_crops=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "n_dom_landunits w trans" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"n_dom_landunits=2, dyn_transient_crops=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "n_dom_pfts w trans" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"n_dom_pfts=2, dyn_transient_crops=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "baset_map without crop" =>{ options=>"-bgc bgc -envxml_dir . -no-crop", namelst=>"baset_mapping='constant'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "mapvary var w/o varymap" =>{ options=>"-crop -bgc bgc -envxml_dir . -crop", namelst=>"baset_mapping='constant', baset_latvary_slope=1.0, baset_latvary_intercept=10.0", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "grainproductWOcrop" =>{ options=>"-bgc bgc -no-crop -envxml_dir .", namelst=>"use_grainproduct=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "interp without finidat" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"use_init_interp=.true. finidat=' '", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "sp and c13" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"use_c13=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "sp and c14" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"use_c14=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "bombspike no c14" =>{ options=>"-bgc bgc -envxml_dir .", namelst=>"use_c14=.false. use_c14_bombspike=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "use c13 timeseries no cn" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"use_c13_timeseries=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "use c13 timeseries no c13"=>{ options=>"-bgc bgc -envxml_dir .", namelst=>"use_c13=.false. use_c13_timeseries=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "bombspike no cn" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"use_c14_bombspike=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lightres no cn" =>{ options=>"-bgc sp -envxml_dir . -light_res 360x720", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "NEONlightresButGlobal" =>{ options=>"--res 4x5 --bgc bgc --envxml_dir . --light_res 106x740", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "spno-fire" =>{ options=>"-bgc sp -envxml_dir . -use_case 2000_control", namelst=>"fire_method='nofire'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lightres no fire" =>{ options=>"-bgc bgc -envxml_dir . -light_res 360x720", namelst=>"fire_method='nofire'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lightres none bgc" =>{ options=>"-bgc bgc -envxml_dir . -light_res none", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lightresnotnone-nofire" =>{ options=>"-bgc bgc -envxml_dir . -light_res 94x192", namelst=>"fire_method='nofire'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lightresnonenofirelightfil"=>{ options=>"-bgc bgc -envxml_dir . -light_res none", namelst=>"fire_method='nofire',stream_fldfilename_lightng='build-namelist_test.pl'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lightrescontradictlightfil"=>{ options=>"-bgc bgc -envxml_dir . -light_res 360x720", namelst=>"stream_fldfilename_lightng='build-namelist_test.pl'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "finundated and not methane"=>{ options=>"-bgc bgc -envxml_dir .", namelst=>"use_lch4=.false.,finundation_method='h2osfc'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "use_cn=true bgc=sp" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"use_cn=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "freeliv wo fun" =>{ options=>"-bgc bgc -envxml_dir .", namelst=>"freelivfix_intercept=9.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "use_cn=false bgc=bgc" =>{ options=>"-bgc bgc -envxml_dir .", namelst=>"use_cn=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "lower=aqu-45 with/o Zeng" =>{ options=>"-envxml_dir .", namelst=>"lower_boundary_condition=4,soilwater_movement_method=1,use_bedrock=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "Zeng w lower=flux" =>{ options=>"-envxml_dir .", namelst=>"lower_boundary_condition=1,soilwater_movement_method=0,use_bedrock=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "Zeng w lower=zeroflux" =>{ options=>"-envxml_dir .", namelst=>"lower_boundary_condition=2,soilwater_movement_method=0", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "Zeng w lower=table" =>{ options=>"-envxml_dir .", namelst=>"lower_boundary_condition=3,soilwater_movement_method=0,use_bedrock=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "use_vic=F with -vic op" =>{ options=>"-vichydro -envxml_dir .", namelst=>"use_vichydro=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "-vic with l_bnd=flux" =>{ options=>"-vichydro -envxml_dir .", namelst=>"lower_boundary_condition=1", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "-vic with l_bnd=zeroflux" =>{ options=>"-vichydro -envxml_dir .", namelst=>"lower_boundary_condition=2", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "bedrock with l_bnc=flux" =>{ options=>"-envxml_dir .", namelst=>"use_bedrock=.true., lower_boundary_condition=1", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "bedrock with l_bnc=tabl" =>{ options=>"-envxml_dir .", namelst=>"use_bedrock=.true., lower_boundary_condition=3", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "bedrock with l_bnc=aqui" =>{ options=>"-envxml_dir .", namelst=>"use_bedrock=.true., lower_boundary_condition=4", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "zengdeck with l_bnc=flux" =>{ options=>"-envxml_dir .", namelst=>"soilwater_movement_method=0, lower_boundary_condition=1", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "zengdeck with l_bnc=z-flux"=>{ options=>"-envxml_dir .", namelst=>"soilwater_movement_method=0, lower_boundary_condition=2", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "zengdeck with l_bnc=tabl" =>{ options=>"-envxml_dir .", namelst=>"soilwater_movement_method=0, lower_boundary_condition=3", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "l_bnd=tabl with h2osfcfl=0"=>{ options=>"-envxml_dir .", namelst=>"h2osfcflag=0, lower_boundary_condition=3", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "l_bnd=flux with h2osfcfl=0"=>{ options=>"-envxml_dir .", namelst=>"h2osfcflag=0, lower_boundary_condition=1", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "l_bnd=zflux with h2osfcfl=0"=>{ options=>"-envxml_dir .", namelst=>"h2osfcflag=0, lower_boundary_condition=2", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "h2osfcfl=0 with clm5.0" =>{ options=>"-envxml_dir .", namelst=>"h2osfcflag=0", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "45bad lnd_tuning_mode value" =>{ options=>"-lnd_tuning_mode clm5_0_GSWP3 -envxml_dir .", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "50bad lnd_tuning_mode value" =>{ options=>"-lnd_tuning_mode clm4_5_CRUNCEP -envxml_dir .", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "bgc_spinup without cn" =>{ options=>"-clm_accelerated_spinup on -bgc sp -envxml_dir .", namelst=>"spinup_state=1", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "spinup=1 without bldnml op"=>{ options=>"-clm_accelerated_spinup off -bgc bgc -envxml_dir .", namelst=>"spinup_state=1",, - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "bgc_spinup without cn" =>{ options=>"-clm_accelerated_spinup on -bgc sp -envxml_dir .", namelst=>"spinup_state=1", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "baseflow w aquifer" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"baseflow_scalar=1.0, lower_boundary_condition=4,use_bedrock=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "baseflow w table" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"baseflow_scalar=1.0, lower_boundary_condition=3,use_bedrock=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "br_root and bgc=sp" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"br_root=1.0", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "both co2_type and on nml" =>{ options=>"-co2_type constant -envxml_dir .", namelst=>"co2_type='prognostic'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "both lnd_frac and on nml" =>{ options=>"-driver mct -lnd_frac $DOMFILE -envxml_dir .", namelst=>"fatmlndfrc='frac.nc'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lnd_frac set to UNSET" =>{ options=>"-driver mct -lnd_frac UNSET -envxml_dir .", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "lnd_frac set but nuopc" =>{ options=>"-driver nuopc -lnd_frac $DOMFILE -envxml_dir .", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "lnd_frac not set but lilac"=>{ options=>"-driver nuopc -lilac -envxml_dir . -lnd_frac UNSET", namelst=>"fsurdat='surfdata.nc'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "fatmlndfrc set but nuopc" =>{ options=>"-driver nuopc -envxml_dir .", namelst=>"fatmlndfrc='frac.nc'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "force_send but not nuopc" =>{ options=>"-driver mct -lnd_frac $DOMFILE -envxml_dir .", namelst=>"force_send_to_atm = .false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "branch but NO nrevsn" =>{ options=>"-clm_start_type branch -envxml_dir .", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "glc_nec inconsistent" =>{ options=>"-envxml_dir .", namelst=>"maxpatch_glc=5", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "NoGLCMec" =>{ options=>"-envxml_dir . -glc_nec 0", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "UpdateGlcContradict" =>{ options=>"-envxml_dir .", @@ -950,321 +861,263 @@ sub cat_and_create_namelistinfile { }, "useFATESContradict" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_fates=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "useFATESContradict2" =>{ options=>"-envxml_dir . -no-megan", namelst=>"use_fates=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "useFATESWCN" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_cn=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "useFATESWcrop" =>{ options=>"-bgc fates -envxml_dir . -no-megan -crop", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "useFATESWcreatecrop" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"create_crop_landunit=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "useFATESWn_dom_pft" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"n_dom_pfts = 1", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "useFATESWbMH" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_biomass_heat_storage=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "FireNoneButFATESfireon" =>{ options=>"-bgc fates -envxml_dir . -no-megan -light_res none", namelst=>"fates_spitfire_mode=4", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "FATESwspitfireOffLigtOn" =>{ options=>"-bgc fates -envxml_dir . -no-megan -light_res 360x720", namelst=>"fates_spitfire_mode=0", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "useFATESWluna" =>{ options=>"--bgc fates --envxml_dir . --no-megan", namelst=>"use_luna=TRUE", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "useFATESWfun" =>{ options=>"--bgc fates --envxml_dir . --no-megan", namelst=>"use_fun=TRUE", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "useFATESWOsuplnitro" =>{ options=>"--bgc fates --envxml_dir . --no-megan", namelst=>"suplnitro='NONE'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "FireNoneButBGCfireon" =>{ options=>"-bgc bgc -envxml_dir . -light_res none", namelst=>"fire_method='li2021gswpfrc'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm6_0", }, "createcropFalse" =>{ options=>"-bgc bgc -envxml_dir . -no-megan", namelst=>"create_crop_landunit=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "usespitfireButNOTFATES" =>{ options=>"-envxml_dir . -no-megan", namelst=>"fates_spitfire_mode=1", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "usespitfireusefatessp" =>{ options=>"-envxml_dir . --bgc fates", namelst=>"fates_spitfire_mode=1,use_fates_sp=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "usefatesspusefateshydro" =>{ options=>"-envxml_dir . --bgc fates", namelst=>"use_fates_sp=.true.,use_fates_planthydro=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "useloggingButNOTFATES" =>{ options=>"-envxml_dir . -no-megan", namelst=>"use_fates_logging=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "useinventorybutnotfile" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_fates_inventory_init=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "inventoryfileDNE" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_fates_inventory_init=.true., fates_inventory_ctrl_filename='zztop'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "useinventorybutnotfile" =>{ options=>"--res 0.9x1.25 --bgc fates --envxml_dir . --no-megan", namelst=>"use_fates_luh=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "inventoryfileDNE" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_fates_luh=.true., fluh_timeseries='zztop'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "useMEGANwithFATES" =>{ options=>"-bgc fates -envxml_dir . -megan", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "useFIREEMISwithFATES" =>{ options=>"-bgc fates -envxml_dir . -fire_emis --no-megan", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "useDRYDEPwithFATES" =>{ options=>"--bgc fates --envxml_dir . --no-megan --drydep", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, "useFATESSPWONOCOMP" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_fates_sp=T,use_fates_nocomp=F", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "useFATESTRANSWdynPFT" =>{ options=>"-bgc fates -envxml_dir . -use_case 20thC_transient -no-megan", namelst=>"do_transient_pfts=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "useHYDSTwithFATES" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_hydrstress=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "useHYDSTwithdynroot" =>{ options=>"-bgc bgc -envxml_dir . -megan", namelst=>"use_hydrstress=.true., use_dynroot=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "specWOfireemis" =>{ options=>"-envxml_dir . -no-fire_emis", namelst=>"fire_emis_specifier='bc_a1 = BC'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "elevWOfireemis" =>{ options=>"-envxml_dir . -no-fire_emis", namelst=>"fire_emis_elevated=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "noanthro_w_crop" =>{ options=>"-envxml_dir . -res 0.9x1.25 -bgc bgc -crop -use_case 1850_noanthro_control", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "noanthro_w_irrig" =>{ options=>"-envxml_dir . -res 0.9x1.25 -bgc bgc -use_case 1850_noanthro_control", namelst=>"irrigate=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "spdotransconflict" =>{ options=>"-envxml_dir . -bgc sp -use_case 20thC_transient", namelst=>"do_transient_pfts=T,do_transient_crops=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "dogrossandsp" =>{ options=>"--envxml_dir . --bgc sp --use_case 20thC_transient", namelst=>"do_grossunrep=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "dogrossandfates" =>{ options=>"--envxml_dir . --bgc fates --use_case 20thC_transient --no-megan", namelst=>"do_grossunrep=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "dogrossandnottrans" =>{ options=>"--envxml_dir . --bgc bgc --use_case 2000_control", namelst=>"do_grossunrep=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "nocropwfert" =>{ options=>"-envxml_dir . -bgc sp -no-crop", namelst=>"use_fertilizer=T", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lmr1WOcn" =>{ options=>"-envxml_dir . -bgc sp", namelst=>"leafresp_method=1", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lmr2WOcn" =>{ options=>"-envxml_dir . -bgc sp", namelst=>"leafresp_method=2", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lmr0Wcn" =>{ options=>"-envxml_dir . -bgc bgc", namelst=>"leafresp_method=0", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "nofireButSetcli_scale" =>{ options=>"-envxml_dir . -bgc bgc", namelst=>"fire_method='nofire', cli_scale=5.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "nocnButSetrh_low" =>{ options=>"-envxml_dir . -bgc sp", namelst=>"rh_low=5.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "funWOcn" =>{ options=>"-envxml_dir . -bgc sp", namelst=>"use_fun=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "flexCNWOcn" =>{ options=>"-envxml_dir . -bgc sp", namelst=>"use_flexibleCN=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "flexCNFUNwcarbonresp" =>{ options=>"-envxml_dir . -bgc bgc", namelst=>"use_flexibleCN=.true.,use_FUN=.true.,carbon_resp_opt=1", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "funWOnitrif" =>{ options=>"-envxml_dir .", namelst=>"use_fun=.true., use_nitrif_denitrif=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "SPModeWNitrifNMethane" =>{ options=>"-envxml_dir . -bgc sp", namelst=>"use_lch4=.true., use_nitrif_denitrif=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "knitrmaxWOnitrif" =>{ options=>"-envxml_dir . -bgc bgc", namelst=>"use_nitrif_denitrif=.false., k_nitr_max=1.0", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "respcoefWOnitrif" =>{ options=>"-envxml_dir . -bgc bgc", namelst=>"use_nitrif_denitrif=.false., denitrif_respiration_coefficient=1.0", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "respexpWOnitrif" =>{ options=>"-envxml_dir . -bgc bgc", namelst=>"use_nitrif_denitrif=.false., denitrif_respiration_exponent=1.0", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "lunaWSPandlnctrue" =>{ options=>"-envxml_dir . -bgc sp", namelst=>"use_luna=.true., lnc_opt=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "NOlunabutsetJmaxb1" =>{ options=>"-envxml_dir . -bgc sp", namelst=>"use_luna=.false., jmaxb1=1.0", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "envxml_not_dir" =>{ options=>"-envxml_dir myuser_nl_clm", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "envxml_emptydir" =>{ options=>"-envxml_dir xFail", namelst=>"", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "fates_non_sp_laistreams" =>{ options=>"--envxml_dir . --bgc fates", namelst=>"use_lai_streams=.true., use_fates_sp=.false.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "bgc_non_sp_laistreams" =>{ options=>"--envxml_dir . -bgc bgc", namelst=>"use_lai_streams=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "bgc_laistreams_input" =>{ options=>"--envxml_dir . --bgc bgc", namelst=>"stream_year_first_lai=1999", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "crop_laistreams_input" =>{ options=>"--envxml_dir . --bgc sp --crop", namelst=>"use_lai_streams=.true.", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "soil_erod_wo_Zender" =>{ options=>"--envxml_dir . --ignore_warnings", namelst=>"dust_emis_method='Leung_2023', " . "stream_meshfile_zendersoilerod = '/dev/null'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_1", }, "soil_erod_wo_lnd_source" =>{ options=>"--envxml_dir .", namelst=>"dust_emis_method='Zender_2003', " . "stream_fldfilename_zendersoilerod = '/dev/null', zender_soil_erod_source='atm'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_1", }, "soil_erod_none_w_Zender" =>{ options=>"--envxml_dir .", namelst=>"dust_emis_method='Zender_2003', " . "zender_soil_erod_source='none'", - GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_1", }, "soil_erod_bad_w_Zender" =>{ options=>"--envxml_dir .", namelst=>"dust_emis_method='Zender_2003', " . "zender_soil_erod_source='zztop'", - GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_1", + }, + "Set_Dust_When_CAM_Sets" =>{ options=>"--envxml_dir .", + namelst=>"dust_emis_method='Zender_2003'", + LND_SETS_DUST_EMIS_DRV_FLDS=>"FALSE", phys=>"clm5_1", }, ); @@ -1273,7 +1126,13 @@ sub cat_and_create_namelistinfile { &make_config_cache($failtest{$key}{"phys"}); my $options = $failtest{$key}{"options"}; my $namelist = $failtest{$key}{"namelst"}; - &make_env_run( GLC_TWO_WAY_COUPLING=>$failtest{$key}{"GLC_TWO_WAY_COUPLING"} ); + my %settings; + foreach my $xmlvar ( "GLC_TWO_WAY_COUPLING", "LND_SETS_DUST_EMIS_DRV_FLDS") { + if ( defined($failtest{$key}{$xmlvar}) ) { + $settings{$xmlvar} = $failtest{$key}{$xmlvar}; + } + } + &make_env_run( %settings ); eval{ system( "$bldnml $options -namelist \"&clmexp $namelist /\" > $tempfile 2>&1 " ); }; isnt( $?, 0, $key ); system( "cat $tempfile" ); @@ -1515,7 +1374,7 @@ sub cat_and_create_namelistinfile { # cases; I'm not sure if it's actually important to test this with all # of the different use cases. my @glc_res = ( "0.9x1.25", "1.9x2.5" ); -my @use_cases = ( +my @use_cases = ( "1850-2100_SSP2-4.5_transient", "1850_control", "2000_control", From 438d85a58b120a1329db4c47520ff473a40bcc5b Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Fri, 17 May 2024 09:27:55 -0600 Subject: [PATCH 113/444] Added a missing bracket --- bld/CLMBuildNamelist.pm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index ad378ffc6d..3658f681af 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -785,7 +785,7 @@ sub setup_cmdl_fates_mode { "use_fates_cohort_age_tracking","use_fates_inventory_init","use_fates_fixed_biogeog", "use_fates_nocomp","use_fates_sp","fates_inventory_ctrl_filename","fates_harvest_mode", "fates_parteh_mode","use_fates_tree_damage","fates_seeddisp_cadence","use_fates_luh","fluh_timeseries", - "flandusepftdat","use_fates_potentialveg","use_fates_lupft","fates_history_dimlevel"); + "flandusepftdat","use_fates_potentialveg","use_fates_lupft","fates_history_dimlevel" ); # dis-allow fates specific namelist items with non-fates runs foreach my $var ( @list ) { @@ -4517,7 +4517,7 @@ sub setup_logic_fates { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_paramfile', 'phys'=>$nl_flags->{'phys'}); my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys", "use_fates_inventory_init","fates_seeddisp_cadence","fates_history_dimlevel", - "fates_harvest_mode","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage"); + "fates_harvest_mode","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage" ); foreach my $var ( @list ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, @@ -4564,12 +4564,12 @@ sub setup_logic_fates { # fates landuse can't be on with FATES SP mode is active if ( &value_is_true($nl->get_value('use_fates_luh')) ) { - $log->fatal_error('use_fates_luh can NOT be true when use_fates_sp is true'); + $log->fatal_error('use_fates_luh can NOT be true when use_fates_sp is true'); + } # hydro isn't currently supported to work when FATES SP mode is active if (&value_is_true( $nl->get_value('use_fates_planthydro') )) { $log->fatal_error('fates sp mode is currently not supported to work with fates hydro'); - } } } From e6f62c431b05460f62c6549e464797df7a7ebf58 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 17 May 2024 15:56:00 -0600 Subject: [PATCH 114/444] fix reading of fates_harvest_modes during namelist build checks --- bld/CLMBuildNamelist.pm | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 01f7918d62..c1ec60fb33 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4487,8 +4487,9 @@ sub setup_logic_fates { if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { $log->fatal_error("use_fates_luh must be true when $var is true" ); } - if ( $nl->get_value('fates_harvest_mode') ne 'no_harvest') { - $log->fatal_error("fates_harvest_mode must be off (i.e. set to zero) when $var is true" ); + my $var = remove_leading_and_trailing_quotes($nl->get_value('fates_harvest_mode')); + if ( $var ne 'no_harvest') { + $log->fatal_error("fates_harvest_mode set to $var. It must set to no_harvest when use_potential_veg is true." ); } my $var = "fluh_timeseries"; if ( defined($nl->get_value($var)) ) { @@ -4500,10 +4501,22 @@ sub setup_logic_fates { my $var = "fates_harvest_mode"; if ( defined($nl->get_value($var)) ) { # using fates_harvest mode with raw luh2 harvest data - if ( $nl->get_value($var) eq 'luhdata_area' || $nl->get_value($var) eq 'luhdata_mass' ) { + my $mode = remove_leading_and_trailing_quotes($nl->get_value($var)); + if ( $mode eq 'luhdata_area' || $mode eq 'luhdata_mass' ) { # Make sure that use_fates_luh is true when using raw fates luh2 harvest data if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { - $log->fatal_error("use_fates_luh is required to be true when $var is greater than 2" ); + $log->fatal_error("use_fates_luh is required to be true when $var is luhdata_mass or luhdata_area" ); + } + } elsif ( $mode eq 'surfdata_file' ) { + # Check to make sure that the user set the flanduse_timeseries file + # Since the flanduse_timeseries logic checking is upstream of the fates logic, + # don't try and add the default here + my $var = "flanduse_timeseries"; + my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); + if ( ! defined($nl->get_value($var)) ) { + $log->fatal_error("$var is required when fates_harvest_mode is surfdata_file" ); + } elsif ( ! -f "$fname" ) { + $log->fatal_error("$var does NOT point to a valid filename" ); } } } From 093f0666b9b1d78701240a2036e1efca8e073133 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 17 May 2024 16:18:20 -0600 Subject: [PATCH 115/444] minor comment update --- bld/CLMBuildNamelist.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index c1ec60fb33..e563bdffa8 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4510,7 +4510,8 @@ sub setup_logic_fates { } elsif ( $mode eq 'surfdata_file' ) { # Check to make sure that the user set the flanduse_timeseries file # Since the flanduse_timeseries logic checking is upstream of the fates logic, - # don't try and add the default here + # don't add the default here. The onus is on the user to match the correct timeseries + # data to the correct surface dataset resolution my $var = "flanduse_timeseries"; my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); if ( ! defined($nl->get_value($var)) ) { From 3967d77a17e4e6a02362aec42aa3feb187ba6c72 Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Wed, 22 May 2024 10:28:47 -0600 Subject: [PATCH 116/444] new fates api 36 paramfile default --- bld/namelist_files/namelist_defaults_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 6ef91bb4a0..fdfeba7719 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -481,7 +481,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). -lnd/clm2/paramdata/fates_params_api.35.0.0_12pft_c240326.nc +lnd/clm2/paramdata/fates_params_api.36.0.0_12pft_c240517.nc From 5b30740bd91e421639bb46239f4d921b8e767b54 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 22 May 2024 13:37:16 -0600 Subject: [PATCH 117/444] Pin FATES external to commit a997af5. --- Externals_CLM.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals_CLM.cfg b/Externals_CLM.cfg index cfb7beb40f..a8d53e4fdb 100644 --- a/Externals_CLM.cfg +++ b/Externals_CLM.cfg @@ -2,7 +2,7 @@ local_path = src/fates protocol = git repo_url = https://github.com/ckoven/fates -branch = luh2_nocomp_merge +hash = a997af58f38db8ffda259e11f3abcc65478a4903 required = True [externals_description] From 2a7ca01b2177b480e8897fd2921bf00a7ac9c48f Mon Sep 17 00:00:00 2001 From: loaner Date: Wed, 22 May 2024 17:43:48 -0700 Subject: [PATCH 118/444] add systemtest for potential vegetation spin up --- cime_config/SystemTests/pvt.py | 120 ++++++++++++++++++++ cime_config/SystemTests/systemtest_utils.py | 20 +++- 2 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 cime_config/SystemTests/pvt.py diff --git a/cime_config/SystemTests/pvt.py b/cime_config/SystemTests/pvt.py new file mode 100644 index 0000000000..e18022220d --- /dev/null +++ b/cime_config/SystemTests/pvt.py @@ -0,0 +1,120 @@ +""" +FATES land use potential vegetation spin up + transient test + +This is a FATES specific test: + +1) conduct a spinup with use_fates_potentialveg on + - write restart file + - use CLM_ACCELERATED_SPINUP? +2) run a transient landuse case with use_fates_lupft + - start from the restart file generated in (1) + +""" +from CIME.XML.standard_module_setup import * +from CIME.SystemTests.system_tests_common import SystemTestsCommon +from systemtest_utils import read_user_nl_clm +import shutil, glob, os + +logger = logging.getLogger(__name__) + +class PVT(SystemTestsCommon): + def __init_(self,case): + SystemTestsCommon.__init__(self,case) + + # Do not allow PVT to be run with certain testmods + # Should this be targeted to a specific testmod for simplicity for now? + # Technically this could be run with the luh fates_harvest_modes + casebaseid = self._case.get_value("CASEBASEID") + casebasid = casebaseid.split("-")[-1] + if casebaseid[0:10] != "FatesLUPFT": + error_message = ( + "Only call PVT with test FatesLUPFT" + ) + logger.error(error_message) + raise RuntimeError(error_message) + + # Only allow to run if resolution is 4x5 for now + # Eventually we could set this up to generate the necessary land use x pft mapping + # on the fly, although this would also require generating the land use timeseries + # regridding on the fly which is a more time consuming endevour currently + lnd_grid = self._case.get_value("LND_GRID") + if lnd_grid != "4x5": + error_message = ( + "PVT can currently only be run with 4x5 resolution" + ) + logger.error(error_message) + raise RuntimeError(error_message) + + def run_phase(self): + # ------------------------------------------------------------------- + # (1) Run FATES spin-up case in potential vegetation mode + # ------------------------------------------------------------------- + orig_case = self._case + orig_casevar = self._case.get_value("CASE") + caseroot = self._case.get_value("CASEROOT") + + # clone the main case to create spinup case + logger.info("PVT log: cloning setup") + clone_path = "{}.potveg".format(caseroot) + if os.path.exists(clone_path): + shutil.rmtree(clone_path) + logger.info("PVT log: cloning") + clone = self._case.create_clone(clone_path, keepexe=True) + logger.info("PVT log: cloning complete") + + # setup the clone case + os.chdir(clone_path) + self._set_active_case(clone) + self._setup_all() + + # Modify the spin up case to use the potential vegetation mode. + # Checks for incompatible cases and necessary mapping files are + # handled in the build case. + # use_fates_lupft should be set to true in the testmod + # save off the harvest mode for reinstating later + found, hmode = self.read_user_nl_clm('fates_harvest_mode') + logger.info("PVT log: modify user_nl_clm file for spin up run") + # TODO: remove fates_harvest_mode if found + self._append_to_user_nl_clm( + [ + "use_fates_potentialveg = .true.", + ] + ) + + stop_n_pveg = 1 + with clone: + # clone.set_value("CLM_ACCELERATED_SPINUP", "on") + clone.set_value("STOP_N", stop_n_pveg) + + # Run the spin up case + # As per SSP test: + # "No history files expected, set suffix=None to avoid compare error" + logger.info("PVT log: starting spin-up run") + dout_sr = clone.get_value("DOUT_S_ROOT") + self._skip_pnl = False + self.run_indv(suffix=None, st_archive=True) + + # ------------------------------------------------------------------- + # (2) Run FATES transient case using restart file from spin-up + # ------------------------------------------------------------------- + os.chdir(caseroot) + self._set_active_case(orig_case) + + # logger.info("PVT log: modify user_nl_clm file for transient run") + # self._append_to_user_nl_clm( + # [ + # "use_fates_potentialveg = .true.", + # ] + # ) + + + self._case.set_value("CLM_ACCELERATED_SPINUP", "off") + self._case.set_value("RUN_TYPE", "hybrid") + self._case.set_value("GET_REFCASE", False) + self._case.set_value("RUN_REFCASE", "{}.potveg".format(orig_casevar)) + self._case.set_value("RUN_REFDATE", "1700-01-01") + self._case.set_value("DOUT_S", False) + self._case.flush() + + # do the restart run (short term archiving is off) + self.run_indv() diff --git a/cime_config/SystemTests/systemtest_utils.py b/cime_config/SystemTests/systemtest_utils.py index c5ac986abd..8447934797 100644 --- a/cime_config/SystemTests/systemtest_utils.py +++ b/cime_config/SystemTests/systemtest_utils.py @@ -2,7 +2,7 @@ Reduce code duplication by putting reused functions here. """ -import os, subprocess +import os, subprocess, re def cmds_to_setup_conda(caseroot): @@ -84,3 +84,21 @@ def run_python_script(caseroot, this_conda_env, command_in, tool_path): except: print(f"ERROR trying to run {tool_name}.") raise + +def read_user_nl_clm(self,namelist_option): + user_nl_clm_path = os.path.join(self._get_caseroot(), "user_nl_clm") + with open(user_nl_clm_path) as f: + user_nl_clm_text = f.read() + reg = fr'{namelist_option}\s*=\s*([^\n]+)' + find_out = re.findall(reg, user_nl_clm_text) + # This could be more robust + if len(find_out) == 0: + return 0, False + elif len(find_out) > 1: + error_message = ( + "ERROR: read_user_nl_clm: namelist option is set more than once" + ) + # logger.error(error_message) + raise RuntimeError(error_message) + else: + return find_out[0], True From b7cf13f6dcfd6c975de294ef90122bb4e2fc0d3e Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 23 May 2024 13:47:07 -0700 Subject: [PATCH 119/444] add PVT system test to the config_test xml file --- cime_config/config_tests.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cime_config/config_tests.xml b/cime_config/config_tests.xml index c0b6afed9d..8a4388c664 100644 --- a/cime_config/config_tests.xml +++ b/cime_config/config_tests.xml @@ -123,6 +123,18 @@ This defines various CTSM-specific system tests $STOP_N + + FATES potential vegetarion spin-up + land use transient run test + 1 + ndays + startup + 4 + FALSE + FALSE + $STOP_OPTION + $STOP_N + + Generate prescribed maturity requirements, then test with them 1 From 8e35d80baf507185ef0dac47a4adee4bf975d47e Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 23 May 2024 14:29:02 -0600 Subject: [PATCH 120/444] add test mode for use_fates_lupft --- .../testdefs/testmods_dirs/clm/FatesLUPFT/include_user_mods | 1 + cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/user_nl_clm | 1 + 2 files changed, 2 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/include_user_mods new file mode 100644 index 0000000000..4c7aa0f2b4 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/include_user_mods @@ -0,0 +1 @@ +../Fates diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/user_nl_clm new file mode 100644 index 0000000000..10044848a0 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/user_nl_clm @@ -0,0 +1 @@ +use_fates_lupft = .true. From af5451b7e37d53d1192fb87315d01fb16b527ba1 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 23 May 2024 14:39:45 -0700 Subject: [PATCH 121/444] remove tabs and correct whitespace --- bld/CLMBuildNamelist.pm | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index acdad5c5cc..b17a245715 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4520,22 +4520,22 @@ sub setup_logic_fates { "fates_harvest_mode","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage" ); foreach my $var ( @list ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, - 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, + 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); } - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_potentialveg', 'use_fates'=>$nl_flags->{'use_fates'}); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_lupft', 'use_fates'=>$nl_flags->{'use_fates'}); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_luh', 'use_fates'=>$nl_flags->{'use_fates'}, - 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), - 'use_fates_potentialveg'=>$nl->get_value('use_fates_potentialveg'), - 'fates_harvest_mode'=>$nl->get_value('fates_harvest_mode') ); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_nocomp', 'use_fates'=>$nl_flags->{'use_fates'}, - 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), - 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_fixed_biogeog', 'use_fates'=>$nl_flags->{'use_fates'}, - 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), - 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_potentialveg', 'use_fates'=>$nl_flags->{'use_fates'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_lupft', 'use_fates'=>$nl_flags->{'use_fates'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_luh', 'use_fates'=>$nl_flags->{'use_fates'}, + 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), + 'use_fates_potentialveg'=>$nl->get_value('use_fates_potentialveg'), + 'fates_harvest_mode'=>$nl->get_value('fates_harvest_mode') ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_nocomp', 'use_fates'=>$nl_flags->{'use_fates'}, + 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), + 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_fixed_biogeog', 'use_fates'=>$nl_flags->{'use_fates'}, + 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), + 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); my $suplnitro = $nl->get_value('suplnitro'); my $parteh_mode = $nl->get_value('fates_parteh_mode'); @@ -4564,8 +4564,8 @@ sub setup_logic_fates { # fates landuse can't be on with FATES SP mode is active if ( &value_is_true($nl->get_value('use_fates_luh')) ) { - $log->fatal_error('use_fates_luh can NOT be true when use_fates_sp is true'); - } + $log->fatal_error('use_fates_luh can NOT be true when use_fates_sp is true'); + } # hydro isn't currently supported to work when FATES SP mode is active if (&value_is_true( $nl->get_value('use_fates_planthydro') )) { @@ -4608,7 +4608,7 @@ sub setup_logic_fates { if ( ! &value_is_true($nl->get_value($var)) ) { $var = "fluh_timeseries"; add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'phys'=>$nl_flags->{'phys'}, - 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, nofail=>1 ); + 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, nofail=>1 ); my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); if ( ! defined($nl->get_value($var)) ) { $log->fatal_error("$var is required when use_fates_luh is set and use_fates_potentialveg is false" ); @@ -4616,21 +4616,21 @@ sub setup_logic_fates { $log->fatal_error("$var does NOT point to a valid filename" ); } } - } + } $var = "use_fates_fixed_biogeog"; if ( defined($nl->get_value($var)) ) { if ( &value_is_true($nl->get_value($var)) ) { - $var = "flandusepftdat"; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); - my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); - if ( ! defined($nl->get_value($var)) ) { - $log->fatal_error("$var is required when use_fates_luh and use_fates_fixed_biogeog is set" ); - } elsif ( ! -f "$fname" ) { - $log->fatal_error("$var does NOT point to a valid filename" ); - } - } - } + $var = "flandusepftdat"; + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, + 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); + my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); + if ( ! defined($nl->get_value($var)) ) { + $log->fatal_error("$var is required when use_fates_luh and use_fates_fixed_biogeog is set" ); + } elsif ( ! -f "$fname" ) { + $log->fatal_error("$var does NOT point to a valid filename" ); + } + } + } } } # check that fates landuse is on and harvest mode is off when potential veg switch is true From 00d23e9adb4139847dc5f855ff4ce43bc845b41e Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 23 May 2024 16:48:55 -0600 Subject: [PATCH 122/444] correct add default for fluh and flandusepftdat --- bld/CLMBuildNamelist.pm | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index b17a245715..d952e7fe89 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4607,8 +4607,8 @@ sub setup_logic_fates { if ( defined($nl->get_value($var)) ) { if ( ! &value_is_true($nl->get_value($var)) ) { $var = "fluh_timeseries"; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'phys'=>$nl_flags->{'phys'}, - 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, nofail=>1 ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, + 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); if ( ! defined($nl->get_value($var)) ) { $log->fatal_error("$var is required when use_fates_luh is set and use_fates_potentialveg is false" ); @@ -4620,17 +4620,17 @@ sub setup_logic_fates { $var = "use_fates_fixed_biogeog"; if ( defined($nl->get_value($var)) ) { if ( &value_is_true($nl->get_value($var)) ) { - $var = "flandusepftdat"; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); - my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); - if ( ! defined($nl->get_value($var)) ) { - $log->fatal_error("$var is required when use_fates_luh and use_fates_fixed_biogeog is set" ); - } elsif ( ! -f "$fname" ) { - $log->fatal_error("$var does NOT point to a valid filename" ); - } - } - } + $var = "flandusepftdat"; + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, + 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); + my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); + if ( ! defined($nl->get_value($var)) ) { + $log->fatal_error("$var is required when use_fates_luh and use_fates_fixed_biogeog is set" ); + } elsif ( ! -f "$fname" ) { + $log->fatal_error("$var does NOT point to a valid filename" ); + } + } + } } } # check that fates landuse is on and harvest mode is off when potential veg switch is true From 2ac13bcb7aeec5a1772635edfe7c0f99be9c532d Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 23 May 2024 17:39:57 -0600 Subject: [PATCH 123/444] correct typos causing RunTimeError to be missed --- cime_config/SystemTests/pvt.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/cime_config/SystemTests/pvt.py b/cime_config/SystemTests/pvt.py index e18022220d..c45c514f39 100644 --- a/cime_config/SystemTests/pvt.py +++ b/cime_config/SystemTests/pvt.py @@ -18,20 +18,17 @@ logger = logging.getLogger(__name__) class PVT(SystemTestsCommon): - def __init_(self,case): + def __init__(self,case): SystemTestsCommon.__init__(self,case) # Do not allow PVT to be run with certain testmods # Should this be targeted to a specific testmod for simplicity for now? # Technically this could be run with the luh fates_harvest_modes + error_message = None casebaseid = self._case.get_value("CASEBASEID") - casebasid = casebaseid.split("-")[-1] + casebaseid = casebaseid.split("-")[-1] if casebaseid[0:10] != "FatesLUPFT": - error_message = ( - "Only call PVT with test FatesLUPFT" - ) - logger.error(error_message) - raise RuntimeError(error_message) + error_message = (f"Only call PVT with testmod FatesLUPFT. {casebaseid} selected.") # Only allow to run if resolution is 4x5 for now # Eventually we could set this up to generate the necessary land use x pft mapping @@ -39,12 +36,11 @@ def __init_(self,case): # regridding on the fly which is a more time consuming endevour currently lnd_grid = self._case.get_value("LND_GRID") if lnd_grid != "4x5": - error_message = ( - "PVT can currently only be run with 4x5 resolution" - ) + error_message = (f"PVT can currently only be run with 4x5 resolution. {lnd_grid} selected.") + + if error_message is not None: logger.error(error_message) raise RuntimeError(error_message) - def run_phase(self): # ------------------------------------------------------------------- # (1) Run FATES spin-up case in potential vegetation mode From f4ff559c831533ab9c901d1f44e5744740a8f302 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 23 May 2024 16:45:42 -0700 Subject: [PATCH 124/444] remove tabs again --- bld/CLMBuildNamelist.pm | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index d952e7fe89..0fb7ba9692 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4608,7 +4608,7 @@ sub setup_logic_fates { if ( ! &value_is_true($nl->get_value($var)) ) { $var = "fluh_timeseries"; add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, - 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); if ( ! defined($nl->get_value($var)) ) { $log->fatal_error("$var is required when use_fates_luh is set and use_fates_potentialveg is false" ); @@ -4620,17 +4620,17 @@ sub setup_logic_fates { $var = "use_fates_fixed_biogeog"; if ( defined($nl->get_value($var)) ) { if ( &value_is_true($nl->get_value($var)) ) { - $var = "flandusepftdat"; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, - 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); - my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); - if ( ! defined($nl->get_value($var)) ) { - $log->fatal_error("$var is required when use_fates_luh and use_fates_fixed_biogeog is set" ); - } elsif ( ! -f "$fname" ) { - $log->fatal_error("$var does NOT point to a valid filename" ); - } - } - } + $var = "flandusepftdat"; + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, + 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); + my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); + if ( ! defined($nl->get_value($var)) ) { + $log->fatal_error("$var is required when use_fates_luh and use_fates_fixed_biogeog is set" ); + } elsif ( ! -f "$fname" ) { + $log->fatal_error("$var does NOT point to a valid filename" ); + } + } + } } } # check that fates landuse is on and harvest mode is off when potential veg switch is true From de8c0a33315693c9dc66b267bd255e703f9010c0 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 24 May 2024 13:53:13 -0600 Subject: [PATCH 125/444] update what new utility function returns as output --- cime_config/SystemTests/systemtest_utils.py | 41 ++++++++++++--------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/cime_config/SystemTests/systemtest_utils.py b/cime_config/SystemTests/systemtest_utils.py index 8447934797..9470799a27 100644 --- a/cime_config/SystemTests/systemtest_utils.py +++ b/cime_config/SystemTests/systemtest_utils.py @@ -2,7 +2,7 @@ Reduce code duplication by putting reused functions here. """ -import os, subprocess, re +import os, subprocess, re, glob def cmds_to_setup_conda(caseroot): @@ -84,21 +84,26 @@ def run_python_script(caseroot, this_conda_env, command_in, tool_path): except: print(f"ERROR trying to run {tool_name}.") raise +""" +Read a user_nl file and return the namelist option if found +""" +def find_user_nl_option(caseroot, component, namelist_option): + + # This is a copy of the CIME _get_list_of_user_nl_files + # which could be used if this moved into the CIME project + file_pattern = "user_nl_" + component + "*" + file_list = glob.glob(os.path.join(caseroot, file_pattern)) + + # Check that there is at least one file + if len(file_list) == 0: + raise RuntimeError("No user_nl files found for component " + component) -def read_user_nl_clm(self,namelist_option): - user_nl_clm_path = os.path.join(self._get_caseroot(), "user_nl_clm") - with open(user_nl_clm_path) as f: - user_nl_clm_text = f.read() - reg = fr'{namelist_option}\s*=\s*([^\n]+)' - find_out = re.findall(reg, user_nl_clm_text) - # This could be more robust - if len(find_out) == 0: - return 0, False - elif len(find_out) > 1: - error_message = ( - "ERROR: read_user_nl_clm: namelist option is set more than once" - ) - # logger.error(error_message) - raise RuntimeError(error_message) - else: - return find_out[0], True + # Read through the file list and look for a match and return the whole entry + output = {} + for one_file in file_list: + with open(one_file, "r") as user_nl_file: + user_nl_text = user_nl_file.read() + reg = fr'{namelist_option}.*?(?=,|\n)' + find_out = re.findall(reg, user_nl_text) + output[one_file] = find_out + return output From cd04c06c06e1399c262c970180f291d583eaf72b Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 24 May 2024 14:06:36 -0600 Subject: [PATCH 126/444] change dictionary to ordered dict --- cime_config/SystemTests/systemtest_utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cime_config/SystemTests/systemtest_utils.py b/cime_config/SystemTests/systemtest_utils.py index 9470799a27..2591ac4223 100644 --- a/cime_config/SystemTests/systemtest_utils.py +++ b/cime_config/SystemTests/systemtest_utils.py @@ -3,6 +3,7 @@ """ import os, subprocess, re, glob +from collections import OrderedDict def cmds_to_setup_conda(caseroot): @@ -99,7 +100,7 @@ def find_user_nl_option(caseroot, component, namelist_option): raise RuntimeError("No user_nl files found for component " + component) # Read through the file list and look for a match and return the whole entry - output = {} + output = OrderedDict() for one_file in file_list: with open(one_file, "r") as user_nl_file: user_nl_text = user_nl_file.read() From dab63611a6088551ff2959f1c04bcfbc4b61c2db Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 24 May 2024 16:13:59 -0600 Subject: [PATCH 127/444] pvt system init step update --- cime_config/SystemTests/pvt.py | 149 ++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 67 deletions(-) diff --git a/cime_config/SystemTests/pvt.py b/cime_config/SystemTests/pvt.py index c45c514f39..184c5de289 100644 --- a/cime_config/SystemTests/pvt.py +++ b/cime_config/SystemTests/pvt.py @@ -12,7 +12,8 @@ """ from CIME.XML.standard_module_setup import * from CIME.SystemTests.system_tests_common import SystemTestsCommon -from systemtest_utils import read_user_nl_clm +from CIME.SystemTests.test_utils.user_nl_utils import append_to_user_nl_files +from systemtest_utils import find_user_nl_option import shutil, glob, os logger = logging.getLogger(__name__) @@ -41,76 +42,90 @@ def __init__(self,case): if error_message is not None: logger.error(error_message) raise RuntimeError(error_message) - def run_phase(self): - # ------------------------------------------------------------------- - # (1) Run FATES spin-up case in potential vegetation mode - # ------------------------------------------------------------------- - orig_case = self._case - orig_casevar = self._case.get_value("CASE") - caseroot = self._case.get_value("CASEROOT") - - # clone the main case to create spinup case - logger.info("PVT log: cloning setup") - clone_path = "{}.potveg".format(caseroot) - if os.path.exists(clone_path): - shutil.rmtree(clone_path) - logger.info("PVT log: cloning") - clone = self._case.create_clone(clone_path, keepexe=True) - logger.info("PVT log: cloning complete") - # setup the clone case - os.chdir(clone_path) - self._set_active_case(clone) - self._setup_all() + # Look to see if a harvest mode has been set in the namelist and save off for the transient run + # If there are more than one entries in the dict, i.e. multiple user_nl_clm's found, abort. + # If there are multiple enteries the user_nl_clm, use the last one as the dict is ordered + caseroot = self._case.get_value("CASEROOT") + harvest_mode_dict = find_user_nl_option(caseroot, 'clm', 'fates_harvest_mode') + harvest_mode = None + if len(harvest_mode_dict) == 1: + hmod = harvest_mode_dict[next(reversed(harvest_mode_dict))] + if len(hmod) != 0: + harvest_mode = hmod[-1] + elif (len(harvest_mode_dict)) > 1: + raise RuntimeError('Multiple user_nl_clm files found. PVT assumes only a single user_nl_clm case') # Modify the spin up case to use the potential vegetation mode. # Checks for incompatible cases and necessary mapping files are # handled in the build case. # use_fates_lupft should be set to true in the testmod - # save off the harvest mode for reinstating later - found, hmode = self.read_user_nl_clm('fates_harvest_mode') - logger.info("PVT log: modify user_nl_clm file for spin up run") - # TODO: remove fates_harvest_mode if found - self._append_to_user_nl_clm( - [ - "use_fates_potentialveg = .true.", - ] - ) - - stop_n_pveg = 1 - with clone: - # clone.set_value("CLM_ACCELERATED_SPINUP", "on") - clone.set_value("STOP_N", stop_n_pveg) - - # Run the spin up case - # As per SSP test: - # "No history files expected, set suffix=None to avoid compare error" - logger.info("PVT log: starting spin-up run") - dout_sr = clone.get_value("DOUT_S_ROOT") - self._skip_pnl = False - self.run_indv(suffix=None, st_archive=True) + # If the testmod has a fates harvest mode, make sure to append 'no_harvest' + # to the spin up case - # ------------------------------------------------------------------- - # (2) Run FATES transient case using restart file from spin-up - # ------------------------------------------------------------------- - os.chdir(caseroot) - self._set_active_case(orig_case) - - # logger.info("PVT log: modify user_nl_clm file for transient run") - # self._append_to_user_nl_clm( - # [ - # "use_fates_potentialveg = .true.", - # ] - # ) - - - self._case.set_value("CLM_ACCELERATED_SPINUP", "off") - self._case.set_value("RUN_TYPE", "hybrid") - self._case.set_value("GET_REFCASE", False) - self._case.set_value("RUN_REFCASE", "{}.potveg".format(orig_casevar)) - self._case.set_value("RUN_REFDATE", "1700-01-01") - self._case.set_value("DOUT_S", False) - self._case.flush() - - # do the restart run (short term archiving is off) - self.run_indv() + logger.info("PVT log: modify user_nl_clm file for spin up run") + added_content = ["use_fates_potentialveg = .true."] + if harvest_mode is not None: + added_content.append("fates_harvest_mode = 'no_harvest'") + append_to_user_nl_files(caseroot, "clm", added_content) + +# def run_phase(self): +# # ------------------------------------------------------------------- +# # (1) Run FATES spin-up case in potential vegetation mode +# # ------------------------------------------------------------------- +# orig_case = self._case +# orig_casevar = self._case.get_value("CASE") +# caseroot = self._case.get_value("CASEROOT") +# +# # clone the main case to create spinup case +# logger.info("PVT log: cloning setup") +# clone_path = "{}.potveg".format(caseroot) +# if os.path.exists(clone_path): +# shutil.rmtree(clone_path) +# logger.info("PVT log: cloning") +# clone = self._case.create_clone(clone_path, keepexe=True) +# logger.info("PVT log: cloning complete") +# +# # setup the clone case +# os.chdir(clone_path) +# self._set_active_case(clone) +# self._setup_all() +# +# +# stop_n_pveg = 1 +# with clone: +# # clone.set_value("CLM_ACCELERATED_SPINUP", "on") +# clone.set_value("STOP_N", stop_n_pveg) +# +# # Run the spin up case +# # As per SSP test: +# # "No history files expected, set suffix=None to avoid compare error" +# logger.info("PVT log: starting spin-up run") +# dout_sr = clone.get_value("DOUT_S_ROOT") +# self._skip_pnl = False +# self.run_indv(suffix=None, st_archive=True) +# +# # ------------------------------------------------------------------- +# # (2) Run FATES transient case using restart file from spin-up +# # ------------------------------------------------------------------- +# os.chdir(caseroot) +# self._set_active_case(orig_case) +# +# # logger.info("PVT log: modify user_nl_clm file for transient run") +# # self._append_to_user_nl_clm( +# # [ +# # "use_fates_potentialveg = .true.", +# # ] +# # ) +# +# +# self._case.set_value("CLM_ACCELERATED_SPINUP", "off") +# self._case.set_value("RUN_TYPE", "hybrid") +# self._case.set_value("GET_REFCASE", False) +# self._case.set_value("RUN_REFCASE", "{}.potveg".format(orig_casevar)) +# self._case.set_value("RUN_REFDATE", "1700-01-01") +# self._case.set_value("DOUT_S", False) +# self._case.flush() +# +# # do the restart run (short term archiving is off) +# self.run_indv() From 175a3d01082437945f15660f75aca860c626d0a4 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 24 May 2024 18:14:18 -0600 Subject: [PATCH 128/444] pvt system test setup looks correct --- cime_config/SystemTests/pvt.py | 132 +++++++++++++-------------------- 1 file changed, 53 insertions(+), 79 deletions(-) diff --git a/cime_config/SystemTests/pvt.py b/cime_config/SystemTests/pvt.py index 184c5de289..6b2a958eaa 100644 --- a/cime_config/SystemTests/pvt.py +++ b/cime_config/SystemTests/pvt.py @@ -43,89 +43,63 @@ def __init__(self,case): logger.error(error_message) raise RuntimeError(error_message) - # Look to see if a harvest mode has been set in the namelist and save off for the transient run - # If there are more than one entries in the dict, i.e. multiple user_nl_clm's found, abort. - # If there are multiple enteries the user_nl_clm, use the last one as the dict is ordered + def run_phase(self): + # ------------------------------------------------------------------- + # (1) Run FATES spin-up case in potential vegetation mode + # ------------------------------------------------------------------- + orig_case = self._case + orig_casevar = self._case.get_value("CASE") caseroot = self._case.get_value("CASEROOT") - harvest_mode_dict = find_user_nl_option(caseroot, 'clm', 'fates_harvest_mode') - harvest_mode = None - if len(harvest_mode_dict) == 1: - hmod = harvest_mode_dict[next(reversed(harvest_mode_dict))] - if len(hmod) != 0: - harvest_mode = hmod[-1] - elif (len(harvest_mode_dict)) > 1: - raise RuntimeError('Multiple user_nl_clm files found. PVT assumes only a single user_nl_clm case') + + # clone the main case to create spinup case + logger.info("PVT log: cloning setup") + clone_path = "{}.potveg".format(caseroot) + if os.path.exists(clone_path): + shutil.rmtree(clone_path) + logger.info("PVT log: cloning") + clone = self._case.create_clone(clone_path, keepexe=True) + logger.info("PVT log: cloning complete") + + # setup the clone case + os.chdir(clone_path) + self._set_active_case(clone) + + # set the clone case values + stop_n_pveg = 1 + with clone: + # clone.set_value("CLM_ACCELERATED_SPINUP", "on") + clone.set_value("STOP_N", stop_n_pveg) # Modify the spin up case to use the potential vegetation mode. # Checks for incompatible cases and necessary mapping files are # handled in the build case. - # use_fates_lupft should be set to true in the testmod - # If the testmod has a fates harvest mode, make sure to append 'no_harvest' - # to the spin up case + # Turn off fates_harvest_mode for the spin up. logger.info("PVT log: modify user_nl_clm file for spin up run") - added_content = ["use_fates_potentialveg = .true."] - if harvest_mode is not None: - added_content.append("fates_harvest_mode = 'no_harvest'") - append_to_user_nl_files(caseroot, "clm", added_content) - -# def run_phase(self): -# # ------------------------------------------------------------------- -# # (1) Run FATES spin-up case in potential vegetation mode -# # ------------------------------------------------------------------- -# orig_case = self._case -# orig_casevar = self._case.get_value("CASE") -# caseroot = self._case.get_value("CASEROOT") -# -# # clone the main case to create spinup case -# logger.info("PVT log: cloning setup") -# clone_path = "{}.potveg".format(caseroot) -# if os.path.exists(clone_path): -# shutil.rmtree(clone_path) -# logger.info("PVT log: cloning") -# clone = self._case.create_clone(clone_path, keepexe=True) -# logger.info("PVT log: cloning complete") -# -# # setup the clone case -# os.chdir(clone_path) -# self._set_active_case(clone) -# self._setup_all() -# -# -# stop_n_pveg = 1 -# with clone: -# # clone.set_value("CLM_ACCELERATED_SPINUP", "on") -# clone.set_value("STOP_N", stop_n_pveg) -# -# # Run the spin up case -# # As per SSP test: -# # "No history files expected, set suffix=None to avoid compare error" -# logger.info("PVT log: starting spin-up run") -# dout_sr = clone.get_value("DOUT_S_ROOT") -# self._skip_pnl = False -# self.run_indv(suffix=None, st_archive=True) -# -# # ------------------------------------------------------------------- -# # (2) Run FATES transient case using restart file from spin-up -# # ------------------------------------------------------------------- -# os.chdir(caseroot) -# self._set_active_case(orig_case) -# -# # logger.info("PVT log: modify user_nl_clm file for transient run") -# # self._append_to_user_nl_clm( -# # [ -# # "use_fates_potentialveg = .true.", -# # ] -# # ) -# -# -# self._case.set_value("CLM_ACCELERATED_SPINUP", "off") -# self._case.set_value("RUN_TYPE", "hybrid") -# self._case.set_value("GET_REFCASE", False) -# self._case.set_value("RUN_REFCASE", "{}.potveg".format(orig_casevar)) -# self._case.set_value("RUN_REFDATE", "1700-01-01") -# self._case.set_value("DOUT_S", False) -# self._case.flush() -# -# # do the restart run (short term archiving is off) -# self.run_indv() + added_content = ["use_fates_potentialveg = .true.","fates_harvest_mode = 'no_harvest'"] + append_to_user_nl_files(clone_path, "clm", added_content) + + # Run the spin up case + # As per SSP test: + # "No history files expected, set suffix=None to avoid compare error" + logger.info("PVT log: starting spin-up run") + dout_sr = clone.get_value("DOUT_S_ROOT") + self._skip_pnl = False + self.run_indv(suffix=None, st_archive=True) + + # ------------------------------------------------------------------- + # (2) Run FATES transient case using restart file from spin-up + # ------------------------------------------------------------------- + os.chdir(caseroot) + self._set_active_case(orig_case) + + self._case.set_value("CLM_ACCELERATED_SPINUP", "off") + self._case.set_value("RUN_TYPE", "hybrid") + self._case.set_value("GET_REFCASE", False) + self._case.set_value("RUN_REFCASE", "{}.potveg".format(orig_casevar)) + self._case.set_value("RUN_REFDATE", "1700-01-01") + self._case.set_value("DOUT_S", False) + self._case.flush() + + # do the restart run (short term archiving is off) + self.run_indv() From 10728d91c8dcaeeb0719429ba11cf857fec50f68 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 24 May 2024 18:15:04 -0600 Subject: [PATCH 129/444] add non-Cold based testmod for spinup + transient --- .../testmods_dirs/clm/FatesLUPFTAreaHarvest/include_user_mods | 1 + .../testdefs/testmods_dirs/clm/FatesLUPFTAreaHarvest/user_nl_clm | 1 + 2 files changed, 2 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesLUPFTAreaHarvest/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesLUPFTAreaHarvest/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesLUPFTAreaHarvest/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesLUPFTAreaHarvest/include_user_mods new file mode 100644 index 0000000000..1ceba4c200 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesLUPFTAreaHarvest/include_user_mods @@ -0,0 +1 @@ +../FatesLUPFT diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesLUPFTAreaHarvest/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesLUPFTAreaHarvest/user_nl_clm new file mode 100644 index 0000000000..426b41b49e --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesLUPFTAreaHarvest/user_nl_clm @@ -0,0 +1 @@ +fates_harvest_mode = 'luhdata_area' From 51d9f095ebe73eb5e1af0731cc85e36988b2b9b7 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jan 2024 13:42:59 -0700 Subject: [PATCH 130/444] Break up a long line. --- src/main/clm_driver.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 00a98e61b4..c4fa1b53f4 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -1078,7 +1078,8 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! ============================================================================ ! Update crop calendars ! ============================================================================ - call cropcal_interp(bounds_clump, filter_inactive_and_active(nc)%num_pcropp, filter_inactive_and_active(nc)%pcropp, crop_inst) + call cropcal_interp(bounds_clump, filter_inactive_and_active(nc)%num_pcropp, & + filter_inactive_and_active(nc)%pcropp, crop_inst) end if ! ============================================================================ From c763d664f23d15cc44d7afbb807359eea6cde30e Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jan 2024 13:45:32 -0700 Subject: [PATCH 131/444] use_cropcal_rx_cultivar_gdds not needed in CropPhenology(). --- src/biogeochem/CNPhenologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index fffb19bc46..bf91532e5a 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -1808,7 +1808,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & use clm_varctl , only : use_fertilizer use clm_varctl , only : use_c13, use_c14 use clm_varcon , only : c13ratio, c14ratio - use clm_varctl , only : use_cropcal_rx_swindows, use_cropcal_rx_cultivar_gdds, use_cropcal_streams + use clm_varctl , only : use_cropcal_rx_swindows, use_cropcal_streams ! ! !ARGUMENTS: integer , intent(in) :: num_pcropp ! number of prog crop patches in filter From 846f1cc0485e6f69682159d9c3a54b0cd6c8d941 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jan 2024 13:54:13 -0700 Subject: [PATCH 132/444] PlantCrop(): Be strict about PFT identification. --- src/biogeochem/CNPhenologyMod.F90 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index bf91532e5a..09515042b8 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -2679,8 +2679,7 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & if (ivt(p) == ntmp_soybean .or. ivt(p) == nirrig_tmp_soybean .or. & ivt(p) == ntrp_soybean .or. ivt(p) == nirrig_trp_soybean) then gddmaturity(p) = min(gdd1020(p), hybgdd(ivt(p))) - end if - if (ivt(p) == ntmp_corn .or. ivt(p) == nirrig_tmp_corn .or. & + else if (ivt(p) == ntmp_corn .or. ivt(p) == nirrig_tmp_corn .or. & ivt(p) == ntrp_corn .or. ivt(p) == nirrig_trp_corn .or. & ivt(p) == nsugarcane .or. ivt(p) == nirrig_sugarcane .or. & ivt(p) == nmiscanthus .or. ivt(p) == nirrig_miscanthus .or. & @@ -2689,11 +2688,13 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & if (do_plant_normal) then gddmaturity(p) = max(950._r8, min(gddmaturity(p)+150._r8, 1850._r8)) end if - end if - if (ivt(p) == nswheat .or. ivt(p) == nirrig_swheat .or. & + else if (ivt(p) == nswheat .or. ivt(p) == nirrig_swheat .or. & ivt(p) == ncotton .or. ivt(p) == nirrig_cotton .or. & ivt(p) == nrice .or. ivt(p) == nirrig_rice) then gddmaturity(p) = min(gdd020(p), hybgdd(ivt(p))) + else + write(iulog, *) 'ERROR: PlantCrop(): unrecognized ivt ',ivt(p) + call endrun(msg="Stopping") end if endif From 5b056b744e64ac59aae5cbc44c99a1b3d9815f59 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jan 2024 14:07:42 -0700 Subject: [PATCH 133/444] PlantCrop: Get gdd20 before setting gddmaturity. --- src/biogeochem/CNPhenologyMod.F90 | 36 ++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index 09515042b8..efc581cffc 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -2590,6 +2590,7 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & ! LOCAL VARAIBLES: integer s ! growing season index integer k ! grain pool index + real(r8) gdd20 ! GDD*20 value for this crop type real(r8) gdd_target ! cultivar GDD target this growing season real(r8) this_sowing_reason ! number representing sowing reason(s) logical did_rx_gdds ! did this patch use a prescribed harvest requirement? @@ -2668,6 +2669,26 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & endif endif + ! which GDD*20 variable does this crop use? + if (ivt(p) == ntmp_soybean .or. ivt(p) == nirrig_tmp_soybean .or. & + ivt(p) == ntrp_soybean .or. ivt(p) == nirrig_trp_soybean) then + gdd20 = gdd1020(p) + else if (ivt(p) == ntmp_corn .or. ivt(p) == nirrig_tmp_corn .or. & + ivt(p) == ntrp_corn .or. ivt(p) == nirrig_trp_corn .or. & + ivt(p) == nsugarcane .or. ivt(p) == nirrig_sugarcane .or. & + ivt(p) == nmiscanthus .or. ivt(p) == nirrig_miscanthus .or. & + ivt(p) == nswitchgrass .or. ivt(p) == nirrig_switchgrass) then + gdd20 = gdd820(p) + else if (ivt(p) == nswheat .or. ivt(p) == nirrig_swheat .or. & + ivt(p) == nwwheat .or. ivt(p) == nirrig_wwheat .or. & + ivt(p) == ncotton .or. ivt(p) == nirrig_cotton .or. & + ivt(p) == nrice .or. ivt(p) == nirrig_rice) then + gdd20 = gdd020(p) + else + write(iulog, *) 'ERROR: PlantCrop(): unrecognized ivt for gdd20: ',ivt(p) + call endrun(msg="Stopping") + end if + ! set GDD target did_rx_gdds = .false. if (use_cropcal_rx_cultivar_gdds .and. crop_inst%rx_cultivar_gdds_thisyr_patch(p,sowing_count(p)) .ge. 0._r8) then @@ -2677,23 +2698,22 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & gddmaturity(p) = hybgdd(ivt(p)) else if (ivt(p) == ntmp_soybean .or. ivt(p) == nirrig_tmp_soybean .or. & - ivt(p) == ntrp_soybean .or. ivt(p) == nirrig_trp_soybean) then - gddmaturity(p) = min(gdd1020(p), hybgdd(ivt(p))) + ivt(p) == ntrp_soybean .or. ivt(p) == nirrig_trp_soybean .or. & + ivt(p) == nswheat .or. ivt(p) == nirrig_swheat .or. & + ivt(p) == ncotton .or. ivt(p) == nirrig_cotton .or. & + ivt(p) == nrice .or. ivt(p) == nirrig_rice) then + gddmaturity(p) = min(gdd20, hybgdd(ivt(p))) else if (ivt(p) == ntmp_corn .or. ivt(p) == nirrig_tmp_corn .or. & ivt(p) == ntrp_corn .or. ivt(p) == nirrig_trp_corn .or. & ivt(p) == nsugarcane .or. ivt(p) == nirrig_sugarcane .or. & ivt(p) == nmiscanthus .or. ivt(p) == nirrig_miscanthus .or. & ivt(p) == nswitchgrass .or. ivt(p) == nirrig_switchgrass) then - gddmaturity(p) = max(950._r8, min(gdd820(p)*0.85_r8, hybgdd(ivt(p)))) + gddmaturity(p) = max(950._r8, min(gdd20*0.85_r8, hybgdd(ivt(p)))) if (do_plant_normal) then gddmaturity(p) = max(950._r8, min(gddmaturity(p)+150._r8, 1850._r8)) end if - else if (ivt(p) == nswheat .or. ivt(p) == nirrig_swheat .or. & - ivt(p) == ncotton .or. ivt(p) == nirrig_cotton .or. & - ivt(p) == nrice .or. ivt(p) == nirrig_rice) then - gddmaturity(p) = min(gdd020(p), hybgdd(ivt(p))) else - write(iulog, *) 'ERROR: PlantCrop(): unrecognized ivt ',ivt(p) + write(iulog, *) 'ERROR: PlantCrop(): unrecognized ivt for GDD target: ',ivt(p) call endrun(msg="Stopping") end if From 08906bb13054f32bb48e9a412beefd02bff9a3e2 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jan 2024 14:25:50 -0700 Subject: [PATCH 134/444] Correct a comment. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 0ea63f2c6d..23f00a1759 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -35,7 +35,7 @@ module cropcalStreamMod integer, allocatable :: g_to_ig(:) ! Array matching gridcell index to data index type(shr_strdata_type) :: sdat_cropcal_swindow_start ! sowing window start input data stream type(shr_strdata_type) :: sdat_cropcal_swindow_end ! sowing window end input data stream - type(shr_strdata_type) :: sdat_cropcal_cultivar_gdds ! sdate input data stream + type(shr_strdata_type) :: sdat_cropcal_cultivar_gdds ! maturity requirement input data stream character(len=CS), allocatable :: stream_varnames_sdate(:) ! used for both start and end dates character(len=CS), allocatable :: stream_varnames_cultivar_gdds(:) integer :: ncft ! Number of crop functional types (excl. generic crops) From 6ef52cdc8a980d62a596e21d9e7e57878145a5bb Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jan 2024 14:26:11 -0700 Subject: [PATCH 135/444] Remove a troubleshooting write to iulog. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 23f00a1759..75c3820e7e 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -490,7 +490,6 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, crop_inst) call ESMF_Finalize(endflag=ESMF_END_ABORT) endif end do - write(iulog,*) 'cropcal_interp(): Reading cultivar_gdds file DONE' end if ! use_cropcal_rx_cultivar_gdds deallocate(dataptr2d_cultivar_gdds) From 98f68e784fe4ab30fd559be0126cb847675b74fc Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jan 2024 14:43:16 -0700 Subject: [PATCH 136/444] Optionally adjust rx maturity reqt based on recent climate. --- bld/CLMBuildNamelist.pm | 7 ++ .../namelist_definition_ctsm.xml | 5 + src/biogeochem/CNPhenologyMod.F90 | 6 +- src/biogeochem/CropType.F90 | 2 + src/cpl/share_esmf/cropcalStreamMod.F90 | 113 +++++++++++++++++- src/main/clm_driver.F90 | 2 +- src/main/clm_initializeMod.F90 | 2 +- src/main/clm_varctl.F90 | 1 + 8 files changed, 133 insertions(+), 5 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index fb44023cd5..54752b6dbc 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4198,10 +4198,14 @@ sub setup_logic_cropcal_streams { my $swindow_start_file = $nl->get_value('stream_fldFileName_swindow_start') ; my $swindow_end_file = $nl->get_value('stream_fldFileName_swindow_end') ; my $gdd_file = $nl->get_value('stream_fldFileName_cultivar_gdds') ; + my $gdd20_baseline_file = $nl->get_value('stream_fldFileName_gdd20_baseline') ; my $mesh_file = $nl->get_value('stream_meshfile_cropcal') ; if ( ($swindow_start_file eq '' and $swindow_start_file ne '') or ($swindow_start_file ne '' and $swindow_start_file eq '') ) { $log->fatal_error("When specifying sowing window dates, you must provide both swindow_start_file and swindow_end_file. To specify exact sowing dates, use the same file." ); } + if ( $gdd_file eq '' and $gdd20_baseline_file ne '' ) { + $log->fatal_error("If not providing stream_fldFileName_cultivar_gdds, don't provide stream_fldFileName_gdd20_baseline"); + } if ( $generate_crop_gdds eq '.true.' ) { if ( $use_mxmat eq '.true.' ) { $log->fatal_error("If generate_crop_gdds is true, you must also set use_mxmat to false" ); @@ -4215,6 +4219,9 @@ sub setup_logic_cropcal_streams { if ( $gdd_file ne '' ) { $log->fatal_error("If generate_crop_gdds is true, do not specify stream_fldFileName_cultivar_gdds") } + if ( $gdd20_baseline_file ne '' ) { + $log->fatal_error("If generate_crop_gdds is true, do not specify stream_fldFileName_gdd20_baseline") + } } if ( $mesh_file eq '' and ( $swindow_start_file ne '' or $gdd_file ne '' ) ) { $log->fatal_error("If prescribing crop sowing dates and/or maturity requirements, you must specify stream_meshfile_cropcal") diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 37c457141c..c88e987756 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1808,6 +1808,11 @@ Filename of input stream data for date (day of year) of end of sowing window. Ce Filename of input stream data for cultivar growing degree-day targets + +Filename of input stream data for baseline GDD20 values + + Filename of input stream data for crop calendar inputs diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index efc581cffc..f1f2d5fcc0 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -2559,7 +2559,7 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & ! !USES: use clm_varctl , only : use_c13, use_c14 - use clm_varctl , only : use_cropcal_rx_cultivar_gdds, use_cropcal_streams + use clm_varctl , only : use_cropcal_rx_cultivar_gdds, use_cropcal_streams, adapt_cropcal_rx_cultivar_gdds use clm_varcon , only : c13ratio, c14ratio use clm_varpar , only : mxsowings use pftconMod , only : ntmp_corn, nswheat, nwwheat, ntmp_soybean @@ -2694,6 +2694,10 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & if (use_cropcal_rx_cultivar_gdds .and. crop_inst%rx_cultivar_gdds_thisyr_patch(p,sowing_count(p)) .ge. 0._r8) then gddmaturity(p) = crop_inst%rx_cultivar_gdds_thisyr_patch(p,sowing_count(p)) did_rx_gdds = .true. + if (adapt_cropcal_rx_cultivar_gdds) then + gddmaturity(p) = gddmaturity(p) * gdd20 / crop_inst%gdd20_baseline_patch(p) + !TODO SSR: Set maximum gddmaturity + end if else if (ivt(p) == nwwheat .or. ivt(p) == nirrig_wwheat) then gddmaturity(p) = hybgdd(ivt(p)) else diff --git a/src/biogeochem/CropType.F90 b/src/biogeochem/CropType.F90 index 760aa21b76..a7bccf1a73 100644 --- a/src/biogeochem/CropType.F90 +++ b/src/biogeochem/CropType.F90 @@ -52,6 +52,7 @@ module CropType integer , pointer :: rx_swindow_starts_thisyr_patch(:,:) ! all prescribed sowing window start dates for this patch this year (day of year) [patch, mxsowings] integer , pointer :: rx_swindow_ends_thisyr_patch (:,:) ! all prescribed sowing window end dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: rx_cultivar_gdds_thisyr_patch (:,:) ! all cultivar GDD targets for this patch this year (ddays) [patch, mxsowings] + real(r8), pointer :: gdd20_baseline_patch (:) ! GDD20 baseline for this patch (ddays) [patch] real(r8), pointer :: sdates_thisyr_patch (:,:) ! all actual sowing dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: swindow_starts_thisyr_patch(:,:) ! all sowing window start dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: swindow_ends_thisyr_patch (:,:) ! all sowing window end dates for this patch this year (day of year) [patch, mxsowings] @@ -235,6 +236,7 @@ subroutine InitAllocate(this, bounds) allocate(this%rx_swindow_starts_thisyr_patch(begp:endp,1:mxsowings)); this%rx_swindow_starts_thisyr_patch(:,:) = -1 allocate(this%rx_swindow_ends_thisyr_patch(begp:endp,1:mxsowings)) ; this%rx_swindow_ends_thisyr_patch (:,:) = -1 allocate(this%rx_cultivar_gdds_thisyr_patch(begp:endp,1:mxsowings)) ; this%rx_cultivar_gdds_thisyr_patch(:,:) = spval + allocate(this%gdd20_baseline_patch(begp:endp)) ; this%gdd20_baseline_patch(:) = spval allocate(this%sdates_thisyr_patch(begp:endp,1:mxsowings)) ; this%sdates_thisyr_patch(:,:) = spval allocate(this%swindow_starts_thisyr_patch(begp:endp,1:mxsowings)) ; this%swindow_starts_thisyr_patch(:,:) = spval allocate(this%swindow_ends_thisyr_patch (begp:endp,1:mxsowings)) ; this%swindow_ends_thisyr_patch (:,:) = spval diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 75c3820e7e..83f7fc0eb0 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -15,6 +15,7 @@ module cropcalStreamMod use abortutils , only : endrun use clm_varctl , only : iulog use clm_varctl , only : use_cropcal_rx_swindows, use_cropcal_rx_cultivar_gdds, use_cropcal_streams + use clm_varctl , only : adapt_cropcal_rx_cultivar_gdds use clm_varpar , only : mxpft use clm_varpar , only : mxsowings use perf_mod , only : t_startf, t_stopf @@ -36,13 +37,16 @@ module cropcalStreamMod type(shr_strdata_type) :: sdat_cropcal_swindow_start ! sowing window start input data stream type(shr_strdata_type) :: sdat_cropcal_swindow_end ! sowing window end input data stream type(shr_strdata_type) :: sdat_cropcal_cultivar_gdds ! maturity requirement input data stream + type(shr_strdata_type) :: sdat_cropcal_gdd20_baseline ! GDD20 baseline input data stream character(len=CS), allocatable :: stream_varnames_sdate(:) ! used for both start and end dates character(len=CS), allocatable :: stream_varnames_cultivar_gdds(:) + character(len=CS), allocatable :: stream_varnames_gdd20_baseline(:) integer :: ncft ! Number of crop functional types (excl. generic crops) logical :: allow_invalid_swindow_inputs ! Fall back on paramfile sowing windows in cases of invalid values in stream_fldFileName_swindow_start and _end? character(len=CL) :: stream_fldFileName_swindow_start ! sowing window start stream filename to read character(len=CL) :: stream_fldFileName_swindow_end ! sowing window end stream filename to read character(len=CL) :: stream_fldFileName_cultivar_gdds ! cultivar growing degree-days stream filename to read + character(len=CL) :: stream_fldFileName_gdd20_baseline ! GDD20 baseline stream filename to read character(len=*), parameter :: sourcefile = & __FILE__ @@ -90,6 +94,7 @@ subroutine cropcal_init(bounds) stream_fldFileName_swindow_start, & stream_fldFileName_swindow_end, & stream_fldFileName_cultivar_gdds, & + stream_fldFileName_gdd20_baseline, & stream_meshfile_cropcal ! Default values for namelist @@ -101,14 +106,17 @@ subroutine cropcal_init(bounds) stream_fldFileName_swindow_start = '' stream_fldFileName_swindow_end = '' stream_fldFileName_cultivar_gdds = '' + stream_fldFileName_gdd20_baseline = '' ! Will need modification to work with mxsowings > 1 ncft = mxpft - npcropmin + 1 ! Ignores generic crops allocate(stream_varnames_sdate(ncft)) allocate(stream_varnames_cultivar_gdds(ncft)) + allocate(stream_varnames_gdd20_baseline(ncft)) do n = 1,ncft ivt = npcropmin + n - 1 write(stream_varnames_sdate(n),'(a,i0)') "sdate1_",ivt write(stream_varnames_cultivar_gdds(n),'(a,i0)') "gdd1_",ivt + write(stream_varnames_gdd20_baseline(n),'(a,i0)') "gdd20bl_",ivt end do ! Read cropcal_streams namelist @@ -132,6 +140,7 @@ subroutine cropcal_init(bounds) call shr_mpi_bcast(stream_fldFileName_swindow_start, mpicom) call shr_mpi_bcast(stream_fldFileName_swindow_end , mpicom) call shr_mpi_bcast(stream_fldFileName_cultivar_gdds, mpicom) + call shr_mpi_bcast(stream_fldFileName_gdd20_baseline, mpicom) call shr_mpi_bcast(stream_meshfile_cropcal , mpicom) if (masterproc) then @@ -144,10 +153,12 @@ subroutine cropcal_init(bounds) write(iulog,'(a,a)' ) ' stream_fldFileName_swindow_start = ',trim(stream_fldFileName_swindow_start) write(iulog,'(a,a)' ) ' stream_fldFileName_swindow_end = ',trim(stream_fldFileName_swindow_end) write(iulog,'(a,a)' ) ' stream_fldFileName_cultivar_gdds = ',trim(stream_fldFileName_cultivar_gdds) + write(iulog,'(a,a)' ) ' stream_fldFileName_gdd20_baseline = ',trim(stream_fldFileName_gdd20_baseline) write(iulog,'(a,a)' ) ' stream_meshfile_cropcal = ',trim(stream_meshfile_cropcal) do n = 1,ncft write(iulog,'(a,a)' ) ' stream_varnames_sdate = ',trim(stream_varnames_sdate(n)) write(iulog,'(a,a)' ) ' stream_varnames_cultivar_gdds = ',trim(stream_varnames_cultivar_gdds(n)) + write(iulog,'(a,a)' ) ' stream_varnames_gdd20_baseline = ',trim(stream_varnames_gdd20_baseline(n)) end do write(iulog,*) endif @@ -155,6 +166,7 @@ subroutine cropcal_init(bounds) ! CLMBuildNamelist checks that both start and end files are provided if either is use_cropcal_rx_swindows = stream_fldFileName_swindow_start /= '' use_cropcal_rx_cultivar_gdds = stream_fldFileName_cultivar_gdds /= '' + adapt_cropcal_rx_cultivar_gdds = stream_fldFileName_gdd20_baseline /= '' use_cropcal_streams = use_cropcal_rx_swindows .or. use_cropcal_rx_cultivar_gdds if (use_cropcal_rx_swindows) then @@ -242,6 +254,36 @@ subroutine cropcal_init(bounds) end if end if + ! Initialize the cdeps data type sdat_cropcal_gdd20_baseline + ! NOTE: stream_dtlimit 1.5 didn't work for some reason + !TODO SSR: Do not allow time axis length > 1 + if (adapt_cropcal_rx_cultivar_gdds) then + call shr_strdata_init_from_inline(sdat_cropcal_gdd20_baseline, & + my_task = iam, & + logunit = iulog, & + compname = 'LND', & + model_clock = model_clock, & + model_mesh = mesh, & + stream_meshfile = trim(stream_meshfile_cropcal), & + stream_lev_dimname = 'null', & + stream_mapalgo = 'bilinear', & + stream_filenames = (/trim(stream_fldFileName_gdd20_baseline)/), & + stream_fldlistFile = stream_varnames_gdd20_baseline, & + stream_fldListModel = stream_varnames_gdd20_baseline, & + stream_yearFirst = 2000, & + stream_yearLast = 2000, & + stream_yearAlign = 2000, & + stream_offset = cropcal_offset, & + stream_taxmode = 'extend', & + stream_dtlimit = 1.0e30_r8, & + stream_tintalgo = cropcal_tintalgo, & + stream_name = 'GDD20 baseline data', & + rc = rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + end if + end subroutine cropcal_init !================================================================ @@ -285,6 +327,8 @@ subroutine cropcal_advance( bounds ) end if end if + ! GDD20 baseline values do not have an associated time axis and thus will not be advanced here + if ( .not. allocated(g_to_ig) )then allocate (g_to_ig(bounds%begg:bounds%endg) ) ig = 0 @@ -298,7 +342,7 @@ end subroutine cropcal_advance !================================================================ - subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, crop_inst) + subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! ! Interpolate data stream information for crop calendars. ! @@ -314,6 +358,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, crop_inst) type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_pcropp ! number of prog. crop patches in filter integer , intent(in) :: filter_pcropp(:) ! filter for prognostic crop patches + logical , intent(in) :: init ! is this being called as initialization? type(crop_type) , intent(inout) :: crop_inst ! ! !LOCAL VARIABLES: @@ -327,9 +372,11 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, crop_inst) real(r8), pointer :: dataptr1d_swindow_start(:) real(r8), pointer :: dataptr1d_swindow_end (:) real(r8), pointer :: dataptr1d_cultivar_gdds(:) + real(r8), pointer :: dataptr1d_gdd20_baseline(:) real(r8), pointer :: dataptr2d_swindow_start(:,:) real(r8), pointer :: dataptr2d_swindow_end (:,:) real(r8), pointer :: dataptr2d_cultivar_gdds(:,:) + real(r8), pointer :: dataptr2d_gdd20_baseline(:,:) !----------------------------------------------------------------------- associate( & @@ -345,7 +392,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, crop_inst) lsize = bounds%endg - bounds%begg + 1 begp = bounds%begp - endp= bounds%endp + endp = bounds%endp dayspyr = get_curr_days_per_year() @@ -494,6 +541,68 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, crop_inst) deallocate(dataptr2d_cultivar_gdds) + allocate(dataptr2d_gdd20_baseline(lsize, ncft)) + if (adapt_cropcal_rx_cultivar_gdds .and. init) then + ! Read GDD20 baselines from input files + ! Starting with npcropmin will skip generic crops + do n = 1, ncft + call dshr_fldbun_getFldPtr(sdat_cropcal_gdd20_baseline%pstrm(1)%fldbun_model, trim(stream_varnames_gdd20_baseline(n)), & + fldptr1=dataptr1d_gdd20_baseline, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize + ! So an explicit loop is required here + do g = 1,lsize + + ! Ensure valid values + if (dataptr1d_gdd20_baseline(g) < 0 .or. dataptr1d_gdd20_baseline(g) > 1000000._r8) then + write(iulog, *) 'ERROR: invalid read-in gdd20_baseline value: ',dataptr1d_gdd20_baseline(g) + call ESMF_Finalize(endflag=ESMF_END_ABORT) + else if (dataptr1d_gdd20_baseline(g) == 0) then + write(iulog, *) 'ERROR: read-in gdd20_baseline value 0 will cause inf' + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + dataptr2d_gdd20_baseline(g,n) = dataptr1d_gdd20_baseline(g) + end do + end do + + ! Set gdd20_baseline_patch for each gridcell/patch combination + do fp = 1, num_pcropp + p = filter_pcropp(fp) + + ivt = patch%itype(p) + ! Will skip generic crops + if (ivt >= npcropmin) then + n = ivt - npcropmin + 1 + + if (n > ncft) then + write(iulog,'(a,i0,a,i0,a)') 'n (',n,') > ncft (',ncft,')' + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! vegetated pft + ig = g_to_ig(patch%gridcell(p)) + + if (ig > lsize) then + write(iulog,'(a,i0,a,i0,a)') 'ig (',ig,') > lsize (',lsize,')' + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + crop_inst%gdd20_baseline_patch(p) = dataptr2d_gdd20_baseline(ig,n) + + else + write(iulog,'(a,i0)') 'cropcal_interp(), rx_gdd20_baseline: Crop patch has ivt ',ivt + call ESMF_Finalize(endflag=ESMF_END_ABORT) + endif + end do + end if ! adapt_cropcal_rx_cultivar_gdds + + deallocate(dataptr2d_gdd20_baseline) + + end associate end subroutine cropcal_interp diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index c4fa1b53f4..2a3cef4b8b 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -1079,7 +1079,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! Update crop calendars ! ============================================================================ call cropcal_interp(bounds_clump, filter_inactive_and_active(nc)%num_pcropp, & - filter_inactive_and_active(nc)%pcropp, crop_inst) + filter_inactive_and_active(nc)%pcropp, .false., crop_inst) end if ! ============================================================================ diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 9bf0cc59a2..e8f70bdef8 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -667,7 +667,7 @@ subroutine initialize2(ni,nj) do nc = 1,nclumps call get_clump_bounds(nc, bounds_clump) call cropcal_interp(bounds_clump, filter_inactive_and_active(nc)%num_pcropp, & - filter_inactive_and_active(nc)%pcropp, crop_inst) + filter_inactive_and_active(nc)%pcropp, .true., crop_inst) end do !$OMP END PARALLEL DO end if diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 7d0b2b55ad..fe67380fd2 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -391,6 +391,7 @@ module clm_varctl logical, public :: use_cropcal_streams = .false. logical, public :: use_cropcal_rx_swindows = .false. logical, public :: use_cropcal_rx_cultivar_gdds = .false. + logical, public :: adapt_cropcal_rx_cultivar_gdds = .false. !---------------------------------------------------------- ! biomass heat storage switch From b73bcfdd104d8d591afb41ef6d6c18398cf8ef69 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 23 May 2024 15:09:16 -0600 Subject: [PATCH 137/444] =?UTF-8?q?Don't=20adapt=20rx=20cultivar=20gdd=20r?= =?UTF-8?q?eqts=20if=20baseline=20gdd20=20is=20=E2=89=A40.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/biogeochem/CNPhenologyMod.F90 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index f1f2d5fcc0..cfeee0b867 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -143,6 +143,9 @@ module CNPhenologyMod logical, public :: generate_crop_gdds = .false. ! If true, harvest the day before next sowing logical, public :: use_mxmat = .true. ! If true, ignore crop maximum growing season length + ! For use with adapt_cropcal_rx_cultivar_gdds .true. + real(r8), parameter :: min_gdd20_baseline = 0._r8 ! If gdd20_baseline_patch is ≤ this, do not consider baseline. + ! Constants for seasonal decidious leaf onset and offset logical, private :: onset_thresh_depends_on_veg = .false. ! If onset threshold depends on vegetation type integer, public, parameter :: critical_daylight_constant = 1 @@ -2694,9 +2697,9 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & if (use_cropcal_rx_cultivar_gdds .and. crop_inst%rx_cultivar_gdds_thisyr_patch(p,sowing_count(p)) .ge. 0._r8) then gddmaturity(p) = crop_inst%rx_cultivar_gdds_thisyr_patch(p,sowing_count(p)) did_rx_gdds = .true. - if (adapt_cropcal_rx_cultivar_gdds) then + if (adapt_cropcal_rx_cultivar_gdds .and. crop_inst%gdd20_baseline_patch(p) > min_gdd20_baseline) then gddmaturity(p) = gddmaturity(p) * gdd20 / crop_inst%gdd20_baseline_patch(p) - !TODO SSR: Set maximum gddmaturity + !TODO SSR: Set maximum and minimum gddmaturity end if else if (ivt(p) == nwwheat .or. ivt(p) == nirrig_wwheat) then gddmaturity(p) = hybgdd(ivt(p)) From 20f32c1d70d709a96416c70a1d143d142b52fecf Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 24 May 2024 12:45:18 -0600 Subject: [PATCH 138/444] Ignore 'invalid' values in stream_fldFileName_gdd20_baseline on read. They're being handled in PlantCrop() instead. (cherry picked from commit 045b3d72c54319769e50500b2bd445215e07446d) --- src/cpl/share_esmf/cropcalStreamMod.F90 | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 83f7fc0eb0..f60ab51000 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -555,16 +555,6 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize ! So an explicit loop is required here do g = 1,lsize - - ! Ensure valid values - if (dataptr1d_gdd20_baseline(g) < 0 .or. dataptr1d_gdd20_baseline(g) > 1000000._r8) then - write(iulog, *) 'ERROR: invalid read-in gdd20_baseline value: ',dataptr1d_gdd20_baseline(g) - call ESMF_Finalize(endflag=ESMF_END_ABORT) - else if (dataptr1d_gdd20_baseline(g) == 0) then - write(iulog, *) 'ERROR: read-in gdd20_baseline value 0 will cause inf' - call ESMF_Finalize(endflag=ESMF_END_ABORT) - end if - dataptr2d_gdd20_baseline(g,n) = dataptr1d_gdd20_baseline(g) end do end do From a7cd0573ddfdef805f97c1f9aba3083492515ca3 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 24 May 2024 14:05:36 -0600 Subject: [PATCH 139/444] Add generate_gdd20_baseline tool. (cherry picked from commit 3ae50b7402fb1e3580f11ba09883e9ddaa563fda) --- .../crop_calendars/generate_gdd20_baseline.py | 243 ++++++++++++++++++ tools/crop_calendars/generate_gdd20_baseline | 19 ++ 2 files changed, 262 insertions(+) create mode 100644 python/ctsm/crop_calendars/generate_gdd20_baseline.py create mode 100755 tools/crop_calendars/generate_gdd20_baseline diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py new file mode 100644 index 0000000000..d5cbd779e0 --- /dev/null +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -0,0 +1,243 @@ +""" +Generate stream_fldFileName_gdd20_baseline file from CTSM outputs +""" + +import sys +import argparse +import os +import datetime as dt +import numpy as np +import xarray as xr +import cftime + +# -- add python/ctsm to path (needed if we want to run generate_gdd20_baseline stand-alone) +_CTSM_PYTHON = os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir) +sys.path.insert(1, _CTSM_PYTHON) + +# pylint: disable=wrong-import-position +from ctsm.crop_calendars.import_ds import import_ds +import ctsm.crop_calendars.cropcal_utils as utils + +VAR_LIST_IN = ["GDD0", "GDD8", "GDD10"] +VAR_LIST_IN = [x + "20" for x in VAR_LIST_IN] # TODO: Delete this once using the right variables +MISSING_FILL = -1 # Something negative to ensure that gddmaturity never changes (see PlantCrop) +STREAM_YEAR = 2000 # The year specified for stream_yearFirst and stream_yearLast in the call of + # shr_strdata_init_from_inline() for sdat_cropcal_gdd20_baseline + + +def _parse_args(): + """ + Set up and parse input arguments + """ + parser = argparse.ArgumentParser( + description=( + "Given a list of CTSM history files, generate stream_fldFileName_gdd20_baseline input" + + "file from the GDD0, GDD8, and GDD10 variables." + ) + ) + + # Required + parser.add_argument( + "-i", + "--input-files", + help="Space-separated string of CTSM history files", + type=str, + required=True, + ) + parser.add_argument( + "-o", + "--output-file", + help="Path to which output file should be saved", + type=str, + required=True, + ) + parser.add_argument( + "-a", + "--author", + help=( + "String to be saved in author attribute of output files." + + "E.g., 'Author Name (authorname@ucar.edu)'" + ), + type=str, + required=True, + ) + + # Optional + parser.add_argument( + "--overwrite", + help="Overwrite existing output file, if any", + action="store_true", + ) + + # Get arguments + args = parser.parse_args(sys.argv[1:]) + + # Check arguments + if os.path.exists(args.output_file) and not args.overwrite: + raise FileExistsError("Output file exists but --overwrite is not specified") + + return args + + +def _get_cft_list(crop_list): + """ + Given a list of strings, return a list of CFT names that contain any of those strings. + Will include both irrigated and rainfed! + + Args: + crop_list (list): List of crops to look for. + E.g.: ["corn", "cotton"] + + Returns: + cft_str_list: List of CFTs containing any of the crop names in crop_list. + E.g.: ["tropical_corn", "irrigated_tropical_corn", + "temperate_corn", "irrigated_temperate_corn", + "cotton", "irrigated_cotton"] + """ + + mgdcrop_list = utils.define_mgdcrop_list() + cft_str_list = [] + for crop_str in crop_list: + cft_str_list += [x for x in mgdcrop_list if crop_str in x] + return cft_str_list + + +def _get_gddn_for_cft(cft_str): + """ + Given a CFT name, return the GDDN variable it uses. + + Args: + cft_str (str): E.g., "irrigated_temperate_corn" + + Returns: + str or None: Name of variable to use (e.g., "GDD8"). If crop isn't yet handled, return None. + """ + + gddn = None + + gdd0_list_str = ["wheat", "cotton", "rice"] + if cft_str in _get_cft_list(gdd0_list_str): + gddn = "GDD0" + + gdd8_list_str = ["corn", "sugarcane", "miscanthus", "switchgrass"] + if cft_str in _get_cft_list(gdd8_list_str): + gddn = "GDD8" + + gdd10_list_str = ["soybean"] + if cft_str in _get_cft_list(gdd10_list_str): + gddn = "GDD10" + + # TODO: Delete this once using the right variables + if gddn is not None: + gddn += "20" + + return gddn + + +def _get_output_varname(cft_str): + cft_int = utils.vegtype_str2int(cft_str)[0] + return f"gdd20bl_{cft_int}" + + +def _add_time_axis(da_in): + """ + Adds a size-1 time axis to a DataArray. Needed because CDEPS streams code requires a time axis, + even if the data in question is not supposed to vary over time. + + Args: + da_in (DataArray): xarray DataArray which needs a time axis added + + Returns: + DataArray: da_in with a new 1-step time axis + """ + this_date = np.array(cftime.DatetimeNoLeap(STREAM_YEAR, 1, 1, 0, 0, 0, 0, has_year_zero=True)) + this_date = np.expand_dims(this_date, axis=0) + da_time = xr.DataArray( + data=this_date, + dims={"time": this_date}, + ) + da_out = da_in.expand_dims(time=da_time) + return da_out + + +def generate_gdd20_baseline(input_files, output_file, author): + """ + Generate stream_fldFileName_gdd20_baseline file from CTSM outputs + """ + + # Get input file list + input_files = input_files.split(sep=" ") + # Get unique values and sort + input_files = list(set(input_files)) + input_files.sort() + + # Import history files and ensure they have lat/lon dims + ds_in = import_ds(input_files, VAR_LIST_IN) + if not all(x in ds_in.dims for x in ["lat", "lon"]): + raise RuntimeError("Input files must have lat and lon dimensions") + + # If needed, find mean over time + if "time" in ds_in.dims: + ds_in = ds_in.mean(dim="time", skipna=True) + + # Set up a dummy DataArray to use for crops without an assigned GDDN variable + dummy_da = xr.DataArray( + data=MISSING_FILL * np.ones_like(ds_in[VAR_LIST_IN[0]].values), + dims=ds_in[VAR_LIST_IN[0]].dims, + coords=ds_in[VAR_LIST_IN[0]].coords, + ) + dummy_da = _add_time_axis(dummy_da) + + # Process all crops + ds_out = xr.Dataset( + data_vars=None, + attrs={ + "author": author, + "created": dt.datetime.now().astimezone().isoformat(), + }, + ) + for cft_str in utils.define_mgdcrop_list(): + cft_int = utils.vegtype_str2int(cft_str)[0] + print(f"{cft_str} ({cft_int})") + + # Which GDDN history variable does this crop use? E.g., GDD0, GDD10 + gddn = _get_gddn_for_cft(cft_str) + + # Fill any missing values with MISSING_FILL. This will mean that gddmaturity in these cells + # never changes. + if gddn is None: + # Crop not handled yet? Fill it entirely with missing value + this_da = dummy_da + long_name = "Dummy GDD20" + print(" dummy GDD20") + else: + this_da = ds_in[gddn].fillna(MISSING_FILL) + this_da = _add_time_axis(this_da) + long_name = gddn + print(f" {gddn}") + + # Add attributes + this_da.attrs["long_name"] = long_name + f" baseline for {cft_str}" + this_da.attrs["units"] = "°C days" + + # Copy that to ds_out + var_out = _get_output_varname(cft_str) + print(f" Output variable {var_out}") + ds_out[var_out] = this_da + + # Save + ds_out.to_netcdf(output_file) + + print("Done!") + + +def main(): + """ + main() function for calling generate_gdd20_baseline.py from command line. + """ + args = _parse_args() + generate_gdd20_baseline( + args.input_files, + args.output_file, + args.author, + ) diff --git a/tools/crop_calendars/generate_gdd20_baseline b/tools/crop_calendars/generate_gdd20_baseline new file mode 100755 index 0000000000..a0238c8d0f --- /dev/null +++ b/tools/crop_calendars/generate_gdd20_baseline @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +""" +For description and instructions, please see README. +""" + +import os +import sys + +_CTSM_PYTHON = os.path.join(os.path.dirname(os.path.realpath(__file__)), + os.pardir, + os.pardir, + 'python') +sys.path.insert(1, _CTSM_PYTHON) + +from ctsm.crop_calendars.generate_gdd20_baseline import main + +if __name__ == "__main__": + main() + From fd5f177131d63d39e79a13918390bdfb642d781e Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Tue, 28 May 2024 11:27:09 -0600 Subject: [PATCH 140/444] Format generate_gdd20_baseline.py with black. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index d5cbd779e0..d28bfda0e7 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -22,7 +22,7 @@ VAR_LIST_IN = [x + "20" for x in VAR_LIST_IN] # TODO: Delete this once using the right variables MISSING_FILL = -1 # Something negative to ensure that gddmaturity never changes (see PlantCrop) STREAM_YEAR = 2000 # The year specified for stream_yearFirst and stream_yearLast in the call of - # shr_strdata_init_from_inline() for sdat_cropcal_gdd20_baseline +# shr_strdata_init_from_inline() for sdat_cropcal_gdd20_baseline def _parse_args(): From 5eafae73aeeaec3950123a955d9c781d3840e157 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Tue, 28 May 2024 11:28:14 -0600 Subject: [PATCH 141/444] Add previous commit to .git-blame-ignore-revs. --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index e769d3187c..2620839223 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -26,6 +26,7 @@ d866510188d26d51bcd6d37239283db690af7e82 0dcd0a3c1abcaffe5529f8d79a6bc34734b195c7 e096358c832ab292ddfd22dd5878826c7c788968 475831f0fb0e31e97f630eac4e078c886558b61c +fd5f177131d63d39e79a13918390bdfb642d781e # Ran SystemTests and python/ctsm through black python formatter 5364ad66eaceb55dde2d3d598fe4ce37ac83a93c 8056ae649c1b37f5e10aaaac79005d6e3a8b2380 From 38d6888fd04cef4f2d507df99e9c4d1a3a16c4ac Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 May 2024 07:50:21 -0600 Subject: [PATCH 142/444] Add testmods RxCropCals, RxCropCalsAdapt. --- .../testmods_dirs/clm/RxCropCals/include_user_mods | 1 + .../testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm | 8 ++++++++ .../testmods_dirs/clm/RxCropCalsAdapt/include_user_mods | 1 + .../testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm | 3 +++ 4 files changed, 13 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCals/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCals/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/RxCropCals/include_user_mods new file mode 100644 index 0000000000..23ea3745e6 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCals/include_user_mods @@ -0,0 +1 @@ +../crop diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm new file mode 100644 index 0000000000..9cbfea97f0 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm @@ -0,0 +1,8 @@ + +! Sowing windows +stream_fldFileName_swindow_start = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc' +stream_fldFileName_swindow_end = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc' +stream_fldFileName_cultivar_gdds = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc' +stream_year_first_cropcal = 2000 +stream_year_last_cropcal = 2000 +stream_meshfile_cropcal = '$DIN_LOC_ROOT/share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc' diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods new file mode 100644 index 0000000000..88c9694365 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods @@ -0,0 +1 @@ +../RxCropCals diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm new file mode 100644 index 0000000000..1bba9d2a89 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm @@ -0,0 +1,3 @@ + +! Eventually replace this with half-degree version in the proper place +stream_fldFileName_gdd20_baseline = '/glade/u/home/samrabin/ctsm_scale-mat-reqs/tools/crop_calendars/test.nc' From 0537a6a32d586e62c237b6e2a6d645b7895bf76a Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 29 May 2024 11:23:15 -0600 Subject: [PATCH 143/444] add potential veg check to avoid accessing timeseries file --- src/dyn_subgrid/dynFATESLandUseChangeMod.F90 | 88 ++++++++++---------- src/dyn_subgrid/dynSubgridDriverMod.F90 | 4 +- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 index f330ee2b78..d7c1063494 100644 --- a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 +++ b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 @@ -107,6 +107,7 @@ subroutine dynFatesLandUseInit(bounds, landuse_filename) ! !USES: use clm_varctl , only : use_cn, use_fates_luh, fates_harvest_mode + use clm_varctl , only : use_fates_potentialveg use dynVarTimeUninterpMod , only : dyn_var_time_uninterp_type use dynTimeInfoMod , only : YEAR_POSITION_START_OF_TIMESTEP use dynTimeInfoMod , only : YEAR_POSITION_END_OF_TIMESTEP @@ -148,55 +149,58 @@ subroutine dynFatesLandUseInit(bounds, landuse_filename) landuse_transitions = 0._r8 landuse_harvest = 0._r8 - if (use_fates_luh) then + ! Avoid initializing the landuse timeseries file if in fates potential vegetation mode + if (.not. use_fates_potentialveg) then + if (use_fates_luh) then - ! Generate the dyn_file_type object. - ! Start calls get_prev_date, whereas end calls get_curr_date - dynFatesLandUse_file = dyn_file_type(landuse_filename, YEAR_POSITION_END_OF_TIMESTEP) + ! Generate the dyn_file_type object. + ! Start calls get_prev_date, whereas end calls get_curr_date + dynFatesLandUse_file = dyn_file_type(landuse_filename, YEAR_POSITION_END_OF_TIMESTEP) - ! Get initial land use data from the fates luh2 timeseries dataset - num_points = (bounds%endg - bounds%begg + 1) - landuse_shape(1) = num_points ! Does this need an explicit array shape to be passed to the constructor? - do varnum = 1, num_landuse_transition_vars - landuse_transition_vars(varnum) = dyn_var_time_uninterp_type( & - dyn_file=dynFatesLandUse_file, varname=landuse_transition_varnames(varnum), & - dim1name=grlnd, conversion_factor=1.0_r8, & - do_check_sums_equal_1=.false., data_shape=landuse_shape) - end do - do varnum = 1, num_landuse_state_vars - landuse_state_vars(varnum) = dyn_var_time_uninterp_type( & - dyn_file=dynFatesLandUse_file, varname=landuse_state_varnames(varnum), & - dim1name=grlnd, conversion_factor=1.0_r8, & - do_check_sums_equal_1=.false., data_shape=landuse_shape) - end do - - ! Get the harvest rate data from the fates luh2 timeseries dataset if enabled - if (trim(fates_harvest_mode) .eq. fates_harvest_luh_area .or. & - trim(fates_harvest_mode) .eq. fates_harvest_luh_mass) then - - ! change the harvest varnames being used depending on the mode selected - if (trim(fates_harvest_mode) .eq. fates_harvest_luh_area ) then - landuse_harvest_varnames => landuse_harvest_area_varnames - landuse_harvest_units = landuse_harvest_area_units - elseif (trim(fates_harvest_mode) .eq. fates_harvest_luh_mass ) then - landuse_harvest_varnames => landuse_harvest_mass_varnames - landuse_harvest_units = landuse_harvest_mass_units - else - call endrun(msg=' undefined fates harvest mode selected'//errMsg(__FILE__, __LINE__)) - end if - - do varnum = 1, num_landuse_harvest_vars - landuse_harvest_vars(varnum) = dyn_var_time_uninterp_type( & - dyn_file=dynFatesLandUse_file, varname=landuse_harvest_varnames(varnum), & + ! Get initial land use data from the fates luh2 timeseries dataset + num_points = (bounds%endg - bounds%begg + 1) + landuse_shape(1) = num_points ! Does this need an explicit array shape to be passed to the constructor? + do varnum = 1, num_landuse_transition_vars + landuse_transition_vars(varnum) = dyn_var_time_uninterp_type( & + dyn_file=dynFatesLandUse_file, varname=landuse_transition_varnames(varnum), & + dim1name=grlnd, conversion_factor=1.0_r8, & + do_check_sums_equal_1=.false., data_shape=landuse_shape) + end do + do varnum = 1, num_landuse_state_vars + landuse_state_vars(varnum) = dyn_var_time_uninterp_type( & + dyn_file=dynFatesLandUse_file, varname=landuse_state_varnames(varnum), & dim1name=grlnd, conversion_factor=1.0_r8, & do_check_sums_equal_1=.false., data_shape=landuse_shape) end do + + ! Get the harvest rate data from the fates luh2 timeseries dataset if enabled + if (trim(fates_harvest_mode) .eq. fates_harvest_luh_area .or. & + trim(fates_harvest_mode) .eq. fates_harvest_luh_mass) then + + ! change the harvest varnames being used depending on the mode selected + if (trim(fates_harvest_mode) .eq. fates_harvest_luh_area ) then + landuse_harvest_varnames => landuse_harvest_area_varnames + landuse_harvest_units = landuse_harvest_area_units + elseif (trim(fates_harvest_mode) .eq. fates_harvest_luh_mass ) then + landuse_harvest_varnames => landuse_harvest_mass_varnames + landuse_harvest_units = landuse_harvest_mass_units + else + call endrun(msg=' undefined fates harvest mode selected'//errMsg(__FILE__, __LINE__)) + end if + + do varnum = 1, num_landuse_harvest_vars + landuse_harvest_vars(varnum) = dyn_var_time_uninterp_type( & + dyn_file=dynFatesLandUse_file, varname=landuse_harvest_varnames(varnum), & + dim1name=grlnd, conversion_factor=1.0_r8, & + do_check_sums_equal_1=.false., data_shape=landuse_shape) + end do + end if end if - end if - ! Since fates needs state data during initialization, make sure to call - ! the interpolation routine at the start - call dynFatesLandUseInterp(bounds,init_state=.true.) + ! Since fates needs state data during initialization, make sure to call + ! the interpolation routine at the start + call dynFatesLandUseInterp(bounds,init_state=.true.) + end if end subroutine dynFatesLandUseInit diff --git a/src/dyn_subgrid/dynSubgridDriverMod.F90 b/src/dyn_subgrid/dynSubgridDriverMod.F90 index faef029b40..ea1210521d 100644 --- a/src/dyn_subgrid/dynSubgridDriverMod.F90 +++ b/src/dyn_subgrid/dynSubgridDriverMod.F90 @@ -206,7 +206,7 @@ subroutine dynSubgrid_driver(bounds_proc, ! OUTSIDE any loops over clumps in the driver. ! ! !USES: - use clm_varctl , only : use_cn, use_fates, use_fates_luh + use clm_varctl , only : use_cn, use_fates, use_fates_luh, use_fates_potentialveg use dynInitColumnsMod , only : initialize_new_columns use dynConsBiogeophysMod , only : dyn_hwcontent_init, dyn_hwcontent_final use dynEDMod , only : dyn_ED @@ -295,7 +295,7 @@ subroutine dynSubgrid_driver(bounds_proc, call dynurban_interp(bounds_proc) end if - if (use_fates_luh) then + if (use_fates_luh .and. .not. use_fates_potentialveg) then call dynFatesLandUseInterp(bounds_proc) end if From 317f77d7b692a58644e679d48c8f4ec026c8a697 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 May 2024 11:30:54 -0600 Subject: [PATCH 144/444] Add cropcals_rx namelist boolean. --- bld/namelist_files/namelist_defaults_ctsm.xml | 15 +++++++++++---- bld/namelist_files/namelist_definition_ctsm.xml | 9 +++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 655e97c47c..08f67a2712 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1686,10 +1686,17 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c nn nn - -1850 -2100 -1850 + +.false. +2000 +2000 +2000 + + +lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc +lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc +lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc +share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index c88e987756..366b7498e8 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1773,14 +1773,19 @@ Mapping method from LAI input file to the model resolution + +Flag to enable prescribed crop calendars (sowing window dates and maturity requirement) + + -First year to loop over for crop calendar data +First year to loop over for crop calendar data (not including gdd20_baseline file) -Last year to loop over for crop calendar data +Last year to loop over for crop calendar data (not including gdd20_baseline file) Date: Wed, 29 May 2024 11:38:29 -0600 Subject: [PATCH 145/444] CLMBuildNamelist: Fix logic and message for check of sowing window start/end files. --- bld/CLMBuildNamelist.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 54752b6dbc..9753549db1 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4200,8 +4200,8 @@ sub setup_logic_cropcal_streams { my $gdd_file = $nl->get_value('stream_fldFileName_cultivar_gdds') ; my $gdd20_baseline_file = $nl->get_value('stream_fldFileName_gdd20_baseline') ; my $mesh_file = $nl->get_value('stream_meshfile_cropcal') ; - if ( ($swindow_start_file eq '' and $swindow_start_file ne '') or ($swindow_start_file ne '' and $swindow_start_file eq '') ) { - $log->fatal_error("When specifying sowing window dates, you must provide both swindow_start_file and swindow_end_file. To specify exact sowing dates, use the same file." ); + if ( ($swindow_start_file eq '' and $swindow_end_file ne '') or ($swindow_start_file ne '' and $swindow_end_file eq '') ) { + $log->fatal_error("When specifying sowing window dates, you must provide both stream_fldFileName_swindow_start and stream_fldFileName_swindow_end. To specify exact sowing dates, use the same file." ); } if ( $gdd_file eq '' and $gdd20_baseline_file ne '' ) { $log->fatal_error("If not providing stream_fldFileName_cultivar_gdds, don't provide stream_fldFileName_gdd20_baseline"); From b19573466744c3426de70a1edbb9a3725821de67 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 May 2024 11:42:11 -0600 Subject: [PATCH 146/444] CLMBuildNamelist: Use &string_is_undef_or_empty() instead of comparing to ''. --- bld/CLMBuildNamelist.pm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 9753549db1..833a254f1a 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4200,30 +4200,30 @@ sub setup_logic_cropcal_streams { my $gdd_file = $nl->get_value('stream_fldFileName_cultivar_gdds') ; my $gdd20_baseline_file = $nl->get_value('stream_fldFileName_gdd20_baseline') ; my $mesh_file = $nl->get_value('stream_meshfile_cropcal') ; - if ( ($swindow_start_file eq '' and $swindow_end_file ne '') or ($swindow_start_file ne '' and $swindow_end_file eq '') ) { + if ( (&string_is_undef_or_empty($swindow_start_file) and !&string_is_undef_or_empty($swindow_end_file)) or (!&string_is_undef_or_empty($swindow_start_file) and &string_is_undef_or_empty($swindow_end_file)) ) { $log->fatal_error("When specifying sowing window dates, you must provide both stream_fldFileName_swindow_start and stream_fldFileName_swindow_end. To specify exact sowing dates, use the same file." ); } - if ( $gdd_file eq '' and $gdd20_baseline_file ne '' ) { + if ( &string_is_undef_or_empty($gdd_file) and ! &string_is_undef_or_empty($gdd20_baseline_file) ) { $log->fatal_error("If not providing stream_fldFileName_cultivar_gdds, don't provide stream_fldFileName_gdd20_baseline"); } if ( $generate_crop_gdds eq '.true.' ) { if ( $use_mxmat eq '.true.' ) { $log->fatal_error("If generate_crop_gdds is true, you must also set use_mxmat to false" ); } - if ( $swindow_start_file eq '' or $swindow_end_file eq '' ) { + if ( &string_is_undef_or_empty($swindow_start_file) or &string_is_undef_or_empty($swindow_end_file) ) { $log->fatal_error("If generate_crop_gdds is true, you must specify stream_fldFileName_swindow_start and stream_fldFileName_swindow_end") } if ( $swindow_start_file ne $swindow_end_file ) { $log->fatal_error("If generate_crop_gdds is true, you must specify exact sowing dates by setting stream_fldFileName_swindow_start and stream_fldFileName_swindow_end to the same file") } - if ( $gdd_file ne '' ) { + if ( ! &string_is_undef_or_empty($gdd_file) ) { $log->fatal_error("If generate_crop_gdds is true, do not specify stream_fldFileName_cultivar_gdds") } - if ( $gdd20_baseline_file ne '' ) { + if ( ! &string_is_undef_or_empty($gdd20_baseline_file) ) { $log->fatal_error("If generate_crop_gdds is true, do not specify stream_fldFileName_gdd20_baseline") } } - if ( $mesh_file eq '' and ( $swindow_start_file ne '' or $gdd_file ne '' ) ) { + if ( &string_is_undef_or_empty($mesh_file) and ( ! &string_is_undef_or_empty($swindow_start_file) or ! &string_is_undef_or_empty($gdd_file) ) ) { $log->fatal_error("If prescribing crop sowing dates and/or maturity requirements, you must specify stream_meshfile_cropcal") } } From 4b18a5bb159e1a98a5905ec939dffb5981e55185 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 May 2024 11:48:50 -0600 Subject: [PATCH 147/444] CLMBuildNamelist: Use &value_is_true() instead of comparing to '.true.' --- bld/CLMBuildNamelist.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 833a254f1a..d35649bef4 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4206,8 +4206,8 @@ sub setup_logic_cropcal_streams { if ( &string_is_undef_or_empty($gdd_file) and ! &string_is_undef_or_empty($gdd20_baseline_file) ) { $log->fatal_error("If not providing stream_fldFileName_cultivar_gdds, don't provide stream_fldFileName_gdd20_baseline"); } - if ( $generate_crop_gdds eq '.true.' ) { - if ( $use_mxmat eq '.true.' ) { + if ( &value_is_true($generate_crop_gdds) ) { + if ( &value_is_true($use_mxmat) ) { $log->fatal_error("If generate_crop_gdds is true, you must also set use_mxmat to false" ); } if ( &string_is_undef_or_empty($swindow_start_file) or &string_is_undef_or_empty($swindow_end_file) ) { From e76fbbc134ab5c4c6186f35732d11b46879a5a13 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 May 2024 12:02:17 -0600 Subject: [PATCH 148/444] CLMBuildNamelist: Update setup_logic_cropcal_streams() with cropcals_rx. --- bld/CLMBuildNamelist.pm | 77 ++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index d35649bef4..aff46be3f0 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4172,41 +4172,73 @@ sub setup_logic_lai_streams { sub setup_logic_cropcal_streams { my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; - # Set first and last stream years - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_cropcal', - 'sim_year'=>$nl_flags->{'sim_year'}, - 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_cropcal', - 'sim_year'=>$nl_flags->{'sim_year'}, - 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - - # Set align year, if first and last years are different - if ( $nl->get_value('stream_year_first_cropcal') != - $nl->get_value('stream_year_last_cropcal') ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, - 'model_year_align_cropcal', 'sim_year'=>$nl_flags->{'sim_year'}, - 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - } - # Set up other crop calendar parameters + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'cropcals_rx'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'generate_crop_gdds'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_mxmat'); - # Option checks - my $generate_crop_gdds = $nl->get_value('generate_crop_gdds') ; - my $use_mxmat = $nl->get_value('use_mxmat') ; + # Add defaults if using prescribed crop calendars + my $cropcals_rx = $nl->get_value('cropcals_rx') ; + if ( &value_is_true($cropcals_rx) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_swindow_start'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_swindow_end'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_cultivar_gdds'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_cropcal'); + } + + # Add defaults if using any potentially time-varying crop calendar input files my $swindow_start_file = $nl->get_value('stream_fldFileName_swindow_start') ; my $swindow_end_file = $nl->get_value('stream_fldFileName_swindow_end') ; my $gdd_file = $nl->get_value('stream_fldFileName_cultivar_gdds') ; my $gdd20_baseline_file = $nl->get_value('stream_fldFileName_gdd20_baseline') ; my $mesh_file = $nl->get_value('stream_meshfile_cropcal') ; - if ( (&string_is_undef_or_empty($swindow_start_file) and !&string_is_undef_or_empty($swindow_end_file)) or (!&string_is_undef_or_empty($swindow_start_file) and &string_is_undef_or_empty($swindow_end_file)) ) { - $log->fatal_error("When specifying sowing window dates, you must provide both stream_fldFileName_swindow_start and stream_fldFileName_swindow_end. To specify exact sowing dates, use the same file." ); + if ( !&string_is_undef_or_empty($swindow_start_file) or !&string_is_undef_or_empty($swindow_end_file) or !&string_is_undef_or_empty($gdd_file) or !&string_is_undef_or_empty($gdd20_baseline_file) or !&string_is_undef_or_empty($mesh_file)) { + + # User gave an input file without specifying cropcals_rx = .true. + # Changing this means nothing to the code, but helps namelist make more sense + if ( ! &value_is_true($cropcals_rx) ){ + $log->fatal_error("If providing any crop calendar input file(s), cropcals_rx must be true" ); + } + + # User provided an input file but set mesh file to empty + if ( &string_is_undef_or_empty($mesh_file) ) { + $log->fatal_error("If providing any crop calendar input file(s), you must provide stream_meshfile_cropcal" ); + } + + # Set first and last stream years + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_cropcal', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_cropcal', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + + # Set align year, if first and last years are different + if ( $nl->get_value('stream_year_first_cropcal') != + $nl->get_value('stream_year_last_cropcal') ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + 'model_year_align_cropcal', 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + } } + + # If running with prescribed crop calendars, certain files must be provided + my $generate_crop_gdds = $nl->get_value('generate_crop_gdds') ; + if ( &value_is_true($cropcals_rx) ) { + if ( &string_is_undef_or_empty($swindow_start_file) or &string_is_undef_or_empty($swindow_end_file) ) { + $log->fatal_error("If cropcals_rx is true, sowing window start and end files must be provided. To specify exact sowing dates, use the same file." ); + } + if ( &string_is_undef_or_empty($gdd_file) and (! &value_is_true($generate_crop_gdds)) ){ + $log->fatal_error("If cropcals_rx is true and generate_crop_gdds is false, maturity requirement file stream_fldFileName_cultivar_gdds must be provided" ); + } + } + + # Option checks if ( &string_is_undef_or_empty($gdd_file) and ! &string_is_undef_or_empty($gdd20_baseline_file) ) { $log->fatal_error("If not providing stream_fldFileName_cultivar_gdds, don't provide stream_fldFileName_gdd20_baseline"); } if ( &value_is_true($generate_crop_gdds) ) { + my $use_mxmat = $nl->get_value('use_mxmat') ; if ( &value_is_true($use_mxmat) ) { $log->fatal_error("If generate_crop_gdds is true, you must also set use_mxmat to false" ); } @@ -4223,9 +4255,6 @@ sub setup_logic_cropcal_streams { $log->fatal_error("If generate_crop_gdds is true, do not specify stream_fldFileName_gdd20_baseline") } } - if ( &string_is_undef_or_empty($mesh_file) and ( ! &string_is_undef_or_empty($swindow_start_file) or ! &string_is_undef_or_empty($gdd_file) ) ) { - $log->fatal_error("If prescribing crop sowing dates and/or maturity requirements, you must specify stream_meshfile_cropcal") - } } #------------------------------------------------------------------------------- From dbbd7954a9b5e9a38d0afe45648b19dd5597c4fe Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 29 May 2024 12:17:31 -0600 Subject: [PATCH 149/444] change fluh_timeseries to use an file with wider time range --- bld/namelist_files/namelist_defaults_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index fe34e9f4b8..37aff979f9 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1557,7 +1557,7 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c lnd/clm2/surfdata_map/fates-sci.1.68.3_api.31.0.0_tools.1.0.1/LUH2_states_transitions_management.timeseries_4x5_hist_simyr1850-2015_c231101.nc + >lnd/clm2/surfdata_map/fates-sci.1.68.3_api.31.0.0_tools.1.0.1/LUH2_states_transitions_management.timeseries_4x5_hist_simyr1650-2015_c240216.nc .false. From 2848873409be7eddecb0f62326116afaf9a2e319 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 29 May 2024 12:18:24 -0600 Subject: [PATCH 150/444] fix pvt system test --- cime_config/SystemTests/pvt.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/cime_config/SystemTests/pvt.py b/cime_config/SystemTests/pvt.py index 6b2a958eaa..05da935a0e 100644 --- a/cime_config/SystemTests/pvt.py +++ b/cime_config/SystemTests/pvt.py @@ -51,6 +51,11 @@ def run_phase(self): orig_casevar = self._case.get_value("CASE") caseroot = self._case.get_value("CASEROOT") + # Set the run start date based on the desired starting reference case year + refcase_year = 1700 + stop_n_pveg = 5 + startyear_pveg = refcase_year - stop_n_pveg + # clone the main case to create spinup case logger.info("PVT log: cloning setup") clone_path = "{}.potveg".format(caseroot) @@ -65,10 +70,11 @@ def run_phase(self): self._set_active_case(clone) # set the clone case values - stop_n_pveg = 1 with clone: - # clone.set_value("CLM_ACCELERATED_SPINUP", "on") + clone.set_value("CLM_ACCELERATED_SPINUP", "off") clone.set_value("STOP_N", stop_n_pveg) + clone.set_value("STOP_OPTION", "nyears") + clone.set_value("RUN_STARTDATE", "{}-01-01".format(startyear_pveg)) # Modify the spin up case to use the potential vegetation mode. # Checks for incompatible cases and necessary mapping files are @@ -93,11 +99,33 @@ def run_phase(self): os.chdir(caseroot) self._set_active_case(orig_case) + # Copy restart files from spin up to the transient case run directory + # obtain rpointer files and necessary restart files from short term archiving directory + rundir = self._case.get_value("RUNDIR") + + refdate = str(refcase_year) + '-01-01-00000' + rest_path = os.path.join(dout_sr, "rest", "{}".format(refdate)) + + for item in glob.glob("{}/*{}*".format(rest_path, refdate)): + link_name = os.path.join(rundir, os.path.basename(item)) + if os.path.islink(link_name) and os.readlink(link_name) == item: + # Link is already set up correctly: do nothing + # (os.symlink raises an exception if you try to replace an + # existing file) + pass + else: + os.symlink(item, link_name) + + for item in glob.glob("{}/*rpointer*".format(rest_path)): + shutil.copy(item, rundir) + + # Update run case settings self._case.set_value("CLM_ACCELERATED_SPINUP", "off") self._case.set_value("RUN_TYPE", "hybrid") self._case.set_value("GET_REFCASE", False) self._case.set_value("RUN_REFCASE", "{}.potveg".format(orig_casevar)) - self._case.set_value("RUN_REFDATE", "1700-01-01") + self._case.set_value("RUN_REFDATE", "{}-01-01".format(refcase_year)) + self._case.set_value("RUN_STARTDATE", "{}-01-01".format(refcase_year)) self._case.set_value("DOUT_S", False) self._case.flush() From 0f729d8edcec2fa97db471bb766cc8964b01ed81 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 May 2024 14:16:45 -0600 Subject: [PATCH 151/444] Bugfix: cropcalStreamMod now handles cropcals_rx. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index f60ab51000..101ad9f2a4 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -47,6 +47,7 @@ module cropcalStreamMod character(len=CL) :: stream_fldFileName_swindow_end ! sowing window end stream filename to read character(len=CL) :: stream_fldFileName_cultivar_gdds ! cultivar growing degree-days stream filename to read character(len=CL) :: stream_fldFileName_gdd20_baseline ! GDD20 baseline stream filename to read + logical :: cropcals_rx ! Used only for setting input files in namelist; does nothing in code, but needs to be here so namelist read doesn't crash character(len=*), parameter :: sourcefile = & __FILE__ @@ -95,7 +96,8 @@ subroutine cropcal_init(bounds) stream_fldFileName_swindow_end, & stream_fldFileName_cultivar_gdds, & stream_fldFileName_gdd20_baseline, & - stream_meshfile_cropcal + stream_meshfile_cropcal, & + cropcals_rx ! Default values for namelist stream_year_first_cropcal = 1 ! first year in stream to use From 74411ea31189969410205a3edba96c14670a38f4 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 May 2024 14:17:05 -0600 Subject: [PATCH 152/444] Update RxCropCals testmod to use cropcals_rx true. --- .../testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm index 9cbfea97f0..8a0b4a91be 100644 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm @@ -1,8 +1,2 @@ -! Sowing windows -stream_fldFileName_swindow_start = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc' -stream_fldFileName_swindow_end = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc' -stream_fldFileName_cultivar_gdds = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc' -stream_year_first_cropcal = 2000 -stream_year_last_cropcal = 2000 -stream_meshfile_cropcal = '$DIN_LOC_ROOT/share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc' +cropcals_rx = .true. From 9d1f88d15ac942cb7176b30bc48163ab6e5031fc Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 May 2024 15:30:41 -0600 Subject: [PATCH 153/444] Add RxCropCals and RxCropCalsAdapt tests to new suite crop_calendars. --- cime_config/testdefs/testlist_clm.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 9cfba6f5b3..bf763c4775 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3719,5 +3719,23 @@ + + + + + + + + + + + + + + + + + + From 7e5257a94efa920f7b608a97b041fef63b1d9aa7 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 29 May 2024 16:12:06 -0600 Subject: [PATCH 154/444] Add cropcals_rx_adapt option. --- bld/CLMBuildNamelist.pm | 50 +++++++++++++++---- bld/namelist_files/namelist_defaults_ctsm.xml | 6 +++ .../namelist_definition_ctsm.xml | 5 ++ .../clm/RxCropCalsAdapt/user_nl_clm | 4 +- src/cpl/share_esmf/cropcalStreamMod.F90 | 4 +- 5 files changed, 55 insertions(+), 14 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index aff46be3f0..fc80379201 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4174,19 +4174,29 @@ sub setup_logic_cropcal_streams { # Set up other crop calendar parameters add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'cropcals_rx'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'cropcals_rx_adapt'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'generate_crop_gdds'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_mxmat'); - # Add defaults if using prescribed crop calendars + # These can't both be true my $cropcals_rx = $nl->get_value('cropcals_rx') ; - if ( &value_is_true($cropcals_rx) ) { + my $cropcals_rx_adapt = $nl->get_value('cropcals_rx_adapt') ; + if (&value_is_true($cropcals_rx) and &value_is_true($cropcals_rx_adapt)) { + $log->fatal_error("cropcals_rx and cropcals_rx_adapt may not both be true" ); + } + + # Add defaults if using prescribed crop calendars + if ( &value_is_true($cropcals_rx) or &value_is_true($cropcals_rx_adapt) ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_swindow_start'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_swindow_end'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_cultivar_gdds'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_cropcal'); + if ( &value_is_true($cropcals_rx_adapt) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_gdd20_baseline'); + } } - # Add defaults if using any potentially time-varying crop calendar input files + # Add defaults if using any crop calendar input files my $swindow_start_file = $nl->get_value('stream_fldFileName_swindow_start') ; my $swindow_end_file = $nl->get_value('stream_fldFileName_swindow_end') ; my $gdd_file = $nl->get_value('stream_fldFileName_cultivar_gdds') ; @@ -4194,10 +4204,20 @@ sub setup_logic_cropcal_streams { my $mesh_file = $nl->get_value('stream_meshfile_cropcal') ; if ( !&string_is_undef_or_empty($swindow_start_file) or !&string_is_undef_or_empty($swindow_end_file) or !&string_is_undef_or_empty($gdd_file) or !&string_is_undef_or_empty($gdd20_baseline_file) or !&string_is_undef_or_empty($mesh_file)) { - # User gave an input file without specifying cropcals_rx = .true. - # Changing this means nothing to the code, but helps namelist make more sense - if ( ! &value_is_true($cropcals_rx) ){ - $log->fatal_error("If providing any crop calendar input file(s), cropcals_rx must be true" ); + # User gave an input file without specifying cropcals_rx or cropcals_rx_adapt = .true. + # Requiring this means nothing to the code, but helps namelist make more sense + if ( !&value_is_true($cropcals_rx) and !&value_is_true($cropcals_rx_adapt) ){ + $log->fatal_error("If providing any crop calendar input file(s), cropcals_rx or cropcals_rx_adapt must be true" ); + } + + # User set cropcals_rx_adapt to true but set stream_fldFileName_gdd20_baseline to empty + if ( &value_is_true($cropcals_rx_adapt) and &string_is_undef_or_empty($gdd20_baseline_file) ) { + $log->fatal_error("If cropcals_rx_adapt is true, stream_fldFileName_gdd20_baseline must be provided" ); + } + + # cropcals_rx_adapt is false but user provided stream_fldFileName_gdd20_baseline + if ( !&value_is_true($cropcals_rx_adapt) and !&string_is_undef_or_empty($gdd20_baseline_file) ) { + $log->fatal_error("If stream_fldFileName_gdd20_baseline provided, cropcals_rx_adapt must be true" ); } # User provided an input file but set mesh file to empty @@ -4213,9 +4233,17 @@ sub setup_logic_cropcal_streams { 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - # Set align year, if first and last years are different + # Check/set things if first and last years are different if ( $nl->get_value('stream_year_first_cropcal') != $nl->get_value('stream_year_last_cropcal') ) { + + # Do not allow maturity requirements to change over time if stream_fldFileName_gdd20_baseline is provided. That would be nonsensical. + # Note that this restricts sowing windows from changing over time as well, because there are not separate stream_year settings for that. + if ( !&string_is_undef_or_empty($gdd20_baseline_file) ) { + $log->fatal_error("If cropcals_rx_adapt is true (i.e., stream_fldFileName_gdd20_baseline is provided), no crop calendar input is allowed to vary over time (i.e., stream_year_first_cropcal and stream_year_last_cropcal must be the same)." ); + } + + # Set align year add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_cropcal', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); @@ -4224,12 +4252,12 @@ sub setup_logic_cropcal_streams { # If running with prescribed crop calendars, certain files must be provided my $generate_crop_gdds = $nl->get_value('generate_crop_gdds') ; - if ( &value_is_true($cropcals_rx) ) { + if ( &value_is_true($cropcals_rx) or &value_is_true($cropcals_rx_adapt) ) { if ( &string_is_undef_or_empty($swindow_start_file) or &string_is_undef_or_empty($swindow_end_file) ) { - $log->fatal_error("If cropcals_rx is true, sowing window start and end files must be provided. To specify exact sowing dates, use the same file." ); + $log->fatal_error("If cropcals_rx or cropcals_rx_adapt is true, sowing window start and end files must be provided. To specify exact sowing dates, use the same file." ); } if ( &string_is_undef_or_empty($gdd_file) and (! &value_is_true($generate_crop_gdds)) ){ - $log->fatal_error("If cropcals_rx is true and generate_crop_gdds is false, maturity requirement file stream_fldFileName_cultivar_gdds must be provided" ); + $log->fatal_error("If cropcals_rx or cropcals_rx_adapt is true and generate_crop_gdds is false, maturity requirement file stream_fldFileName_cultivar_gdds must be provided" ); } } diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 08f67a2712..85f37a22fd 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1688,6 +1688,7 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c .false. +.false. 2000 2000 2000 @@ -1697,6 +1698,11 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc +lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc +lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc +lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc +lnd/clm2/testdata/gdd20baseline.tmp_dontupload.nc +share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 366b7498e8..f37ada6847 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1778,6 +1778,11 @@ Mapping method from LAI input file to the model resolution Flag to enable prescribed crop calendars (sowing window dates and maturity requirement) + +Flag to enable prescribed crop calendars (sowing window dates and maturity requirement), with maturity requirement adaptive based on recent climate + + First year to loop over for crop calendar data (not including gdd20_baseline file) diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm index 1bba9d2a89..709c7221e0 100644 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm @@ -1,3 +1,3 @@ -! Eventually replace this with half-degree version in the proper place -stream_fldFileName_gdd20_baseline = '/glade/u/home/samrabin/ctsm_scale-mat-reqs/tools/crop_calendars/test.nc' +cropcals_rx = .false. +cropcals_rx_adapt = .true. diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 101ad9f2a4..3333b6cfdc 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -48,6 +48,7 @@ module cropcalStreamMod character(len=CL) :: stream_fldFileName_cultivar_gdds ! cultivar growing degree-days stream filename to read character(len=CL) :: stream_fldFileName_gdd20_baseline ! GDD20 baseline stream filename to read logical :: cropcals_rx ! Used only for setting input files in namelist; does nothing in code, but needs to be here so namelist read doesn't crash + logical :: cropcals_rx_adapt ! Used only for setting input files in namelist; does nothing in code, but needs to be here so namelist read doesn't crash character(len=*), parameter :: sourcefile = & __FILE__ @@ -97,7 +98,8 @@ subroutine cropcal_init(bounds) stream_fldFileName_cultivar_gdds, & stream_fldFileName_gdd20_baseline, & stream_meshfile_cropcal, & - cropcals_rx + cropcals_rx, & + cropcals_rx_adapt ! Default values for namelist stream_year_first_cropcal = 1 ! first year in stream to use From 709c3da94d1816b42268bf98a4b3d947bdc29a9d Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 29 May 2024 16:30:06 -0600 Subject: [PATCH 155/444] remove unnecessary import call --- cime_config/SystemTests/pvt.py | 2 -- cime_config/SystemTests/systemtest_utils.py | 5 ++--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/cime_config/SystemTests/pvt.py b/cime_config/SystemTests/pvt.py index 05da935a0e..feef6cb04c 100644 --- a/cime_config/SystemTests/pvt.py +++ b/cime_config/SystemTests/pvt.py @@ -8,12 +8,10 @@ - use CLM_ACCELERATED_SPINUP? 2) run a transient landuse case with use_fates_lupft - start from the restart file generated in (1) - """ from CIME.XML.standard_module_setup import * from CIME.SystemTests.system_tests_common import SystemTestsCommon from CIME.SystemTests.test_utils.user_nl_utils import append_to_user_nl_files -from systemtest_utils import find_user_nl_option import shutil, glob, os logger = logging.getLogger(__name__) diff --git a/cime_config/SystemTests/systemtest_utils.py b/cime_config/SystemTests/systemtest_utils.py index 2591ac4223..c39f5171ba 100644 --- a/cime_config/SystemTests/systemtest_utils.py +++ b/cime_config/SystemTests/systemtest_utils.py @@ -85,9 +85,8 @@ def run_python_script(caseroot, this_conda_env, command_in, tool_path): except: print(f"ERROR trying to run {tool_name}.") raise -""" -Read a user_nl file and return the namelist option if found -""" + +# Read a user_nl file and return the namelist option if found def find_user_nl_option(caseroot, component, namelist_option): # This is a copy of the CIME _get_list_of_user_nl_files From 5911cea434581d33f1a4892699f029c32132e63e Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 31 May 2024 13:13:02 -0600 Subject: [PATCH 156/444] Move add_default() of model_year_align_cropcal to be with other year params. --- bld/CLMBuildNamelist.pm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index fc80379201..bbe83a3dc5 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4225,13 +4225,16 @@ sub setup_logic_cropcal_streams { $log->fatal_error("If providing any crop calendar input file(s), you must provide stream_meshfile_cropcal" ); } - # Set first and last stream years + # Set stream years add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_cropcal', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_cropcal', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_cropcal', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); # Check/set things if first and last years are different if ( $nl->get_value('stream_year_first_cropcal') != @@ -4242,11 +4245,6 @@ sub setup_logic_cropcal_streams { if ( !&string_is_undef_or_empty($gdd20_baseline_file) ) { $log->fatal_error("If cropcals_rx_adapt is true (i.e., stream_fldFileName_gdd20_baseline is provided), no crop calendar input is allowed to vary over time (i.e., stream_year_first_cropcal and stream_year_last_cropcal must be the same)." ); } - - # Set align year - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, - 'model_year_align_cropcal', 'sim_year'=>$nl_flags->{'sim_year'}, - 'sim_year_range'=>$nl_flags->{'sim_year_range'}); } } From d89cb9d4bc3cd8ab5761d23cf398b9b682a047fa Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 31 May 2024 13:38:31 -0600 Subject: [PATCH 157/444] Split streams year params for swindows vs maturity reqts. --- bld/CLMBuildNamelist.pm | 29 +++++---- bld/namelist_files/namelist_defaults_ctsm.xml | 9 ++- .../namelist_definition_ctsm.xml | 27 ++++++-- cime_config/SystemTests/rxcropmaturity.py | 6 +- .../clm/sowingWindows/user_nl_clm | 4 +- .../Running-with-custom-crop-calendars.rst | 10 +-- src/cpl/share_esmf/cropcalStreamMod.F90 | 63 ++++++++++++------- 7 files changed, 93 insertions(+), 55 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index bbe83a3dc5..26725b7d96 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4226,25 +4226,30 @@ sub setup_logic_cropcal_streams { } # Set stream years - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_cropcal', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_cropcal_swindows', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_cropcal', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_cropcal_swindows', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_cropcal', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_cropcal_swindows', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_cropcal_cultivar_gdds', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_cropcal_cultivar_gdds', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_cropcal_cultivar_gdds', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - # Check/set things if first and last years are different - if ( $nl->get_value('stream_year_first_cropcal') != - $nl->get_value('stream_year_last_cropcal') ) { - - # Do not allow maturity requirements to change over time if stream_fldFileName_gdd20_baseline is provided. That would be nonsensical. - # Note that this restricts sowing windows from changing over time as well, because there are not separate stream_year settings for that. - if ( !&string_is_undef_or_empty($gdd20_baseline_file) ) { - $log->fatal_error("If cropcals_rx_adapt is true (i.e., stream_fldFileName_gdd20_baseline is provided), no crop calendar input is allowed to vary over time (i.e., stream_year_first_cropcal and stream_year_last_cropcal must be the same)." ); - } + # Do not allow maturity requirements to change over time if stream_fldFileName_gdd20_baseline is provided. That would be nonsensical. + if ( $nl->get_value('stream_year_first_cropcal_cultivar_gdds') != + $nl->get_value('stream_year_last_cropcal_cultivar_gdds') + and !&string_is_undef_or_empty($gdd20_baseline_file) ) { + $log->fatal_error("If cropcals_rx_adapt is true (i.e., stream_fldFileName_gdd20_baseline is provided), baseline maturity requirements are allowed to vary over time (i.e., stream_year_first_cropcal_cultivar_gdds and stream_year_last_cropcal_cultivar_gdds must be the same)." ); } } diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 85f37a22fd..da0a523adc 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1689,9 +1689,12 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c .false. .false. -2000 -2000 -2000 +2000 +2000 +2000 +2000 +2000 +2000 lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index f37ada6847..50e645519c 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1783,19 +1783,34 @@ Flag to enable prescribed crop calendars (sowing window dates and maturity requi Flag to enable prescribed crop calendars (sowing window dates and maturity requirement), with maturity requirement adaptive based on recent climate - -First year to loop over for crop calendar data (not including gdd20_baseline file) +First year to loop over for crop sowing windows - -Last year to loop over for crop calendar data (not including gdd20_baseline file) +Last year to loop over for crop sowing windows - -Simulation year that aligns with stream_year_first_cropcal value +Simulation year that aligns with stream_year_first_cropcal_swindows value + + + +First year to loop over for crop maturity requirements + + + +Last year to loop over for crop maturity requirements + + + +Simulation year that aligns with stream_year_first_cropcal_cultivar_gdds value Date: Fri, 31 May 2024 13:55:29 -0600 Subject: [PATCH 158/444] Explain hard-coding of 2000 when reading GDD20 baseline file. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 8f444a0479..413ddbefce 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -274,8 +274,9 @@ subroutine cropcal_init(bounds) end if ! Initialize the cdeps data type sdat_cropcal_gdd20_baseline - ! NOTE: stream_dtlimit 1.5 didn't work for some reason - !TODO SSR: Do not allow time axis length > 1 + ! NOTE: Hard-coded to one particular year because it should NOT vary over time. Note that the + ! particular year chosen doesn't matter. Users can base their file on whatever baseline they + ! want; they just need to put 2000 on the time axis. if (adapt_cropcal_rx_cultivar_gdds) then call shr_strdata_init_from_inline(sdat_cropcal_gdd20_baseline, & my_task = iam, & From 75d7df65dc721083f19a92e801f883c6e4b5d8cb Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 31 May 2024 15:07:12 -0600 Subject: [PATCH 159/444] Functionize UpdateAccVars_CropGDDs(). --- src/biogeophys/TemperatureType.F90 | 121 ++++++++++++++++------------- 1 file changed, 69 insertions(+), 52 deletions(-) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index ab310650c8..1b28b2e1aa 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -129,6 +129,7 @@ module TemperatureType procedure, public :: InitAccBuffer procedure, public :: InitAccVars procedure, public :: UpdateAccVars + procedure, private :: UpdateAccVars_CropGDDs end type temperature_type @@ -1357,6 +1358,71 @@ subroutine InitAccVars(this, bounds) end subroutine InitAccVars + subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, dtime, nstep, basetemp_int, gddx_patch) + ! + ! USES + use shr_const_mod , only : SHR_CONST_CDAY, SHR_CONST_TKFRZ + use accumulMod , only : update_accum_field, extract_accum_field, accumResetVal + ! + ! !ARGUMENTS + class(temperature_type) :: this + real(r8), intent(inout), pointer, dimension(:) :: rbufslp ! temporary single level - pft level + integer, intent(in) :: begp, endp + integer, intent(in) :: month, day, secs, dtime, nstep + integer, intent(in) :: basetemp_int ! Crop base temperature. Integer to avoid possible float weirdness + real(r8), intent(inout), pointer, dimension(:) :: gddx_patch ! E.g., gdd0_patch + ! + ! !LOCAL VARIABLES + real(r8) :: basetemp_r8 ! real(r8) version of basetemp for arithmetic + real(r8) :: max_accum ! Maximum daily accumulation + character(8) :: field_name ! E.g., GDD0 + character(32) :: format_string + integer :: p, g + + basetemp_r8 = real(basetemp_int, r8) + + ! Get maximum daily accumulation + if (basetemp_int == 0) then + ! SSR 2024-05-31: I'm not sure why this was different for base temp 0, but I'm keeping it as I refactor into UpdateAccVars_CropGDDs() + max_accum = 26._r8 + else + max_accum = 30._r8 + end if + + do p = begp,endp + + ! Avoid unnecessary calculations over inactive points + if (.not. patch%active(p)) then + cycle + end if + + g = patch%gridcell(p) + if (month==1 .and. day==1 .and. secs==dtime) then + rbufslp(p) = accumResetVal ! reset gdd + else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & + ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then + rbufslp(p) = max(0._r8, min(max_accum, & + this%t_ref2m_patch(p)-(SHR_CONST_TKFRZ + basetemp_r8))) * dtime/SHR_CONST_CDAY + else + rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) + end if + end do + + ! Get field name + if (basetemp_int < 10) then + format_string = "(A3,I1)" + else if (basetemp_int < 100) then + format_string = "(A3,I2)" + else + format_string = "(A3,I3)" + end if + write(field_name, format_string) "GDD",basetemp_int + + ! Save + call update_accum_field (trim(field_name), rbufslp, nstep) + call extract_accum_field (trim(field_name), gddx_patch, nstep) + end subroutine UpdateAccVars_CropGDDs + !----------------------------------------------------------------------- subroutine UpdateAccVars (this, bounds) ! @@ -1538,63 +1604,14 @@ subroutine UpdateAccVars (this, bounds) ! Accumulate and extract GDD0 - - do p = begp,endp - ! Avoid unnecessary calculations over inactive points - if (patch%active(p)) then - g = patch%gridcell(p) - if (month==1 .and. day==1 .and. secs==dtime) then - rbufslp(p) = accumResetVal ! reset gdd - else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & - ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then - rbufslp(p) = max(0._r8, min(26._r8, this%t_ref2m_patch(p)-SHR_CONST_TKFRZ)) * dtime/SHR_CONST_CDAY - else - rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) - end if - end if - end do - call update_accum_field ('GDD0', rbufslp, nstep) - call extract_accum_field ('GDD0', this%gdd0_patch, nstep) + call this%UpdateAccVars_CropGDDs(rbufslp, begp, endp, month, day, secs, dtime, nstep, 0, this%gdd0_patch) ! Accumulate and extract GDD8 - - do p = begp,endp - ! Avoid unnecessary calculations over inactive points - if (patch%active(p)) then - g = patch%gridcell(p) - if (month==1 .and. day==1 .and. secs==dtime) then - rbufslp(p) = accumResetVal ! reset gdd - else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & - ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then - rbufslp(p) = max(0._r8, min(30._r8, & - this%t_ref2m_patch(p)-(SHR_CONST_TKFRZ + 8._r8))) * dtime/SHR_CONST_CDAY - else - rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) - end if - end if - end do - call update_accum_field ('GDD8', rbufslp, nstep) - call extract_accum_field ('GDD8', this%gdd8_patch, nstep) + call this%UpdateAccVars_CropGDDs(rbufslp, begp, endp, month, day, secs, dtime, nstep, 8, this%gdd8_patch) ! Accumulate and extract GDD10 + call this%UpdateAccVars_CropGDDs(rbufslp, begp, endp, month, day, secs, dtime, nstep, 10, this%gdd10_patch) - do p = begp,endp - ! Avoid unnecessary calculations over inactive points - if (patch%active(p)) then - g = patch%gridcell(p) - if (month==1 .and. day==1 .and. secs==dtime) then - rbufslp(p) = accumResetVal ! reset gdd - else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & - ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then - rbufslp(p) = max(0._r8, min(30._r8, & - this%t_ref2m_patch(p)-(SHR_CONST_TKFRZ + 10._r8))) * dtime/SHR_CONST_CDAY - else - rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) - end if - end if - end do - call update_accum_field ('GDD10', rbufslp, nstep) - call extract_accum_field ('GDD10', this%gdd10_patch, nstep) ! Accumulate and extract running 20-year means if (is_end_curr_year()) then From 45aff290b33baed02b48b089858de6f0f4a89a74 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 31 May 2024 17:08:01 -0600 Subject: [PATCH 160/444] Optionally read/use gdd20 accum seasons from stream files. --- bld/CLMBuildNamelist.pm | 15 ++ bld/namelist_files/namelist_defaults_ctsm.xml | 3 + .../namelist_definition_ctsm.xml | 15 ++ src/biogeochem/CropType.F90 | 4 + src/biogeophys/TemperatureType.F90 | 54 +++-- src/cpl/share_esmf/cropcalStreamMod.F90 | 198 ++++++++++++++++-- src/main/clm_driver.F90 | 2 +- 7 files changed, 265 insertions(+), 26 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 26725b7d96..dddd17ced9 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4175,6 +4175,7 @@ sub setup_logic_cropcal_streams { # Set up other crop calendar parameters add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'cropcals_rx'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'cropcals_rx_adapt'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_gdd20_seasons'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'generate_crop_gdds'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_mxmat'); @@ -4185,6 +4186,20 @@ sub setup_logic_cropcal_streams { $log->fatal_error("cropcals_rx and cropcals_rx_adapt may not both be true" ); } + # Add defaults if reading gdd20 seasons from stream files + my $stream_gdd20_seasons = $nl->get_value('stream_gdd20_seasons') ; + my $gdd20_season_start_file = $nl->get_value('stream_fldFileName_gdd20_season_start') ; + my $gdd20_season_end_file = $nl->get_value('stream_fldFileName_gdd20_season_end') ; + if ( &value_is_true($stream_gdd20_seasons)) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_gdd20_season_start'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_gdd20_season_end'); + + # Check + if ( &string_is_undef_or_empty($gdd20_season_start_file) or &string_is_undef_or_empty($gdd20_season_end_file) ) { + $log->fatal_error("If stream_gdd20_seasons is true, gdd20 season start and end files must be provided." ); + } + } + # Add defaults if using prescribed crop calendars if ( &value_is_true($cropcals_rx) or &value_is_true($cropcals_rx_adapt) ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_swindow_start'); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index da0a523adc..7e3ddb7c64 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1689,6 +1689,7 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c .false. .false. +.false. 2000 2000 2000 @@ -1705,6 +1706,8 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc lnd/clm2/testdata/gdd20baseline.tmp_dontupload.nc +lnd/clm2/cropdata/calendars/processed/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc +lnd/clm2/cropdata/calendars/processed/hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 50e645519c..036b9aca72 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1838,6 +1838,21 @@ Filename of input stream data for cultivar growing degree-day targets Filename of input stream data for baseline GDD20 values + +Filename of input stream data for date (day of year) of start of gdd20 accumulation season. + + + +Set this to true to read gdd20 accumulation season start and end dates from stream files, rather than using hard-coded hemisphere-specific "warm seasons." + + + +Filename of input stream data for date (day of year) of end of gdd20 accumulation season. + + Filename of input stream data for crop calendar inputs diff --git a/src/biogeochem/CropType.F90 b/src/biogeochem/CropType.F90 index a7bccf1a73..04806f9349 100644 --- a/src/biogeochem/CropType.F90 +++ b/src/biogeochem/CropType.F90 @@ -53,6 +53,8 @@ module CropType integer , pointer :: rx_swindow_ends_thisyr_patch (:,:) ! all prescribed sowing window end dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: rx_cultivar_gdds_thisyr_patch (:,:) ! all cultivar GDD targets for this patch this year (ddays) [patch, mxsowings] real(r8), pointer :: gdd20_baseline_patch (:) ! GDD20 baseline for this patch (ddays) [patch] + integer , pointer :: gdd20_season_start_patch(:) ! gdd20 season start date for this patch (day of year) [patch] + integer , pointer :: gdd20_season_end_patch (:) ! gdd20 season end date for this patch (day of year) [patch] real(r8), pointer :: sdates_thisyr_patch (:,:) ! all actual sowing dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: swindow_starts_thisyr_patch(:,:) ! all sowing window start dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: swindow_ends_thisyr_patch (:,:) ! all sowing window end dates for this patch this year (day of year) [patch, mxsowings] @@ -237,6 +239,8 @@ subroutine InitAllocate(this, bounds) allocate(this%rx_swindow_ends_thisyr_patch(begp:endp,1:mxsowings)) ; this%rx_swindow_ends_thisyr_patch (:,:) = -1 allocate(this%rx_cultivar_gdds_thisyr_patch(begp:endp,1:mxsowings)) ; this%rx_cultivar_gdds_thisyr_patch(:,:) = spval allocate(this%gdd20_baseline_patch(begp:endp)) ; this%gdd20_baseline_patch(:) = spval + allocate(this%gdd20_season_start_patch(begp:endp)); this%gdd20_season_start_patch(:) = -1 + allocate(this%gdd20_season_end_patch(begp:endp)) ; this%gdd20_season_end_patch (:) = -1 allocate(this%sdates_thisyr_patch(begp:endp,1:mxsowings)) ; this%sdates_thisyr_patch(:,:) = spval allocate(this%swindow_starts_thisyr_patch(begp:endp,1:mxsowings)) ; this%swindow_starts_thisyr_patch(:,:) = spval allocate(this%swindow_ends_thisyr_patch (begp:endp,1:mxsowings)) ; this%swindow_ends_thisyr_patch (:,:) = spval diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 1b28b2e1aa..31fba16274 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -1358,11 +1358,13 @@ subroutine InitAccVars(this, bounds) end subroutine InitAccVars - subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, dtime, nstep, basetemp_int, gddx_patch) + subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, dtime, nstep, basetemp_int, gddx_patch, crop_inst) ! ! USES use shr_const_mod , only : SHR_CONST_CDAY, SHR_CONST_TKFRZ use accumulMod , only : update_accum_field, extract_accum_field, accumResetVal + use clm_time_manager , only : is_doy_in_interval + use CropType, only : crop_type ! ! !ARGUMENTS class(temperature_type) :: this @@ -1371,13 +1373,22 @@ subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, d integer, intent(in) :: month, day, secs, dtime, nstep integer, intent(in) :: basetemp_int ! Crop base temperature. Integer to avoid possible float weirdness real(r8), intent(inout), pointer, dimension(:) :: gddx_patch ! E.g., gdd0_patch + type(crop_type), intent(inout) :: crop_inst ! ! !LOCAL VARIABLES real(r8) :: basetemp_r8 ! real(r8) version of basetemp for arithmetic real(r8) :: max_accum ! Maximum daily accumulation character(8) :: field_name ! E.g., GDD0 character(32) :: format_string - integer :: p, g + integer :: p + logical :: in_accumulation_season + real(r8) :: lat ! latitude + integer :: gdd20_season_start, gdd20_season_end + + associate( & + gdd20_season_starts => crop_inst%gdd20_season_start_patch, & + gdd20_season_ends => crop_inst%gdd20_season_end_patch & + ) basetemp_r8 = real(basetemp_int, r8) @@ -1396,15 +1407,28 @@ subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, d cycle end if - g = patch%gridcell(p) + ! Is this patch in its gdd20 accumulation season? + ! First, check based on latitude. This will be fallback if read-in gdd20 accumulation season is invalid. + lat = grc%latdeg(patch%gridcell(p)) + in_accumulation_season = & + ((month > 3 .and. month < 10) .and. lat >= 0._r8) .or. & + ((month > 9 .or. month < 4) .and. lat < 0._r8) + ! Replace with read-in gdd20 accumulation season, if valid + ! (If these aren't being read in or they're invalid, they'll be -1) + gdd20_season_start = crop_inst%gdd20_season_start_patch(p) + gdd20_season_end = crop_inst%gdd20_season_end_patch(p) + if (gdd20_season_start >= 1 .and. gdd20_season_end >= 1) then + in_accumulation_season = is_doy_in_interval( & + gdd20_season_starts(p), gdd20_season_ends(p), day) + end if + if (month==1 .and. day==1 .and. secs==dtime) then rbufslp(p) = accumResetVal ! reset gdd - else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & - ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then + else if (in_accumulation_season) then rbufslp(p) = max(0._r8, min(max_accum, & this%t_ref2m_patch(p)-(SHR_CONST_TKFRZ + basetemp_r8))) * dtime/SHR_CONST_CDAY else - rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) + rbufslp(p) = 0._r8 ! keeps gdd unchanged outside accumulation season end if end do @@ -1421,24 +1445,28 @@ subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, d ! Save call update_accum_field (trim(field_name), rbufslp, nstep) call extract_accum_field (trim(field_name), gddx_patch, nstep) + + end associate end subroutine UpdateAccVars_CropGDDs !----------------------------------------------------------------------- - subroutine UpdateAccVars (this, bounds) + subroutine UpdateAccVars (this, bounds, crop_inst) ! ! USES - use shr_const_mod , only : SHR_CONST_CDAY, SHR_CONST_TKFRZ + use shr_const_mod , only : SHR_CONST_TKFRZ use clm_time_manager , only : get_step_size, get_nstep, is_end_curr_day, get_curr_date, is_end_curr_year - use accumulMod , only : update_accum_field, extract_accum_field, accumResetVal + use accumulMod , only : update_accum_field, extract_accum_field use CNSharedParamsMod, only : upper_soil_layer + use CropType , only : crop_type ! ! !ARGUMENTS: class(temperature_type) :: this type(bounds_type) , intent(in) :: bounds + type(crop_type), intent(inout) :: crop_inst ! ! !LOCAL VARIABLES: - integer :: m,g,l,c,p ! indices + integer :: m,l,c,p ! indices integer :: ier ! error status integer :: dtime ! timestep size [seconds] integer :: nstep ! timestep number @@ -1604,13 +1632,13 @@ subroutine UpdateAccVars (this, bounds) ! Accumulate and extract GDD0 - call this%UpdateAccVars_CropGDDs(rbufslp, begp, endp, month, day, secs, dtime, nstep, 0, this%gdd0_patch) + call this%UpdateAccVars_CropGDDs(rbufslp, begp, endp, month, day, secs, dtime, nstep, 0, this%gdd0_patch, crop_inst) ! Accumulate and extract GDD8 - call this%UpdateAccVars_CropGDDs(rbufslp, begp, endp, month, day, secs, dtime, nstep, 8, this%gdd8_patch) + call this%UpdateAccVars_CropGDDs(rbufslp, begp, endp, month, day, secs, dtime, nstep, 8, this%gdd8_patch, crop_inst) ! Accumulate and extract GDD10 - call this%UpdateAccVars_CropGDDs(rbufslp, begp, endp, month, day, secs, dtime, nstep, 10, this%gdd10_patch) + call this%UpdateAccVars_CropGDDs(rbufslp, begp, endp, month, day, secs, dtime, nstep, 10, this%gdd10_patch, crop_inst) ! Accumulate and extract running 20-year means diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 413ddbefce..8196ca1dfb 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -38,9 +38,12 @@ module cropcalStreamMod type(shr_strdata_type) :: sdat_cropcal_swindow_end ! sowing window end input data stream type(shr_strdata_type) :: sdat_cropcal_cultivar_gdds ! maturity requirement input data stream type(shr_strdata_type) :: sdat_cropcal_gdd20_baseline ! GDD20 baseline input data stream + type(shr_strdata_type) :: sdat_cropcal_gdd20_season_start ! gdd20 season start input data stream + type(shr_strdata_type) :: sdat_cropcal_gdd20_season_end ! gdd20 season end input data stream character(len=CS), allocatable :: stream_varnames_sdate(:) ! used for both start and end dates character(len=CS), allocatable :: stream_varnames_cultivar_gdds(:) character(len=CS), allocatable :: stream_varnames_gdd20_baseline(:) + character(len=CS), allocatable :: stream_varnames_gdd20_season_enddate(:) ! start uses stream_varnames_sdate integer :: ncft ! Number of crop functional types (excl. generic crops) logical :: allow_invalid_swindow_inputs ! Fall back on paramfile sowing windows in cases of invalid values in stream_fldFileName_swindow_start and _end? character(len=CL) :: stream_fldFileName_swindow_start ! sowing window start stream filename to read @@ -49,6 +52,10 @@ module cropcalStreamMod character(len=CL) :: stream_fldFileName_gdd20_baseline ! GDD20 baseline stream filename to read logical :: cropcals_rx ! Used only for setting input files in namelist; does nothing in code, but needs to be here so namelist read doesn't crash logical :: cropcals_rx_adapt ! Used only for setting input files in namelist; does nothing in code, but needs to be here so namelist read doesn't crash + logical :: stream_gdd20_seasons ! Read stream file for GDD20 accumulation seasons, instead of per-hemisphere periods + logical :: allow_invalid_gdd20_season_inputs ! Fall back on hemisphere "warm periods" in cases of invalid values in stream_fldFileName_gdd20_season_start and _end? + character(len=CL) :: stream_fldFileName_gdd20_season_start ! Stream filename to read for start of gdd20 season + character(len=CL) :: stream_fldFileName_gdd20_season_end ! Stream filename to read for end of gdd20 season character(len=*), parameter :: sourcefile = & __FILE__ @@ -105,7 +112,11 @@ subroutine cropcal_init(bounds) stream_fldFileName_gdd20_baseline, & stream_meshfile_cropcal, & cropcals_rx, & - cropcals_rx_adapt + cropcals_rx_adapt, & + stream_gdd20_seasons, & + allow_invalid_gdd20_season_inputs, & + stream_fldFileName_gdd20_season_start, & + stream_fldFileName_gdd20_season_end ! Default values for namelist stream_year_first_cropcal_swindows = 1 ! first year in sowing window streams to use @@ -120,16 +131,22 @@ subroutine cropcal_init(bounds) stream_fldFileName_swindow_end = '' stream_fldFileName_cultivar_gdds = '' stream_fldFileName_gdd20_baseline = '' + stream_gdd20_seasons = .false. + allow_invalid_gdd20_season_inputs = .false. + stream_fldFileName_gdd20_season_start = '' + stream_fldFileName_gdd20_season_end = '' ! Will need modification to work with mxsowings > 1 ncft = mxpft - npcropmin + 1 ! Ignores generic crops allocate(stream_varnames_sdate(ncft)) allocate(stream_varnames_cultivar_gdds(ncft)) allocate(stream_varnames_gdd20_baseline(ncft)) + allocate(stream_varnames_gdd20_season_enddate(ncft)) do n = 1,ncft ivt = npcropmin + n - 1 write(stream_varnames_sdate(n),'(a,i0)') "sdate1_",ivt write(stream_varnames_cultivar_gdds(n),'(a,i0)') "gdd1_",ivt write(stream_varnames_gdd20_baseline(n),'(a,i0)') "gdd20bl_",ivt + write(stream_varnames_gdd20_season_enddate(n),'(a,i0)') "hdate1_",ivt end do ! Read cropcal_streams namelist @@ -158,6 +175,10 @@ subroutine cropcal_init(bounds) call shr_mpi_bcast(stream_fldFileName_cultivar_gdds, mpicom) call shr_mpi_bcast(stream_fldFileName_gdd20_baseline, mpicom) call shr_mpi_bcast(stream_meshfile_cropcal , mpicom) + call shr_mpi_bcast(stream_gdd20_seasons, mpicom) + call shr_mpi_bcast(allow_invalid_gdd20_season_inputs, mpicom) + call shr_mpi_bcast(stream_fldFileName_gdd20_season_start, mpicom) + call shr_mpi_bcast(stream_fldFileName_gdd20_season_end, mpicom) if (masterproc) then write(iulog,*) @@ -174,9 +195,14 @@ subroutine cropcal_init(bounds) write(iulog,'(a,a)' ) ' stream_fldFileName_cultivar_gdds = ',trim(stream_fldFileName_cultivar_gdds) write(iulog,'(a,a)' ) ' stream_fldFileName_gdd20_baseline = ',trim(stream_fldFileName_gdd20_baseline) write(iulog,'(a,a)' ) ' stream_meshfile_cropcal = ',trim(stream_meshfile_cropcal) + write(iulog,'(a,l1)') ' stream_gdd20_seasons = ',stream_gdd20_seasons + write(iulog,'(a,l1)') ' allow_invalid_gdd20_season_inputs = ',allow_invalid_gdd20_season_inputs + write(iulog,'(a,a)' ) ' stream_fldFileName_gdd20_season_start = ',stream_fldFileName_gdd20_season_start + write(iulog,'(a,a)' ) ' stream_fldFileName_gdd20_season_end = ',stream_fldFileName_gdd20_season_end do n = 1,ncft write(iulog,'(a,a)' ) ' stream_varnames_sdate = ',trim(stream_varnames_sdate(n)) write(iulog,'(a,a)' ) ' stream_varnames_cultivar_gdds = ',trim(stream_varnames_cultivar_gdds(n)) + write(iulog,'(a,a)' ) ' stream_varnames_gdd20_season_enddate = ',trim(stream_varnames_gdd20_season_enddate(n)) write(iulog,'(a,a)' ) ' stream_varnames_gdd20_baseline = ',trim(stream_varnames_gdd20_baseline(n)) end do write(iulog,*) @@ -304,6 +330,65 @@ subroutine cropcal_init(bounds) end if end if + if (stream_gdd20_seasons) then + ! Initialize the cdeps data type sdat_cropcal_gdd20_season_start + ! NOTE: Hard-coded to one particular year because it should NOT vary over time. Note that the + ! particular year chosen doesn't matter. + call shr_strdata_init_from_inline(sdat_cropcal_gdd20_season_start, & + my_task = iam, & + logunit = iulog, & + compname = 'LND', & + model_clock = model_clock, & + model_mesh = mesh, & + stream_meshfile = trim(stream_meshfile_cropcal), & + stream_lev_dimname = 'null', & + stream_mapalgo = trim(cropcal_mapalgo), & + stream_filenames = (/trim(stream_fldFileName_gdd20_season_start)/), & + stream_fldlistFile = stream_varnames_sdate, & + stream_fldListModel = stream_varnames_sdate, & + stream_yearFirst = 2000, & + stream_yearLast = 2000, & + stream_yearAlign = 2000, & + stream_offset = cropcal_offset, & + stream_taxmode = 'extend', & + stream_dtlimit = 1.0e30_r8, & + stream_tintalgo = cropcal_tintalgo, & + stream_name = 'gdd20 season start data', & + rc = rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! Initialize the cdeps data type sdat_cropcal_gdd20_season_end + ! NOTE: Hard-coded to one particular year because it should NOT vary over time. Note that the + ! particular year chosen doesn't matter. + call shr_strdata_init_from_inline(sdat_cropcal_gdd20_season_end, & + my_task = iam, & + logunit = iulog, & + compname = 'LND', & + model_clock = model_clock, & + model_mesh = mesh, & + stream_meshfile = trim(stream_meshfile_cropcal), & + stream_lev_dimname = 'null', & + stream_mapalgo = trim(cropcal_mapalgo), & + stream_filenames = (/trim(stream_fldFileName_gdd20_season_end)/), & + stream_fldlistFile = stream_varnames_gdd20_season_enddate, & + stream_fldListModel = stream_varnames_gdd20_season_enddate, & + stream_yearFirst = 2000, & + stream_yearLast = 2000, & + stream_yearAlign = 2000, & + stream_offset = cropcal_offset, & + stream_taxmode = 'extend', & + stream_dtlimit = 1.0e30_r8, & + stream_tintalgo = cropcal_tintalgo, & + stream_name = 'gdd20 season start data', & + rc = rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + end if + end subroutine cropcal_init !================================================================ @@ -347,7 +432,10 @@ subroutine cropcal_advance( bounds ) end if end if - ! GDD20 baseline values do not have an associated time axis and thus will not be advanced here + ! The following should not have an associated time axis and thus will not be advanced here: + ! - GDD20 baseline values + ! - GDD20 season start dates + ! - GDD20 season end dates if ( .not. allocated(g_to_ig) )then allocate (g_to_ig(bounds%begg:bounds%endg) ) @@ -393,15 +481,21 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) real(r8), pointer :: dataptr1d_swindow_end (:) real(r8), pointer :: dataptr1d_cultivar_gdds(:) real(r8), pointer :: dataptr1d_gdd20_baseline(:) + real(r8), pointer :: dataptr1d_gdd20_season_start(:) + real(r8), pointer :: dataptr1d_gdd20_season_end (:) real(r8), pointer :: dataptr2d_swindow_start(:,:) real(r8), pointer :: dataptr2d_swindow_end (:,:) real(r8), pointer :: dataptr2d_cultivar_gdds(:,:) real(r8), pointer :: dataptr2d_gdd20_baseline(:,:) + real(r8), pointer :: dataptr2d_gdd20_season_start(:,:) + real(r8), pointer :: dataptr2d_gdd20_season_end (:,:) !----------------------------------------------------------------------- associate( & - starts => crop_inst%rx_swindow_starts_thisyr_patch, & - ends => crop_inst%rx_swindow_ends_thisyr_patch & + swindow_starts => crop_inst%rx_swindow_starts_thisyr_patch, & + swindow_ends => crop_inst%rx_swindow_ends_thisyr_patch, & + gdd20_season_starts => crop_inst%gdd20_season_start_patch, & + gdd20_season_ends => crop_inst%gdd20_season_end_patch & ) SHR_ASSERT_FL( (lbound(g_to_ig,1) <= bounds%begg ), sourcefile, __LINE__) @@ -459,8 +553,8 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) n = ivt - npcropmin + 1 ! vegetated pft ig = g_to_ig(patch%gridcell(p)) - starts(p,1) = dataptr2d_swindow_start(ig,n) - ends(p,1) = dataptr2d_swindow_end (ig,n) + swindow_starts(p,1) = dataptr2d_swindow_start(ig,n) + swindow_ends(p,1) = dataptr2d_swindow_end (ig,n) else write(iulog,'(a,i0)') 'cropcal_interp(), prescribed sowing windows: Crop patch has ivt ',ivt call ESMF_Finalize(endflag=ESMF_END_ABORT) @@ -469,23 +563,23 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Ensure that, if mxsowings > 1, sowing windows are ordered such that ENDS are monotonically increasing. This is necessary because of how get_swindow() works. if (mxsowings > 1) then - if (any(ends(begp:endp,2:mxsowings) <= ends(begp:endp,1:mxsowings-1) .and. & - ends(begp:endp,2:mxsowings) >= 1)) then + if (any(swindow_ends(begp:endp,2:mxsowings) <= swindow_ends(begp:endp,1:mxsowings-1) .and. & + swindow_ends(begp:endp,2:mxsowings) >= 1)) then write(iulog, *) 'Sowing window inputs must be ordered such that end dates are monotonically increasing.' call ESMF_Finalize(endflag=ESMF_END_ABORT) end if end if ! Handle invalid sowing window values - if (any(starts(begp:endp,:) < 1 .or. ends(begp:endp,:) < 1)) then + if (any(swindow_starts(begp:endp,:) < 1 .or. swindow_ends(begp:endp,:) < 1)) then ! Fail if not allowing fallback to paramfile sowing windows - if ((.not. allow_invalid_swindow_inputs) .and. any(all(starts(begp:endp,:) < 1, dim=2) .and. patch%wtgcell > 0._r8 .and. patch%itype >= npcropmin)) then + if ((.not. allow_invalid_swindow_inputs) .and. any(all(swindow_starts(begp:endp,:) < 1, dim=2) .and. patch%wtgcell > 0._r8 .and. patch%itype >= npcropmin)) then write(iulog, *) 'At least one crop in one gridcell has invalid prescribed sowing window start date(s). To ignore and fall back to paramfile sowing windows, set allow_invalid_swindow_inputs to .true.' write(iulog, *) 'Affected crops:' do ivt = npcropmin, mxpft do fp = 1, num_pcropp p = filter_pcropp(fp) - if (ivt == patch%itype(p) .and. patch%wtgcell(p) > 0._r8 .and. all(starts(p,:) < 1)) then + if (ivt == patch%itype(p) .and. patch%wtgcell(p) > 0._r8 .and. all(swindow_starts(p,:) < 1)) then write(iulog, *) ' ',pftname(ivt),' (',ivt,')' exit ! Stop looking for patches of this type end if @@ -494,7 +588,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) call ESMF_Finalize(endflag=ESMF_END_ABORT) ! Fail if a sowing window start date is prescribed without an end date (or vice versa) - else if (any((starts(begp:endp,:) >= 1 .and. ends(begp:endp,:) < 1) .or. (starts(begp:endp,:) < 1 .and. ends(begp:endp,:) >= 1))) then + else if (any((swindow_starts(begp:endp,:) >= 1 .and. swindow_ends(begp:endp,:) < 1) .or. (swindow_starts(begp:endp,:) < 1 .and. swindow_ends(begp:endp,:) >= 1))) then write(iulog, *) 'Every prescribed sowing window start date must have a corresponding end date.' call ESMF_Finalize(endflag=ESMF_END_ABORT) end if @@ -613,6 +707,86 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) deallocate(dataptr2d_gdd20_baseline) + ! Read prescribed gdd20 season start dates from input files + allocate(dataptr2d_gdd20_season_start(lsize, ncft)) + dataptr2d_gdd20_season_start(:,:) = -1._r8 + allocate(dataptr2d_gdd20_season_end (lsize, ncft)) + dataptr2d_gdd20_season_end(:,:) = -1._r8 + if (stream_gdd20_seasons .and. init) then + ! Starting with npcropmin will skip generic crops + do n = 1, ncft + call dshr_fldbun_getFldPtr(sdat_cropcal_gdd20_season_start%pstrm(1)%fldbun_model, trim(stream_varnames_sdate(n)), & + fldptr1=dataptr1d_gdd20_season_start, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + call dshr_fldbun_getFldPtr(sdat_cropcal_gdd20_season_end%pstrm(1)%fldbun_model, trim(stream_varnames_gdd20_season_enddate(n)), & + fldptr1=dataptr1d_gdd20_season_end, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize + ! So an explicit loop is required here + do g = 1,lsize + + ! If read-in value is invalid, set to -1. Will be handled later in this subroutine. + if (dataptr1d_gdd20_season_start(g) <= 0 .or. dataptr1d_gdd20_season_start(g) > 366 & + .or. dataptr1d_gdd20_season_end(g) <= 0 .or. dataptr1d_gdd20_season_end(g) > 366) then + dataptr1d_gdd20_season_start(g) = -1 + dataptr1d_gdd20_season_end (g) = -1 + end if + + dataptr2d_gdd20_season_start(g,n) = dataptr1d_gdd20_season_start(g) + dataptr2d_gdd20_season_end (g,n) = dataptr1d_gdd20_season_end (g) + end do + end do + + ! Set gdd20 season for each gridcell/patch combination + do fp = 1, num_pcropp + p = filter_pcropp(fp) + ivt = patch%itype(p) + ! Will skip generic crops + if (ivt >= npcropmin) then + n = ivt - npcropmin + 1 + ! vegetated pft + ig = g_to_ig(patch%gridcell(p)) + gdd20_season_starts(p) = dataptr2d_gdd20_season_start(ig,n) + gdd20_season_ends(p) = dataptr2d_gdd20_season_end (ig,n) + else + write(iulog,'(a,i0)') 'cropcal_interp(), gdd20 seasons: Crop patch has ivt ',ivt + call ESMF_Finalize(endflag=ESMF_END_ABORT) + endif + end do + + ! Handle invalid gdd20 season values + if (any(gdd20_season_starts(begp:endp) < 1 .or. gdd20_season_ends(begp:endp) < 1)) then + ! Fail if not allowing fallback to paramfile sowing windows + if ((.not. allow_invalid_gdd20_season_inputs) .and. any(gdd20_season_starts(begp:endp) < 1 .and. patch%wtgcell(begp:endp) > 0._r8 .and. patch%itype(begp:endp) >= npcropmin)) then + write(iulog, *) 'At least one crop in one gridcell has invalid gdd20 season start date(s). To ignore and fall back to paramfile sowing windows, set allow_invalid_gdd20_season_inputs to .true.' + write(iulog, *) 'Affected crops:' + do ivt = npcropmin, mxpft + do fp = 1, num_pcropp + p = filter_pcropp(fp) + if (ivt == patch%itype(p) .and. patch%wtgcell(p) > 0._r8 .and. gdd20_season_starts(p) < 1) then + write(iulog, *) ' ',pftname(ivt),' (',ivt,')' + exit ! Stop looking for patches of this type + end if + end do + end do + call ESMF_Finalize(endflag=ESMF_END_ABORT) + + ! Fail if a gdd20 season start date is given without an end date (or vice versa) + else if (any((gdd20_season_starts(begp:endp) >= 1 .and. gdd20_season_ends(begp:endp) < 1) .or. (gdd20_season_starts(begp:endp) < 1 .and. gdd20_season_ends(begp:endp) >= 1))) then + write(iulog, *) 'Every gdd20 season start date must have a corresponding end date.' + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + end if + + end if ! stream_gdd20_seasons and init + deallocate(dataptr2d_gdd20_season_start) + deallocate(dataptr2d_gdd20_season_end) + + end associate end subroutine cropcal_interp diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 2a3cef4b8b..e660ab9d8d 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -1374,7 +1374,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call atm2lnd_inst%UpdateAccVars(bounds_proc) - call temperature_inst%UpdateAccVars(bounds_proc) + call temperature_inst%UpdateAccVars(bounds_proc, crop_inst) call canopystate_inst%UpdateAccVars(bounds_proc) From 0feff1f3d641ec47c616d41d8c6fe3e4b9208db1 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 31 May 2024 18:26:51 -0600 Subject: [PATCH 161/444] Fix check of invalid swindow inputs. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 8196ca1dfb..4c4925f88e 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -573,7 +573,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Handle invalid sowing window values if (any(swindow_starts(begp:endp,:) < 1 .or. swindow_ends(begp:endp,:) < 1)) then ! Fail if not allowing fallback to paramfile sowing windows - if ((.not. allow_invalid_swindow_inputs) .and. any(all(swindow_starts(begp:endp,:) < 1, dim=2) .and. patch%wtgcell > 0._r8 .and. patch%itype >= npcropmin)) then + if ((.not. allow_invalid_swindow_inputs) .and. any(all(swindow_starts(begp:endp,:) < 1, dim=2) .and. patch%wtgcell(begp:endp) > 0._r8 .and. patch%itype(begp:endp) >= npcropmin)) then write(iulog, *) 'At least one crop in one gridcell has invalid prescribed sowing window start date(s). To ignore and fall back to paramfile sowing windows, set allow_invalid_swindow_inputs to .true.' write(iulog, *) 'Affected crops:' do ivt = npcropmin, mxpft From 3729b6db9f2139399618e39c4c48084144eecf12 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 31 May 2024 22:35:35 -0600 Subject: [PATCH 162/444] Add RxCropCalsAdaptGGCMI testmod and test. --- cime_config/testdefs/testlist_clm.xml | 9 +++++++++ .../clm/RxCropCalsAdaptGGCMI/include_user_mods | 1 + .../testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm | 2 ++ 3 files changed, 12 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index bf763c4775..edb932d24e 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3737,5 +3737,14 @@ + + + + + + + + + diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/include_user_mods new file mode 100644 index 0000000000..af5fe8591e --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/include_user_mods @@ -0,0 +1 @@ +../RxCropCalsAdapt diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm new file mode 100644 index 0000000000..fa0e4ec663 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm @@ -0,0 +1,2 @@ + +stream_gdd20_seasons = .true. From d020eada257e99055b2b90600f78c630286492c1 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 09:10:40 -0600 Subject: [PATCH 163/444] Fix check that gdd20 season files are provided. --- bld/CLMBuildNamelist.pm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index dddd17ced9..d5c2ffd54f 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4188,14 +4188,17 @@ sub setup_logic_cropcal_streams { # Add defaults if reading gdd20 seasons from stream files my $stream_gdd20_seasons = $nl->get_value('stream_gdd20_seasons') ; - my $gdd20_season_start_file = $nl->get_value('stream_fldFileName_gdd20_season_start') ; - my $gdd20_season_end_file = $nl->get_value('stream_fldFileName_gdd20_season_end') ; if ( &value_is_true($stream_gdd20_seasons)) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_gdd20_season_start'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_gdd20_season_end'); # Check + my $gdd20_season_start_file = $nl->get_value('stream_fldFileName_gdd20_season_start') ; + my $gdd20_season_end_file = $nl->get_value('stream_fldFileName_gdd20_season_end') ; if ( &string_is_undef_or_empty($gdd20_season_start_file) or &string_is_undef_or_empty($gdd20_season_end_file) ) { + $log->message($gdd20_season_start_file); + $log->message('abcd'); + $log->message($gdd20_season_end_file); $log->fatal_error("If stream_gdd20_seasons is true, gdd20 season start and end files must be provided." ); } } From 42b0dbb9f7e02ab2138710904af129704867e466 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 09:11:09 -0600 Subject: [PATCH 164/444] Minor rearrangement in cropcal namelist definition. --- bld/namelist_files/namelist_definition_ctsm.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 036b9aca72..5b6dcef87e 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1838,16 +1838,16 @@ Filename of input stream data for cultivar growing degree-day targets Filename of input stream data for baseline GDD20 values - -Filename of input stream data for date (day of year) of start of gdd20 accumulation season. - - Set this to true to read gdd20 accumulation season start and end dates from stream files, rather than using hard-coded hemisphere-specific "warm seasons." + +Filename of input stream data for date (day of year) of start of gdd20 accumulation season. + + Filename of input stream data for date (day of year) of end of gdd20 accumulation season. From 92555b9c394a4542ff7412335a459dfab57a8979 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 12:13:20 -0600 Subject: [PATCH 165/444] generate_gdd20_baseline.py now saves NETCDF3_CLASSIC. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index d28bfda0e7..7b5fd625d6 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -226,7 +226,7 @@ def generate_gdd20_baseline(input_files, output_file, author): ds_out[var_out] = this_da # Save - ds_out.to_netcdf(output_file) + ds_out.to_netcdf(output_file, format="NETCDF3_CLASSIC") print("Done!") From 30eb31ce8e92a05bd104268e01e3d62b964ee486 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 12:16:49 -0600 Subject: [PATCH 166/444] Update default to point to classic version. --- bld/namelist_files/namelist_defaults_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 7e3ddb7c64..2683c2e535 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1705,7 +1705,7 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc -lnd/clm2/testdata/gdd20baseline.tmp_dontupload.nc +lnd/clm2/testdata/gdd20baseline.tmp_dontupload.classic.nc lnd/clm2/cropdata/calendars/processed/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc lnd/clm2/cropdata/calendars/processed/hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc From a6e2c1e23964b6e9c3bf35d1778a14187a0b62e9 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 12:59:29 -0600 Subject: [PATCH 167/444] Add allow_invalid_gdd20_season_inputs to namelist XML. --- bld/namelist_files/namelist_definition_ctsm.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 5b6dcef87e..675c912900 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1843,6 +1843,11 @@ Filename of input stream data for baseline GDD20 values Set this to true to read gdd20 accumulation season start and end dates from stream files, rather than using hard-coded hemisphere-specific "warm seasons." + +By default, a value in stream_fldFileName_gdd20_season_start or _end outside the range [1, 365] (or 366 in leap years) will cause the run to fail. Set this to .true. to instead have such cells fall back to the hard-coded hemisphere-specific "warm seasons." + + Filename of input stream data for date (day of year) of start of gdd20 accumulation season. From 9f04d71e0ac7f5e4f0bcadd195281dfcc2134f81 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 13:22:59 -0600 Subject: [PATCH 168/444] Update missing values from generate_gdd20_baseline.py. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 7b5fd625d6..fd56d61550 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -20,7 +20,8 @@ VAR_LIST_IN = ["GDD0", "GDD8", "GDD10"] VAR_LIST_IN = [x + "20" for x in VAR_LIST_IN] # TODO: Delete this once using the right variables -MISSING_FILL = -1 # Something negative to ensure that gddmaturity never changes (see PlantCrop) +MISSING_FILL = -1 # Something impossible to ensure that you can mark it as a missing value, to be +# bilinear-interpolated STREAM_YEAR = 2000 # The year specified for stream_yearFirst and stream_yearLast in the call of # shr_strdata_init_from_inline() for sdat_cropcal_gdd20_baseline @@ -211,7 +212,8 @@ def generate_gdd20_baseline(input_files, output_file, author): long_name = "Dummy GDD20" print(" dummy GDD20") else: - this_da = ds_in[gddn].fillna(MISSING_FILL) + # this_da = ds_in[gddn].fillna(MISSING_FILL) + this_da = ds_in[gddn] this_da = _add_time_axis(this_da) long_name = gddn print(f" {gddn}") @@ -219,6 +221,7 @@ def generate_gdd20_baseline(input_files, output_file, author): # Add attributes this_da.attrs["long_name"] = long_name + f" baseline for {cft_str}" this_da.attrs["units"] = "°C days" + # this_da.attrs["_FillValue"] = MISSING_FILL # Copy that to ds_out var_out = _get_output_varname(cft_str) From 625fd5e7b9eebc61bf8e93824e92a3079bf937cd Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 13:23:16 -0600 Subject: [PATCH 169/444] RxCropCalsAdaptGGCMI now uses allow_invalid_gdd20_season_inputs. --- .../testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm index fa0e4ec663..42e57a675c 100644 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm @@ -1,2 +1,4 @@ stream_gdd20_seasons = .true. +!TODO SSR: Try without this once you have half-degree inputs +allow_invalid_gdd20_season_inputs = .true. From 0156d1aa928f5bc002c1eb8508962138c76f4a1d Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 13:25:02 -0600 Subject: [PATCH 170/444] Move hist_addfld1d() for GDD0 to be with its siblings. --- src/biogeophys/TemperatureType.F90 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 31fba16274..89dfd11074 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -597,9 +597,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) call hist_addfld1d (fname='GDD0', units='ddays', & avgflag='A', long_name='Growing degree days base 0C from planting', & ptr_patch=this%gdd0_patch, default='inactive') - end if - if (use_crop) then this%gdd8_patch(begp:endp) = spval call hist_addfld1d (fname='GDD8', units='ddays', & avgflag='A', long_name='Growing degree days base 8C from planting', & From b7c34ffcd7b4421f5266051d3bb7aeef2f790744 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 13:34:16 -0600 Subject: [PATCH 171/444] Add max versions of GDD season accum outputs. --- src/biogeophys/TemperatureType.F90 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 89dfd11074..f8d5206a1e 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -608,6 +608,21 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) avgflag='A', long_name='Growing degree days base 10C from planting', & ptr_patch=this%gdd10_patch, default='inactive') + this%gdd0_patch(begp:endp) = spval + call hist_addfld1d (fname='GDD0X', units='ddays', & + avgflag='X', long_name='Growing degree days base 0C from planting, max', & + ptr_patch=this%gdd0_patch, default='inactive') + + this%gdd8_patch(begp:endp) = spval + call hist_addfld1d (fname='GDD8X', units='ddays', & + avgflag='X', long_name='Growing degree days base 8C from planting, max', & + ptr_patch=this%gdd8_patch, default='inactive') + + this%gdd10_patch(begp:endp) = spval + call hist_addfld1d (fname='GDD10X', units='ddays', & + avgflag='X', long_name='Growing degree days base 10C from planting, max', & + ptr_patch=this%gdd10_patch, default='inactive') + this%gdd020_patch(begp:endp) = spval call hist_addfld1d (fname='GDD020', units='ddays', & avgflag='A', long_name='Twenty year average of growing degree days base 0C from planting', & From 535e2c5a43f309ea3bbe8eb851c963ee7cb33dcf Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 17:01:44 -0600 Subject: [PATCH 172/444] Even gdd20 files need to be advance()d. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 4c4925f88e..faa13b5fda 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -432,10 +432,26 @@ subroutine cropcal_advance( bounds ) end if end if - ! The following should not have an associated time axis and thus will not be advanced here: + ! The following should not have an associated time axis, but still need to be here ! - GDD20 baseline values ! - GDD20 season start dates ! - GDD20 season end dates + if (adapt_cropcal_rx_cultivar_gdds) then + call shr_strdata_advance(sdat_cropcal_gdd20_baseline, ymd=mcdate, tod=sec, logunit=iulog, istr='cropcaldyn', rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + end if + if (stream_gdd20_seasons) then + call shr_strdata_advance(sdat_cropcal_gdd20_season_start, ymd=mcdate, tod=sec, logunit=iulog, istr='cropcaldyn', rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + call shr_strdata_advance(sdat_cropcal_gdd20_season_end, ymd=mcdate, tod=sec, logunit=iulog, istr='cropcaldyn', rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + end if if ( .not. allocated(g_to_ig) )then allocate (g_to_ig(bounds%begg:bounds%endg) ) From 3e524db1aa4f34a70cd08c48c740c8c35033db9d Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 17:03:43 -0600 Subject: [PATCH 173/444] generate_gdd20_baseline.py now saves to double instead of float. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index fd56d61550..8cf30bf44d 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -197,6 +197,7 @@ def generate_gdd20_baseline(input_files, output_file, author): "created": dt.datetime.now().astimezone().isoformat(), }, ) + encoding_dict = {} for cft_str in utils.define_mgdcrop_list(): cft_int = utils.vegtype_str2int(cft_str)[0] print(f"{cft_str} ({cft_int})") @@ -227,9 +228,10 @@ def generate_gdd20_baseline(input_files, output_file, author): var_out = _get_output_varname(cft_str) print(f" Output variable {var_out}") ds_out[var_out] = this_da + encoding_dict[var_out] = {"dtype": "float64"} # Save - ds_out.to_netcdf(output_file, format="NETCDF3_CLASSIC") + ds_out.to_netcdf(output_file, format="NETCDF3_CLASSIC", encoding=encoding_dict) print("Done!") From 18df6b4a04ac901737ccb5d9b806619e66ebe532 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sat, 1 Jun 2024 17:06:19 -0600 Subject: [PATCH 174/444] stream_fldFileName_gdd20_baseline now defaults to half-deg fake file. --- bld/namelist_files/namelist_defaults_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 2683c2e535..bd5f7132ca 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1705,7 +1705,7 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc -lnd/clm2/testdata/gdd20baseline.tmp_dontupload.classic.nc +lnd/clm2/cropdata/calendars/processed/gdd20bl.copied_from.gdds_20230829_161011.nc lnd/clm2/cropdata/calendars/processed/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc lnd/clm2/cropdata/calendars/processed/hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc From a3feed96de079cdc04f42e60a5cfc4ff22959606 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sun, 2 Jun 2024 08:25:06 -0600 Subject: [PATCH 175/444] Use fixed gdd20 baseline file. --- bld/namelist_files/namelist_defaults_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index bd5f7132ca..8ed75be01a 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1705,7 +1705,7 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc -lnd/clm2/cropdata/calendars/processed/gdd20bl.copied_from.gdds_20230829_161011.nc +lnd/clm2/cropdata/calendars/processed/gdd20bl.copied_from.gdds_20230829_161011.v2.nc lnd/clm2/cropdata/calendars/processed/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc lnd/clm2/cropdata/calendars/processed/hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc From 5144b36a7993ae6363bd8bb16b41219ed3e032ed Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 3 Jun 2024 10:58:43 -0600 Subject: [PATCH 176/444] gdd20 baseline now interpolated w/ nearest-neighbor. Revert this! --- src/cpl/share_esmf/cropcalStreamMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index faa13b5fda..ce595c0d70 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -312,7 +312,7 @@ subroutine cropcal_init(bounds) model_mesh = mesh, & stream_meshfile = trim(stream_meshfile_cropcal), & stream_lev_dimname = 'null', & - stream_mapalgo = 'bilinear', & + stream_mapalgo = 'nn', & stream_filenames = (/trim(stream_fldFileName_gdd20_baseline)/), & stream_fldlistFile = stream_varnames_gdd20_baseline, & stream_fldListModel = stream_varnames_gdd20_baseline, & From 90b938b5bbf8bc3e13d86e1211bb9519409b477d Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 3 Jun 2024 10:59:37 -0600 Subject: [PATCH 177/444] generate_gdd20_nbaseline: Use GDDNX. --- .../ctsm/crop_calendars/generate_gdd20_baseline.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 8cf30bf44d..7f60fb6a68 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -18,8 +18,7 @@ from ctsm.crop_calendars.import_ds import import_ds import ctsm.crop_calendars.cropcal_utils as utils -VAR_LIST_IN = ["GDD0", "GDD8", "GDD10"] -VAR_LIST_IN = [x + "20" for x in VAR_LIST_IN] # TODO: Delete this once using the right variables +VAR_LIST_IN = ["GDD0X", "GDD8X", "GDD10X"] MISSING_FILL = -1 # Something impossible to ensure that you can mark it as a missing value, to be # bilinear-interpolated STREAM_YEAR = 2000 # The year specified for stream_yearFirst and stream_yearLast in the call of @@ -111,26 +110,25 @@ def _get_gddn_for_cft(cft_str): cft_str (str): E.g., "irrigated_temperate_corn" Returns: - str or None: Name of variable to use (e.g., "GDD8"). If crop isn't yet handled, return None. + str or None: Name of variable to use (e.g., "GDD8X"). If crop isn't yet handled, return None. """ gddn = None gdd0_list_str = ["wheat", "cotton", "rice"] if cft_str in _get_cft_list(gdd0_list_str): - gddn = "GDD0" + gddn = 0 gdd8_list_str = ["corn", "sugarcane", "miscanthus", "switchgrass"] if cft_str in _get_cft_list(gdd8_list_str): - gddn = "GDD8" + gddn = 8 gdd10_list_str = ["soybean"] if cft_str in _get_cft_list(gdd10_list_str): - gddn = "GDD10" + gddn = 10 - # TODO: Delete this once using the right variables if gddn is not None: - gddn += "20" + gddn = f"GDD{gddn}X" return gddn From e82679df56e1a514f28ee4a38ae4d9c9b581b120 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 3 Jun 2024 11:25:37 -0600 Subject: [PATCH 178/444] generate_gdd20_baseline: Grid, if needed. --- .../ctsm/crop_calendars/generate_gdd20_baseline.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 7f60fb6a68..71125e332d 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -17,8 +17,10 @@ # pylint: disable=wrong-import-position from ctsm.crop_calendars.import_ds import import_ds import ctsm.crop_calendars.cropcal_utils as utils +from ctsm.crop_calendars.grid_one_variable import grid_one_variable VAR_LIST_IN = ["GDD0X", "GDD8X", "GDD10X"] +GRIDDING_VAR_LIST = ["patches1d_ixy", "patches1d_jxy", "lat", "lon"] MISSING_FILL = -1 # Something impossible to ensure that you can mark it as a missing value, to be # bilinear-interpolated STREAM_YEAR = 2000 # The year specified for stream_yearFirst and stream_yearLast in the call of @@ -171,7 +173,7 @@ def generate_gdd20_baseline(input_files, output_file, author): input_files.sort() # Import history files and ensure they have lat/lon dims - ds_in = import_ds(input_files, VAR_LIST_IN) + ds_in = import_ds(input_files, VAR_LIST_IN + GRIDDING_VAR_LIST) if not all(x in ds_in.dims for x in ["lat", "lon"]): raise RuntimeError("Input files must have lat and lon dimensions") @@ -188,8 +190,11 @@ def generate_gdd20_baseline(input_files, output_file, author): dummy_da = _add_time_axis(dummy_da) # Process all crops + data_var_dict = {} + for v in GRIDDING_VAR_LIST: + data_var_dict[v] = ds_in[v] ds_out = xr.Dataset( - data_vars=None, + data_vars=data_var_dict, attrs={ "author": author, "created": dt.datetime.now().astimezone().isoformat(), @@ -228,6 +233,10 @@ def generate_gdd20_baseline(input_files, output_file, author): ds_out[var_out] = this_da encoding_dict[var_out] = {"dtype": "float64"} + # Grid, if needed + if any(x not in this_da.dims for x in ["lat", "lon"]): + ds_out[var_out] = grid_one_variable(ds_out, var_out) + # Save ds_out.to_netcdf(output_file, format="NETCDF3_CLASSIC", encoding=encoding_dict) From 8b43fec5168d56df1b7c5ac6e22635d70024c3b0 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 3 Jun 2024 11:28:32 -0600 Subject: [PATCH 179/444] generate_gdd20_baseline: Improve long names. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 71125e332d..89a38a0a08 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -219,7 +219,7 @@ def generate_gdd20_baseline(input_files, output_file, author): # this_da = ds_in[gddn].fillna(MISSING_FILL) this_da = ds_in[gddn] this_da = _add_time_axis(this_da) - long_name = gddn + long_name = gddn.replace("X", "20") print(f" {gddn}") # Add attributes From dcacbd4003585edf1a8608bc9d70232285f01202 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 3 Jun 2024 11:47:38 -0600 Subject: [PATCH 180/444] Minor cleanup in UpdateAccVars_CropGDDs. --- src/biogeophys/TemperatureType.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index f8d5206a1e..5ae0b7b20c 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -1428,11 +1428,11 @@ subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, d ((month > 9 .or. month < 4) .and. lat < 0._r8) ! Replace with read-in gdd20 accumulation season, if valid ! (If these aren't being read in or they're invalid, they'll be -1) - gdd20_season_start = crop_inst%gdd20_season_start_patch(p) - gdd20_season_end = crop_inst%gdd20_season_end_patch(p) + gdd20_season_start = gdd20_season_starts(p) + gdd20_season_end = gdd20_season_ends(p) if (gdd20_season_start >= 1 .and. gdd20_season_end >= 1) then in_accumulation_season = is_doy_in_interval( & - gdd20_season_starts(p), gdd20_season_ends(p), day) + gdd20_season_start, gdd20_season_end, day) end if if (month==1 .and. day==1 .and. secs==dtime) then From 2cf491da0127f1caeec5ae6d7152d637f2975599 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 3 Jun 2024 11:53:44 -0600 Subject: [PATCH 181/444] Add outputs: GDD20_BASELINE, GDD20_SEASON_START/END. --- src/biogeochem/CropType.F90 | 28 +++++++++++++++++++++---- src/biogeophys/TemperatureType.F90 | 5 +++-- src/cpl/share_esmf/cropcalStreamMod.F90 | 18 ++++++++++------ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/biogeochem/CropType.F90 b/src/biogeochem/CropType.F90 index 04806f9349..fdfdaa05aa 100644 --- a/src/biogeochem/CropType.F90 +++ b/src/biogeochem/CropType.F90 @@ -53,8 +53,11 @@ module CropType integer , pointer :: rx_swindow_ends_thisyr_patch (:,:) ! all prescribed sowing window end dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: rx_cultivar_gdds_thisyr_patch (:,:) ! all cultivar GDD targets for this patch this year (ddays) [patch, mxsowings] real(r8), pointer :: gdd20_baseline_patch (:) ! GDD20 baseline for this patch (ddays) [patch] - integer , pointer :: gdd20_season_start_patch(:) ! gdd20 season start date for this patch (day of year) [patch] - integer , pointer :: gdd20_season_end_patch (:) ! gdd20 season end date for this patch (day of year) [patch] + + ! REAL FOR DEVELOPMENT ONLY; REVERT TO INTEGER BEFORE MERGE + real(r8), pointer :: gdd20_season_start_patch(:) ! gdd20 season start date for this patch (day of year) [patch] + real(r8), pointer :: gdd20_season_end_patch (:) ! gdd20 season end date for this patch (day of year) [patch] + real(r8), pointer :: sdates_thisyr_patch (:,:) ! all actual sowing dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: swindow_starts_thisyr_patch(:,:) ! all sowing window start dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: swindow_ends_thisyr_patch (:,:) ! all sowing window end dates for this patch this year (day of year) [patch, mxsowings] @@ -239,8 +242,11 @@ subroutine InitAllocate(this, bounds) allocate(this%rx_swindow_ends_thisyr_patch(begp:endp,1:mxsowings)) ; this%rx_swindow_ends_thisyr_patch (:,:) = -1 allocate(this%rx_cultivar_gdds_thisyr_patch(begp:endp,1:mxsowings)) ; this%rx_cultivar_gdds_thisyr_patch(:,:) = spval allocate(this%gdd20_baseline_patch(begp:endp)) ; this%gdd20_baseline_patch(:) = spval - allocate(this%gdd20_season_start_patch(begp:endp)); this%gdd20_season_start_patch(:) = -1 - allocate(this%gdd20_season_end_patch(begp:endp)) ; this%gdd20_season_end_patch (:) = -1 + + ! REAL FOR DEVELOPMENT ONLY; REVERT TO INTEGER BEFORE MERGE + allocate(this%gdd20_season_start_patch(begp:endp)); this%gdd20_season_start_patch(:) = spval + allocate(this%gdd20_season_end_patch(begp:endp)) ; this%gdd20_season_end_patch (:) = spval + allocate(this%sdates_thisyr_patch(begp:endp,1:mxsowings)) ; this%sdates_thisyr_patch(:,:) = spval allocate(this%swindow_starts_thisyr_patch(begp:endp,1:mxsowings)) ; this%swindow_starts_thisyr_patch(:,:) = spval allocate(this%swindow_ends_thisyr_patch (begp:endp,1:mxsowings)) ; this%swindow_ends_thisyr_patch (:,:) = spval @@ -364,6 +370,20 @@ subroutine InitHistory(this, bounds) avgflag='I', long_name='Reason for each crop harvest; should only be output annually', & ptr_patch=this%harvest_reason_thisyr_patch, default='inactive') + ! DEVELOPMENT ONLY; DELETE BEFORE MERGE + this%gdd20_baseline_patch(begp:endp) = spval + call hist_addfld1d (fname='GDD20_BASELINE', units='ddays', & + avgflag='A', long_name='Baseline mean growing-degree days accumulated during accumulation period (from input)', & + ptr_patch=this%gdd20_baseline_patch, default='inactive') + this%gdd20_season_start_patch(begp:endp) = spval + call hist_addfld1d (fname='GDD20_SEASON_START', units='day of year', & + avgflag='A', long_name='Start of the GDD20 accumulation season (from input)', & + ptr_patch=this%gdd20_season_start_patch, default='inactive') + this%gdd20_season_end_patch(begp:endp) = spval + call hist_addfld1d (fname='GDD20_SEASON_END', units='day of year', & + avgflag='A', long_name='End of the GDD20 accumulation season (from input)', & + ptr_patch=this%gdd20_season_end_patch, default='inactive') + end subroutine InitHistory subroutine InitCold(this, bounds) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 5ae0b7b20c..ae5703237e 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -1428,8 +1428,9 @@ subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, d ((month > 9 .or. month < 4) .and. lat < 0._r8) ! Replace with read-in gdd20 accumulation season, if valid ! (If these aren't being read in or they're invalid, they'll be -1) - gdd20_season_start = gdd20_season_starts(p) - gdd20_season_end = gdd20_season_ends(p) + ! REAL FOR DEVELOPMENT ONLY; REVERT TO INTEGER BEFORE MERGE + gdd20_season_start = int(gdd20_season_starts(p)) + gdd20_season_end = int(gdd20_season_ends(p)) if (gdd20_season_start >= 1 .and. gdd20_season_end >= 1) then in_accumulation_season = is_doy_in_interval( & gdd20_season_start, gdd20_season_end, day) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index ce595c0d70..802b669905 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -766,8 +766,10 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) n = ivt - npcropmin + 1 ! vegetated pft ig = g_to_ig(patch%gridcell(p)) - gdd20_season_starts(p) = dataptr2d_gdd20_season_start(ig,n) - gdd20_season_ends(p) = dataptr2d_gdd20_season_end (ig,n) + + ! REAL FOR DEVELOPMENT ONLY; REVERT TO INTEGER BEFORE MERGE + gdd20_season_starts(p) = real(dataptr2d_gdd20_season_start(ig,n), r8) + gdd20_season_ends(p) = real(dataptr2d_gdd20_season_end (ig,n), r8) else write(iulog,'(a,i0)') 'cropcal_interp(), gdd20 seasons: Crop patch has ivt ',ivt call ESMF_Finalize(endflag=ESMF_END_ABORT) @@ -775,15 +777,18 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) end do ! Handle invalid gdd20 season values - if (any(gdd20_season_starts(begp:endp) < 1 .or. gdd20_season_ends(begp:endp) < 1)) then + ! gdd20_season_starts and gdd20_season_ends REAL FOR DEVELOPMENT ONLY; REVERT TO INTEGER BEFORE MERGE + if (any(gdd20_season_starts(begp:endp) < 1._r8 .or. gdd20_season_ends(begp:endp) < 1._r8)) then ! Fail if not allowing fallback to paramfile sowing windows - if ((.not. allow_invalid_gdd20_season_inputs) .and. any(gdd20_season_starts(begp:endp) < 1 .and. patch%wtgcell(begp:endp) > 0._r8 .and. patch%itype(begp:endp) >= npcropmin)) then + ! gdd20_season_starts REAL FOR DEVELOPMENT ONLY; REVERT TO INTEGER BEFORE MERGE + if ((.not. allow_invalid_gdd20_season_inputs) .and. any(gdd20_season_starts(begp:endp) < 1._r8 .and. patch%wtgcell(begp:endp) > 0._r8 .and. patch%itype(begp:endp) >= npcropmin)) then write(iulog, *) 'At least one crop in one gridcell has invalid gdd20 season start date(s). To ignore and fall back to paramfile sowing windows, set allow_invalid_gdd20_season_inputs to .true.' write(iulog, *) 'Affected crops:' do ivt = npcropmin, mxpft do fp = 1, num_pcropp p = filter_pcropp(fp) - if (ivt == patch%itype(p) .and. patch%wtgcell(p) > 0._r8 .and. gdd20_season_starts(p) < 1) then + ! gdd20_season_starts REAL FOR DEVELOPMENT ONLY; REVERT TO INTEGER BEFORE MERGE + if (ivt == patch%itype(p) .and. patch%wtgcell(p) > 0._r8 .and. gdd20_season_starts(p) < 1._r8) then write(iulog, *) ' ',pftname(ivt),' (',ivt,')' exit ! Stop looking for patches of this type end if @@ -792,7 +797,8 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) call ESMF_Finalize(endflag=ESMF_END_ABORT) ! Fail if a gdd20 season start date is given without an end date (or vice versa) - else if (any((gdd20_season_starts(begp:endp) >= 1 .and. gdd20_season_ends(begp:endp) < 1) .or. (gdd20_season_starts(begp:endp) < 1 .and. gdd20_season_ends(begp:endp) >= 1))) then + ! gdd20_season_starts and gdd20_season_ends REAL FOR DEVELOPMENT ONLY; REVERT TO INTEGER BEFORE MERGE + else if (any((gdd20_season_starts(begp:endp) >= 1._r8 .and. gdd20_season_ends(begp:endp) < 1._r8) .or. (gdd20_season_starts(begp:endp) < 1._r8 .and. gdd20_season_ends(begp:endp) >= 1._r8))) then write(iulog, *) 'Every gdd20 season start date must have a corresponding end date.' call ESMF_Finalize(endflag=ESMF_END_ABORT) end if From 0083a08432859948707cf4e8e7b4937dc7f1d92c Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 3 Jun 2024 12:03:15 -0600 Subject: [PATCH 182/444] rxcropmaturity.py is now parent rxcropmaturityshared.py. --- ...ropmaturity.py => rxcropmaturityshared.py} | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) rename cime_config/SystemTests/{rxcropmaturity.py => rxcropmaturityshared.py} (97%) diff --git a/cime_config/SystemTests/rxcropmaturity.py b/cime_config/SystemTests/rxcropmaturityshared.py similarity index 97% rename from cime_config/SystemTests/rxcropmaturity.py rename to cime_config/SystemTests/rxcropmaturityshared.py index 75fff8a0e0..f8e4b1c9bb 100644 --- a/cime_config/SystemTests/rxcropmaturity.py +++ b/cime_config/SystemTests/rxcropmaturityshared.py @@ -11,6 +11,10 @@ code do the interpolation. However, that wouldn't act on harvest dates (which are needed for generate_gdds.py). I could have Python interpolate those, but this would cause a potential inconsistency. + +Note that this is just a parent class. The actual tests are RXCROPMATURITY and +RXCROPMATURITY_SKIPRUN, the latter of which does everything except perform and +check the CTSM runs. """ import os @@ -25,7 +29,7 @@ logger = logging.getLogger(__name__) -class RXCROPMATURITY(SystemTestsCommon): +class RXCROPMATURITYSHARED(SystemTestsCommon): def __init__(self, case): # initialize an object interface to the SMS system test SystemTestsCommon.__init__(self, case) @@ -84,7 +88,7 @@ def __init__(self, case): # Which conda environment should we use? self._get_conda_env() - def run_phase(self): + def _run_phase(self, skip_run=False): # Modeling this after the SSP test, we create a clone to be the case whose outputs we don't # want to be saved as baseline. @@ -146,9 +150,10 @@ def run_phase(self): # "No history files expected, set suffix=None to avoid compare error" # We *do* expect history files here, but anyway. This works. self._skip_pnl = False - self.run_indv(suffix=None, st_archive=True) - self._run_generate_gdds(case_gddgen) + if not skip_run: + self.run_indv(suffix=None, st_archive=True) + self._run_generate_gdds(case_gddgen) # ------------------------------------------------------------------- # (3) Set up and perform Prescribed Calendars run @@ -168,13 +173,15 @@ def run_phase(self): ] ) - self.run_indv() + if not skip_run: + self.run_indv() # ------------------------------------------------------------------- # (4) Check Prescribed Calendars run # ------------------------------------------------------------------- logger.info("RXCROPMATURITY log: output check: Prescribed Calendars") - self._run_check_rxboth_run() + if not skip_run: + self._run_check_rxboth_run() # Get sowing and harvest dates for this resolution. def _get_rx_dates(self): From f728f9676e5103298dd255fcec2a6796d22e0144 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 3 Jun 2024 13:44:07 -0600 Subject: [PATCH 183/444] Added back RXCROPMATURITY. --- cime_config/SystemTests/rxcropmaturity.py | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 cime_config/SystemTests/rxcropmaturity.py diff --git a/cime_config/SystemTests/rxcropmaturity.py b/cime_config/SystemTests/rxcropmaturity.py new file mode 100644 index 0000000000..3eadccfeb3 --- /dev/null +++ b/cime_config/SystemTests/rxcropmaturity.py @@ -0,0 +1,5 @@ +from RXCROPMATURITYSHARED import RXCROPMATURITYSHARED + +class RXCROPMATURITY(RXCROPMATURITYSHARED): + def run_phase(self): + self._run_phase() \ No newline at end of file From e4b97a233cd722ab915a9b0be27f5ece509c8ca9 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 3 Jun 2024 13:44:51 -0600 Subject: [PATCH 184/444] Add RXCROPMATURITYSKIPRUN. --- cime_config/SystemTests/rxcropmaturityskiprun.py | 6 ++++++ cime_config/config_tests.xml | 10 ++++++++++ 2 files changed, 16 insertions(+) create mode 100644 cime_config/SystemTests/rxcropmaturityskiprun.py diff --git a/cime_config/SystemTests/rxcropmaturityskiprun.py b/cime_config/SystemTests/rxcropmaturityskiprun.py new file mode 100644 index 0000000000..d52742f95a --- /dev/null +++ b/cime_config/SystemTests/rxcropmaturityskiprun.py @@ -0,0 +1,6 @@ +print("pre-import") +from RXCROPMATURITYSHARED import RXCROPMATURITYSHARED + +class RXCROPMATURITYSKIPRUN(RXCROPMATURITYSHARED): + def run_phase(self): + self._run_phase(skip_run=True) \ No newline at end of file diff --git a/cime_config/config_tests.xml b/cime_config/config_tests.xml index c0b6afed9d..98434da10e 100644 --- a/cime_config/config_tests.xml +++ b/cime_config/config_tests.xml @@ -133,6 +133,16 @@ This defines various CTSM-specific system tests $STOP_N + + As RXCROPMATURITY but don't actually run or postprocess; just setup + 1 + FALSE + FALSE + never + $STOP_OPTION + $STOP_N + + lnd/clm2/surfdata_esmf/ctsm5.2.0/landuse.timeseries_1x1_smallvilleIA_SSP2-4.5_1850-1855_78pfts_c240221.nc + + + diff --git a/bld/namelist_files/namelist_defaults_overall.xml b/bld/namelist_files/namelist_defaults_overall.xml index 479b2a02b7..5b7ae1bdd9 100644 --- a/bld/namelist_files/namelist_defaults_overall.xml +++ b/bld/namelist_files/namelist_defaults_overall.xml @@ -62,6 +62,7 @@ determine default values for namelists. 1x1_urbanc_alpha 1x1_numaIA 1x1_smallvilleIA +1x1_cidadinhoBR 2000 @@ -110,6 +111,7 @@ determine default values for namelists. test navy test +test gx1v7 diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index b0ddb1e448..5c8aa3468d 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -1590,21 +1590,23 @@ sub cat_and_create_namelistinfile { print "==================================================\n"; # Check for crop resolutions -my $crop1850_res = "1x1_smallvilleIA"; -$options = "-bgc bgc -crop -res $crop1850_res -use_case 1850_control -envxml_dir ."; -&make_env_run(); -eval{ system( "$bldnml $options > $tempfile 2>&1 " ); }; -is( $@, '', "$options" ); -$cfiles->checkfilesexist( "$options", $mode ); -$cfiles->shownmldiff( "default", "standard" ); -if ( defined($opts{'compare'}) ) { - $cfiles->doNOTdodiffonfile( "$tempfile", "$options", $mode ); - $cfiles->comparefiles( "$options", $mode, $opts{'compare'} ); -} -if ( defined($opts{'generate'}) ) { - $cfiles->copyfiles( "$options", $mode ); +my @crop1850_res = ( "1x1_smallvilleIA", "1x1_cidadinhoBR" ); +foreach my $res ( @crop1850_res ) { + $options = "-bgc bgc -crop -res $res -use_case 1850_control -envxml_dir ."; + &make_env_run(); + eval{ system( "$bldnml $options > $tempfile 2>&1 " ); }; + is( $@, '', "$options" ); + $cfiles->checkfilesexist( "$options", $mode ); + $cfiles->shownmldiff( "default", "standard" ); + if ( defined($opts{'compare'}) ) { + $cfiles->doNOTdodiffonfile( "$tempfile", "$options", $mode ); + $cfiles->comparefiles( "$options", $mode, $opts{'compare'} ); + } + if ( defined($opts{'generate'}) ) { + $cfiles->copyfiles( "$options", $mode ); + } + &cleanup(); } -&cleanup(); my @crop_res = ( "1x1_numaIA", "4x5", "10x15", "0.9x1.25", "1.9x2.5", "ne3np4.pg3", "ne30np4", "ne30np4.pg3", "C96", "mpasa120" ); foreach my $res ( @crop_res ) { diff --git a/tools/mksurfdata_esmf/Makefile b/tools/mksurfdata_esmf/Makefile index d8bacdc5dd..c344843d06 100644 --- a/tools/mksurfdata_esmf/Makefile +++ b/tools/mksurfdata_esmf/Makefile @@ -54,7 +54,10 @@ SUBSETDATA_POINT_URBAN = $(SUBSETDATA_POINT) --include-nonveg # Subset data sites... SUBSETDATA_1X1_BRAZIL := --lat -7 --lon -55 --site 1x1_brazil SUBSETDATA_1X1_NUMAIA := --lat 40.6878 --lon 267.0228 --site 1x1_numaIA -SUBSETDATA_1X1_SMALL := --lat 40.6878 --lon 267.0228 --site 1x1_smallvilleIA \ +SUBSETDATA_1X1_SMALL_IA := --lat 40.6878 --lon 267.0228 --site 1x1_smallvilleIA \ + --dompft 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 \ + --pctpft 6.5 1.5 1.6 1.7 1.8 1.9 1.5 1.6 1.7 1.8 1.9 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 +SUBSETDATA_1X1_SMALL_BR := --lat -12.9952 --lon 305.3233 --site 1x1_cidadinhoBR \ --dompft 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 \ --pctpft 6.5 1.5 1.6 1.7 1.8 1.9 1.5 1.6 1.7 1.8 1.9 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.5 # NOTE: The 1850 smallvilleIA site is constructed to start with 100% natural vegetation, so we can test transition to crops @@ -112,6 +115,7 @@ all-subset : \ 1x1-smallville-present \ 1x1-smallville-1850 \ 1x1-smallville-transient \ + 1x1-cidadinho-present \ urban DEBUG: @@ -239,7 +243,7 @@ crop-global-hist-ne30 : FORCE $(SUBSETDATA_POINT_ALLLU) --create-surface $(SUBSETDATA_1X1_NUMAIA) 1x1-smallville-present : FORCE - $(SUBSETDATA_POINT) --create-surface $(SUBSETDATA_1X1_SMALL) + $(SUBSETDATA_POINT) --create-surface $(SUBSETDATA_1X1_SMALL_IA) # Note that the smallville 1850 dataset is entirely natural vegetation. This # facilitates testing a transient case that starts with no crop, and then later @@ -254,6 +258,9 @@ crop-global-hist-ne30 : FORCE $(SUBSETDATA_POINT) --create-landuse $(SUBSETDATA_1X1_SMALLTRANSIENT) ../modify_input_files/modify_smallville.sh +1x1-cidadinho-present : FORCE + $(SUBSETDATA_POINT) --create-surface $(SUBSETDATA_1X1_SMALL_BR) + # # Crop with future scenarios # From 46307bca0a850876c67a3041bf786a76441ca853 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 14 Jun 2024 14:19:01 -0600 Subject: [PATCH 236/444] generate_gdds: Don't fail if making figures but GDDHARV alll NaN. --- .../crop_calendars/generate_gdds_functions.py | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdds_functions.py b/python/ctsm/crop_calendars/generate_gdds_functions.py index 8af2fdc049..38c5d44384 100644 --- a/python/ctsm/crop_calendars/generate_gdds_functions.py +++ b/python/ctsm/crop_calendars/generate_gdds_functions.py @@ -575,6 +575,7 @@ def import_and_process_1yr( this_crop_gddaccum_da = this_crop_ds[clm_gdd_var] if save_figs: this_crop_gddharv_da = this_crop_ds["GDDHARV"] + check_gddharv = True if not this_crop_gddaccum_da.size: continue log(logger, f" {vegtype_str}...") @@ -625,11 +626,18 @@ def import_and_process_1yr( + "NaN after extracting GDDs accumulated at harvest", ) if save_figs and np.any(np.isnan(gddharv_atharv_p)): - log( - logger, - f" ❗ {np.sum(np.isnan(gddharv_atharv_p))}/{len(gddharv_atharv_p)} " - + "NaN after extracting GDDHARV", - ) + if np.all(np.isnan(gddharv_atharv_p)): + log( + logger, + " ❗ All GDDHARV are NaN; should only affect figure" + ) + check_gddharv = False + else: + log( + logger, + f" ❗ {np.sum(np.isnan(gddharv_atharv_p))}/{len(gddharv_atharv_p)} " + + "NaN after extracting GDDHARV", + ) # Assign these to growing seasons based on whether gs crossed new year this_year_active_patch_indices = [ @@ -712,7 +720,7 @@ def import_and_process_1yr( ) else: error(logger, "Unexpected NaN for last season's GDD accumulation.") - if save_figs and np.any( + if save_figs and check_gddharv and np.any( np.isnan( gddharv_yp_list[var][year_index - 1, active_this_year_where_gs_lastyr_indices] ) @@ -1160,9 +1168,13 @@ def make_figures( else: error(logger, f"layout {layout} not recognized") - this_min = int(np.round(np.nanmin(gddharv_map_yx))) - this_max = int(np.round(np.nanmax(gddharv_map_yx))) - this_title = f"{run1_name} (range {this_min}–{this_max})" + gddharv_all_nan = np.all(np.isnan(gddharv_map_yx.values)) + if gddharv_all_nan: + this_title = f"{run1_name} (GDDHARV all NaN?)" + else: + this_min = int(np.round(np.nanmin(gddharv_map_yx))) + this_max = int(np.round(np.nanmax(gddharv_map_yx))) + this_title = f"{run1_name} (range {this_min}–{this_max})" make_gengdd_map( this_axis, gddharv_map_yx, @@ -1195,7 +1207,7 @@ def make_figures( ) # Difference - if layout == "3x2": + if not gddharv_all_nan and layout == "3x2": this_axis = fig.add_subplot(spec[2, 0], projection=ccrs.PlateCarree()) this_min = int(np.round(np.nanmin(gdd_map_yx))) this_max = int(np.round(np.nanmax(gdd_map_yx))) From faa536eb00c0afb70cacce239423a5af82ccaf5a Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 14 Jun 2024 14:47:19 -0600 Subject: [PATCH 237/444] Revert "PlantCrop: GDD-gen runs get gddmaturity 1e36." GDD-generating runs should get the CLM default gddmaturity values. This reverts commit f2518b611408c12ae262c1b71b9b0a128196c934. --- src/biogeochem/CNPhenologyMod.F90 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index 41d4107f3f..b346cb119f 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -2694,10 +2694,7 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & ! set GDD target did_rx_gdds = .false. - if (generate_crop_gdds) then - ! Value mostly doesn't matter; it just needs to be large enough to avoid divide-by-zero errors. - gddmaturity(p) = 1.e36_r8 - else if (use_cropcal_rx_cultivar_gdds .and. crop_inst%rx_cultivar_gdds_thisyr_patch(p,sowing_count(p)) .ge. 0._r8) then + if (use_cropcal_rx_cultivar_gdds .and. crop_inst%rx_cultivar_gdds_thisyr_patch(p,sowing_count(p)) .ge. 0._r8) then gddmaturity(p) = crop_inst%rx_cultivar_gdds_thisyr_patch(p,sowing_count(p)) did_rx_gdds = .true. if (adapt_cropcal_rx_cultivar_gdds .and. crop_inst%gdd20_baseline_patch(p) > min_gdd20_baseline) then From 81177dd169e3c2f15f97a23216eb9793de4d8f3a Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 14 Jun 2024 16:10:34 -0600 Subject: [PATCH 238/444] Revert all RXCROPMATURITY changes. --- cime_config/SystemTests/rxcropmaturity.py | 445 ++++++++++++++++- .../SystemTests/rxcropmaturityshared.py | 459 ------------------ .../SystemTests/rxcropmaturityskipbuild.py | 9 - .../SystemTests/rxcropmaturityskiprun.py | 9 - cime_config/config_tests.xml | 20 - 5 files changed, 442 insertions(+), 500 deletions(-) delete mode 100644 cime_config/SystemTests/rxcropmaturityshared.py delete mode 100644 cime_config/SystemTests/rxcropmaturityskipbuild.py delete mode 100644 cime_config/SystemTests/rxcropmaturityskiprun.py diff --git a/cime_config/SystemTests/rxcropmaturity.py b/cime_config/SystemTests/rxcropmaturity.py index 206476f051..75fff8a0e0 100644 --- a/cime_config/SystemTests/rxcropmaturity.py +++ b/cime_config/SystemTests/rxcropmaturity.py @@ -1,5 +1,444 @@ -from rxcropmaturityshared import RXCROPMATURITYSHARED +""" +CTSM-specific test that first performs a GDD-generating run, then calls +Python code to generate the maturity requirement file. This is then used +in a sowing+maturity forced run, which finally is tested to ensure +correct behavior. + +Currently only supports 0.9x1.25, 1.9x2.5, and 10x15 resolutions. Eventually, +this test should be able to generate its own files at whatever resolution it's +called at. Well, really, the ultimate goal would be to give CLM the files +at the original resolution (for GGCMI phase 3, 0.5°) and have the stream +code do the interpolation. However, that wouldn't act on harvest dates +(which are needed for generate_gdds.py). I could have Python interpolate +those, but this would cause a potential inconsistency. +""" + +import os +import re +import systemtest_utils as stu +import subprocess +from CIME.SystemTests.system_tests_common import SystemTestsCommon +from CIME.XML.standard_module_setup import * +from CIME.SystemTests.test_utils.user_nl_utils import append_to_user_nl_files +import shutil, glob + +logger = logging.getLogger(__name__) + + +class RXCROPMATURITY(SystemTestsCommon): + def __init__(self, case): + # initialize an object interface to the SMS system test + SystemTestsCommon.__init__(self, case) + + # Ensure run length is at least 5 years. Minimum to produce one complete growing season (i.e., two complete calendar years) actually 4 years, but that only gets you 1 season usable for GDD generation, so you can't check for season-to-season consistency. + stop_n = self._case.get_value("STOP_N") + stop_option = self._case.get_value("STOP_OPTION") + stop_n_orig = stop_n + stop_option_orig = stop_option + if "nsecond" in stop_option: + stop_n /= 60 + stop_option = "nminutes" + if "nminute" in stop_option: + stop_n /= 60 + stop_option = "nhours" + if "nhour" in stop_option: + stop_n /= 24 + stop_option = "ndays" + if "nday" in stop_option: + stop_n /= 365 + stop_option = "nyears" + if "nmonth" in stop_option: + stop_n /= 12 + stop_option = "nyears" + error_message = None + if "nyear" not in stop_option: + error_message = ( + f"STOP_OPTION ({stop_option_orig}) must be nsecond(s), nminute(s), " + + "nhour(s), nday(s), nmonth(s), or nyear(s)" + ) + elif stop_n < 5: + error_message = ( + "RXCROPMATURITY must be run for at least 5 years; you requested " + + f"{stop_n_orig} {stop_option_orig[1:]}" + ) + if error_message is not None: + logger.error(error_message) + raise RuntimeError(error_message) + + # Get the number of complete years that will be run + self._run_Nyears = int(stop_n) + + # Only allow RXCROPMATURITY to be called with test cropMonthOutput + casebaseid = self._case.get_value("CASEBASEID") + if casebaseid.split("-")[-1] != "cropMonthOutput": + error_message = ( + "Only call RXCROPMATURITY with test cropMonthOutput " + + "to avoid potentially huge sets of daily outputs." + ) + logger.error(error_message) + raise RuntimeError(error_message) + + # Get files with prescribed sowing and harvest dates + self._get_rx_dates() + + # Which conda environment should we use? + self._get_conda_env() -class RXCROPMATURITY(RXCROPMATURITYSHARED): def run_phase(self): - self._run_phase() \ No newline at end of file + # Modeling this after the SSP test, we create a clone to be the case whose outputs we don't + # want to be saved as baseline. + + # ------------------------------------------------------------------- + # (1) Set up GDD-generating run + # ------------------------------------------------------------------- + # Create clone to be GDD-Generating case + logger.info("RXCROPMATURITY log: cloning setup") + case_rxboth = self._case + caseroot = self._case.get_value("CASEROOT") + clone_path = f"{caseroot}.gddgen" + self._path_gddgen = clone_path + if os.path.exists(self._path_gddgen): + shutil.rmtree(self._path_gddgen) + logger.info("RXCROPMATURITY log: cloning") + case_gddgen = self._case.create_clone(clone_path, keepexe=True) + logger.info("RXCROPMATURITY log: done cloning") + + os.chdir(self._path_gddgen) + self._set_active_case(case_gddgen) + + # Set up stuff that applies to both tests + self._setup_all() + + # Add stuff specific to GDD-Generating run + logger.info("RXCROPMATURITY log: modify user_nl files: generate GDDs") + self._append_to_user_nl_clm( + [ + "generate_crop_gdds = .true.", + "use_mxmat = .false.", + " ", + "! (h2) Daily outputs for GDD generation and figure-making", + "hist_fincl3 = 'GDDACCUM', 'GDDHARV'", + "hist_nhtfrq(3) = -24", + "hist_mfilt(3) = 365", + "hist_type1d_pertape(3) = 'PFTS'", + "hist_dov2xy(3) = .false.", + ] + ) + + # If flanduse_timeseries is defined, we need to make a static version for this test. This + # should have every crop in most of the world. + self._get_flanduse_timeseries_in(case_gddgen) + if self._flanduse_timeseries_in is not None: + + # Download files from the server, if needed + case_gddgen.check_all_input_data() + + # Make custom version of surface file + logger.info("RXCROPMATURITY log: run fsurdat_modifier") + self._run_fsurdat_modifier() + + # ------------------------------------------------------------------- + # (2) Perform GDD-generating run and generate prescribed GDDs file + # ------------------------------------------------------------------- + logger.info("RXCROPMATURITY log: Start GDD-Generating run") + + # As per SSP test: + # "No history files expected, set suffix=None to avoid compare error" + # We *do* expect history files here, but anyway. This works. + self._skip_pnl = False + self.run_indv(suffix=None, st_archive=True) + + self._run_generate_gdds(case_gddgen) + + # ------------------------------------------------------------------- + # (3) Set up and perform Prescribed Calendars run + # ------------------------------------------------------------------- + os.chdir(caseroot) + self._set_active_case(case_rxboth) + + # Set up stuff that applies to both tests + self._setup_all() + + # Add stuff specific to Prescribed Calendars run + logger.info("RXCROPMATURITY log: modify user_nl files: Prescribed Calendars") + self._append_to_user_nl_clm( + [ + "generate_crop_gdds = .false.", + f"stream_fldFileName_cultivar_gdds = '{self._gdds_file}'", + ] + ) + + self.run_indv() + + # ------------------------------------------------------------------- + # (4) Check Prescribed Calendars run + # ------------------------------------------------------------------- + logger.info("RXCROPMATURITY log: output check: Prescribed Calendars") + self._run_check_rxboth_run() + + # Get sowing and harvest dates for this resolution. + def _get_rx_dates(self): + # Eventually, I want to remove these hard-coded resolutions so that this test can generate + # its own sowing and harvest date files at whatever resolution is requested. + lnd_grid = self._case.get_value("LND_GRID") + input_data_root = self._case.get_value("DIN_LOC_ROOT") + processed_crop_dates_dir = f"{input_data_root}/lnd/clm2/cropdata/calendars/processed" + if lnd_grid == "10x15": + self._sdatefile = os.path.join( + processed_crop_dates_dir, + "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f10_f10_mg37.2000-2000.20230330_165301.nc", + ) + self._hdatefile = os.path.join( + processed_crop_dates_dir, + "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f10_f10_mg37.2000-2000.20230330_165301.nc", + ) + elif lnd_grid == "1.9x2.5": + self._sdatefile = os.path.join( + processed_crop_dates_dir, + "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f19_g17.2000-2000.20230102_175625.nc", + ) + self._hdatefile = os.path.join( + processed_crop_dates_dir, + "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f19_g17.2000-2000.20230102_175625.nc", + ) + elif lnd_grid == "0.9x1.25": + self._sdatefile = os.path.join( + processed_crop_dates_dir, + "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f09_g17.2000-2000.20230520_134417.nc", + ) + self._hdatefile = os.path.join( + processed_crop_dates_dir, + "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f09_g17.2000-2000.20230520_134418.nc", + ) + else: + error_message = "ERROR: RXCROPMATURITY currently only supports 0.9x1.25, 1.9x2.5, and 10x15 resolutions" + logger.error(error_message) + raise RuntimeError(error_message) + + # Ensure files exist + error_message = None + if not os.path.exists(self._sdatefile): + error_message = f"ERROR: Sowing date file not found: {self._sdatefile}" + elif not os.path.exists(self._hdatefile): + error_message = f"ERROR: Harvest date file not found: {self._sdatefile}" + if error_message is not None: + logger.error(error_message) + raise RuntimeError(error_message) + + def _setup_all(self): + logger.info("RXCROPMATURITY log: _setup_all start") + + # Get some info + self._ctsm_root = self._case.get_value("COMP_ROOT_DIR_LND") + run_startdate = self._case.get_value("RUN_STARTDATE") + self._run_startyear = int(run_startdate.split("-")[0]) + + # Set sowing dates file (and other crop calendar settings) for all runs + logger.info("RXCROPMATURITY log: modify user_nl files: all tests") + self._modify_user_nl_allruns() + logger.info("RXCROPMATURITY log: _setup_all done") + + # Make a surface dataset that has every crop in every gridcell + def _run_fsurdat_modifier(self): + + # fsurdat should be defined. Where is it? + self._fsurdat_in = None + with open(self._lnd_in_path, "r") as lnd_in: + for line in lnd_in: + fsurdat_in = re.match(r" *fsurdat *= *'(.*)'", line) + if fsurdat_in: + self._fsurdat_in = fsurdat_in.group(1) + break + if self._fsurdat_in is None: + error_message = "fsurdat not defined" + logger.error(error_message) + raise RuntimeError(error_message) + + # Where we will save the fsurdat version for this test + path, ext = os.path.splitext(self._fsurdat_in) + dir_in, filename_in_noext = os.path.split(path) + self._fsurdat_out = os.path.join( + self._path_gddgen, f"{filename_in_noext}.all_crops_everywhere{ext}" + ) + + # Make fsurdat for this test, if not already done + if not os.path.exists(self._fsurdat_out): + tool_path = os.path.join( + self._ctsm_root, + "tools", + "modify_input_files", + "fsurdat_modifier", + ) + + # Create configuration file for fsurdat_modifier + self._cfg_path = os.path.join( + self._path_gddgen, + "modify_fsurdat_allcropseverywhere.cfg", + ) + self._create_config_file_evenlysplitcrop() + + command = f"python3 {tool_path} {self._cfg_path} " + stu.run_python_script( + self._get_caseroot(), + self._this_conda_env, + command, + tool_path, + ) + + # Modify namelist + logger.info("RXCROPMATURITY log: modify user_nl files: new fsurdat") + self._append_to_user_nl_clm( + [ + "fsurdat = '{}'".format(self._fsurdat_out), + "do_transient_crops = .false.", + "flanduse_timeseries = ''", + "use_init_interp = .true.", + ] + ) + + def _create_config_file_evenlysplitcrop(self): + """ + Open the new and the template .cfg files + Loop line by line through the template .cfg file + When string matches, replace that line's content + """ + cfg_template_path = os.path.join( + self._ctsm_root, "tools/modify_input_files/modify_fsurdat_template.cfg" + ) + + with open(self._cfg_path, "w", encoding="utf-8") as cfg_out: + # Copy template, replacing some lines + with open(cfg_template_path, "r", encoding="utf-8") as cfg_in: + for line in cfg_in: + if re.match(r" *evenly_split_cropland *=", line): + line = f"evenly_split_cropland = True" + elif re.match(r" *fsurdat_in *=", line): + line = f"fsurdat_in = {self._fsurdat_in}" + elif re.match(r" *fsurdat_out *=", line): + line = f"fsurdat_out = {self._fsurdat_out}" + elif re.match(r" *process_subgrid_section *=", line): + line = f"process_subgrid_section = True" + cfg_out.write(line) + + # Add new lines + cfg_out.write("\n") + cfg_out.write("[modify_fsurdat_subgrid_fractions]\n") + cfg_out.write("PCT_CROP = 100.0\n") + cfg_out.write("PCT_NATVEG = 0.0\n") + cfg_out.write("PCT_GLACIER = 0.0\n") + cfg_out.write("PCT_WETLAND = 0.0\n") + cfg_out.write("PCT_LAKE = 0.0\n") + cfg_out.write("PCT_OCEAN = 0.0\n") + cfg_out.write("PCT_URBAN = 0.0 0.0 0.0\n") + + def _run_check_rxboth_run(self): + + output_dir = os.path.join(self._get_caseroot(), "run") + first_usable_year = self._run_startyear + 2 + last_usable_year = self._run_startyear + self._run_Nyears - 2 + + tool_path = os.path.join( + self._ctsm_root, "python", "ctsm", "crop_calendars", "check_rxboth_run.py" + ) + command = ( + f"python3 {tool_path} " + + f"--directory {output_dir} " + + f"-y1 {first_usable_year} " + + f"-yN {last_usable_year} " + + f"--rx-sdates-file {self._sdatefile} " + + f"--rx-gdds-file {self._gdds_file} " + ) + stu.run_python_script( + self._get_caseroot(), + self._this_conda_env, + command, + tool_path, + ) + + def _modify_user_nl_allruns(self): + nl_additions = [ + "stream_meshfile_cropcal = '{}'".format(self._case.get_value("LND_DOMAIN_MESH")), + "stream_fldFileName_swindow_start = '{}'".format(self._sdatefile), + "stream_fldFileName_swindow_end = '{}'".format(self._sdatefile), + "stream_year_first_cropcal_swindows = 2000", + "stream_year_last_cropcal_swindows = 2000", + "model_year_align_cropcal_swindows = 2000", + " ", + "! (h1) Annual outputs on sowing or harvest axis", + "hist_fincl2 = 'GRAINC_TO_FOOD_PERHARV', 'GRAINC_TO_FOOD_ANN', 'SDATES', 'SDATES_PERHARV', 'SYEARS_PERHARV', 'HDATES', 'GDDHARV_PERHARV', 'GDDACCUM_PERHARV', 'HUI_PERHARV', 'SOWING_REASON_PERHARV', 'HARVEST_REASON_PERHARV'", + "hist_nhtfrq(2) = 17520", + "hist_mfilt(2) = 999", + "hist_type1d_pertape(2) = 'PFTS'", + "hist_dov2xy(2) = .false.", + ] + self._append_to_user_nl_clm(nl_additions) + + def _run_generate_gdds(self, case_gddgen): + self._generate_gdds_dir = os.path.join(self._path_gddgen, "generate_gdds_out") + os.makedirs(self._generate_gdds_dir) + + # Get arguments to generate_gdds.py + dout_sr = case_gddgen.get_value("DOUT_S_ROOT") + input_dir = os.path.join(dout_sr, "lnd", "hist") + first_season = self._run_startyear + 2 + last_season = self._run_startyear + self._run_Nyears - 2 + sdates_file = self._sdatefile + hdates_file = self._hdatefile + + # It'd be much nicer to call generate_gdds.main(), but I can't import generate_gdds. + tool_path = os.path.join( + self._ctsm_root, "python", "ctsm", "crop_calendars", "generate_gdds.py" + ) + command = " ".join( + [ + f"python3 {tool_path}", + f"--input-dir {input_dir}", + f"--first-season {first_season}", + f"--last-season {last_season}", + f"--sdates-file {sdates_file}", + f"--hdates-file {hdates_file}", + f"--output-dir generate_gdds_out", + f"--skip-crops miscanthus,irrigated_miscanthus", + ] + ) + stu.run_python_script( + self._get_caseroot(), + self._this_conda_env, + command, + tool_path, + ) + + # Where were the prescribed maturity requirements saved? + generated_gdd_files = glob.glob(os.path.join(self._generate_gdds_dir, "gdds_*.nc")) + if len(generated_gdd_files) != 1: + error_message = f"ERROR: Expected one matching prescribed maturity requirements file; found {len(generated_gdd_files)}: {generated_gdd_files}" + logger.error(error_message) + raise RuntimeError(error_message) + self._gdds_file = generated_gdd_files[0] + + def _get_conda_env(self): + conda_setup_commands = stu.cmds_to_setup_conda(self._get_caseroot()) + + # If npl conda environment is available, use that (It has dask, which + # enables chunking, which makes reading daily 1-degree netCDF files + # much more efficient. + if "npl " in os.popen(conda_setup_commands + "conda env list").read(): + self._this_conda_env = "npl" + else: + self._this_conda_env = "ctsm_pylib" + + def _append_to_user_nl_clm(self, additions): + caseroot = self._get_caseroot() + append_to_user_nl_files(caseroot=caseroot, component="clm", contents=additions) + + # Is flanduse_timeseries defined? If so, where is it? + def _get_flanduse_timeseries_in(self, case): + case.create_namelists(component="lnd") + self._lnd_in_path = os.path.join(self._path_gddgen, "CaseDocs", "lnd_in") + self._flanduse_timeseries_in = None + with open(self._lnd_in_path, "r") as lnd_in: + for line in lnd_in: + flanduse_timeseries_in = re.match(r" *flanduse_timeseries *= *'(.*)'", line) + if flanduse_timeseries_in: + self._flanduse_timeseries_in = flanduse_timeseries_in.group(1) + break diff --git a/cime_config/SystemTests/rxcropmaturityshared.py b/cime_config/SystemTests/rxcropmaturityshared.py deleted file mode 100644 index 8a944efdf9..0000000000 --- a/cime_config/SystemTests/rxcropmaturityshared.py +++ /dev/null @@ -1,459 +0,0 @@ -""" -CTSM-specific test that first performs a GDD-generating run, then calls -Python code to generate the maturity requirement file. This is then used -in a sowing+maturity forced run, which finally is tested to ensure -correct behavior. - -Currently only supports 0.9x1.25, 1.9x2.5, and 10x15 resolutions. Eventually, -this test should be able to generate its own files at whatever resolution it's -called at. Well, really, the ultimate goal would be to give CLM the files -at the original resolution (for GGCMI phase 3, 0.5°) and have the stream -code do the interpolation. However, that wouldn't act on harvest dates -(which are needed for generate_gdds.py). I could have Python interpolate -those, but this would cause a potential inconsistency. - -Note that this is just a parent class. The actual tests are RXCROPMATURITY and -RXCROPMATURITY_SKIPRUN, the latter of which does everything except perform and -check the CTSM runs. -""" - -import os -import re -import systemtest_utils as stu -import subprocess -from CIME.SystemTests.system_tests_common import SystemTestsCommon -from CIME.XML.standard_module_setup import * -from CIME.SystemTests.test_utils.user_nl_utils import append_to_user_nl_files -import shutil, glob - -logger = logging.getLogger(__name__) - - -class RXCROPMATURITYSHARED(SystemTestsCommon): - def __init__(self, case): - # initialize an object interface to the SMS system test - SystemTestsCommon.__init__(self, case) - - # Ensure run length is at least 5 years. Minimum to produce one complete growing season (i.e., two complete calendar years) actually 4 years, but that only gets you 1 season usable for GDD generation, so you can't check for season-to-season consistency. - stop_n = self._case.get_value("STOP_N") - stop_option = self._case.get_value("STOP_OPTION") - stop_n_orig = stop_n - stop_option_orig = stop_option - if "nsecond" in stop_option: - stop_n /= 60 - stop_option = "nminutes" - if "nminute" in stop_option: - stop_n /= 60 - stop_option = "nhours" - if "nhour" in stop_option: - stop_n /= 24 - stop_option = "ndays" - if "nday" in stop_option: - stop_n /= 365 - stop_option = "nyears" - if "nmonth" in stop_option: - stop_n /= 12 - stop_option = "nyears" - error_message = None - if "nyear" not in stop_option: - error_message = ( - f"STOP_OPTION ({stop_option_orig}) must be nsecond(s), nminute(s), " - + "nhour(s), nday(s), nmonth(s), or nyear(s)" - ) - elif stop_n < 5: - error_message = ( - "RXCROPMATURITY must be run for at least 5 years; you requested " - + f"{stop_n_orig} {stop_option_orig[1:]}" - ) - if error_message is not None: - logger.error(error_message) - raise RuntimeError(error_message) - - # Get the number of complete years that will be run - self._run_Nyears = int(stop_n) - - # Only allow RXCROPMATURITY to be called with test cropMonthOutput - casebaseid = self._case.get_value("CASEBASEID") - if casebaseid.split("-")[-1] != "cropMonthOutput": - error_message = ( - "Only call RXCROPMATURITY with test cropMonthOutput " - + "to avoid potentially huge sets of daily outputs." - ) - logger.error(error_message) - raise RuntimeError(error_message) - - # Get files with prescribed sowing and harvest dates - self._get_rx_dates() - - # Which conda environment should we use? - self._get_conda_env() - - def _run_phase(self, skip_run=False): - # Modeling this after the SSP test, we create a clone to be the case whose outputs we don't - # want to be saved as baseline. - - # ------------------------------------------------------------------- - # (1) Set up GDD-generating run - # ------------------------------------------------------------------- - # Create clone to be GDD-Generating case - logger.info("RXCROPMATURITY log: cloning setup") - case_rxboth = self._case - caseroot = self._case.get_value("CASEROOT") - clone_path = f"{caseroot}.gddgen" - self._path_gddgen = clone_path - if os.path.exists(self._path_gddgen): - shutil.rmtree(self._path_gddgen) - logger.info("RXCROPMATURITY log: cloning") - case_gddgen = self._case.create_clone(clone_path, keepexe=True) - logger.info("RXCROPMATURITY log: done cloning") - - os.chdir(self._path_gddgen) - self._set_active_case(case_gddgen) - - # Set up stuff that applies to both tests - self._setup_all() - - # Add stuff specific to GDD-Generating run - logger.info("RXCROPMATURITY log: modify user_nl files: generate GDDs") - self._append_to_user_nl_clm( - [ - "generate_crop_gdds = .true.", - "stream_fldFileName_cultivar_gdds = ''", - "use_mxmat = .false.", - " ", - "! (h2) Daily outputs for GDD generation and figure-making", - "hist_fincl3 = 'GDDACCUM', 'GDDHARV'", - "hist_nhtfrq(3) = -24", - "hist_mfilt(3) = 365", - "hist_type1d_pertape(3) = 'PFTS'", - "hist_dov2xy(3) = .false.", - ] - ) - - # If flanduse_timeseries is defined, we need to make a static version for this test. This - # should have every crop in most of the world. - self._get_flanduse_timeseries_in(case_gddgen) - if self._flanduse_timeseries_in is not None: - - # Download files from the server, if needed - case_gddgen.check_all_input_data() - - # Copy needed file from original to gddgen directory - shutil.copyfile( - os.path.join(caseroot, ".env_mach_specific.sh"), - os.path.join(self._path_gddgen, ".env_mach_specific.sh"), - ) - - # Make custom version of surface file - logger.info("RXCROPMATURITY log: run fsurdat_modifier") - self._run_fsurdat_modifier() - - # ------------------------------------------------------------------- - # (2) Perform GDD-generating run and generate prescribed GDDs file - # ------------------------------------------------------------------- - logger.info("RXCROPMATURITY log: Start GDD-Generating run") - - # As per SSP test: - # "No history files expected, set suffix=None to avoid compare error" - # We *do* expect history files here, but anyway. This works. - self._skip_pnl = False - - if not skip_run: - self.run_indv(suffix=None, st_archive=True) - self._run_generate_gdds(case_gddgen) - - # ------------------------------------------------------------------- - # (3) Set up and perform Prescribed Calendars run - # ------------------------------------------------------------------- - os.chdir(caseroot) - self._set_active_case(case_rxboth) - - # Set up stuff that applies to both tests - self._setup_all() - - # Add stuff specific to Prescribed Calendars run - logger.info("RXCROPMATURITY log: modify user_nl files: Prescribed Calendars") - self._append_to_user_nl_clm( - [ - "generate_crop_gdds = .false.", - f"stream_fldFileName_cultivar_gdds = '{self._gdds_file}'", - ] - ) - - if not skip_run: - self.run_indv() - - # ------------------------------------------------------------------- - # (4) Check Prescribed Calendars run - # ------------------------------------------------------------------- - logger.info("RXCROPMATURITY log: output check: Prescribed Calendars") - if not skip_run: - self._run_check_rxboth_run() - - # Get sowing and harvest dates for this resolution. - def _get_rx_dates(self): - # Eventually, I want to remove these hard-coded resolutions so that this test can generate - # its own sowing and harvest date files at whatever resolution is requested. - lnd_grid = self._case.get_value("LND_GRID") - input_data_root = self._case.get_value("DIN_LOC_ROOT") - processed_crop_dates_dir = f"{input_data_root}/lnd/clm2/cropdata/calendars/processed" - if lnd_grid == "10x15": - self._sdatefile = os.path.join( - processed_crop_dates_dir, - "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f10_f10_mg37.2000-2000.20230330_165301.nc", - ) - self._hdatefile = os.path.join( - processed_crop_dates_dir, - "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f10_f10_mg37.2000-2000.20230330_165301.nc", - ) - elif lnd_grid == "1.9x2.5": - self._sdatefile = os.path.join( - processed_crop_dates_dir, - "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f19_g17.2000-2000.20230102_175625.nc", - ) - self._hdatefile = os.path.join( - processed_crop_dates_dir, - "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f19_g17.2000-2000.20230102_175625.nc", - ) - elif lnd_grid == "0.9x1.25": - self._sdatefile = os.path.join( - processed_crop_dates_dir, - "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f09_g17.2000-2000.20230520_134417.nc", - ) - self._hdatefile = os.path.join( - processed_crop_dates_dir, - "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f09_g17.2000-2000.20230520_134418.nc", - ) - else: - error_message = "ERROR: RXCROPMATURITY currently only supports 0.9x1.25, 1.9x2.5, and 10x15 resolutions" - logger.error(error_message) - raise RuntimeError(error_message) - - # Ensure files exist - error_message = None - if not os.path.exists(self._sdatefile): - error_message = f"ERROR: Sowing date file not found: {self._sdatefile}" - elif not os.path.exists(self._hdatefile): - error_message = f"ERROR: Harvest date file not found: {self._sdatefile}" - if error_message is not None: - logger.error(error_message) - raise RuntimeError(error_message) - - def _setup_all(self): - logger.info("RXCROPMATURITY log: _setup_all start") - - # Get some info - self._ctsm_root = self._case.get_value("COMP_ROOT_DIR_LND") - run_startdate = self._case.get_value("RUN_STARTDATE") - self._run_startyear = int(run_startdate.split("-")[0]) - - # Set sowing dates file (and other crop calendar settings) for all runs - logger.info("RXCROPMATURITY log: modify user_nl files: all tests") - self._modify_user_nl_allruns() - logger.info("RXCROPMATURITY log: _setup_all done") - - # Make a surface dataset that has every crop in every gridcell - def _run_fsurdat_modifier(self): - - # fsurdat should be defined. Where is it? - self._fsurdat_in = None - with open(self._lnd_in_path, "r") as lnd_in: - for line in lnd_in: - fsurdat_in = re.match(r" *fsurdat *= *'(.*)'", line) - if fsurdat_in: - self._fsurdat_in = fsurdat_in.group(1) - break - if self._fsurdat_in is None: - error_message = "fsurdat not defined" - logger.error(error_message) - raise RuntimeError(error_message) - - # Where we will save the fsurdat version for this test - path, ext = os.path.splitext(self._fsurdat_in) - dir_in, filename_in_noext = os.path.split(path) - self._fsurdat_out = os.path.join( - self._path_gddgen, f"{filename_in_noext}.all_crops_everywhere{ext}" - ) - - # Make fsurdat for this test, if not already done - if not os.path.exists(self._fsurdat_out): - tool_path = os.path.join( - self._ctsm_root, - "tools", - "modify_input_files", - "fsurdat_modifier", - ) - - # Create configuration file for fsurdat_modifier - self._cfg_path = os.path.join( - self._path_gddgen, - "modify_fsurdat_allcropseverywhere.cfg", - ) - self._create_config_file_evenlysplitcrop() - - command = f"python3 {tool_path} {self._cfg_path} " - stu.run_python_script( - self._get_caseroot(), - self._this_conda_env, - command, - tool_path, - ) - - # Modify namelist - logger.info("RXCROPMATURITY log: modify user_nl files: new fsurdat") - self._append_to_user_nl_clm( - [ - "fsurdat = '{}'".format(self._fsurdat_out), - "do_transient_crops = .false.", - "flanduse_timeseries = ''", - "use_init_interp = .true.", - ] - ) - - def _create_config_file_evenlysplitcrop(self): - """ - Open the new and the template .cfg files - Loop line by line through the template .cfg file - When string matches, replace that line's content - """ - cfg_template_path = os.path.join( - self._ctsm_root, "tools/modify_input_files/modify_fsurdat_template.cfg" - ) - - with open(self._cfg_path, "w", encoding="utf-8") as cfg_out: - # Copy template, replacing some lines - with open(cfg_template_path, "r", encoding="utf-8") as cfg_in: - for line in cfg_in: - if re.match(r" *evenly_split_cropland *=", line): - line = f"evenly_split_cropland = True" - elif re.match(r" *fsurdat_in *=", line): - line = f"fsurdat_in = {self._fsurdat_in}" - elif re.match(r" *fsurdat_out *=", line): - line = f"fsurdat_out = {self._fsurdat_out}" - elif re.match(r" *process_subgrid_section *=", line): - line = f"process_subgrid_section = True" - cfg_out.write(line) - - # Add new lines - cfg_out.write("\n") - cfg_out.write("[modify_fsurdat_subgrid_fractions]\n") - cfg_out.write("PCT_CROP = 100.0\n") - cfg_out.write("PCT_NATVEG = 0.0\n") - cfg_out.write("PCT_GLACIER = 0.0\n") - cfg_out.write("PCT_WETLAND = 0.0\n") - cfg_out.write("PCT_LAKE = 0.0\n") - cfg_out.write("PCT_OCEAN = 0.0\n") - cfg_out.write("PCT_URBAN = 0.0 0.0 0.0\n") - - def _run_check_rxboth_run(self): - - output_dir = os.path.join(self._get_caseroot(), "run") - first_usable_year = self._run_startyear + 2 - last_usable_year = self._run_startyear + self._run_Nyears - 2 - - tool_path = os.path.join( - self._ctsm_root, "python", "ctsm", "crop_calendars", "check_rxboth_run.py" - ) - command = ( - f"python3 {tool_path} " - + f"--directory {output_dir} " - + f"-y1 {first_usable_year} " - + f"-yN {last_usable_year} " - + f"--rx-sdates-file {self._sdatefile} " - + f"--rx-gdds-file {self._gdds_file} " - ) - stu.run_python_script( - self._get_caseroot(), - self._this_conda_env, - command, - tool_path, - ) - - def _modify_user_nl_allruns(self): - nl_additions = [ - "cropcals_rx = .true.", - "stream_meshfile_cropcal = '{}'".format(self._case.get_value("LND_DOMAIN_MESH")), - "stream_fldFileName_swindow_start = '{}'".format(self._sdatefile), - "stream_fldFileName_swindow_end = '{}'".format(self._sdatefile), - "stream_year_first_cropcal_swindows = 2000", - "stream_year_last_cropcal_swindows = 2000", - "model_year_align_cropcal_swindows = 2000", - " ", - "! (h1) Annual outputs on sowing or harvest axis", - "hist_fincl2 = 'GRAINC_TO_FOOD_PERHARV', 'GRAINC_TO_FOOD_ANN', 'SDATES', 'SDATES_PERHARV', 'SYEARS_PERHARV', 'HDATES', 'GDDHARV_PERHARV', 'GDDACCUM_PERHARV', 'HUI_PERHARV', 'SOWING_REASON_PERHARV', 'HARVEST_REASON_PERHARV'", - "hist_nhtfrq(2) = 17520", - "hist_mfilt(2) = 999", - "hist_type1d_pertape(2) = 'PFTS'", - "hist_dov2xy(2) = .false.", - ] - self._append_to_user_nl_clm(nl_additions) - - def _run_generate_gdds(self, case_gddgen): - self._generate_gdds_dir = os.path.join(self._path_gddgen, "generate_gdds_out") - os.makedirs(self._generate_gdds_dir) - - # Get arguments to generate_gdds.py - dout_sr = case_gddgen.get_value("DOUT_S_ROOT") - input_dir = os.path.join(dout_sr, "lnd", "hist") - first_season = self._run_startyear + 2 - last_season = self._run_startyear + self._run_Nyears - 2 - sdates_file = self._sdatefile - hdates_file = self._hdatefile - - # It'd be much nicer to call generate_gdds.main(), but I can't import generate_gdds. - tool_path = os.path.join( - self._ctsm_root, "python", "ctsm", "crop_calendars", "generate_gdds.py" - ) - command = " ".join( - [ - f"python3 {tool_path}", - f"--input-dir {input_dir}", - f"--first-season {first_season}", - f"--last-season {last_season}", - f"--sdates-file {sdates_file}", - f"--hdates-file {hdates_file}", - f"--output-dir generate_gdds_out", - f"--skip-crops miscanthus,irrigated_miscanthus", - ] - ) - stu.run_python_script( - self._get_caseroot(), - self._this_conda_env, - command, - tool_path, - ) - - # Where were the prescribed maturity requirements saved? - generated_gdd_files = glob.glob(os.path.join(self._generate_gdds_dir, "gdds_*.nc")) - if len(generated_gdd_files) != 1: - error_message = f"ERROR: Expected one matching prescribed maturity requirements file; found {len(generated_gdd_files)}: {generated_gdd_files}" - logger.error(error_message) - raise RuntimeError(error_message) - self._gdds_file = generated_gdd_files[0] - - def _get_conda_env(self): - conda_setup_commands = stu.cmds_to_setup_conda(self._get_caseroot()) - - # If npl conda environment is available, use that (It has dask, which - # enables chunking, which makes reading daily 1-degree netCDF files - # much more efficient. - if "npl " in os.popen(conda_setup_commands + "conda env list").read(): - self._this_conda_env = "npl" - else: - self._this_conda_env = "ctsm_pylib" - - def _append_to_user_nl_clm(self, additions): - caseroot = self._get_caseroot() - append_to_user_nl_files(caseroot=caseroot, component="clm", contents=additions) - - # Is flanduse_timeseries defined? If so, where is it? - def _get_flanduse_timeseries_in(self, case): - case.create_namelists(component="lnd") - self._lnd_in_path = os.path.join(self._path_gddgen, "CaseDocs", "lnd_in") - self._flanduse_timeseries_in = None - with open(self._lnd_in_path, "r") as lnd_in: - for line in lnd_in: - flanduse_timeseries_in = re.match(r" *flanduse_timeseries *= *'(.*)'", line) - if flanduse_timeseries_in: - self._flanduse_timeseries_in = flanduse_timeseries_in.group(1) - break diff --git a/cime_config/SystemTests/rxcropmaturityskipbuild.py b/cime_config/SystemTests/rxcropmaturityskipbuild.py deleted file mode 100644 index 4c3a69fb47..0000000000 --- a/cime_config/SystemTests/rxcropmaturityskipbuild.py +++ /dev/null @@ -1,9 +0,0 @@ -from rxcropmaturityshared import RXCROPMATURITYSHARED - -class RXCROPMATURITYSKIPBUILD(RXCROPMATURITYSHARED): - def build_indv(self, sharedlib_only=False, model_only=False): - self._case.set_value("BUILD_COMPLETE", "TRUE") - - - def run_phase(self): - self._run_phase(skip_run=False) \ No newline at end of file diff --git a/cime_config/SystemTests/rxcropmaturityskiprun.py b/cime_config/SystemTests/rxcropmaturityskiprun.py deleted file mode 100644 index 7fd217c4ff..0000000000 --- a/cime_config/SystemTests/rxcropmaturityskiprun.py +++ /dev/null @@ -1,9 +0,0 @@ -from rxcropmaturityshared import RXCROPMATURITYSHARED - -class RXCROPMATURITYSKIPRUN(RXCROPMATURITYSHARED): - def build_indv(self, sharedlib_only=False, model_only=False): - self._case.set_value("BUILD_COMPLETE", "TRUE") - - - def run_phase(self): - self._run_phase(skip_run=True) \ No newline at end of file diff --git a/cime_config/config_tests.xml b/cime_config/config_tests.xml index 115f4c0e89..c0b6afed9d 100644 --- a/cime_config/config_tests.xml +++ b/cime_config/config_tests.xml @@ -133,26 +133,6 @@ This defines various CTSM-specific system tests $STOP_N - - As RXCROPMATURITY but don't actually run or postprocess; just setup - 1 - FALSE - FALSE - never - $STOP_OPTION - $STOP_N - - - - As RXCROPMATURITY but don't actually build; just setup and then start "run." Will fail when run start is requested, but should successfully test preprocessing. - 1 - FALSE - FALSE - never - $STOP_OPTION - $STOP_N - - From 18e63e354e604d43c6dd0bca4a43abef3f4480ee Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 25 Jun 2024 12:02:01 -0600 Subject: [PATCH 266/444] Abort if matrixcn is .true. and nrepr is not 1 --- src/biogeochem/CropReprPoolsMod.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/biogeochem/CropReprPoolsMod.F90 b/src/biogeochem/CropReprPoolsMod.F90 index dcbb4e4fd9..695af9f00e 100644 --- a/src/biogeochem/CropReprPoolsMod.F90 +++ b/src/biogeochem/CropReprPoolsMod.F90 @@ -98,6 +98,10 @@ subroutine crop_repr_pools_init() end if nrepr = nrepr_grain + nrepr_structure + ! matrixcn works with nrepr = 1 only + if (use_matrixcn .and. nrepr != 1) then + call endrun(msg="ERROR: nrepr should be 1 when use_matrixcn = .true."//errMsg(sourcefile, __LINE__)) + end if allocate(repr_hist_fnames(nrepr)) allocate(repr_rest_fnames(nrepr)) allocate(repr_longnames(nrepr)) From d13508bef6c0b31e8569daa758c44c379f9309b8 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Tue, 25 Jun 2024 12:05:45 -0600 Subject: [PATCH 267/444] run_sys_tests: Check Python env for RXCROPMATURITY. --- python/ctsm/run_sys_tests.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/python/ctsm/run_sys_tests.py b/python/ctsm/run_sys_tests.py index de93081504..9961fd325d 100644 --- a/python/ctsm/run_sys_tests.py +++ b/python/ctsm/run_sys_tests.py @@ -736,13 +736,29 @@ def _check_py_env(test_attributes): # whether import is possible. # pylint: disable=import-error disable - # Check requirements for FSURDATMODIFYCTSM, if needed - if any("FSURDATMODIFYCTSM" in t for t in test_attributes): + # Check requirements for using modify_fsurdat, if needed + modify_fsurdat_users = ["FSURDATMODIFYCTSM", "RXCROPMATURITY"] + if any(any(u in t for u in modify_fsurdat_users) for t in test_attributes): try: import ctsm.modify_input_files.modify_fsurdat except ModuleNotFoundError as err: raise ModuleNotFoundError("modify_fsurdat" + err_msg) from err + # Check requirements for RXCROPMATURITY, if needed + if any("RXCROPMATURITY" in t for t in test_attributes): + try: + import ctsm.crop_calendars.check_rxboth_run + except ModuleNotFoundError as err: + raise ModuleNotFoundError("check_rxboth_run" + err_msg) from err + try: + import ctsm.crop_calendars.generate_gdds + except ModuleNotFoundError as err: + raise ModuleNotFoundError("generate_gdds" + err_msg) from err + try: + import ctsm.crop_calendars.interpolate_gdds + except ModuleNotFoundError as err: + raise ModuleNotFoundError("interpolate_gdds" + err_msg) from err + # Check that list for any testmods that use modify_fates_paramfile.py testmods_to_check = ["clm-FatesColdTwoStream", "clm-FatesColdTwoStreamNoCompFixedBioGeo"] testmods = _get_testmod_list(test_attributes) From 422f06f7389094b32baa763628865a53467d0830 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 25 Jun 2024 13:33:42 -0700 Subject: [PATCH 268/444] add fates potential vegetation spin up to transient test mod --- cime_config/testdefs/testlist_clm.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 85824a4404..0706a1ef53 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2615,6 +2615,15 @@ + + + + + + + + + From f9d8349021458c56912edf626a0c8e229e4f58da Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 25 Jun 2024 13:53:01 -0700 Subject: [PATCH 269/444] rename fates luh2 harvest modes --- .../include_user_mods | 0 .../{FatesColdLUH2Mode3 => FatesColdLUH2HarvestArea}/user_nl_clm | 0 .../include_user_mods | 0 .../{FatesColdLUH2Mode1 => FatesColdLUH2HarvestEvent}/user_nl_clm | 0 .../include_user_mods | 0 .../{FatesColdLUH2Mode4 => FatesColdLUH2HarvestMass}/user_nl_clm | 0 .../include_user_mods | 0 .../{FatesColdLUH2Mode2 => FatesColdLUH2HarvestSurf}/user_nl_clm | 0 .../include_user_mods | 0 .../{FatesColdLUH2Mode0 => FatesColdLUH2NoHarvest}/user_nl_clm | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2Mode0 => FatesColdLUH2HarvestArea}/include_user_mods (100%) rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2Mode3 => FatesColdLUH2HarvestArea}/user_nl_clm (100%) rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2Mode1 => FatesColdLUH2HarvestEvent}/include_user_mods (100%) rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2Mode1 => FatesColdLUH2HarvestEvent}/user_nl_clm (100%) rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2Mode2 => FatesColdLUH2HarvestMass}/include_user_mods (100%) rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2Mode4 => FatesColdLUH2HarvestMass}/user_nl_clm (100%) rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2Mode3 => FatesColdLUH2HarvestSurf}/include_user_mods (100%) rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2Mode2 => FatesColdLUH2HarvestSurf}/user_nl_clm (100%) rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2Mode4 => FatesColdLUH2NoHarvest}/include_user_mods (100%) rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2Mode0 => FatesColdLUH2NoHarvest}/user_nl_clm (100%) diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestArea/include_user_mods similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/include_user_mods rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestArea/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestArea/user_nl_clm similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/user_nl_clm rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestArea/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/include_user_mods similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/include_user_mods rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode1/user_nl_clm rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestMass/include_user_mods similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/include_user_mods rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestMass/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestMass/user_nl_clm similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/user_nl_clm rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestMass/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/include_user_mods similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode3/include_user_mods rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/user_nl_clm similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode2/user_nl_clm rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/include_user_mods similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode4/include_user_mods rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/user_nl_clm similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2Mode0/user_nl_clm rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/user_nl_clm From f8330c9a7fba12652562efbc87a56f0de358b669 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 25 Jun 2024 17:16:45 -0600 Subject: [PATCH 270/444] Correct earlier commit 47234a9: warning about cnmatrix and transient --- bld/CLMBuildNamelist.pm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index ffe1c4e522..329030d985 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4651,9 +4651,7 @@ sub setup_logic_cnmatrix { } @matrixlist = ( "use_matrixcn", "use_soil_matrixcn", "hist_wrt_matrixcn_diag", "spinup_matrixcn" ); # Matrix items can't be on for transient - $nl_flags->{'flanduse_timeseries'} = "null"; - my $flanduse_timeseries = $nl->get_value('flanduse_timeseries'); - if ( $flanduse_timeseries ne "null" ) { + if (not string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) { foreach my $var ( @matrixlist ) { if ( &value_is_true($nl->get_value($var)) ) { $log->warning("$var may FAIL with balance error in transient mode" ); From 17143eea0e9c447eca85bde97b7f1dda7c2b1ffe Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 25 Jun 2024 17:24:15 -0600 Subject: [PATCH 271/444] Correct earlier commit 18e63e3: abort if matrixcn and nrepr not 1 --- src/biogeochem/CropReprPoolsMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeochem/CropReprPoolsMod.F90 b/src/biogeochem/CropReprPoolsMod.F90 index 695af9f00e..cbc2f3e2a2 100644 --- a/src/biogeochem/CropReprPoolsMod.F90 +++ b/src/biogeochem/CropReprPoolsMod.F90 @@ -99,7 +99,7 @@ subroutine crop_repr_pools_init() nrepr = nrepr_grain + nrepr_structure ! matrixcn works with nrepr = 1 only - if (use_matrixcn .and. nrepr != 1) then + if (use_matrixcn .and. nrepr /= 1) then call endrun(msg="ERROR: nrepr should be 1 when use_matrixcn = .true."//errMsg(sourcefile, __LINE__)) end if allocate(repr_hist_fnames(nrepr)) From 4b18e79ae14e8c56c51b718aad722ce679b37972 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 25 Jun 2024 17:29:56 -0600 Subject: [PATCH 272/444] Replace clm45_monthly_matrixcn_soilCN30 testmod and test with clm60 --- .../clm/clm45_monthly_matrixcn_soilCN30/user_nl_clm | 2 -- .../include_user_mods | 0 .../clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm | 4 ++++ 3 files changed, 4 insertions(+), 2 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/clm45_monthly_matrixcn_soilCN30/user_nl_clm rename cime_config/testdefs/testmods_dirs/clm/{clm45_monthly_matrixcn_soilCN30 => clm60_monthly_matrixcn_soilCN30}/include_user_mods (100%) create mode 100644 cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/clm45_monthly_matrixcn_soilCN30/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/clm45_monthly_matrixcn_soilCN30/user_nl_clm deleted file mode 100644 index c7436f5acb..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/clm45_monthly_matrixcn_soilCN30/user_nl_clm +++ /dev/null @@ -1,2 +0,0 @@ - use_soil_matrixcn = .true. - paramfile = '$DIN_LOC_ROOT/lnd/clm2/paramdata/clm45_params.soilCN30.c220321.nc' diff --git a/cime_config/testdefs/testmods_dirs/clm/clm45_monthly_matrixcn_soilCN30/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/include_user_mods similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/clm45_monthly_matrixcn_soilCN30/include_user_mods rename to cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm new file mode 100644 index 0000000000..d22154bef6 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm @@ -0,0 +1,4 @@ +use_soil_matrixcn = .true. +paramfile = '/glade/u/home/slevis/paramfiles/ctsm60_params_cn30.c240625.nc' +! If we keep this paramfile, it should move to the repository +! paramfile = '$DIN_LOC_ROOT/lnd/clm2/paramdata/ctsm60_params_cn30.c240625.nc' From 1761a7becb50cad2849db794243b1f2d37e602c3 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 25 Jun 2024 17:34:50 -0600 Subject: [PATCH 273/444] Move new param file to inputdata and rimport --- .../clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm index d22154bef6..df20ced9e8 100644 --- a/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm @@ -1,4 +1,2 @@ use_soil_matrixcn = .true. -paramfile = '/glade/u/home/slevis/paramfiles/ctsm60_params_cn30.c240625.nc' -! If we keep this paramfile, it should move to the repository -! paramfile = '$DIN_LOC_ROOT/lnd/clm2/paramdata/ctsm60_params_cn30.c240625.nc' +paramfile = '$DIN_LOC_ROOT/lnd/clm2/paramdata/ctsm60_params_cn30.c240625.nc' From 1e97001d0dc5e7359d8fb3b11c37118e3e429fe3 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 25 Jun 2024 17:59:00 -0600 Subject: [PATCH 274/444] Change use_matrixcn, use_soil_matrixcn to default .false. before merge --- bld/namelist_files/namelist_defaults_ctsm.xml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 90e397d544..933b504606 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -618,19 +618,11 @@ attributes from the config_cache.xml file (with keys converted to upper-case). +.false. .true. -.true. -.false. -.false. -.false. - +.false. .true. -.true. -.false. -.false. -.false. -.false. .false. .false. From 7feb6572d51e5d3ba2596ae9a1b4ededd045928d Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 25 Jun 2024 18:04:46 -0600 Subject: [PATCH 275/444] Rm redunant LG* and LR* tests and corresponding expected fails --- cime_config/testdefs/ExpectedTestFails.xml | 13 ------------- cime_config/testdefs/testlist_clm.xml | 20 -------------------- 2 files changed, 33 deletions(-) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 5968e73760..664b1c8e35 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -58,19 +58,6 @@ - - - FAIL - #640, same test with clm-ciso_soil_matrixcn_only works - - - - - FAIL - #640, same test with clm-ciso_soil_matrixcn_only works - - - FAIL diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 9a2390bd58..625a9f3504 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3386,26 +3386,6 @@ - - - - - - - - - - - - - - - - - - - - From 5a46b9382ee15fea803cb5e7091ed6915c2169a1 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 26 Jun 2024 10:53:02 -0700 Subject: [PATCH 276/444] remove fates land use no harvest due to overlap --- .../testmods_dirs/clm/FatesColdLUH2NoHarvest/include_user_mods | 1 - .../testmods_dirs/clm/FatesColdLUH2NoHarvest/user_nl_clm | 1 - 2 files changed, 2 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/include_user_mods deleted file mode 100644 index 7eb8bb1579..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../FatesColdLUH2 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/user_nl_clm deleted file mode 100644 index b3b338e232..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2NoHarvest/user_nl_clm +++ /dev/null @@ -1 +0,0 @@ -fates_harvest_mode = no_harvest From 3318d3b46df34013afcb5fadc4ad9f4184779f28 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 26 Jun 2024 11:03:10 -0700 Subject: [PATCH 277/444] update fates landuse harvest test mod names --- cime_config/testdefs/testlist_clm.xml | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 0706a1ef53..ed0627f242 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2570,7 +2570,7 @@ - + @@ -2579,7 +2579,7 @@ - + @@ -2588,7 +2588,7 @@ - + @@ -2597,16 +2597,7 @@ - - - - - - - - - - + @@ -2621,7 +2612,7 @@ - + From a5da93ec5d016aabc11452870d8c3fab1677ef25 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 26 Jun 2024 12:31:05 -0600 Subject: [PATCH 278/444] generate_gdd20_baseline: Add optional -y1 and -yN args. --- .../crop_calendars/generate_gdd20_baseline.py | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 89a38a0a08..4357bd6dd1 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -70,6 +70,24 @@ def _parse_args(): help="Overwrite existing output file, if any", action="store_true", ) + parser.add_argument( + "-y1", + "--first-year", + help=( + "First calendar year to include" + ), + type=int, + required=False, + ) + parser.add_argument( + "-yN", + "--last-year", + help=( + "Last calendar year to include" + ), + type=int, + required=False, + ) # Get arguments args = parser.parse_args(sys.argv[1:]) @@ -78,7 +96,19 @@ def _parse_args(): if os.path.exists(args.output_file) and not args.overwrite: raise FileExistsError("Output file exists but --overwrite is not specified") - return args + # Process time slice + # Assumes CESM behavior where data for e.g. 1987 is saved as 1988-01-01 + 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 def _get_cft_list(crop_list): @@ -161,7 +191,7 @@ def _add_time_axis(da_in): return da_out -def generate_gdd20_baseline(input_files, output_file, author): +def generate_gdd20_baseline(input_files, output_file, author, time_slice): """ Generate stream_fldFileName_gdd20_baseline file from CTSM outputs """ @@ -173,7 +203,7 @@ def generate_gdd20_baseline(input_files, output_file, author): input_files.sort() # Import history files and ensure they have lat/lon dims - ds_in = import_ds(input_files, VAR_LIST_IN + GRIDDING_VAR_LIST) + ds_in = import_ds(input_files, VAR_LIST_IN + GRIDDING_VAR_LIST, time_slice=time_slice) if not all(x in ds_in.dims for x in ["lat", "lon"]): raise RuntimeError("Input files must have lat and lon dimensions") @@ -247,9 +277,10 @@ def main(): """ main() function for calling generate_gdd20_baseline.py from command line. """ - args = _parse_args() + args, time_slice = _parse_args() generate_gdd20_baseline( args.input_files, args.output_file, args.author, + time_slice ) From 23c8743ae67e8b550ee3ba89c10f2a2d17a51c3b Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 26 Jun 2024 14:27:22 -0600 Subject: [PATCH 279/444] generate_gdds: Map sdate in/out diffs. --- .../crop_calendars/generate_gdd20_baseline.py | 5 +++- python/ctsm/crop_calendars/generate_gdds.py | 1 + .../crop_calendars/generate_gdds_functions.py | 28 +++++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 4357bd6dd1..476717b887 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -97,7 +97,10 @@ def _parse_args(): raise FileExistsError("Output file exists but --overwrite is not specified") # Process time slice - # Assumes CESM behavior where data for e.g. 1987 is saved as 1988-01-01 + # 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: diff --git a/python/ctsm/crop_calendars/generate_gdds.py b/python/ctsm/crop_calendars/generate_gdds.py index 156ebfb20e..49226e6f75 100644 --- a/python/ctsm/crop_calendars/generate_gdds.py +++ b/python/ctsm/crop_calendars/generate_gdds.py @@ -178,6 +178,7 @@ def main( mxmats, cc.get_gs_len_da, skip_crops, + outdir_figs, logger, ) diff --git a/python/ctsm/crop_calendars/generate_gdds_functions.py b/python/ctsm/crop_calendars/generate_gdds_functions.py index 38c5d44384..2658e1de87 100644 --- a/python/ctsm/crop_calendars/generate_gdds_functions.py +++ b/python/ctsm/crop_calendars/generate_gdds_functions.py @@ -22,6 +22,7 @@ # pylint: disable=import-error from ctsm.crop_calendars.cropcal_figs_module import * from matplotlib.transforms import Bbox + import matplotlib.pyplot as plt warnings.filterwarnings( "ignore", @@ -63,7 +64,7 @@ def error(logger, string): raise RuntimeError(string) -def check_sdates(dates_ds, sdates_rx, logger, verbose=False): +def check_sdates(dates_ds, sdates_rx, outdir_figs, logger, verbose=False): """ Checking that input and output sdates match """ @@ -106,8 +107,28 @@ def check_sdates(dates_ds, sdates_rx, logger, verbose=False): log(logger, out_map_notnan[here][0:4]) log(logger, "diff:") log(logger, diff_map_notnan[here][0:4]) + first_diff = all_ok all_ok = False + if CAN_PLOT: + sdate_diffs_dir = os.path.join(outdir_figs, "sdate_diffs") + if first_diff: + log(logger, f"Saving sdate difference figures to {sdate_diffs_dir}") + if not os.path.exists(sdate_diffs_dir): + os.makedirs(sdate_diffs_dir) + in_map.where(~np.isnan(out_map)).plot() + plt.title(f"{vegtype_str} sdates in (masked)") + plt.savefig(os.path.join(sdate_diffs_dir, f"{vegtype_str}.in.png")) + plt.close() + out_map.plot() + plt.title(f"{vegtype_str} sdates out") + plt.savefig(os.path.join(sdate_diffs_dir, f"{vegtype_str}.out.png")) + plt.close() + diff_map.plot() + plt.title(f"{vegtype_str} sdates diff (out - in)") + plt.savefig(os.path.join(sdate_diffs_dir, f"{vegtype_str}.diff.png")) + plt.close() + if not any_found: error(logger, "No matching variables found in sdates_rx!") @@ -234,6 +255,7 @@ def import_and_process_1yr( mxmats, get_gs_len_da, skip_crops, + outdir_figs, logger, ): """ @@ -272,6 +294,8 @@ def import_and_process_1yr( time_slice=slice(f"{this_year}-01-01", f"{this_year}-12-31"), chunks=chunks, ) + for timestep in dates_ds["time"].values: + print(timestep) if dates_ds.dims["time"] > 1: if dates_ds.dims["time"] == 365: @@ -466,7 +490,7 @@ def import_and_process_1yr( # Import expected sowing dates. This will also be used as our template output file. imported_sdates = isinstance(sdates_rx, str) sdates_rx = import_rx_dates("s", sdates_rx, incl_patches1d_itype_veg, mxsowings, logger) - check_sdates(dates_incl_ds, sdates_rx, logger) + check_sdates(dates_incl_ds, sdates_rx, outdir_figs, logger) # Import hdates, if needed imported_hdates = isinstance(hdates_rx, str) From 34c4db0b185b4cb62fc6fa22de96b23c949c0dfd Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 26 Jun 2024 23:47:14 -0700 Subject: [PATCH 280/444] Revert "Apply relevant changes from rgknox/fates-auto-params." This reverts commit 7216006b1c2400d1ca2932899671f9bcec85b6af. --- .../testdefs/testmods_dirs/clm/Fates/shell_commands | 5 ----- .../testdefs/testmods_dirs/clm/Fates/user_nl_clm | 1 - .../testdefs/testmods_dirs/clm/_scripts/README | 2 -- .../clm/_scripts/get_fates_shell_commands_vars.sh | 11 ----------- 4 files changed, 19 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/_scripts/README delete mode 100755 cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh diff --git a/cime_config/testdefs/testmods_dirs/clm/Fates/shell_commands b/cime_config/testdefs/testmods_dirs/clm/Fates/shell_commands index 3443bacef0..41a2342a51 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Fates/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/Fates/shell_commands @@ -1,7 +1,2 @@ ./xmlchange CLM_BLDNML_OPTS="-no-megan" --append ./xmlchange BFBFLAG="TRUE" - -SRCROOT=`./xmlquery SRCROOT --value` -. "${SRCROOT}"/cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh - -ncgen -o $FATESPARAMFILE $FATESDIR/parameter_files/fates_params_default.cdl diff --git a/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm index 57adea1ff6..91df3e2e61 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/Fates/user_nl_clm @@ -4,7 +4,6 @@ hist_nhtfrq = -24 hist_empty_htapes = .true. hist_ndens = 1 fates_spitfire_mode = 1 -fates_paramfile='${SRCROOT}/src/fates/parameter_files/binaries/${CASE}-params.nc' hist_fincl1 = 'FATES_NCOHORTS', 'FATES_TRIMMING', 'FATES_AREA_PLANTS', 'FATES_AREA_TREES', 'FATES_COLD_STATUS', 'FATES_GDD', 'FATES_NCHILLDAYS', 'FATES_NCOLDDAYS', 'FATES_DAYSINCE_COLDLEAFOFF','FATES_DAYSINCE_COLDLEAFON', diff --git a/cime_config/testdefs/testmods_dirs/clm/_scripts/README b/cime_config/testdefs/testmods_dirs/clm/_scripts/README deleted file mode 100644 index 66eb22a375..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/_scripts/README +++ /dev/null @@ -1,2 +0,0 @@ -This directory contains scripts that can be called in -shell_commands of multiple testmods. diff --git a/cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh b/cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh deleted file mode 100755 index 382fb4e53e..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh +++ /dev/null @@ -1,11 +0,0 @@ -# This script should be called in shell_commands with -# . "${SRCROOT}"/cime_config/testdefs/testmods_dirs/clm/_scripts/get_fates_shell_commands_vars.sh -# where the leading period ensures it's run in the same shell. - -CASE=`./xmlquery CASE --value` -FATESDIR="${SRCROOT}/src/fates" -FATESPARAMDIR="${SRCROOT}/src/fates/parameter_files/binaries" -mkdir -p "${FATESPARAMDIR}" -FATESPARAMFILE="${FATESPARAMDIR}/${CASE}-params.nc" - -# No exit status because it should be called in the same shell. From 99d0f2bb4c93c739e5875781070a3d66c6bb8cbd Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 27 Jun 2024 16:56:21 -0700 Subject: [PATCH 281/444] move fates landuse test mods to fates suite --- cime_config/testdefs/testlist_clm.xml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index ef4358f763..347fd33e8e 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2573,8 +2573,7 @@ - - + @@ -2582,8 +2581,7 @@ - - + @@ -2591,8 +2589,7 @@ - - + @@ -2600,8 +2597,7 @@ - - + @@ -2609,8 +2605,7 @@ - - + From 535033b959f6eab9c5d39d7edff410c47dfacb80 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 27 Jun 2024 17:11:47 -0700 Subject: [PATCH 282/444] remove flandusepft and fluh_times pointers for testmod Use default currently. --- .../testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm | 2 -- 1 file changed, 2 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm index 970e7df7cd..e25490ffbb 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/user_nl_clm @@ -2,10 +2,8 @@ ! Run a transient case, with vegetation starting from bare ground, but land use starting from LUH state vector on starting date, in a nocomp configuration. ! From Charlie's list of valid FATES configurations: ! https://docs.google.com/spreadsheets/d/1eE3sRMYxfocZKbT8uIQhXpjjtfM2feXPRSWXJNoo4jM/edit#gid=0 -flandusepftdat = '$DIN_LOC_ROOT/lnd/clm2/surfdata_map/fates-sci.1.73.0_api.36.0.0/fates_landuse_pft_map_4x5_240206.nc' use_fates_luh = .true. use_fates_nocomp = .true. use_fates_fixed_biogeog = .true. use_fates_sp = .false. use_fates_potentialveg = .false. -fluh_timeseries = '$DIN_LOC_ROOT/lnd/clm2/surfdata_map/fates-sci.1.68.3_api.31.0.0_tools.1.0.1/LUH2_states_transitions_management.timeseries_4x5_hist_simyr1850-2015_c231101.nc' From 8793f477483bf0332bf423e3c7b3bb66b31f88aa Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 27 Jun 2024 17:15:29 -0700 Subject: [PATCH 283/444] add readme noting grid resolution limitation --- cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/README | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/README diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/README b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/README new file mode 100644 index 0000000000..79d6511d17 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/README @@ -0,0 +1,2 @@ +Currently the FATES LUH2 category of test mods currently only supports +4x5 grid resolutions. From 95bf3f82fb09d4022ac1af285569e9c1fd1aefa0 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 28 Jun 2024 13:52:40 -0700 Subject: [PATCH 284/444] add fates harvest event expected failure --- cime_config/testdefs/ExpectedTestFails.xml | 7 +++++++ cime_config/testdefs/testlist_clm.xml | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 65419a5903..de864aeee6 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -165,6 +165,13 @@ + + + FAIL + FATES#1216 + + + FAIL diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 347fd33e8e..16359b88be 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2579,7 +2579,7 @@ - + @@ -2609,6 +2609,7 @@ + From 889cc97d4172e85edc7f6c53f4a71ec89048a4d5 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 27 Jun 2024 17:51:13 -0600 Subject: [PATCH 285/444] update seed dispersal test mod to put on-the-fly generated paramfile in the case directory --- .../testdefs/testmods_dirs/clm/FatesColdSeedDisp/shell_commands | 2 +- .../testdefs/testmods_dirs/clm/FatesColdSeedDisp/user_nl_clm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/shell_commands b/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/shell_commands index 94a832af25..db5a1f8672 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/shell_commands @@ -1,7 +1,7 @@ SRCDIR=`./xmlquery SRCROOT --value` CASEDIR=`./xmlquery CASEROOT --value` FATESDIR=$SRCDIR/src/fates/ -FATESPARAMFILE=$SRCDIR/fates_params_seeddisp_4x5.nc +FATESPARAMFILE=$CASEDIR/fates_params_seeddisp_4x5.nc ncgen -o $FATESPARAMFILE $FATESDIR/parameter_files/fates_params_default.cdl diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/user_nl_clm index e8d24253c1..ecd1dc8b57 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/user_nl_clm @@ -1,3 +1,3 @@ -fates_paramfile = '$SRCROOT/fates_params_seeddisp_4x5.nc' +fates_paramfile = '$CASEROOT/fates_params_seeddisp_4x5.nc' fates_seeddisp_cadence = 1 hist_fincl1 = 'FATES_SEEDS_IN_GRIDCELL_PF', 'FATES_SEEDS_OUT_GRIDCELL_PF' From f58cd7ee463f5ad7d8838a618f6e51bc7c37fb07 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 27 Jun 2024 23:43:20 -0600 Subject: [PATCH 286/444] reinstate fates-landuse as a second, shorter test list --- cime_config/testdefs/testlist_clm.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 16359b88be..68862c0dce 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2565,6 +2565,7 @@ + @@ -2574,6 +2575,7 @@ + @@ -2582,6 +2584,7 @@ + @@ -2590,6 +2593,7 @@ + @@ -2598,6 +2602,7 @@ + @@ -2606,6 +2611,7 @@ + From 9465da6202b0fd2ca8cbd9d39b6ffb5cc2e9f1e0 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 27 Jun 2024 23:44:49 -0600 Subject: [PATCH 287/444] fix luh2 harvest testmod --- .../testmods_dirs/clm/FatesColdLUH2HarvestArea/user_nl_clm | 2 +- .../testmods_dirs/clm/FatesColdLUH2HarvestMass/user_nl_clm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestArea/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestArea/user_nl_clm index d760105e68..426b41b49e 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestArea/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestArea/user_nl_clm @@ -1 +1 @@ -fates_harvest_mode = luhdata_area +fates_harvest_mode = 'luhdata_area' diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestMass/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestMass/user_nl_clm index bb5f30f75d..7b6bc24f5a 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestMass/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestMass/user_nl_clm @@ -1 +1 @@ -fates_harvest_mode = luhdata_mass +fates_harvest_mode = 'luhdata_mass' From c2deb25a278e7b177c47b5ae189f1c8697cd8d58 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 27 Jun 2024 23:48:18 -0600 Subject: [PATCH 288/444] rename fates landuse to luh2harvestevent --- .../testmods_dirs/clm/FatesColdLUH2HarvestSurf/user_nl_clm | 3 ++- .../testmods_dirs/clm/FatesColdLandUse/include_user_mods | 1 - .../testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/user_nl_clm index 61e1daaa93..a23336f36c 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/user_nl_clm @@ -1 +1,2 @@ -fates_harvest_mode = surfdata_file +flanduse_timeseries = '$DIN_LOC_ROOT/lnd/clm2/surfdata_esmf/ctsm5.2.0/landuse.timeseries_4x5_hist_16_CMIP6_1850-2015_c230620.nc' +fates_harvest_mode = 'surfdata_file' diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/include_user_mods deleted file mode 100644 index 14f7591b72..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../FatesCold diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm deleted file mode 100644 index 668f9c861d..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm +++ /dev/null @@ -1,2 +0,0 @@ -flanduse_timeseries = '$DIN_LOC_ROOT/lnd/clm2/surfdata_esmf/ctsm5.2.0/landuse.timeseries_4x5_hist_16_CMIP6_1850-2015_c230620.nc' -do_harvest = .true. From 4d0b49a81fa68653ba92ca59cfdd791cc053378a Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 28 Jun 2024 12:32:36 -0600 Subject: [PATCH 289/444] fix fates harvest event code testmod --- .../testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm index c0e1c476be..d2079d9e43 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm @@ -1 +1 @@ -fates_harvest_mode = event_code +fates_harvest_mode = 'event_code' From 387ac5ed9163f77bd037ff8f935e56e73a832702 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 28 Jun 2024 14:49:55 -0600 Subject: [PATCH 290/444] add description to flandusepftdat definition --- bld/namelist_files/namelist_definition_ctsm.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index c12cb75ab6..fd3020f320 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -826,7 +826,13 @@ types to vary over time. -Full pathname of fates landuse x pft static data map. +Full pathname of fates landuse x pft association static data map. +The file associates land use types with pfts across a static global map. +This file is necessary for running FATES with use_fates_luh, +use_fates_nocomp, and use_fates_fixedbiogeo engaged. The file is output +by the FATES land use data tool (https://github.com/NGEET/tools-fates-landusedata) +which processes the raw land use data from the THEMIS tool data sets +(https://doi.org/10.5065/29s7-7b41) Date: Fri, 28 Jun 2024 14:04:09 -0700 Subject: [PATCH 291/444] update flandusepftdat description with note about use_fates_lupft --- bld/namelist_files/namelist_definition_ctsm.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index fd3020f320..fb4f5d07a9 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -829,7 +829,8 @@ types to vary over time. Full pathname of fates landuse x pft association static data map. The file associates land use types with pfts across a static global map. This file is necessary for running FATES with use_fates_luh, -use_fates_nocomp, and use_fates_fixedbiogeo engaged. The file is output +use_fates_nocomp, and use_fates_fixedbiogeo engaged (note that use_fates_lupft +is provided as a namelist option to engage all necessary options). The file is output by the FATES land use data tool (https://github.com/NGEET/tools-fates-landusedata) which processes the raw land use data from the THEMIS tool data sets (https://doi.org/10.5065/29s7-7b41) From f985fbafafd5710e944d7715522966e042743361 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 28 Jun 2024 14:23:29 -0700 Subject: [PATCH 292/444] rename misleading surfdata_file option name to the landuse_timeseries --- bld/CLMBuildNamelist.pm | 4 ++-- bld/namelist_files/namelist_definition_ctsm.xml | 7 ++++--- .../testmods_dirs/clm/FatesColdLUH2HarvestSurf/user_nl_clm | 2 +- src/dyn_subgrid/dynFATESLandUseChangeMod.F90 | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index c336d41ca9..0fb7963c67 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4652,7 +4652,7 @@ sub setup_logic_fates { if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { $log->fatal_error("use_fates_luh is required to be true when $var is luhdata_mass or luhdata_area" ); } - } elsif ( $mode eq 'surfdata_file' ) { + } elsif ( $mode eq 'landuse_timeseries' ) { # Check to make sure that the user set the flanduse_timeseries file # Since the flanduse_timeseries logic checking is upstream of the fates logic, # don't add the default here. The onus is on the user to match the correct timeseries @@ -4660,7 +4660,7 @@ sub setup_logic_fates { my $var = "flanduse_timeseries"; my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); if ( ! defined($nl->get_value($var)) ) { - $log->fatal_error("$var is required when fates_harvest_mode is surfdata_file" ); + $log->fatal_error("$var is required when fates_harvest_mode is landuse_timeseries" ); } elsif ( ! -f "$fname" ) { $log->fatal_error("$var does NOT point to a valid filename" ); } diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index fb4f5d07a9..046de32c11 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -734,15 +734,16 @@ Toggle to turn on no competition mode (only relevant if FATES is being used). Toggle to turn on FATES satellite phenology mode (only relevant if FATES is being used). - + Set FATES harvesting mode by setting fates_harvest_mode to a valid string option. Allowed values are: no_harvest: no fates harvesting of any kind event_code: fates logging via fates logging event codes (see fates parameter file) only - surfdata_file: fates harvest driven by CLM landuse timeseries data (dynHarvestMod) + landuse_timeseries: fates harvest driven by CLM flanduse_timeseries file (dynHarvestMod) luhdata_area: fates harvest driven by LUH2 raw harvest data, area-based (dynFATESLandUseChangeMod) luhdata_mass: fates harvest driven by LUH2 raw harvest data, mass-based (dynFATESLandUseChangeMod) +Note that the landuse_timeseries option is not the same as the FATES fluh_timeseries data file. Date: Fri, 28 Jun 2024 14:25:37 -0700 Subject: [PATCH 293/444] add language about age and possible future deprication of landuse_timeseries option --- bld/namelist_files/namelist_definition_ctsm.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 046de32c11..9b495ccda4 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -744,6 +744,7 @@ Allowed values are: luhdata_area: fates harvest driven by LUH2 raw harvest data, area-based (dynFATESLandUseChangeMod) luhdata_mass: fates harvest driven by LUH2 raw harvest data, mass-based (dynFATESLandUseChangeMod) Note that the landuse_timeseries option is not the same as the FATES fluh_timeseries data file. +This option is older than the luhdata options and may be depricated at some point in the future. Date: Fri, 28 Jun 2024 14:29:38 -0700 Subject: [PATCH 294/444] fix copy/paste typo --- bld/namelist_files/namelist_definition_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 9b495ccda4..b80bbda2d6 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -806,7 +806,7 @@ This is enabled by default if fates_harvest_mode is set to use the raw LUH2 harv + group="clm_inparm" valid_values="" value=".false."> If TRUE, enable use of fates land use x pft mapping data file. (Only valid for use_fates = true and is incompatible with transient runs currently.) From 32b2554189d6cbdb11361ed376eb53c4bb8d2857 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 28 Jun 2024 14:32:39 -0700 Subject: [PATCH 295/444] add clarifying language for use_fates_potentialveg --- bld/namelist_files/namelist_definition_ctsm.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index b80bbda2d6..bbc860df6c 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -814,7 +814,9 @@ If TRUE, enable use of fates land use x pft mapping data file. If TRUE, ignore the land-use state vector and transitions, and assert that all lands -are primary, and that there is no harvest. +are primary, and that there is no harvest. This mode is only relevant for FATES +spin-up workflows that are intending to use the spin-up restart output to start a +FATES land use transient case using the use_fates_lupft namelist option. From aaaff224b18585a4f93c4b83595b2017ee96f607 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 28 Jun 2024 14:40:32 -0700 Subject: [PATCH 296/444] add clearer instructions about when to use_fates_potentialveg --- bld/namelist_files/namelist_definition_ctsm.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index bbc860df6c..252d83aa21 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -816,7 +816,8 @@ If TRUE, enable use of fates land use x pft mapping data file. If TRUE, ignore the land-use state vector and transitions, and assert that all lands are primary, and that there is no harvest. This mode is only relevant for FATES spin-up workflows that are intending to use the spin-up restart output to start a -FATES land use transient case using the use_fates_lupft namelist option. +FATES land use transient case using the use_fates_lupft namelist option. The option +should be set to true for the spin-up case and false for the transient case. From f6f7b2d135253f5a13dbd6e5ae66328a01c97d76 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 28 Jun 2024 14:45:13 -0700 Subject: [PATCH 297/444] add language explaining what use_fates_lupft does --- bld/namelist_files/namelist_definition_ctsm.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 252d83aa21..5a478f0bfa 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -807,7 +807,9 @@ This is enabled by default if fates_harvest_mode is set to use the raw LUH2 harv -If TRUE, enable use of fates land use x pft mapping data file. +If TRUE, enable use of FATES land use with no competition and fixed biogeography. This mode +requires the use of the land use x pft association static data map file. See the +flandusepftdat definition entry in this file for more information. (Only valid for use_fates = true and is incompatible with transient runs currently.) From 2539cea91b481f4680e2696c6c517df3d952befa Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 28 Jun 2024 16:31:36 -0700 Subject: [PATCH 298/444] add readme to FatesLUPFT test mod --- cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/README | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/README diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/README b/cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/README new file mode 100644 index 0000000000..88f5c2c8fb --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesLUPFT/README @@ -0,0 +1,9 @@ +This test mod does not use cold start and is intended to +be used in conjunction with a test workflow that provides +an initialization file. Currently this is accomplished +by using the test mod in conjunction with the PVT +system test. The PVT system test runs a FATES spin-up +case using the use_fates_potentialveg mode and then +references the restart output to run a use_fates_lupft +transient mode case. + From bf46d33d289f85077082dc01ec79c1945c42c3f4 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Sun, 30 Jun 2024 23:04:07 -0700 Subject: [PATCH 299/444] update fates logging test with new harvest event code Remove duplicate and misnamed FatesColdLUH2HarvestEvent --- .../clm/FatesColdLUH2HarvestEvent/include_user_mods | 1 - .../testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm | 1 - .../testdefs/testmods_dirs/clm/FatesColdLogging/user_nl_clm | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/include_user_mods deleted file mode 100644 index 7eb8bb1579..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../FatesColdLUH2 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm deleted file mode 100644 index d2079d9e43..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestEvent/user_nl_clm +++ /dev/null @@ -1 +0,0 @@ -fates_harvest_mode = 'event_code' diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLogging/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLogging/user_nl_clm index 5f457f3f1c..d2079d9e43 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLogging/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLogging/user_nl_clm @@ -1,2 +1 @@ -! TODO SSR: Replace this with fates_harvest_mode -use_fates_logging= .true. +fates_harvest_mode = 'event_code' From 96d1a78b3c28c9f1bc8185e646f6a4f975236a42 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Sun, 30 Jun 2024 23:07:59 -0700 Subject: [PATCH 300/444] reinstate FatesColdLandUse This will provide continuity to the previous test and fixes the incorrect use of FatesColdLUH2 as the test to inherit from --- .../testmods_dirs/clm/FatesColdLUH2HarvestSurf/include_user_mods | 1 - .../testmods_dirs/clm/FatesColdLandUse/include_user_mods | 1 + .../{FatesColdLUH2HarvestSurf => FatesColdLandUse}/user_nl_clm | 0 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/include_user_mods rename cime_config/testdefs/testmods_dirs/clm/{FatesColdLUH2HarvestSurf => FatesColdLandUse}/user_nl_clm (100%) diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/include_user_mods deleted file mode 100644 index 7eb8bb1579..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../FatesColdLUH2 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/include_user_mods new file mode 100644 index 0000000000..14f7591b72 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/include_user_mods @@ -0,0 +1 @@ +../FatesCold diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2HarvestSurf/user_nl_clm rename to cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm From f47e2bfe035571268743f5bed11b2b97169d31e0 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Sun, 30 Jun 2024 23:10:43 -0700 Subject: [PATCH 301/444] remove duplicate tests --- cime_config/testdefs/testlist_clm.xml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 68862c0dce..272d4093d8 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2581,15 +2581,6 @@ - - - - - - - - - @@ -2599,15 +2590,6 @@ - - - - - - - - - From 6dd55eeef55c093e53f500867d516df1beb16f39 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Mon, 1 Jul 2024 11:31:06 -0600 Subject: [PATCH 302/444] Update .gitmodules with new cismwrapper, cmeps, and ccs_config tags --- .gitmodules | 12 ++++++------ ccs_config | 2 +- components/cism | 2 +- components/cmeps | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitmodules b/.gitmodules index 6d4298befc..eb2a0980f4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,8 +7,8 @@ fxDONOTUSEurl = https://github.com/NCAR/fates-release [submodule "cism"] path = components/cism -url = https://github.com/mvertens/CISM-wrapper -fxtag = 34339777afa7b810fd4822fce1039826668b33e4 +url = https://github.com/ESCOMP/CISM-wrapper +fxtag = cismwrap_2_2_001 fxrequired = ToplevelRequired fxDONOTUSEurl = https://github.com/ESCOMP/CISM-wrapper @@ -35,8 +35,8 @@ fxDONOTUSEurl = https://github.com/ESCOMP/mizuRoute [submodule "ccs_config"] path = ccs_config -url = https://github.com/mvertens/ccs_config_cesm.git -fxtag = dbb02c0ccd1492fe278885f8a07a71fa80064319 +url = https://github.com/ESMCI/ccs_config_cesm.git +fxtag = ccs_config_cesm0.0.110 fxrequired = ToplevelRequired fxDONOTUSEurl = https://github.com/ESMCI/ccs_config_cesm.git @@ -49,8 +49,8 @@ fxDONOTUSEurl = https://github.com/ESMCI/cime [submodule "cmeps"] path = components/cmeps -url = https://github.com/mvertens/CMEPS.git -fxtag = 4dca7c602e54189b74b1d0195c433d1b83475553 +url = https://github.com/ESCOMP/CMEPS.git +fxtag = cmeps0.14.67 fxrequired = ToplevelRequired fxDONOTUSEurl = https://github.com/ESCOMP/CMEPS.git diff --git a/ccs_config b/ccs_config index dbb02c0ccd..c30a283155 160000 --- a/ccs_config +++ b/ccs_config @@ -1 +1 @@ -Subproject commit dbb02c0ccd1492fe278885f8a07a71fa80064319 +Subproject commit c30a2831556f269675971b11c5c156ea92599878 diff --git a/components/cism b/components/cism index 34339777af..c05dd5c4fc 160000 --- a/components/cism +++ b/components/cism @@ -1 +1 @@ -Subproject commit 34339777afa7b810fd4822fce1039826668b33e4 +Subproject commit c05dd5c4fc85327e76523aaea9cfe1e388748928 diff --git a/components/cmeps b/components/cmeps index 4dca7c602e..90f815ba9e 160000 --- a/components/cmeps +++ b/components/cmeps @@ -1 +1 @@ -Subproject commit 4dca7c602e54189b74b1d0195c433d1b83475553 +Subproject commit 90f815ba9e7493d71043b5d8e627a3f20bd5dc78 From fb9529577c1e1f294cce17c0a0285f78b98554ce Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Mon, 1 Jul 2024 12:59:23 -0600 Subject: [PATCH 303/444] Update cismwrapper tag to the correct new one --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index eb2a0980f4..615de28b6f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,7 +8,7 @@ fxDONOTUSEurl = https://github.com/NCAR/fates-release [submodule "cism"] path = components/cism url = https://github.com/ESCOMP/CISM-wrapper -fxtag = cismwrap_2_2_001 +fxtag = cismwrap_2_2_002 fxrequired = ToplevelRequired fxDONOTUSEurl = https://github.com/ESCOMP/CISM-wrapper From de1b44ca4c9ef7c9116b41f1969a7998bcf21a84 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Mon, 1 Jul 2024 13:01:37 -0600 Subject: [PATCH 304/444] Ran ./bin/git-fleximod update, so now update the cism module itself --- components/cism | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/cism b/components/cism index c05dd5c4fc..c84cc9f5b3 160000 --- a/components/cism +++ b/components/cism @@ -1 +1 @@ -Subproject commit c05dd5c4fc85327e76523aaea9cfe1e388748928 +Subproject commit c84cc9f5b3103766a35d0a7ddd5e9dbd7deae762 From e1b2bdabb4b2c74a27bbf12d4cca677452396de7 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 2 Jul 2024 17:03:19 -0600 Subject: [PATCH 305/444] Correct the tags that I used for ccs_config and cmeps --- .gitmodules | 4 ++-- ccs_config | 2 +- components/cmeps | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitmodules b/.gitmodules index 615de28b6f..897824e9cc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,7 +36,7 @@ fxDONOTUSEurl = https://github.com/ESCOMP/mizuRoute [submodule "ccs_config"] path = ccs_config url = https://github.com/ESMCI/ccs_config_cesm.git -fxtag = ccs_config_cesm0.0.110 +fxtag = ccs_config_cesm1.0.0 fxrequired = ToplevelRequired fxDONOTUSEurl = https://github.com/ESMCI/ccs_config_cesm.git @@ -50,7 +50,7 @@ fxDONOTUSEurl = https://github.com/ESMCI/cime [submodule "cmeps"] path = components/cmeps url = https://github.com/ESCOMP/CMEPS.git -fxtag = cmeps0.14.67 +fxtag = cmeps0.14.77 fxrequired = ToplevelRequired fxDONOTUSEurl = https://github.com/ESCOMP/CMEPS.git diff --git a/ccs_config b/ccs_config index c30a283155..69a958581e 160000 --- a/ccs_config +++ b/ccs_config @@ -1 +1 @@ -Subproject commit c30a2831556f269675971b11c5c156ea92599878 +Subproject commit 69a958581ecd2d32ee9cb1c38bcd3847b8b920bf diff --git a/components/cmeps b/components/cmeps index 90f815ba9e..47fb4e633a 160000 --- a/components/cmeps +++ b/components/cmeps @@ -1 +1 @@ -Subproject commit 90f815ba9e7493d71043b5d8e627a3f20bd5dc78 +Subproject commit 47fb4e633a76ec6d60969b1af751f90790387246 From 0e6eed5f399eb85744410ecf1962c0416c7846ba Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 5 Jul 2024 10:57:34 -0700 Subject: [PATCH 306/444] Revert "update seed dispersal test mod to put on-the-fly generated paramfile in the case directory" This reverts commit 889cc97d4172e85edc7f6c53f4a71ec89048a4d5. I forgot that #2322 prevents this from working. --- .../testdefs/testmods_dirs/clm/FatesColdSeedDisp/shell_commands | 2 +- .../testdefs/testmods_dirs/clm/FatesColdSeedDisp/user_nl_clm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/shell_commands b/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/shell_commands index db5a1f8672..94a832af25 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/shell_commands @@ -1,7 +1,7 @@ SRCDIR=`./xmlquery SRCROOT --value` CASEDIR=`./xmlquery CASEROOT --value` FATESDIR=$SRCDIR/src/fates/ -FATESPARAMFILE=$CASEDIR/fates_params_seeddisp_4x5.nc +FATESPARAMFILE=$SRCDIR/fates_params_seeddisp_4x5.nc ncgen -o $FATESPARAMFILE $FATESDIR/parameter_files/fates_params_default.cdl diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/user_nl_clm index ecd1dc8b57..e8d24253c1 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/user_nl_clm @@ -1,3 +1,3 @@ -fates_paramfile = '$CASEROOT/fates_params_seeddisp_4x5.nc' +fates_paramfile = '$SRCROOT/fates_params_seeddisp_4x5.nc' fates_seeddisp_cadence = 1 hist_fincl1 = 'FATES_SEEDS_IN_GRIDCELL_PF', 'FATES_SEEDS_OUT_GRIDCELL_PF' From 03fb25a2a6d94753d7abbb4300fa32b917883969 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 5 Jul 2024 16:18:47 -0600 Subject: [PATCH 307/444] Two new tests in testlist_clm and two new tests in expected fails --- cime_config/testdefs/ExpectedTestFails.xml | 15 +++++++++++++++ cime_config/testdefs/testlist_clm.xml | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 664b1c8e35..59802d9109 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -44,6 +44,21 @@ + + + FAIL + #2619 + This failure relates to the following REP failure. + + + + + FAIL + #2619 + This failure relates to the preceding ERP failure. + + + FAIL diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 625a9f3504..23cc5ebcc5 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -1445,6 +1445,26 @@ + + + + + + + + + + + + + + + + + + + + From 0efd37fe16814134389b9c49a30c7c033828c462 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 5 Jul 2024 17:55:44 -0600 Subject: [PATCH 308/444] New testmods /matrixcnOn_Hist to use -ignore_warnings in IHist compsets --- cime_config/testdefs/ExpectedTestFails.xml | 4 +-- cime_config/testdefs/testlist_clm.xml | 28 +++++++++---------- .../clm/matrixcnOn_Hist/include_user_mods | 1 + .../clm/matrixcnOn_Hist/shell_commands | 3 ++ 4 files changed, 20 insertions(+), 16 deletions(-) create mode 100644 cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/shell_commands diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 59802d9109..1243c125c0 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -44,14 +44,14 @@ - + FAIL #2619 This failure relates to the following REP failure. - + FAIL #2619 diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 23cc5ebcc5..1fe5ed770d 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -548,7 +548,7 @@ - + @@ -794,7 +794,7 @@ - + @@ -1002,7 +1002,7 @@ - + @@ -1020,7 +1020,7 @@ - + @@ -1038,7 +1038,7 @@ - + @@ -1234,7 +1234,7 @@ - + @@ -1354,7 +1354,7 @@ - + @@ -1435,7 +1435,7 @@ - + @@ -1445,7 +1445,7 @@ - + @@ -1455,7 +1455,7 @@ - + @@ -1793,7 +1793,7 @@ - + @@ -1849,7 +1849,7 @@ - + @@ -1925,7 +1925,7 @@ - + @@ -2369,7 +2369,7 @@ - + diff --git a/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/include_user_mods new file mode 100644 index 0000000000..a3c70cba11 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/include_user_mods @@ -0,0 +1 @@ +../matrixcnOn diff --git a/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/shell_commands b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/shell_commands new file mode 100644 index 0000000000..f0547f3f26 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/shell_commands @@ -0,0 +1,3 @@ +#!/bin/bash + +./xmlchange CLM_BLDNML_OPTS="-ignore_warnings" --append From a486e86065223a882790a6078647a82c592ffdaf Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 5 Jul 2024 17:15:08 -0700 Subject: [PATCH 309/444] update harvest parameter variables lengths Updating all lengths to account for the update to the clmlanduse name option change --- src/dyn_subgrid/dynFATESLandUseChangeMod.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 index b440b55dc9..681d39f38c 100644 --- a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 +++ b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 @@ -35,11 +35,11 @@ module dynFATESLandUseChangeMod integer, public, parameter :: num_landuse_harvest_vars = 5 ! Define the fates landuse namelist mode switch values - character(len=13), public, parameter :: fates_harvest_no_logging = 'no_harvest' - character(len=13), public, parameter :: fates_harvest_logging_only = 'event_code' - character(len=13), public, parameter :: fates_harvest_clmlanduse = 'landuse_timeseries' - character(len=13), public, parameter :: fates_harvest_luh_area = 'luhdata_area' - character(len=13), public, parameter :: fates_harvest_luh_mass = 'luhdata_mass' + character(len=18), public, parameter :: fates_harvest_no_logging = 'no_harvest' + character(len=18), public, parameter :: fates_harvest_logging_only = 'event_code' + character(len=18), public, parameter :: fates_harvest_clmlanduse = 'landuse_timeseries' + character(len=18), public, parameter :: fates_harvest_luh_area = 'luhdata_area' + character(len=18), public, parameter :: fates_harvest_luh_mass = 'luhdata_mass' ! Define landuse harvest unit integer representation integer, public, parameter :: landuse_harvest_area_units = 1 From fafc8137baeb39c07c65e697def4488b86aab612 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 8 Jul 2024 14:53:52 -0700 Subject: [PATCH 310/444] update fates submodule to api 36 --- .gitmodules | 4 ++-- src/fates | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 049c62ade8..9ed4402c7e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -27,8 +27,8 @@ # [submodule "fates"] path = src/fates -url = https://github.com/ckoven/fates -fxtag = 4b018eade498d063b21dddf26f77c9658ff80261 +url = https://github.com/NGEET/fates +fxtag = sci.1.77.0_api.36.0.0 fxrequired = AlwaysRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/NCAR/fates-release diff --git a/src/fates b/src/fates index 4b018eade4..fd7f3438c2 160000 --- a/src/fates +++ b/src/fates @@ -1 +1 @@ -Subproject commit 4b018eade498d063b21dddf26f77c9658ff80261 +Subproject commit fd7f3438c2ff821672b703050e7011f293649ee9 From cb7376eb55987f0785dd9a857c2fd24a720e6017 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 9 Jul 2024 01:25:57 -0600 Subject: [PATCH 311/444] Remove whitespace at end of lines --- src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf index 467d00de59..c811cab5f5 100644 --- a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf +++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf @@ -59,7 +59,7 @@ contains @assertFalse(not_init) end subroutine check_when_initialized_runs - + @Test subroutine check_dust_emis(this) ! Test that the dust_emis logical functions work as expected @@ -75,7 +75,6 @@ contains end subroutine check_dust_emis - @Test subroutine check_zender_soil(this) ! Test that the dust_emis_Zender logical functions work as expected @@ -91,7 +90,6 @@ contains end subroutine check_zender_soil - @Test subroutine check_options(this) ! Test that the check_options subroutine catches errors that should die @@ -110,5 +108,5 @@ contains @assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: zender_soil_erod_source can only be lnd or atm')) end subroutine check_options - + end module test_shr_dust_emis From e49c11dafe49ec306848a31cabfbf6b87d0d62da Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 9 Jul 2024 10:25:04 -0700 Subject: [PATCH 312/444] update ChangeLog and ChangeSum --- doc/ChangeLog | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++ doc/ChangeSum | 1 + 2 files changed, 118 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index 2ab7676ddc..26deed83db 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,121 @@ =============================================================== +Tag name: ctsm5.2.009 +Originator(s): glemieux (Gregory Lemieux, LBNL, glemieux@lbl.gov) +Date: Tue 9 Jul 2024 10:50:00 AM MDT +One-line Summary: FATES Land Use V2 + +Purpose and description of changes +---------------------------------- + +This tag enables FATES to utilize its land use mode with fixed +biogeography and no competition mode engaged. To facilitate +this update, the host land model reads in a new static map data +set that associates land use with FATES plant functional types. +This tag also updates the pre-existing FATES dynamic land use +module to provide access to the raw LUH2 harvest data from the +FATES LUH2 timeseries data set (added in ctsm5.1.dev160). + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + FATES satellite phenology mode and land use mode are currently incompatible + and trying to engage both will result in a graceful build failure message + +Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): + New FATES namelist option: fates_harvest_mode + - This new option provides five harvest modes + - The 'event_code' mode takes over the now defunct use_fates_logging option + + New FATES namelist option: use_fates_lupft + - This option enables the necessary namelist options and data sets to run + FATES with land use, no competition, and fixed biogeography modes. + + New FATES namelist option: flandusepftdat + - This data set is necessary for running with use_fates_lupft. + + New FATES namelist option: use_potential_veg + - This option is only necessary for use with FATES spin-up to transient + workflows that will engage the use_fates_lupft mode for the transient case + +Changes made to namelist defaults (e.g., changed parameter values): + The default FATES parameter file has been updated to account for the new + parameters necessary for land use v2. + + A new default data set has been provided for flandusepftdat. Only a 4x5 grid + resolution is currently provided. + +Changes to the datasets (e.g., parameter, surface or initial files): + The FATES land use timeseries data set, fluh_timeseries, has been updated to + provide a wider timeseries range, from 0850-2015. + + +Notes of particular relevance for developers: +--------------------------------------------- +Changes to tests or testing: + New FATES testmods have been added to account for the additional harvest mode + and use_fates_lupft namelist options. Additoinally a new system text prefix, + PVT, has been added to test the use_fates_potentialveg spin-up to use_fates_lupft + transient workflow. These have been added to the fates test suite. + + +Testing summary: +---------------- + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- TBD + izumi ------- TBD + + fates tests: (give name of baseline if different from CTSM tagname, normally fates baselines are fates--) + derecho ----- OK + +If the tag used for baseline comparisons was NOT the previous tag, note that here: + fates tested against fates-sci.1.76.4_api.35.1.0-ctsm5.2.008 + + +Answer changes +-------------- + +Changes answers relative to baseline: Only for FATES test mods, otherwise B4B + + +Other details +------------- +List any git submodules updated (cime, rtm, mosart, cism, fates, etc.): + FATES: sci.1.73.0_api.35.0.0 -> sci.1.77.0_api.36.0.0 + +Pull Requests that document the changes (include PR ids): +(https://github.com/ESCOMP/ctsm/pull) + +#2507 -- FATES land use v2 API update (CTSM-side) +NGEET#1116 -- V2 Land Use Change + +=============================================================== +=============================================================== Tag name: ctsm5.2.008 Originator(s): erik (Erik Kluzek,UCAR/TSS,303-497-1326) Date: Fri 28 Jun 2024 12:22:46 PM MDT diff --git a/doc/ChangeSum b/doc/ChangeSum index ea9417fe41..209c7e9a51 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,6 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.2.009 glemieux 07/09/2024 FATES Land Use V2 ctsm5.2.008 erik 06/28/2024 Bring changes on temp-branch to master: b4b-dev, git-fleximod, hillslope fsat tmp-240620.n03.ctsm5.2.007 06/27/2024 Set upland hillslope column fsat values to zero (samrabin) tmp-240620.n02.ctsm5.2.007 06/21/2024 Another update of git-fleximod (erik) From da50efd1477e53db42abc11db90b97648daabadf Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 9 Jul 2024 10:27:48 -0700 Subject: [PATCH 313/444] add clarifying language for user about FATES and do_harvest --- doc/ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index 26deed83db..7b40fe908a 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -45,6 +45,8 @@ Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): New FATES namelist option: fates_harvest_mode - This new option provides five harvest modes - The 'event_code' mode takes over the now defunct use_fates_logging option + - The 'landuse_timeseries' option supersedes the use of do_harvest option + with FATES. Using do_harvest is no longer compatible with FATES. New FATES namelist option: use_fates_lupft - This option enables the necessary namelist options and data sets to run From 2b50ebb8dfcfaa609a13b50d04270ed3169fcce8 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 9 Jul 2024 10:29:14 -0700 Subject: [PATCH 314/444] correct fluh_timeseries file name --- bld/namelist_files/namelist_defaults_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 754510289f..97424eb13a 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1558,7 +1558,7 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c lnd/clm2/surfdata_map/fates-sci.1.68.3_api.31.0.0_tools.1.0.1/LUH2_states_transitions_management.timeseries_4x5_hist_simyr1650-2015_c240216.nc + >lnd/clm2/surfdata_map/fates-sci.1.68.3_api.31.0.0_tools.1.0.1/LUH2_states_transitions_management.timeseries_4x5_hist_simyr0850-2015_c240216.nc .false. From 03ab3bdefa98b776263c057b50cf4b803f6c4fd7 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 9 Jul 2024 10:41:40 -0700 Subject: [PATCH 315/444] remove out-dated-comment Checking the landuse x pft data is handled on the fates-side --- src/utils/clmfates_interfaceMod.F90 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index 43a574d6e3..d15288d3a3 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -3915,8 +3915,6 @@ subroutine GetLandusePFTData(bounds, landuse_pft_file, landuse_pft_map, landuse_ deallocate(arraylocal_bareground) call ncd_pio_closefile(ncid) - ! Check that sums equal to unity - end subroutine GetLandusePFTData From 272f99f405e95adec9774519323a34c0f2f9c874 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 9 Jul 2024 13:41:55 -0700 Subject: [PATCH 316/444] remove unused land use mod subroutine --- src/utils/clmfates_interfaceMod.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index d15288d3a3..e3e7644b90 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -182,7 +182,6 @@ module CLMFatesInterfaceMod use dynFATESLandUseChangeMod, only : num_landuse_transition_vars, num_landuse_state_vars use dynFATESLandUseChangeMod, only : landuse_transitions, landuse_states use dynFATESLandUseChangeMod, only : landuse_transition_varnames, landuse_state_varnames - use dynFATESLandUseChangeMod, only : dynFatesLandUseInterp use dynFATESLandUseChangeMod, only : num_landuse_harvest_vars use dynFATESLandUseChangeMod, only : fates_harvest_no_logging use dynFATESLandUseChangeMod, only : fates_harvest_clmlanduse From 4ca2b6aeeb3388efa9b4026b826d902d8a9f6f95 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Wed, 10 Jul 2024 18:17:29 -0600 Subject: [PATCH 317/444] Add error: matrixcn not ok with NTHRDS_LND > 1 (the check does not work) --- bld/CLMBuildNamelist.pm | 16 ++++++++++++++-- bld/unit_testers/build-namelist_test.pl | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 329030d985..7038351688 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -1655,7 +1655,7 @@ sub process_namelist_inline_logic { if ( remove_leading_and_trailing_quotes($nl_flags->{'clm_start_type'}) ne "branch" ) { setup_logic_initial_conditions($opts, $nl_flags, $definition, $defaults, $nl, $physv); } - setup_logic_cnmatrix($opts, $nl_flags, $definition, $defaults, $nl); + setup_logic_cnmatrix($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref); setup_logic_spinup($opts, $nl_flags, $definition, $defaults, $nl); setup_logic_supplemental_nitrogen($opts, $nl_flags, $definition, $defaults, $nl); setup_logic_snowpack($opts, $nl_flags, $definition, $defaults, $nl); @@ -4640,7 +4640,7 @@ sub setup_logic_cnmatrix { # # Set some default options related to the CN Matrix options # - my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref) = @_; my @matrixlist = ( "use_matrixcn", "hist_wrt_matrixcn_diag" ); foreach my $var ( @matrixlist ) { @@ -4650,6 +4650,18 @@ sub setup_logic_cnmatrix { , 'spinup_matrixcn'=>$nl_flags->{'spinup_matrixcn'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} ); } @matrixlist = ( "use_matrixcn", "use_soil_matrixcn", "hist_wrt_matrixcn_diag", "spinup_matrixcn" ); + # Matrix items can't be on for NTHRDS_LND > 1 + my $var_xml = "NTHRDS_LND"; + my $val_xml = int($envxml_ref->{$var_xml}); + print "$var_xml = $val_xml"; + if ( $val_xml > 1) { + foreach my $var ( @matrixlist ) { + if ( &value_is_true($nl->get_value($var)) ) { + $log->warning("$var and $var_xml > 1 causes a clm threading test to FAIL (as of 2024/7/10), so use at your own risk." ); + } + } + } + # Matrix items can't be on for transient if (not string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) { foreach my $var ( @matrixlist ) { diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 9b83f9e7ec..df159a8870 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -42,7 +42,7 @@ sub make_env_run { my %settings = @_; # Set default settings - my %env_vars = ( DIN_LOC_ROOT=>"MYDINLOCROOT", GLC_TWO_WAY_COUPLING=>"FALSE", NEONSITE=>"" ); + my %env_vars = ( DIN_LOC_ROOT=>"MYDINLOCROOT", GLC_TWO_WAY_COUPLING=>"FALSE", NTHRDS_LND=>"1", NEONSITE=>"" ); # Set any settings that came in from function call foreach my $item ( keys(%settings) ) { $env_vars{$item} = $settings{$item}; From 17fb3d8ee57c94c757405b8f77afcf97de5b927f Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 11 Jul 2024 01:27:49 -0600 Subject: [PATCH 318/444] Changes to remove dust_emis namelist items from CTSM fortran code and use shr_dust_emis_mod from CMEPS --- components/cmeps | 2 +- src/biogeochem/DustEmisBase.F90 | 1 - src/biogeochem/DustEmisFactory.F90 | 14 ++++++-------- .../DustEmis_test/test_DustEmisZender2003.pf | 2 ++ src/cpl/nuopc/lnd_import_export.F90 | 5 +++++ .../share_esmf/ZenderSoilErodStreamType.F90 | 18 ++++++------------ src/main/clm_varctl.F90 | 5 ----- src/main/controlMod.F90 | 6 ------ 8 files changed, 20 insertions(+), 33 deletions(-) diff --git a/components/cmeps b/components/cmeps index 6384ff4e4a..e1335d32fc 160000 --- a/components/cmeps +++ b/components/cmeps @@ -1 +1 @@ -Subproject commit 6384ff4e4a6bc82a678f9419a43ffbd5d53ac209 +Subproject commit e1335d32fca0e5571a0d5a7edb0d1473266b7923 diff --git a/src/biogeochem/DustEmisBase.F90 b/src/biogeochem/DustEmisBase.F90 index c5e4260634..47f2f32688 100644 --- a/src/biogeochem/DustEmisBase.F90 +++ b/src/biogeochem/DustEmisBase.F90 @@ -31,7 +31,6 @@ module DustEmisBase use LandunitType , only : lun use ColumnType , only : col use PatchType , only : patch - use clm_varctl , only : dust_emis_method ! ! !PUBLIC TYPES implicit none diff --git a/src/biogeochem/DustEmisFactory.F90 b/src/biogeochem/DustEmisFactory.F90 index 371e77d6dc..24162fde24 100644 --- a/src/biogeochem/DustEmisFactory.F90 +++ b/src/biogeochem/DustEmisFactory.F90 @@ -28,9 +28,9 @@ function create_dust_emissions(bounds, NLFilename) result(dust_emis) !--------------------------------------------------------------------------- use DustEmisBase , only : dust_emis_base_type use DustEmisZender2003, only : dust_emis_zender2003_type - use clm_varctl , only : dust_emis_method use decompMod , only : bounds_type use shr_kind_mod , only : CL => shr_kind_cl + use shr_dust_emis_mod , only : is_dust_emis_zender, is_dust_emis_leung implicit none ! Arguments class(dust_emis_base_type), allocatable :: dust_emis @@ -38,20 +38,18 @@ function create_dust_emissions(bounds, NLFilename) result(dust_emis) character(len=*), intent(in) :: NLFilename ! Local variables - select case ( trim(dust_emis_method) ) - - case( "Zender_2003" ) + if ( is_dust_emis_zender() )then allocate(dust_emis, source=dust_emis_zender2003_type() ) ! This will be added when the Leung2023 comes in - !case( "Leung_2023" ) + !else if ( is_dust_emis_leung() ) ! allocate(dust_emis, source=dust_emis_zender2003_type() ) - case default - write(iulog,*) 'ERROR: unknown dust_emis_method: ', dust_emis_method, & + else + write(iulog,*) 'ERROR: unknown dust_emis_method: ', & errMsg(sourcefile, __LINE__) call endrun( "Unrecognized dust_emis_method" ) - end select + end if call dust_emis%Init(bounds, NLFilename) diff --git a/src/biogeochem/test/DustEmis_test/test_DustEmisZender2003.pf b/src/biogeochem/test/DustEmis_test/test_DustEmisZender2003.pf index 8641b8cceb..0289cadabc 100644 --- a/src/biogeochem/test/DustEmis_test/test_DustEmisZender2003.pf +++ b/src/biogeochem/test/DustEmis_test/test_DustEmisZender2003.pf @@ -9,6 +9,7 @@ module test_DustEmisZender2003 use DustEmisZender2003 use shr_kind_mod , only : r8 => shr_kind_r8 use DustEmisFactory, only : create_dust_emissions + use shr_dust_emis_mod, only : dust_emis_set_options implicit none @@ -37,6 +38,7 @@ contains call this%input%setUp() ! Create the dust emission object last + call dust_emis_set_options( 'Zender_2003', 'atm') allocate(this%dust_emis, source = create_dust_emissions(bounds, NLFilename)) end subroutine setUp diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index b9966f81e9..624590b9a6 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -160,9 +160,11 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r use shr_carma_mod , only : shr_carma_readnl use shr_ndep_mod , only : shr_ndep_readnl + use shr_dust_emis_mod , only : shr_dust_emis_readnl use shr_fire_emis_mod , only : shr_fire_emis_readnl use clm_varctl , only : ndep_from_cpl use controlMod , only : NLFilename + use spmdMod , only : mpicom ! input/output variables type(ESMF_GridComp) :: gcomp @@ -237,6 +239,9 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r ! The following namelist reads should always be called regardless of the send_to_atm value + ! Dust emissions from land to atmosphere + call shr_dust_emis_readnl( mpicom, "drv_flds_in") + ! Dry Deposition velocities from land - ALSO initialize drydep here call shr_drydep_readnl("drv_flds_in", drydep_nflds) diff --git a/src/cpl/share_esmf/ZenderSoilErodStreamType.F90 b/src/cpl/share_esmf/ZenderSoilErodStreamType.F90 index 194e022132..32e776063b 100644 --- a/src/cpl/share_esmf/ZenderSoilErodStreamType.F90 +++ b/src/cpl/share_esmf/ZenderSoilErodStreamType.F90 @@ -42,7 +42,6 @@ module ZenderSoilErodStreamType ! ! PRIVATE DATA: type, private :: streamcontrol_type - character(len=CL) :: zender_soil_erod_source ! if calculed in lnd or atm character(len=CL) :: stream_fldFileName_zendersoilerod ! data Filename character(len=CL) :: stream_meshfile_zendersoilerod ! mesh Filename character(len=CL) :: zendersoilerod_mapalgo ! map algo @@ -179,7 +178,7 @@ logical function UseStreams(this) ! file is being used with it ! ! !USES: - use clm_varctl, only : dust_emis_method + use shr_dust_emis_mod, only : is_dust_emis_zender, is_zender_soil_erod_from_land ! ! !ARGUMENTS: implicit none @@ -189,7 +188,7 @@ logical function UseStreams(this) if ( .not. control%namelist_set )then call endrun(msg=' ERROR namelist NOT set before being used'//errMsg(sourcefile, __LINE__)) end if - if ( (trim(dust_emis_method) == 'Zender_2003') .and. (control%zender_soil_erod_source == "lnd") )then + if ( is_dust_emis_zender() .and. is_zender_soil_erod_from_land() )then UseStreams = .true. else UseStreams = .false. @@ -289,6 +288,7 @@ subroutine ReadNML(this, bounds, NLFilename) use shr_nl_mod , only : shr_nl_find_group_name use shr_log_mod , only : errMsg => shr_log_errMsg use shr_mpi_mod , only : shr_mpi_bcast + use shr_dust_emis_mod, only : is_zender_soil_erod_from_land ! ! arguments implicit none @@ -304,14 +304,13 @@ subroutine ReadNML(this, bounds, NLFilename) character(len=CL) :: stream_meshfile_zendersoilerod = ' ' character(len=CL) :: zendersoilerod_mapalgo = ' ' character(len=CL) :: tmp_file_array(3) - character(len=3) :: zender_soil_erod_source = 'atm' character(len=*), parameter :: namelist_name = 'zendersoilerod' ! MUST agree with group name in namelist definition to read. character(len=*), parameter :: subName = "('zendersoilerod::ReadNML')" !----------------------------------------------------------------------- namelist /zendersoilerod/ & ! MUST agree with namelist_name above zendersoilerod_mapalgo, stream_fldFileName_zendersoilerod, & - stream_meshfile_zendersoilerod, zender_soil_erod_source + stream_meshfile_zendersoilerod ! Default values for namelist @@ -330,12 +329,11 @@ subroutine ReadNML(this, bounds, NLFilename) close(nu_nml) endif - call shr_mpi_bcast(zender_soil_erod_source , mpicom) call shr_mpi_bcast(zendersoilerod_mapalgo , mpicom) call shr_mpi_bcast(stream_fldFileName_zendersoilerod , mpicom) call shr_mpi_bcast(stream_meshfile_zendersoilerod , mpicom) - if (masterproc .and. (zender_soil_erod_source == "lnd") ) then + if (masterproc .and. is_zender_soil_erod_from_land() ) then write(iulog,*) ' ' write(iulog,*) namelist_name, ' stream settings:' write(iulog,*) ' stream_fldFileName_zendersoilerod = ',stream_fldFileName_zendersoilerod @@ -343,13 +341,10 @@ subroutine ReadNML(this, bounds, NLFilename) write(iulog,*) ' zendersoilerod_mapalgo = ',zendersoilerod_mapalgo endif - if ( (trim(zender_soil_erod_source) /= 'atm') .and. (trim(zender_soil_erod_source) /= 'lnd') )then - call endrun(msg=' ERROR zender_soil_erod_source must be either lnd or atm and is NOT'//errMsg(sourcefile, __LINE__)) - end if tmp_file_array(1) = stream_fldFileName_zendersoilerod tmp_file_array(2) = stream_meshfile_zendersoilerod tmp_file_array(3) = zendersoilerod_mapalgo - if ( trim(zender_soil_erod_source) == 'lnd' )then + if ( is_zender_soil_erod_from_land() ) then do i = 1, size(tmp_file_array) if ( len_trim(tmp_file_array(i)) == 0 )then call endrun(msg=' ERROR '//trim(tmp_file_array(i))//' must be set when Zender_2003 is being used and zender_soil_erod_source is lnd'//errMsg(sourcefile, __LINE__)) @@ -365,7 +360,6 @@ subroutine ReadNML(this, bounds, NLFilename) this%stream_fldFileName_zendersoilerod = stream_fldFileName_zendersoilerod this%stream_meshfile_zendersoilerod = stream_meshfile_zendersoilerod this%zendersoilerod_mapalgo = zendersoilerod_mapalgo - this%zender_soil_erod_source = zender_soil_erod_source this%namelist_set = .true. diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index cbfcbfd8ea..97c818af94 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -276,11 +276,6 @@ module clm_varctl ! option to activate OC in snow in SNICAR logical, public :: do_sno_oc = .false. ! control to include organic carbon (OC) in snow - !---------------------------------------------------------- - ! DUST emission method - !---------------------------------------------------------- - character(len=25), public :: dust_emis_method = 'Zender_2003' ! Dust emisison method to use: Zender_2003 or Leung_2023 - !---------------------------------------------------------- ! C isotopes !---------------------------------------------------------- diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 4773cc6921..c92732806c 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -207,12 +207,6 @@ subroutine control_init(dtime) for_testing_no_crop_seed_replenishment, & z0param_method, use_z0m_snowmelt - ! NOTE: EBK 02/26/2024: dust_emis_method is here in CTSM temporarily until it's moved to CMEPS - ! See: https://github.com/ESCOMP/CMEPS/pull/429 - ! Normally this should also need error checking and a broadcast, but since - ! there is only one hardcoded option right now that is unneeded. - namelist /clm_inparm/ dust_emis_method - ! vertical soil mixing variables namelist /clm_inparm/ & som_adv_flux, max_depth_cryoturb From 7dd9af0195592c2a2d9c49fc6767f53ea1bff128 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 11 Jul 2024 02:48:19 -0600 Subject: [PATCH 319/444] Update test number --- bld/unit_testers/build-namelist_test.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index a24b308620..cf5aedef9b 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 3259; +my $ntests = 3256; if ( defined($opts{'compare'}) ) { $ntests += 2001; From 976347ddcd0e158a54483b72f7a48d8825c96f37 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 11 Jul 2024 13:16:32 -0600 Subject: [PATCH 320/444] Update cmeps and ccs_config to versions used in #2590 which allows cases to build --- .gitmodules | 4 ++-- ccs_config | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index b48068c9f6..ee06997ce5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,7 +36,7 @@ fxDONOTUSEurl = https://github.com/ESCOMP/mizuRoute [submodule "ccs_config"] path = ccs_config url = https://github.com/ESMCI/ccs_config_cesm.git -fxtag = ccs_config_cesm0.0.106 +fxtag = ccs_config_cesm1.0.0 fxrequired = ToplevelRequired fxDONOTUSEurl = https://github.com/ESMCI/ccs_config_cesm.git @@ -50,7 +50,7 @@ fxDONOTUSEurl = https://github.com/ESMCI/cime [submodule "cmeps"] path = components/cmeps url = https://github.com/ESCOMP/CMEPS.git -fxtag = cmeps0.14.73 +fxtag = cmeps0.14.77 fxrequired = ToplevelRequired fxDONOTUSEurl = https://github.com/ESCOMP/CMEPS.git diff --git a/ccs_config b/ccs_config index 2ff978f92a..69a958581e 160000 --- a/ccs_config +++ b/ccs_config @@ -1 +1 @@ -Subproject commit 2ff978f92a5ac9a6ab243e5c14d06a7e2d2f5799 +Subproject commit 69a958581ecd2d32ee9cb1c38bcd3847b8b920bf From 170b3a518701e7fb0494423bcc9ef11d90e87f62 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 11 Jul 2024 13:17:21 -0600 Subject: [PATCH 321/444] Update cmeps and ccs_config to versions used in #2590 which allows cases to build --- components/cmeps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/cmeps b/components/cmeps index e1335d32fc..47fb4e633a 160000 --- a/components/cmeps +++ b/components/cmeps @@ -1 +1 @@ -Subproject commit e1335d32fca0e5571a0d5a7edb0d1473266b7923 +Subproject commit 47fb4e633a76ec6d60969b1af751f90790387246 From ba28bea5ca49e44e48d3739647baae04915d805f Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Thu, 11 Jul 2024 13:20:10 -0600 Subject: [PATCH 322/444] Update number of tests and comment out the whole values section as it fails without at least one thing set --- bld/unit_testers/build-namelist_test.pl | 2 +- cime_config/config_component.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index cf5aedef9b..5abb381c16 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -166,7 +166,7 @@ sub cat_and_create_namelistinfile { my $ntests = 3256; if ( defined($opts{'compare'}) ) { - $ntests += 2001; + $ntests += 1965; } plan( tests=>$ntests ); diff --git a/cime_config/config_component.xml b/cime_config/config_component.xml index 01990e162f..7500668905 100644 --- a/cime_config/config_component.xml +++ b/cime_config/config_component.xml @@ -166,11 +166,11 @@ logical TRUE,FALSE TRUE + + --> run_component_cpl env_run.xml If CTSM will set the dust settings in drv_flds_in (TRUE), or if ATM (i.e. CAM) will - DO NOT EDIT (set by compset name) From 7994c82a4427860494c79611fc32fa0efecadeb3 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 11 Jul 2024 16:29:12 -0600 Subject: [PATCH 323/444] Save crop date variables in testmods more frequently. --- cime_config/testdefs/testmods_dirs/clm/crop/user_nl_clm | 7 +++++-- .../testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/crop/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/crop/user_nl_clm index a368e97593..aea8e39e6c 100644 --- a/cime_config/testdefs/testmods_dirs/clm/crop/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/crop/user_nl_clm @@ -9,9 +9,12 @@ hist_fincl2 += 'DYN_COL_SOIL_ADJUSTMENTS_C' -! Annual instantaneous crop variables (including per-sowing/per-harvest axes), per PFT. +! Instantaneous crop variables (including per-sowing/per-harvest axes), per PFT. +! Note that, under normal circumstances, these should only be saved annually. +! That's needed for the mxsowings and mxharvests axes to make sense. +! However, for testing purposes, it makes sense to save more frequently. hist_fincl3 = 'SDATES', 'SDATES_PERHARV', 'SYEARS_PERHARV', 'HDATES', 'GRAINC_TO_FOOD_PERHARV', 'GRAINC_TO_FOOD_ANN', 'GRAINN_TO_FOOD_PERHARV', 'GRAINN_TO_FOOD_ANN', 'GRAINC_TO_SEED_PERHARV', 'GRAINC_TO_SEED_ANN', 'GRAINN_TO_SEED_PERHARV', 'GRAINN_TO_SEED_ANN', 'HDATES', 'GDDHARV_PERHARV', 'GDDACCUM_PERHARV', 'HUI_PERHARV', 'SOWING_REASON_PERHARV', 'HARVEST_REASON_PERHARV', 'SWINDOW_STARTS', 'SWINDOW_ENDS', 'GDD20_BASELINE', 'GDD20_SEASON_START', 'GDD20_SEASON_END' -hist_nhtfrq(3) = 17520 +hist_nhtfrq(3) = -24 hist_mfilt(3) = 1 hist_type1d_pertape(3) = 'PFTS' hist_dov2xy(3) = .false. diff --git a/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm index 8f779ed011..18220de5ef 100644 --- a/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm @@ -1,4 +1,4 @@ - hist_nhtfrq = 0,-240,17520 + hist_nhtfrq = 0,-240,0 hist_mfilt = 1,1,1 ! NOTE slevis (2024/2/23) Adding option for tests to pass. In the long term From 014800df4825a909f3a0297951fcd4f8f05f232b Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 11 Jul 2024 16:32:25 -0600 Subject: [PATCH 324/444] Add tweak_latlons.py. --- python/ctsm/crop_calendars/tweak_latlons.py | 168 ++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 python/ctsm/crop_calendars/tweak_latlons.py diff --git a/python/ctsm/crop_calendars/tweak_latlons.py b/python/ctsm/crop_calendars/tweak_latlons.py new file mode 100644 index 0000000000..de35ced0d1 --- /dev/null +++ b/python/ctsm/crop_calendars/tweak_latlons.py @@ -0,0 +1,168 @@ +# %% +import numpy as np +import xarray as xr +import os +import sys +from netCDF4 import Dataset +import contextlib + +# -- add python/ctsm to path (needed if we want to run this stand-alone) +_CTSM_PYTHON = os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir) +sys.path.insert(1, _CTSM_PYTHON) +# pylint: disable=wrong-import-position +from ctsm.mesh_maker import main as mesh_maker + +topdir = "/glade/campaign/cesm/cesmdata/inputdata/lnd/clm2/cropdata/calendars/processed/" +file_list_in = [ + "swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc", + "swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc", + "gdds_20230829_161011.nc", +] +file_mesh_in = ( + "/glade/campaign/cesm/cesmdata/inputdata/share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc" +) + +file_list_out = [] +coord_list = ["lat", "lon"] + +# %% + + +def apply_tweak(ds, coord_str, tweak=1e-6): + # Apply tweak + da = ds[coord_str] + coord2 = da.values + coord2 += tweak + while np.any(coord2 == da.values): + tweak *= 10 + coord2 = da.values + coord2 += tweak + coord_tweak = np.full_like(coord2, tweak) + + # Ensure that no value is above maximum in input data. This is needed for mesh_maker to work. + max_coord = np.max(da.values) + where_toohigh = np.where(coord2 > max_coord) + Ntoohigh = len(where_toohigh[0]) + if Ntoohigh != 1: + raise RuntimeError(f"Expected 1 coordinate value too high; got {Ntoohigh}") + coord2[where_toohigh] = max_coord + coord_tweak[where_toohigh] = max_coord + + # Convert to DataArray + new_coords_dict = {coord_str: coord2} + da2 = xr.DataArray( + data=coord2, + coords=new_coords_dict, + dims=da.dims, + attrs=da.attrs, + ) + + # Replace coordinate in dataset + ds[coord_str] = da2 + + # Add a variable with the amount of the tweak + tweak_attrs = {} + if "standard_name" in da: + coord_name = da.attrs["standard_name"] + else: + coord_name = da.attrs["long_name"].replace("coordinate_", "") + tweak_attrs["standard_name"] = coord_name + "_tweak" + tweak_attrs[ + "long_name" + ] = f"Amount {coord_name} was shifted to avoid ambiguous nearest neighbors" + tweak_attrs["units"] = da.attrs["units"] + da_tweak = xr.DataArray( + data=coord_tweak, + coords=new_coords_dict, + dims=da.dims, + attrs=tweak_attrs, + ) + tweak_name = coord_str + "_tweak" + ds[tweak_name] = da_tweak + + return ds + + +# %% Apply tweak to all files + +for filename in file_list_in: + file_in = os.path.join(topdir, filename) + ds = xr.open_dataset(file_in) + + for coord in coord_list: + ds = apply_tweak(ds, coord, tweak=1e-6) + + # Set up for save + file_out = file_in.replace(".nc", ".tweaked_latlons.nc") + with Dataset(file_in, "r") as netcdf_file: + netcdf_format = netcdf_file.data_model + + # Save + print(f"Saving {file_out}") + ds.to_netcdf(file_out, format=netcdf_format) + file_list_out.append(file_out) +print("Done") + + +# %% Ensure all files got the same tweaks + +ds = xr.open_dataset(file_list_out[0]) + +for filename in file_list_out[1:]: + ds2 = xr.open_dataset(filename) + for coord in coord_list: + # Ensure that coordinates are the same + var = coord + assert np.array_equal(ds[var].values, ds2[var].values) + # Ensure that tweaks were the same + var = coord + "_tweak" + assert np.array_equal(ds[var].values, ds2[var].values) +print("All good!") + + +# %% Save new mesh file + +outfile_name = os.path.basename(file_mesh_in) +outfile_name = outfile_name.replace(".nc", ".tweaked_latlons.nc") +outdir = os.path.dirname(file_list_out[0]) +file_mesh_out = os.path.join(outdir, outfile_name) + +@contextlib.contextmanager +def redirect_argv(arglist): + argv_tmp = sys.argv[:] + sys.argv=arglist + yield + sys.argv = argv_tmp + + +mesh_maker_args = [ + "mesh_maker", + "--input", + file_list_out[0], + "--output", + file_mesh_out, + "--lat", + "lat", + "--lon", + "lon", + "--overwrite", +] +print(f"Saving {file_mesh_out}...") +with redirect_argv(mesh_maker_args): + mesh_maker() + +# Change format, if needed +with Dataset(file_mesh_in, "r") as netcdf_file: + netcdf_format_in = netcdf_file.data_model +with Dataset(file_mesh_out, "r") as netcdf_file: + netcdf_format_out = netcdf_file.data_model +if netcdf_format_in != netcdf_format_out: + file_mesh_out_tmp = file_mesh_out + ".tmp" + os.rename(file_mesh_out, file_mesh_out_tmp) + ds = xr.open_dataset(file_mesh_out_tmp) + ds.to_netcdf(file_mesh_out, format=netcdf_format_in) + os.remove(file_mesh_out_tmp) + + +print("Done") +# %% From 4c1d66f88985340b2b95dc909b55587475d75514 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 11 Jul 2024 16:37:20 -0600 Subject: [PATCH 325/444] mesh_type.py: Handle a broadcast error. --- python/ctsm/site_and_regional/mesh_type.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/python/ctsm/site_and_regional/mesh_type.py b/python/ctsm/site_and_regional/mesh_type.py index be785e745d..0260f1c816 100644 --- a/python/ctsm/site_and_regional/mesh_type.py +++ b/python/ctsm/site_and_regional/mesh_type.py @@ -235,8 +235,16 @@ def create_2d_coords(self): lons_size = self.center_lons.size # -- convert center points from 1d to 2d - self.center_lat2d = np.broadcast_to(self.center_lats[:], (lons_size, lats_size)) - self.center_lon2d = np.broadcast_to(self.center_lons[:], (lons_size, lats_size)) + try: + self.center_lat2d = np.broadcast_to(self.center_lats[:], (lons_size, lats_size)) + self.center_lon2d = np.broadcast_to(self.center_lons[:], (lons_size, lats_size)) + except ValueError: + self.center_lat2d = np.broadcast_to( + np.expand_dims(self.center_lats[:], 0), (lons_size, lats_size) + ) + self.center_lon2d = np.broadcast_to( + np.expand_dims(self.center_lons[:], 1), (lons_size, lats_size) + ) elif self.lat_dims == 2: # -- 2D lats and lons dims = self.center_lons.shape From f11003ba4e751e7749ebf2ddfb7a26a73ebb04f7 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 11 Jul 2024 16:37:46 -0600 Subject: [PATCH 326/444] mesh_type.py: Improve error for lon > 360. --- python/ctsm/site_and_regional/mesh_type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctsm/site_and_regional/mesh_type.py b/python/ctsm/site_and_regional/mesh_type.py index 0260f1c816..47c0295593 100644 --- a/python/ctsm/site_and_regional/mesh_type.py +++ b/python/ctsm/site_and_regional/mesh_type.py @@ -359,7 +359,7 @@ def calculate_corners(self, unit="degrees"): ) # Longitudes should stay within 0 to 360 if np.any(self.corner_lons > 360.0): - abort("Corners have longitudes greater than 360") + abort(f"Corners have longitudes greater than 360 (max: {np.max(self.corner_lons)})") if np.any(self.corner_lons < 0.0): logger.warning( "Corners have longitudes less than zero -- %s %s", From 231b4ac4372421a714106ec10178416dcb3cb2c6 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 11 Jul 2024 16:44:31 -0600 Subject: [PATCH 327/444] tweak_latlons.py: Add more files. --- python/ctsm/crop_calendars/tweak_latlons.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/ctsm/crop_calendars/tweak_latlons.py b/python/ctsm/crop_calendars/tweak_latlons.py index de35ced0d1..89144a80ae 100644 --- a/python/ctsm/crop_calendars/tweak_latlons.py +++ b/python/ctsm/crop_calendars/tweak_latlons.py @@ -17,6 +17,9 @@ "swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc", "swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc", "gdds_20230829_161011.nc", + "gdd20bl.copied_from.gdds_20230829_161011.v2.nc", + "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc", + "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc", ] file_mesh_in = ( "/glade/campaign/cesm/cesmdata/inputdata/share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc" From 9f186d489d9ce2d3b982cd367756dd43102262a8 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 11 Jul 2024 16:45:50 -0600 Subject: [PATCH 328/444] Use tweaked_latlon cropcal inputs. This avoids different "nearest neighbors" being chosen when using a different number of processors. See https://github.com/orgs/esmf-org/discussions/261 --- bld/namelist_files/namelist_defaults_ctsm.xml | 22 +++++++++---------- .../clm/sowingWindows/user_nl_clm | 6 ++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index ae9f9dee6a..d1f9d8545c 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1704,17 +1704,17 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c 2000 -lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc -lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc -lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc -share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc -lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc -lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc -lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc -lnd/clm2/cropdata/calendars/processed/gdd20bl.copied_from.gdds_20230829_161011.v2.nc -lnd/clm2/cropdata/calendars/processed/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc -lnd/clm2/cropdata/calendars/processed/hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc -share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc +lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/gdd20bl.copied_from.gdds_20230829_161011.v2.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc diff --git a/cime_config/testdefs/testmods_dirs/clm/sowingWindows/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/sowingWindows/user_nl_clm index 545e5f6ebd..7024e99b96 100644 --- a/cime_config/testdefs/testmods_dirs/clm/sowingWindows/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/sowingWindows/user_nl_clm @@ -1,5 +1,5 @@ -stream_fldFileName_swindow_start = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc' -stream_fldFileName_swindow_end = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc' -stream_meshfile_cropcal = '$DIN_LOC_ROOT/share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc' +stream_fldFileName_swindow_start = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc' +stream_fldFileName_swindow_end = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc' +stream_meshfile_cropcal = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc' stream_year_first_cropcal_swindows = 2000 stream_year_last_cropcal_swindows = 2000 From 3ce1bb42c09670d87cd9fdca86cdbd24b19fd1f2 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 11 Jul 2024 17:34:25 -0600 Subject: [PATCH 329/444] Code mods to get the error check in the previous commit to work --- bld/CLMBuildNamelist.pm | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 7038351688..caa116e3bc 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4650,14 +4650,13 @@ sub setup_logic_cnmatrix { , 'spinup_matrixcn'=>$nl_flags->{'spinup_matrixcn'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} ); } @matrixlist = ( "use_matrixcn", "use_soil_matrixcn", "hist_wrt_matrixcn_diag", "spinup_matrixcn" ); - # Matrix items can't be on for NTHRDS_LND > 1 - my $var_xml = "NTHRDS_LND"; - my $val_xml = int($envxml_ref->{$var_xml}); - print "$var_xml = $val_xml"; + # Matrix items can't be on for OMP_NUM_THREADS (also known as NTHRDS_LND) > 1 + my $var_xml = "OMP_NUM_THREADS"; + my $val_xml = $ENV{$var_xml}; if ( $val_xml > 1) { foreach my $var ( @matrixlist ) { if ( &value_is_true($nl->get_value($var)) ) { - $log->warning("$var and $var_xml > 1 causes a clm threading test to FAIL (as of 2024/7/10), so use at your own risk." ); + $log->warning("$var and $var_xml > 1 (in this case $val_xml) causes a clm threading test to FAIL (as of 2024/7/10), so use at your own risk." ); } } } From 1377d48022c5db5a7352744b7356aa4cce1e8413 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 12 Jul 2024 10:12:26 -0600 Subject: [PATCH 330/444] Fix default stream_meshfile_cropcal. --- bld/namelist_files/namelist_defaults_ctsm.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index d1f9d8545c..3f8bc1f382 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1707,14 +1707,14 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.tweaked_latlons.nc -lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/360x720_120830_ESMFmesh_c20210507_cdf5.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/gdd20bl.copied_from.gdds_20230829_161011.v2.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.tweaked_latlons.nc -lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/360x720_120830_ESMFmesh_c20210507_cdf5.tweaked_latlons.nc From d60dc80d74609096b63c942ca41e0ca38177683b Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 12 Jul 2024 10:13:06 -0600 Subject: [PATCH 331/444] Fix reset of sowing_reason_perharv_patch. --- src/biogeochem/CNPhenologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index d4f486acb7..d1d3c85b21 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -1976,7 +1976,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & cnveg_state_inst%gddmaturity_thisyr(p,s) = -1._r8 crop_inst%gddaccum_thisyr_patch(p,s) = -1._r8 crop_inst%hui_thisyr_patch(p,s) = -1._r8 - crop_inst%sowing_reason_perharv_patch = -1._r8 + crop_inst%sowing_reason_perharv_patch(p,s) = -1._r8 crop_inst%harvest_reason_thisyr_patch(p,s) = -1._r8 do k = repr_grain_min, repr_grain_max cnveg_carbonflux_inst%repr_grainc_to_food_perharv_patch(p,s,k) = 0._r8 From 093f5fb615988c4ec3cf9e41997178ca45e4808c Mon Sep 17 00:00:00 2001 From: Gregory Lemieux <7565064+glemieux@users.noreply.github.com> Date: Fri, 12 Jul 2024 09:55:43 -0700 Subject: [PATCH 332/444] Update bld/namelist_files/namelist_definition_ctsm.xml with note asterisks --- bld/namelist_files/namelist_definition_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index c8118031cc..ce2c1b3c5a 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -740,7 +740,7 @@ Set FATES harvesting mode by setting fates_harvest_mode to a valid string option Allowed values are: no_harvest: no fates harvesting of any kind event_code: fates logging via fates logging event codes (see fates parameter file) only - landuse_timeseries: fates harvest driven by CLM flanduse_timeseries file (dynHarvestMod) + landuse_timeseries: fates harvest driven by CLM flanduse_timeseries file (dynHarvestMod)** luhdata_area: fates harvest driven by LUH2 raw harvest data, area-based (dynFATESLandUseChangeMod) luhdata_mass: fates harvest driven by LUH2 raw harvest data, mass-based (dynFATESLandUseChangeMod) Note that the landuse_timeseries option is not the same as the FATES fluh_timeseries data file. From 63c458254274edf650aac6bb0da359630446bfca Mon Sep 17 00:00:00 2001 From: Gregory Lemieux <7565064+glemieux@users.noreply.github.com> Date: Fri, 12 Jul 2024 09:57:09 -0700 Subject: [PATCH 333/444] Update bld/namelist_files/namelist_definition_ctsm.xml with astericks Link to note --- bld/namelist_files/namelist_definition_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index ce2c1b3c5a..208c42038e 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -743,7 +743,7 @@ Allowed values are: landuse_timeseries: fates harvest driven by CLM flanduse_timeseries file (dynHarvestMod)** luhdata_area: fates harvest driven by LUH2 raw harvest data, area-based (dynFATESLandUseChangeMod) luhdata_mass: fates harvest driven by LUH2 raw harvest data, mass-based (dynFATESLandUseChangeMod) -Note that the landuse_timeseries option is not the same as the FATES fluh_timeseries data file. +**Note that the landuse_timeseries option is not the same as the FATES fluh_timeseries data file. This option is older than the luhdata options and may be depricated at some point in the future. From 7417640e49d9b83932b0ba608b13987b5e62de2c Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 12 Jul 2024 11:07:12 -0600 Subject: [PATCH 334/444] Allow tests with threading to proceed with -ignore_warnings --- cime_config/testdefs/testlist_clm.xml | 42 +++++++++---------- .../clm/matrixcnOn_Hist/shell_commands | 3 -- .../include_user_mods | 0 .../matrixcnOn_ignore_warnings/shell_commands | 7 ++++ 4 files changed, 28 insertions(+), 24 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/shell_commands rename cime_config/testdefs/testmods_dirs/clm/{matrixcnOn_Hist => matrixcnOn_ignore_warnings}/include_user_mods (100%) create mode 100644 cime_config/testdefs/testmods_dirs/clm/matrixcnOn_ignore_warnings/shell_commands diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 1fe5ed770d..7ead363a6d 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -548,7 +548,7 @@ - + @@ -794,7 +794,7 @@ - + @@ -1002,7 +1002,7 @@ - + @@ -1020,7 +1020,7 @@ - + @@ -1038,7 +1038,7 @@ - + @@ -1074,7 +1074,7 @@ - + @@ -1092,7 +1092,7 @@ - + @@ -1145,7 +1145,7 @@ - + @@ -1162,7 +1162,7 @@ - + @@ -1234,7 +1234,7 @@ - + @@ -1354,7 +1354,7 @@ - + @@ -1390,7 +1390,7 @@ - + @@ -1435,7 +1435,7 @@ - + @@ -1445,7 +1445,7 @@ - + @@ -1455,7 +1455,7 @@ - + @@ -1793,7 +1793,7 @@ - + @@ -1849,7 +1849,7 @@ - + @@ -1897,7 +1897,7 @@ - + @@ -1925,7 +1925,7 @@ - + @@ -1982,7 +1982,7 @@ - + @@ -2369,7 +2369,7 @@ - + diff --git a/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/shell_commands b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/shell_commands deleted file mode 100644 index f0547f3f26..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/shell_commands +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -./xmlchange CLM_BLDNML_OPTS="-ignore_warnings" --append diff --git a/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_ignore_warnings/include_user_mods similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/matrixcnOn_Hist/include_user_mods rename to cime_config/testdefs/testmods_dirs/clm/matrixcnOn_ignore_warnings/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_ignore_warnings/shell_commands b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_ignore_warnings/shell_commands new file mode 100644 index 0000000000..d94ef06a5c --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn_ignore_warnings/shell_commands @@ -0,0 +1,7 @@ +#!/bin/bash + +./xmlchange CLM_BLDNML_OPTS="-ignore_warnings" --append + +# In this testmod directory we are ignoring warnings about running +# matrixcn in transient simulations AND/OR +# warnings about running matrixcn with threading NTHRDS_LND > 1. From 1e9df4973fdfcb9e685026ecaed2b56745b24663 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux <7565064+glemieux@users.noreply.github.com> Date: Fri, 12 Jul 2024 10:27:07 -0700 Subject: [PATCH 335/444] update comment regarding landuse x pft data set Pre-generating files is a more likely next step relative to auto-gen --- cime_config/SystemTests/pvt.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cime_config/SystemTests/pvt.py b/cime_config/SystemTests/pvt.py index feef6cb04c..2a3dbafdc3 100644 --- a/cime_config/SystemTests/pvt.py +++ b/cime_config/SystemTests/pvt.py @@ -30,9 +30,8 @@ def __init__(self,case): error_message = (f"Only call PVT with testmod FatesLUPFT. {casebaseid} selected.") # Only allow to run if resolution is 4x5 for now - # Eventually we could set this up to generate the necessary land use x pft mapping - # on the fly, although this would also require generating the land use timeseries - # regridding on the fly which is a more time consuming endevour currently + # Other grid resolutions will be pre-processed and included in the namelist defaults at a future date. + # Potentially we could generate these on the fly although doing so would result in increased build time lnd_grid = self._case.get_value("LND_GRID") if lnd_grid != "4x5": error_message = (f"PVT can currently only be run with 4x5 resolution. {lnd_grid} selected.") From 48aeb43c9575c80a1547a85c1b02b529b690ac05 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux <7565064+glemieux@users.noreply.github.com> Date: Fri, 12 Jul 2024 10:40:15 -0700 Subject: [PATCH 336/444] Update README with suggested clarification --- cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/README | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/README b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/README index 79d6511d17..9b782cb2a7 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/README +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLUH2/README @@ -1,2 +1,4 @@ Currently the FATES LUH2 category of test mods currently only supports -4x5 grid resolutions. +4x5 grid resolutions. This is because we only have one LUH2 time series +dataset for the 4x5 resolution. In the future we will provide more resolutions +which will be added to the namelist defaults. From 5c3e71fe608c73c47f8f3e9b8ac6ee4102ce63a5 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 12 Jul 2024 11:46:58 -0600 Subject: [PATCH 337/444] Remove midDecStart-RxCropCalsAdaptGGCMI test from expected fails. --- cime_config/testdefs/ExpectedTestFails.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 0fac518374..03eb6a157d 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -170,13 +170,6 @@ - - - FAIL - #2593 - - - From dc488c77a715bba7115c92c43948b668c6c38bc0 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 12 Jul 2024 14:46:59 -0600 Subject: [PATCH 338/444] Improve interpolate_gdds.py. --- python/ctsm/crop_calendars/interpolate_gdds.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/python/ctsm/crop_calendars/interpolate_gdds.py b/python/ctsm/crop_calendars/interpolate_gdds.py index 2aa0b79997..809be98826 100755 --- a/python/ctsm/crop_calendars/interpolate_gdds.py +++ b/python/ctsm/crop_calendars/interpolate_gdds.py @@ -64,6 +64,14 @@ def _setup_process_args(): type=str, required=True, ) + parser.add_argument( + "-p", + "--variable-prefix", + help="Interpolate variables whose names start with this string", + type=str, + required=False, + default="gdd1_" + ) parser.add_argument( "--overwrite", help="If output file exists, overwrite it.", @@ -110,8 +118,12 @@ def interpolate_gdds(args): for var in ds_in: # Check variable - if "gdd1_" not in var: - raise RuntimeError(f"Unexpected variable {var} on input file") + if "lat" not in ds_in[var].dims and "lon" not in ds_in[var].dims: + print(f"Skipping variable {var} with dimensions {ds_in[var].dims}") + continue + elif args.variable_prefix not in var: + print(f"Unexpected variable {var} on input file. Skipping.") + continue if args.dry_run: continue From 9ee75610973c32376f6dc407c99a0bc8d55cad83 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 12 Jul 2024 14:09:26 -0700 Subject: [PATCH 339/444] fix how harvest mode is passed to add_default for use_fates_luh --- bld/CLMBuildNamelist.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 47e0fff402..ac87d6f4ca 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4522,7 +4522,7 @@ sub setup_logic_fates { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_luh', 'use_fates'=>$nl_flags->{'use_fates'}, 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), 'use_fates_potentialveg'=>$nl->get_value('use_fates_potentialveg'), - 'fates_harvest_mode'=>$nl->get_value('fates_harvest_mode') ); + 'fates_harvest_mode'=>remove_leading_and_trailing_quotes($nl->get_value('fates_harvest_mode')) ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_nocomp', 'use_fates'=>$nl_flags->{'use_fates'}, 'use_fates_lupft'=>$nl->get_value('use_fates_lupft'), 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); From 48368ac9a5fd2c36fb57cd21c3be76f773e3744d Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 12 Jul 2024 15:11:48 -0700 Subject: [PATCH 340/444] add comment pointing to luh2 data set readme --- src/dyn_subgrid/dynFATESLandUseChangeMod.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 index 681d39f38c..1bc6ab929e 100644 --- a/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 +++ b/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 @@ -50,6 +50,7 @@ module dynFATESLandUseChangeMod type(dyn_file_type), target :: dynFatesLandUse_file ! LUH2 raw wood harvest area fraction + ! LUH2 data set variable names can be found at https://luh.umd.edu/LUH2/LUH2_v2h_README.pdf character(len=10), target :: landuse_harvest_area_varnames(num_landuse_harvest_vars) = & [character(len=10) :: 'primf_harv', 'primn_harv', 'secmf_harv', 'secyf_harv', 'secnf_harv'] From b0e6565a8d802db3c1a4a2ad3322726ed680b09f Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 12 Jul 2024 15:18:54 -0700 Subject: [PATCH 341/444] add single quotes around fates_harvest_mode in unit tests --- bld/unit_testers/build-namelist_test.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index b343e3d194..e60a411ccb 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -1009,7 +1009,7 @@ sub cat_and_create_namelistinfile { phys=>"clm5_0", }, "useloggingButNOTFATES" =>{ options=>"-envxml_dir . -no-megan", - namelst=>"fates_harvest_mode=event_code", + namelst=>"fates_harvest_mode='event_code'", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, @@ -1064,12 +1064,12 @@ sub cat_and_create_namelistinfile { phys=>"clm5_0", }, "useFATESPOTVEGwithHARVEST" =>{ options=>"-bgc fates -envxml_dir . -no-megan", - namelst=>"use_fates_potentialveg=T,fates_harvest_mode=event_code", + namelst=>"use_fates_potentialveg=T,fates_harvest_mode='event_code'", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, "useFATESHARVEST3WOLUH" =>{ options=>"-bgc fates -envxml_dir . -no-megan", - namelst=>"use_fates_luh=F,fates_harvest_mode=luhdata_area", + namelst=>"use_fates_luh=F,fates_harvest_mode='luhdata_area'", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, From 3db9bf2788141d9eaea0d9f8dd331c96f7d01165 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 12 Jul 2024 15:08:03 -0600 Subject: [PATCH 342/444] tweak_latlons: Include gdd20 files. --- python/ctsm/crop_calendars/tweak_latlons.py | 105 +++++++++++++++----- 1 file changed, 80 insertions(+), 25 deletions(-) diff --git a/python/ctsm/crop_calendars/tweak_latlons.py b/python/ctsm/crop_calendars/tweak_latlons.py index 89144a80ae..0031d492e0 100644 --- a/python/ctsm/crop_calendars/tweak_latlons.py +++ b/python/ctsm/crop_calendars/tweak_latlons.py @@ -20,6 +20,8 @@ "gdd20bl.copied_from.gdds_20230829_161011.v2.nc", "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc", "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc", + "/glade/work/samrabin/cropCals_testing_20240626/gdds_20240712_114642_10x15_interpd_halfdeg.nc", + "/glade/work/samrabin/gdd20_baselines/gswp3.10x15_interpd_halfdeg.1980-2009.nc", ] file_mesh_in = ( "/glade/campaign/cesm/cesmdata/inputdata/share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc" @@ -27,19 +29,43 @@ file_list_out = [] coord_list = ["lat", "lon"] +COORD_DATATYPE = np.float64 -# %% - +# %% Define functions -def apply_tweak(ds, coord_str, tweak=1e-6): - # Apply tweak - da = ds[coord_str] - coord2 = da.values +def get_ds(topdir, file_in): + if not os.path.exists(file_in): + file_in = os.path.join(topdir, file_in) + ds = xr.open_dataset(file_in) + return file_in, ds + +def get_tweak(ds_in, coord_str, init_tweak): + """ + Get the tweak that will be applied to all datasets' lat/lon coordinates + """ + da = ds_in[coord_str] + coord2_orig = da.values.astype(COORD_DATATYPE) + coord2 = coord2_orig + tweak = init_tweak coord2 += tweak + + # This is necessary if precision is lower than float64 + max_tweak = 1e-2 while np.any(coord2 == da.values): tweak *= 10 - coord2 = da.values + if tweak > max_tweak: + raise RuntimeError(f"Tweaking by +{max_tweak} failed to 'take'") + coord2 = coord2_orig coord2 += tweak + return tweak + +def apply_tweak(ds_in, coord_str, tweak): + # Apply tweak + da = ds_in[coord_str] + coord2 = da.values.astype(COORD_DATATYPE) + coord2 += tweak + if np.any(coord2 == da.values): + raise RuntimeError('Tweak didn''t "take"') coord_tweak = np.full_like(coord2, tweak) # Ensure that no value is above maximum in input data. This is needed for mesh_maker to work. @@ -61,19 +87,22 @@ def apply_tweak(ds, coord_str, tweak=1e-6): ) # Replace coordinate in dataset - ds[coord_str] = da2 + ds_in[coord_str] = da2 # Add a variable with the amount of the tweak tweak_attrs = {} - if "standard_name" in da: + if "standard_name" in da.attrs: coord_name = da.attrs["standard_name"] - else: + elif "long_name" in da.attrs: coord_name = da.attrs["long_name"].replace("coordinate_", "") + else: + coord_name = coord_str tweak_attrs["standard_name"] = coord_name + "_tweak" tweak_attrs[ "long_name" ] = f"Amount {coord_name} was shifted to avoid ambiguous nearest neighbors" - tweak_attrs["units"] = da.attrs["units"] + if "units" in da.attrs: + tweak_attrs["units"] = da.attrs["units"] da_tweak = xr.DataArray( data=coord_tweak, coords=new_coords_dict, @@ -81,19 +110,48 @@ def apply_tweak(ds, coord_str, tweak=1e-6): attrs=tweak_attrs, ) tweak_name = coord_str + "_tweak" - ds[tweak_name] = da_tweak + ds_in[tweak_name] = da_tweak + + return ds_in + +def check(ds, f0_base, ds2, f_base, var): + if not np.array_equal(ds[var].values, ds2[var].values): + if not np.array_equal(ds[var].shape, ds2[var].shape): + msg = f"{var} shapes differ b/w {f0_base} ({ds[var].shape}) and {f_base} ({ds2[var].shape})" + raise RuntimeError(msg) + max_diff = np.max(np.abs(ds[var].values - ds2[var].values)) + msg = f"{var}s differ between {f0_base} and {f_base}; max = {max_diff}" + type0 = type(ds[var].values[0]) + type2 = type(ds2[var].values[0]) + if type0 != type2: + msg += f"\nTypes also differ: {type0} vs. {type2}" + raise RuntimeError(msg) - return ds +# %% Apply tweak to all files +# Set up empty dicts +tweak_dict = {} +coord_type_dict = {} +for coord in coord_list: + tweak_dict[coord] = -np.inf -# %% Apply tweak to all files +# Get tweaks +for file_in in file_list_in: + file_in, ds = get_ds(topdir, file_in) + for coord in coord_list: + this_tweak = get_tweak(ds, coord, init_tweak=1e-6) + if this_tweak > tweak_dict[coord]: + tweak_dict[coord] = this_tweak +for coord in coord_list: + print(f"Tweaking {coord} by {tweak_dict[coord]}") +print(" ") -for filename in file_list_in: - file_in = os.path.join(topdir, filename) - ds = xr.open_dataset(file_in) +# Apply tweaks +for file_in in file_list_in: + file_in, ds = get_ds(topdir, file_in) for coord in coord_list: - ds = apply_tweak(ds, coord, tweak=1e-6) + ds = apply_tweak(ds, coord, tweak_dict[coord]) # Set up for save file_out = file_in.replace(".nc", ".tweaked_latlons.nc") @@ -110,16 +168,14 @@ def apply_tweak(ds, coord_str, tweak=1e-6): # %% Ensure all files got the same tweaks ds = xr.open_dataset(file_list_out[0]) +f0_base = os.path.basename(file_list_out[0]) for filename in file_list_out[1:]: ds2 = xr.open_dataset(filename) + f_base = os.path.basename(filename) for coord in coord_list: - # Ensure that coordinates are the same - var = coord - assert np.array_equal(ds[var].values, ds2[var].values) - # Ensure that tweaks were the same - var = coord + "_tweak" - assert np.array_equal(ds[var].values, ds2[var].values) + check(ds, f0_base, ds2, f_base, coord) + check(ds, f0_base, ds2, f_base, coord + "_tweak") print("All good!") @@ -168,4 +224,3 @@ def redirect_argv(arglist): print("Done") -# %% From 8e618bb5384ba72d2b53b45a778aad29be542221 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 12 Jul 2024 16:44:47 -0600 Subject: [PATCH 343/444] Add new test to build-namelist_test.pl (currently failing) --- bld/unit_testers/build-namelist_test.pl | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 005f2c3f96..1810d4434b 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -41,7 +41,7 @@ sub make_env_run { # my %settings = @_; - # Set default settings + # Set default settings TODO slevis: NTHRDS_LND fails, OMP_NUM_THREADS fails my %env_vars = ( DIN_LOC_ROOT=>"MYDINLOCROOT", GLC_TWO_WAY_COUPLING=>"FALSE", NTHRDS_LND=>"1", NEONSITE=>"" ); # Set any settings that came in from function call foreach my $item ( keys(%settings) ) { @@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 3306; +my $ntests = 3309; if ( defined($opts{'compare'}) ) { $ntests += 2045; @@ -1320,6 +1320,12 @@ sub cat_and_create_namelistinfile { my %warntest = ( # Warnings without the -ignore_warnings option given + "matrixcnOn_with_threading" =>{ options=>"-envxml_dir . -bgc bgc", + namelst=>"use_matrixcn=.true.", + GLC_TWO_WAY_COUPLING=>"TRUE", + NTHRDS_LND=>"2", + phys=>"clm5_0", + }, "dustemisLeung" =>{ options=>"-envxml_dir .", namelst=>"dust_emis_method = 'Leung_2023'", GLC_TWO_WAY_COUPLING=>"FALSE", @@ -1376,7 +1382,13 @@ sub cat_and_create_namelistinfile { &make_config_cache($warntest{$key}{"phys"}); my $options = $warntest{$key}{"options"}; my $namelist = $warntest{$key}{"namelst"}; - &make_env_run( GLC_TWO_WAY_COUPLING=>$warntest{$key}{"GLC_TWO_WAY_COUPLING"} ); + my %settings; + foreach my $xmlvar ( "GLC_TWO_WAY_COUPLING", "NTHRDS_LND") { + if ( defined($failtest{$key}{$xmlvar}) ) { + $settings{$xmlvar} = $failtest{$key}{$xmlvar}; + } + } + &make_env_run( %settings ); eval{ system( "$bldnml $options -namelist \"&clmexp $namelist /\" > $tempfile 2>&1 " ); }; isnt( $?, 0, $key ); system( "cat $tempfile" ); From 64302ad0c48b2afd7a074659c6509ae3344a4ac3 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 12 Jul 2024 16:54:46 -0600 Subject: [PATCH 344/444] Additions/tweaks to CLM testlist. --- cime_config/testdefs/testlist_clm.xml | 44 +++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 40f351ab4a..3fde176440 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3663,6 +3663,8 @@ + + @@ -3673,6 +3675,7 @@ + @@ -3684,6 +3687,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3754,13 +3793,14 @@ - + + @@ -3773,7 +3813,7 @@ - + From 12c60f3de477bbdaa2cf7a8afe0d089886d2c960 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 12 Jul 2024 16:01:12 -0700 Subject: [PATCH 345/444] correct POTVEG fail unit test This needs to have use_fates_luh to avoid the false negative of failing due to not having this mode with use_fates_potentialveg --- bld/unit_testers/build-namelist_test.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index fc1e83f162..741964d8a1 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -1063,7 +1063,7 @@ sub cat_and_create_namelistinfile { phys=>"clm5_0", }, "useFATESPOTVEGwithHARVEST" =>{ options=>"-bgc fates -envxml_dir . -no-megan", - namelst=>"use_fates_potentialveg=T,fates_harvest_mode='event_code'", + namelst=>"use_fates_potentialveg=T,fates_harvest_mode='event_code',use_fates_luh=T", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, From 0da6eb5c706217606c1323b2b1a57eb136e32f1a Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sun, 14 Jul 2024 12:01:58 -0600 Subject: [PATCH 346/444] Remove Clm50 RXCROPMATURITY tests. --- cime_config/testdefs/testlist_clm.xml | 37 +-------------------------- 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 3fde176440..86210256ff 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3660,42 +3660,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + From 87d1fa1a4b2a69c2d01898be9d8f9e661af8d163 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sun, 14 Jul 2024 12:43:31 -0600 Subject: [PATCH 347/444] Move tweak_latlons.py to tools/contrib/. This is hopefully not something that will be needed permanently or even in the medium term, so it's not worth cleaning up and unit-/system-testing. --- {python/ctsm/crop_calendars => tools/contrib}/tweak_latlons.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {python/ctsm/crop_calendars => tools/contrib}/tweak_latlons.py (100%) diff --git a/python/ctsm/crop_calendars/tweak_latlons.py b/tools/contrib/tweak_latlons.py similarity index 100% rename from python/ctsm/crop_calendars/tweak_latlons.py rename to tools/contrib/tweak_latlons.py From f6ff13409d58a50299d0d62207e99a12b2c426a6 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sun, 14 Jul 2024 14:07:51 -0600 Subject: [PATCH 348/444] Rework tweak_latlons.py to run from command line. --- tools/contrib/tweak_latlons.py | 285 +++++++++++++++++++-------------- 1 file changed, 164 insertions(+), 121 deletions(-) diff --git a/tools/contrib/tweak_latlons.py b/tools/contrib/tweak_latlons.py index 0031d492e0..2bae06d229 100644 --- a/tools/contrib/tweak_latlons.py +++ b/tools/contrib/tweak_latlons.py @@ -1,44 +1,23 @@ -# %% -import numpy as np -import xarray as xr +""" +'Tweak' the latitude and longitude coordinates to avoid ambiguous nearest neighbors +""" import os import sys -from netCDF4 import Dataset import contextlib +import argparse +import numpy as np +import xarray as xr +from netCDF4 import Dataset # pylint: disable=no-name-in-module # -- add python/ctsm to path (needed if we want to run this stand-alone) -_CTSM_PYTHON = os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir) +_CTSM_PYTHON = os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir, "python") sys.path.insert(1, _CTSM_PYTHON) # pylint: disable=wrong-import-position from ctsm.mesh_maker import main as mesh_maker -topdir = "/glade/campaign/cesm/cesmdata/inputdata/lnd/clm2/cropdata/calendars/processed/" -file_list_in = [ - "swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc", - "swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc", - "gdds_20230829_161011.nc", - "gdd20bl.copied_from.gdds_20230829_161011.v2.nc", - "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc", - "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.nc", - "/glade/work/samrabin/cropCals_testing_20240626/gdds_20240712_114642_10x15_interpd_halfdeg.nc", - "/glade/work/samrabin/gdd20_baselines/gswp3.10x15_interpd_halfdeg.1980-2009.nc", -] -file_mesh_in = ( - "/glade/campaign/cesm/cesmdata/inputdata/share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc" -) - -file_list_out = [] -coord_list = ["lat", "lon"] +COORD_LIST = ["lat", "lon"] COORD_DATATYPE = np.float64 -# %% Define functions - -def get_ds(topdir, file_in): - if not os.path.exists(file_in): - file_in = os.path.join(topdir, file_in) - ds = xr.open_dataset(file_in) - return file_in, ds - def get_tweak(ds_in, coord_str, init_tweak): """ Get the tweak that will be applied to all datasets' lat/lon coordinates @@ -73,7 +52,9 @@ def apply_tweak(ds_in, coord_str, tweak): where_toohigh = np.where(coord2 > max_coord) Ntoohigh = len(where_toohigh[0]) if Ntoohigh != 1: - raise RuntimeError(f"Expected 1 coordinate value too high; got {Ntoohigh}") + raise RuntimeError( + f"Expected 1 coordinate value too high; got {Ntoohigh}" + ) coord2[where_toohigh] = max_coord coord_tweak[where_toohigh] = max_coord @@ -127,100 +108,162 @@ def check(ds, f0_base, ds2, f_base, var): msg += f"\nTypes also differ: {type0} vs. {type2}" raise RuntimeError(msg) -# %% Apply tweak to all files - -# Set up empty dicts -tweak_dict = {} -coord_type_dict = {} -for coord in coord_list: - tweak_dict[coord] = -np.inf - -# Get tweaks -for file_in in file_list_in: - file_in, ds = get_ds(topdir, file_in) - for coord in coord_list: - this_tweak = get_tweak(ds, coord, init_tweak=1e-6) - if this_tweak > tweak_dict[coord]: - tweak_dict[coord] = this_tweak -for coord in coord_list: - print(f"Tweaking {coord} by {tweak_dict[coord]}") -print(" ") - -# Apply tweaks -for file_in in file_list_in: - file_in, ds = get_ds(topdir, file_in) - - for coord in coord_list: - ds = apply_tweak(ds, coord, tweak_dict[coord]) - - # Set up for save - file_out = file_in.replace(".nc", ".tweaked_latlons.nc") - with Dataset(file_in, "r") as netcdf_file: - netcdf_format = netcdf_file.data_model - - # Save - print(f"Saving {file_out}") - ds.to_netcdf(file_out, format=netcdf_format) - file_list_out.append(file_out) -print("Done") - - -# %% Ensure all files got the same tweaks - -ds = xr.open_dataset(file_list_out[0]) -f0_base = os.path.basename(file_list_out[0]) - -for filename in file_list_out[1:]: - ds2 = xr.open_dataset(filename) - f_base = os.path.basename(filename) - for coord in coord_list: - check(ds, f0_base, ds2, f_base, coord) - check(ds, f0_base, ds2, f_base, coord + "_tweak") -print("All good!") - - -# %% Save new mesh file - -outfile_name = os.path.basename(file_mesh_in) -outfile_name = outfile_name.replace(".nc", ".tweaked_latlons.nc") -outdir = os.path.dirname(file_list_out[0]) -file_mesh_out = os.path.join(outdir, outfile_name) - @contextlib.contextmanager def redirect_argv(arglist): + """ + Preserve actual arg list while giving a new one to mesh_maker + """ argv_tmp = sys.argv[:] - sys.argv=arglist + sys.argv = arglist yield sys.argv = argv_tmp +def main(input_files, mesh_file_in, output_files): + """ + Apply tweak to all files + """ + + # Set up + tweak_dict = {} + for coord in COORD_LIST: + tweak_dict[coord] = -np.inf + mesh_file_out = output_files[-1] + output_files = output_files[:-1] + + # Get tweaks + for file_in in input_files: + ds = xr.open_dataset(file_in) + for coord in COORD_LIST: + this_tweak = get_tweak(ds, coord, init_tweak=1e-6) + if this_tweak > tweak_dict[coord]: + tweak_dict[coord] = this_tweak + for coord in COORD_LIST: + print(f"Tweaking {coord} by {tweak_dict[coord]}") + print(" ") + + # Apply tweaks + for i, file_in in enumerate(input_files): + ds = xr.open_dataset(file_in) + + for coord in COORD_LIST: + ds = apply_tweak(ds, coord, tweak_dict[coord]) + + # Set up for save + file_out = output_files[i] + with Dataset(file_in, "r") as netcdf_file: + netcdf_format = netcdf_file.data_model + + # Make output dir, if needed + output_dir = os.path.dirname(file_out) + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + # Save + print(f"Saving {file_out}") + ds.to_netcdf(file_out, format=netcdf_format) + print("Done") + + + # Ensure all files got the same tweaks + ds = xr.open_dataset(output_files[0]) + f0_base = os.path.basename(output_files[0]) + for file_out in output_files[1:]: + ds2 = xr.open_dataset(file_out) + f_base = os.path.basename(file_out) + for coord in COORD_LIST: + check(ds, f0_base, ds2, f_base, coord) + check(ds, f0_base, ds2, f_base, coord + "_tweak") + + + # Save new mesh file + mesh_maker_args = [ + "mesh_maker", + "--input", + output_files[0], + "--output", + mesh_file_out, + "--lat", + "lat", + "--lon", + "lon", + "--overwrite", + ] + print(f"Saving {mesh_file_out}...") + with redirect_argv(mesh_maker_args): + mesh_maker() + + # Change format, if needed + with Dataset(mesh_file_in, "r") as netcdf_file: + netcdf_format_in = netcdf_file.data_model + with Dataset(mesh_file_out, "r") as netcdf_file: + netcdf_format_out = netcdf_file.data_model + if netcdf_format_in != netcdf_format_out: + mesh_file_out_tmp = mesh_file_out + ".tmp" + os.rename(mesh_file_out, mesh_file_out_tmp) + ds = xr.open_dataset(mesh_file_out_tmp) + ds.to_netcdf(mesh_file_out, format=netcdf_format_in) + os.remove(mesh_file_out_tmp) + + print("Done") + + + + +if __name__ == "__main__": + ############################### + ### Process input arguments ### + ############################### + parser = argparse.ArgumentParser( + description="'Tweak' the latitude and longitude coordinates to avoid ambiguous nearest neighbors", + ) + + # Required + parser.add_argument( + "-i", + "--input-files", + help="Comma-separated stream files whose coordinates need tweaking", + required=True, + ) + parser.add_argument( + "-m", + "--mesh-file", + help="Mesh file associated with input files", + required=True, + ) + + # Optional + parser.add_argument( + "--overwrite", + help="Overwrite any existing output files", + action="store_true", + default=False, + ) + default_output_dir = os.getcwd() + parser.add_argument( + "-o", + "--output-dir", + help=f"Directory where output files should be saved. Default is current working directory: {default_output_dir}", + default=default_output_dir, + ) -mesh_maker_args = [ - "mesh_maker", - "--input", - file_list_out[0], - "--output", - file_mesh_out, - "--lat", - "lat", - "--lon", - "lon", - "--overwrite", -] -print(f"Saving {file_mesh_out}...") -with redirect_argv(mesh_maker_args): - mesh_maker() - -# Change format, if needed -with Dataset(file_mesh_in, "r") as netcdf_file: - netcdf_format_in = netcdf_file.data_model -with Dataset(file_mesh_out, "r") as netcdf_file: - netcdf_format_out = netcdf_file.data_model -if netcdf_format_in != netcdf_format_out: - file_mesh_out_tmp = file_mesh_out + ".tmp" - os.rename(file_mesh_out, file_mesh_out_tmp) - ds = xr.open_dataset(file_mesh_out_tmp) - ds.to_netcdf(file_mesh_out, format=netcdf_format_in) - os.remove(file_mesh_out_tmp) - - -print("Done") + # Get arguments + args = parser.parse_args(sys.argv[1:]) + + # Check/process input and output files + _input_files = args.input_files.split(",") + _output_files = [] + for file in _input_files + [args.mesh_file]: + if not os.path.exists(file): + raise FileNotFoundError(f"File not found: {file}") + + filename, ext = os.path.splitext(os.path.basename(file)) + output_file = os.path.join( + args.output_dir, filename + ".tweaked_latlons" + ext + ) + if os.path.exists(output_file) and not args.overwrite: + raise FileExistsError( + f"Output file exists but --overwrite not specified: {output_file}" + ) + _output_files.append(output_file) + + main(_input_files, args.mesh_file, _output_files) From 227426345fcd0bd552e755b5c4cceb503cea94c6 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Sun, 14 Jul 2024 14:28:50 -0600 Subject: [PATCH 349/444] Refine RxCropCals* testlist. --- cime_config/testdefs/testlist_clm.xml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 86210256ff..c2926a25e7 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3755,7 +3755,7 @@ - + @@ -3765,7 +3765,8 @@ - + + @@ -3782,6 +3783,17 @@ + + + + + + + + + + + From 5686defdd31c03cdba0bcc247e3d590a0069d9d4 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Mon, 15 Jul 2024 11:40:38 -0600 Subject: [PATCH 350/444] Update bld/unit_testers/build-namelist_test.pl Syntax of breaking up into two lines was confusing, so just making a longer line that is more clear. --- bld/unit_testers/build-namelist_test.pl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 5abb381c16..a22cdd4059 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -1095,8 +1095,7 @@ sub cat_and_create_namelistinfile { phys=>"clm5_1", }, "soil_erod_none_w_Zender" =>{ options=>"--envxml_dir .", - namelst=>"dust_emis_method='Zender_2003', " . - "zender_soil_erod_source='none'", + namelst=>"dust_emis_method='Zender_2003', zender_soil_erod_source='none'", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_1", }, From af11aaab0644357cbff66aecbbc2f94a25778ab7 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Mon, 15 Jul 2024 14:02:15 -0600 Subject: [PATCH 351/444] Remove new test from build-namelist_test.pl for now --- bld/unit_testers/build-namelist_test.pl | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 1810d4434b..16f6ba2a62 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -41,8 +41,8 @@ sub make_env_run { # my %settings = @_; - # Set default settings TODO slevis: NTHRDS_LND fails, OMP_NUM_THREADS fails - my %env_vars = ( DIN_LOC_ROOT=>"MYDINLOCROOT", GLC_TWO_WAY_COUPLING=>"FALSE", NTHRDS_LND=>"1", NEONSITE=>"" ); + # Set default settings + my %env_vars = ( DIN_LOC_ROOT=>"MYDINLOCROOT", GLC_TWO_WAY_COUPLING=>"FALSE", NEONSITE=>"" ); # Set any settings that came in from function call foreach my $item ( keys(%settings) ) { $env_vars{$item} = $settings{$item}; @@ -1320,12 +1320,6 @@ sub cat_and_create_namelistinfile { my %warntest = ( # Warnings without the -ignore_warnings option given - "matrixcnOn_with_threading" =>{ options=>"-envxml_dir . -bgc bgc", - namelst=>"use_matrixcn=.true.", - GLC_TWO_WAY_COUPLING=>"TRUE", - NTHRDS_LND=>"2", - phys=>"clm5_0", - }, "dustemisLeung" =>{ options=>"-envxml_dir .", namelst=>"dust_emis_method = 'Leung_2023'", GLC_TWO_WAY_COUPLING=>"FALSE", @@ -1383,7 +1377,7 @@ sub cat_and_create_namelistinfile { my $options = $warntest{$key}{"options"}; my $namelist = $warntest{$key}{"namelst"}; my %settings; - foreach my $xmlvar ( "GLC_TWO_WAY_COUPLING", "NTHRDS_LND") { + foreach my $xmlvar ( "GLC_TWO_WAY_COUPLING" ) { if ( defined($failtest{$key}{$xmlvar}) ) { $settings{$xmlvar} = $failtest{$key}{$xmlvar}; } From 322097f0a2b5cf0c3b6bdd5a3eccb70845cb6990 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 15 Jul 2024 13:05:59 -0700 Subject: [PATCH 352/444] change folder name for fates land use x pft files This matches the corresponding fates tag that also impliments using this file --- bld/namelist_files/namelist_defaults_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 6f29513e6b..d4167228b9 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2019,7 +2019,7 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c >lnd/clm2/surfdata_map/fates-sci.1.68.3_api.31.0.0_tools.1.0.1/LUH2_states_transitions_management.timeseries_4x5_hist_simyr1850-2015_c231101.nc -lnd/clm2/surfdata_map/fates-sci.1.73.0_api.36.0.0/fates_landuse_pft_map_4x5_240206.nc +lnd/clm2/surfdata_map/fates-sci.1.77.0_api.36.0.0/fates_landuse_pft_map_4x5_240206.nc Date: Mon, 15 Jul 2024 15:08:44 -0600 Subject: [PATCH 353/444] Remove duplicated tests, and new dust tests with clm6_0 --- bld/unit_testers/build-namelist_test.pl | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 5abb381c16..0b26e86476 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -1072,39 +1072,27 @@ sub cat_and_create_namelistinfile { "soil_erod_wo_Zender" =>{ options=>"--envxml_dir . --ignore_warnings", namelst=>"dust_emis_method='Leung_2023', " . "stream_meshfile_zendersoilerod = '/dev/null'", - phys=>"clm5_1", + phys=>"clm6_0", }, "soil_erod_wo_lnd_source" =>{ options=>"--envxml_dir .", namelst=>"dust_emis_method='Zender_2003', " . "stream_fldfilename_zendersoilerod = '/dev/null', zender_soil_erod_source='atm'", - phys=>"clm5_1", + phys=>"clm6_0", }, "soil_erod_none_w_Zender" =>{ options=>"--envxml_dir .", namelst=>"dust_emis_method='Zender_2003', " . "zender_soil_erod_source='none'", - phys=>"clm5_1", + phys=>"clm6_0", }, "soil_erod_bad_w_Zender" =>{ options=>"--envxml_dir .", namelst=>"dust_emis_method='Zender_2003', " . "zender_soil_erod_source='zztop'", - phys=>"clm5_1", + phys=>"clm6_0", }, "Set_Dust_When_CAM_Sets" =>{ options=>"--envxml_dir .", namelst=>"dust_emis_method='Zender_2003'", LND_SETS_DUST_EMIS_DRV_FLDS=>"FALSE", - phys=>"clm5_1", - }, - "soil_erod_none_w_Zender" =>{ options=>"--envxml_dir .", - namelst=>"dust_emis_method='Zender_2003', " . - "zender_soil_erod_source='none'", - GLC_TWO_WAY_COUPLING=>"FALSE", - phys=>"clm5_1", - }, - "soil_erod_bad_w_Zender" =>{ options=>"--envxml_dir .", - namelst=>"dust_emis_method='Zender_2003', " . - "zender_soil_erod_source='zztop'", - GLC_TWO_WAY_COUPLING=>"FALSE", - phys=>"clm5_1", + phys=>"clm6_0", }, ); foreach my $key ( keys(%failtest) ) { From 02f9cb325d3884add3ecfb45904c34bb3edb0f62 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Mon, 15 Jul 2024 15:25:35 -0600 Subject: [PATCH 354/444] Make fail tests lines where the namelst option is split up into two lines into one long line, because the way they were concatonated look obscure and possibly wrong, the long lines are easier to read --- bld/unit_testers/build-namelist_test.pl | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 0b26e86476..d72331b1c2 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -1070,23 +1070,19 @@ sub cat_and_create_namelistinfile { phys=>"clm5_0", }, "soil_erod_wo_Zender" =>{ options=>"--envxml_dir . --ignore_warnings", - namelst=>"dust_emis_method='Leung_2023', " . - "stream_meshfile_zendersoilerod = '/dev/null'", + namelst=>"dust_emis_method='Leung_2023', stream_meshfile_zendersoilerod = '/dev/null'", phys=>"clm6_0", }, "soil_erod_wo_lnd_source" =>{ options=>"--envxml_dir .", - namelst=>"dust_emis_method='Zender_2003', " . - "stream_fldfilename_zendersoilerod = '/dev/null', zender_soil_erod_source='atm'", + namelst=>"dust_emis_method='Zender_2003', stream_fldfilename_zendersoilerod = '/dev/null', zender_soil_erod_source='atm'", phys=>"clm6_0", }, "soil_erod_none_w_Zender" =>{ options=>"--envxml_dir .", - namelst=>"dust_emis_method='Zender_2003', " . - "zender_soil_erod_source='none'", + namelst=>"dust_emis_method='Zender_2003', zender_soil_erod_source='none'", phys=>"clm6_0", }, "soil_erod_bad_w_Zender" =>{ options=>"--envxml_dir .", - namelst=>"dust_emis_method='Zender_2003', " . - "zender_soil_erod_source='zztop'", + namelst=>"dust_emis_method='Zender_2003', zender_soil_erod_source='zztop'", phys=>"clm6_0", }, "Set_Dust_When_CAM_Sets" =>{ options=>"--envxml_dir .", From aa923a4d2dc279cd9a85c2f691fd73ab7ab83e56 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 16 Jul 2024 12:12:33 -0600 Subject: [PATCH 355/444] Correct two test names in ExpectedTestFails.xml --- cime_config/testdefs/ExpectedTestFails.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 6a2186d6d9..7a07a056f7 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -37,14 +37,14 @@ - + FAIL #2619 This failure relates to the following REP failure. - + FAIL #2619 From ef970e2e8062e0852583216acda18c4ade60cd5e Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Tue, 16 Jul 2024 12:13:21 -0600 Subject: [PATCH 356/444] Make hillslope_fsat_equals_zero .false. unless use_hillslope = .true. --- bld/namelist_files/namelist_defaults_ctsm.xml | 3 ++- bld/namelist_files/namelist_definition_ctsm.xml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 0777f423ca..e2ba2de74b 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -625,7 +625,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). Standard Uniform .true. -.true. +.false. +.true. .false. diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 52f5aee138..bc92dafbf0 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -829,7 +829,7 @@ Toggle to turn on surface water routing in the hillslope hydrology model + group="clm_inparm" valid_values="" value=".false."> If true, set fsat to zero for hillslope columns From 8478b730663ee4a6698b70804e95a1f029662aab Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 16 Jul 2024 13:58:00 -0600 Subject: [PATCH 357/444] Comments about move to CMEPS --- src/drv_test/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/drv_test/CMakeLists.txt b/src/drv_test/CMakeLists.txt index adf66b8b92..938e55a598 100644 --- a/src/drv_test/CMakeLists.txt +++ b/src/drv_test/CMakeLists.txt @@ -1 +1,3 @@ +# This test should be moved to be under CMEPS +# See: https://github.com/ESCOMP/CMEPS/issues/458 add_subdirectory(shr_dust_emis_test) From 9db4d48623697669e5120830ded96ea2cb7047e0 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 16 Jul 2024 15:38:28 -0700 Subject: [PATCH 358/444] add izumi luh2 failure to expected list --- cime_config/testdefs/ExpectedTestFails.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index a4033aa6cd..ee1f188f15 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -150,6 +150,13 @@ + + + FAIL + #2653 + + + FAIL From 1de58fbb04d862245f69239835a00c15e062dc54 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 17 Jul 2024 12:37:45 -0700 Subject: [PATCH 359/444] update fates to sci.1.77.1_api.36.0.0 --- .gitmodules | 2 +- src/fates | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 9ed4402c7e..8127cac482 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,7 +28,7 @@ [submodule "fates"] path = src/fates url = https://github.com/NGEET/fates -fxtag = sci.1.77.0_api.36.0.0 +fxtag = sci.1.77.1_api.36.0.0 fxrequired = AlwaysRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/NCAR/fates-release diff --git a/src/fates b/src/fates index fd7f3438c2..1982b0032c 160000 --- a/src/fates +++ b/src/fates @@ -1 +1 @@ -Subproject commit fd7f3438c2ff821672b703050e7011f293649ee9 +Subproject commit 1982b0032c3cab6278892eccb85f643114ffb1af From 47571d844674d836a7501c3cd98f65ac545f4e39 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 17 Jul 2024 13:23:11 -0700 Subject: [PATCH 360/444] formatting fixed for changelog --- doc/ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index 71b07aa2f2..54e3b4cc4b 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,5 @@ +=============================================================== +Tag name: ctsm5.2.013 Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) glemieux (Gregory Lemieux, LBNL, glemieux@lbl.gov) Date: Wed 17 Jul 2024 01:20:00 PM MDT From e4142b96425712afa44cb6ab440d297a56aeaae1 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 17 Jul 2024 13:26:45 -0700 Subject: [PATCH 361/444] fixing bad merge with changelog --- doc/ChangeLog | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 54e3b4cc4b..3c6a104725 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -79,7 +79,6 @@ Changes to tests or testing: and use_fates_lupft namelist options. Additoinally a new system text prefix, PVT, has been added to test the use_fates_potentialveg spin-up to use_fates_lupft transient workflow. These have been added to the fates test suite. -======= Bugs fixed ---------- @@ -154,6 +153,19 @@ Does this tag change answers significantly for any of the following physics conf [ ] clm4_5 + +Bugs fixed +---------- +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: +Fixes #2444 Failing water isotope test on the ctsm5.2 branch + +Notes of particular relevance for users +--------------------------------------- +Changes to documentation: None + +Testing summary: +---------------- + [PASS means all tests PASS; OK means tests PASS other than expected fails.] regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): From 75cd2f4c866bd8148dff0e310e1ba0711bef13f3 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 17 Jul 2024 14:07:23 -0700 Subject: [PATCH 362/444] reformat new and updated systests with black --- cime_config/SystemTests/pvt.py | 15 +++++++++------ cime_config/SystemTests/systemtest_utils.py | 7 ++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/cime_config/SystemTests/pvt.py b/cime_config/SystemTests/pvt.py index 2a3dbafdc3..cf923dd334 100644 --- a/cime_config/SystemTests/pvt.py +++ b/cime_config/SystemTests/pvt.py @@ -16,9 +16,10 @@ logger = logging.getLogger(__name__) + class PVT(SystemTestsCommon): - def __init__(self,case): - SystemTestsCommon.__init__(self,case) + def __init__(self, case): + SystemTestsCommon.__init__(self, case) # Do not allow PVT to be run with certain testmods # Should this be targeted to a specific testmod for simplicity for now? @@ -27,14 +28,16 @@ def __init__(self,case): casebaseid = self._case.get_value("CASEBASEID") casebaseid = casebaseid.split("-")[-1] if casebaseid[0:10] != "FatesLUPFT": - error_message = (f"Only call PVT with testmod FatesLUPFT. {casebaseid} selected.") + error_message = f"Only call PVT with testmod FatesLUPFT. {casebaseid} selected." # Only allow to run if resolution is 4x5 for now # Other grid resolutions will be pre-processed and included in the namelist defaults at a future date. # Potentially we could generate these on the fly although doing so would result in increased build time lnd_grid = self._case.get_value("LND_GRID") if lnd_grid != "4x5": - error_message = (f"PVT can currently only be run with 4x5 resolution. {lnd_grid} selected.") + error_message = ( + f"PVT can currently only be run with 4x5 resolution. {lnd_grid} selected." + ) if error_message is not None: logger.error(error_message) @@ -79,7 +82,7 @@ def run_phase(self): # Turn off fates_harvest_mode for the spin up. logger.info("PVT log: modify user_nl_clm file for spin up run") - added_content = ["use_fates_potentialveg = .true.","fates_harvest_mode = 'no_harvest'"] + added_content = ["use_fates_potentialveg = .true.", "fates_harvest_mode = 'no_harvest'"] append_to_user_nl_files(clone_path, "clm", added_content) # Run the spin up case @@ -100,7 +103,7 @@ def run_phase(self): # obtain rpointer files and necessary restart files from short term archiving directory rundir = self._case.get_value("RUNDIR") - refdate = str(refcase_year) + '-01-01-00000' + refdate = str(refcase_year) + "-01-01-00000" rest_path = os.path.join(dout_sr, "rest", "{}".format(refdate)) for item in glob.glob("{}/*{}*".format(rest_path, refdate)): diff --git a/cime_config/SystemTests/systemtest_utils.py b/cime_config/SystemTests/systemtest_utils.py index c39f5171ba..c252f73251 100644 --- a/cime_config/SystemTests/systemtest_utils.py +++ b/cime_config/SystemTests/systemtest_utils.py @@ -86,14 +86,15 @@ def run_python_script(caseroot, this_conda_env, command_in, tool_path): print(f"ERROR trying to run {tool_name}.") raise + # Read a user_nl file and return the namelist option if found def find_user_nl_option(caseroot, component, namelist_option): - + # This is a copy of the CIME _get_list_of_user_nl_files # which could be used if this moved into the CIME project file_pattern = "user_nl_" + component + "*" file_list = glob.glob(os.path.join(caseroot, file_pattern)) - + # Check that there is at least one file if len(file_list) == 0: raise RuntimeError("No user_nl files found for component " + component) @@ -103,7 +104,7 @@ def find_user_nl_option(caseroot, component, namelist_option): for one_file in file_list: with open(one_file, "r") as user_nl_file: user_nl_text = user_nl_file.read() - reg = fr'{namelist_option}.*?(?=,|\n)' + reg = rf"{namelist_option}.*?(?=,|\n)" find_out = re.findall(reg, user_nl_text) output[one_file] = find_out return output From e14313858df6e9e6f2488951af2551349e349c65 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 10:11:33 -0600 Subject: [PATCH 363/444] generate_gdd20_baseline: Clarity rearrangement. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 476717b887..5d4fac3aff 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -246,16 +246,18 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice): if gddn is None: # Crop not handled yet? Fill it entirely with missing value this_da = dummy_da - long_name = "Dummy GDD20" print(" dummy GDD20") else: # this_da = ds_in[gddn].fillna(MISSING_FILL) this_da = ds_in[gddn] this_da = _add_time_axis(this_da) - long_name = gddn.replace("X", "20") print(f" {gddn}") - # Add attributes + # Add attributes of output file + if gddn is None: + long_name = "Dummy GDD20" + else: + long_name = gddn.replace("X", "20") this_da.attrs["long_name"] = long_name + f" baseline for {cft_str}" this_da.attrs["units"] = "°C days" # this_da.attrs["_FillValue"] = MISSING_FILL From 3416574a862e2f1df62d29abb82efe76686084dd Mon Sep 17 00:00:00 2001 From: adrifoster Date: Thu, 18 Jul 2024 10:51:28 -0600 Subject: [PATCH 364/444] update date --- doc/ChangeLog | 2 +- doc/ChangeSum | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 3c6a104725..8cc3198fae 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -2,7 +2,7 @@ Tag name: ctsm5.2.013 Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) glemieux (Gregory Lemieux, LBNL, glemieux@lbl.gov) -Date: Wed 17 Jul 2024 01:20:00 PM MDT +Date: Thu Jul 18 10:51:11 MDT 2024 One-line Summary: FATES Land Use V2 Purpose and description of changes diff --git a/doc/ChangeSum b/doc/ChangeSum index 92ca8281cf..df8e6dcf6a 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,6 +1,6 @@ Tag Who Date Summary ============================================================================================================================ - ctsm5.2.013 glemieux 07/17/2024 FATES Land Use V2 + ctsm5.2.013 glemieux 07/18/2024 FATES Land Use V2 ctsm5.2.012 sacks 07/16/2024 Relax tolerance for truncating small snocan values in CanopyFluxes ctsm5.2.011 slevis 07/12/2024 Merge b4b-dev ctsm5.2.010 multiple 07/11/2024 Explicit A/C adoption From 647fc52df1eb32b10646eb54ed4240d4cc9cfc00 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 11:07:00 -0600 Subject: [PATCH 365/444] import_ds: Workaround to import multiple files without dask. --- python/ctsm/crop_calendars/import_ds.py | 53 +++++++++++++++++-------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/python/ctsm/crop_calendars/import_ds.py b/python/ctsm/crop_calendars/import_ds.py index 77a22b626b..0526d3c720 100644 --- a/python/ctsm/crop_calendars/import_ds.py +++ b/python/ctsm/crop_calendars/import_ds.py @@ -41,6 +41,29 @@ def compute_derived_vars(ds_in, var): return ds_in +def manual_mfdataset(filelist, my_vars, my_vegtypes, time_slice): + """ + Opening a list of files with Xarray's open_mfdataset requires dask. This function is a + workaround for Python environments that don't have dask. + """ + ds_out = None + for filename in filelist: + ds_in = xr.open_dataset(filename) + ds_in = mfdataset_preproc(ds_in, my_vars, my_vegtypes, time_slice) + if ds_out is None: + ds_out = ds_in + else: + ds_out = xr.concat( + [ds_out, ds_in], + data_vars="minimal", + compat="override", + coords="all", + dim="time", + # combine="nested", + ) + return ds_out + + def mfdataset_preproc(ds_in, vars_to_import, vegtypes_to_import, time_slice): """ Function to drop unwanted variables in preprocessing of open_mfdataset(). @@ -221,22 +244,20 @@ def import_ds( if isinstance(filelist, list): with warnings.catch_warnings(): warnings.filterwarnings(action="ignore", category=DeprecationWarning) - if find_spec("dask") is None: - raise ModuleNotFoundError( - "You have asked xarray to import a list of files as a single Dataset using" - " open_mfdataset(), but this requires dask, which is not available.\nFile" - f" list: {filelist}" - ) - this_ds = xr.open_mfdataset( - sorted(filelist), - data_vars="minimal", - preprocess=mfdataset_preproc_closure, - compat="override", - coords="all", - concat_dim="time", - combine="nested", - chunks=chunks, - ) + dask_unavailable = find_spec("dask") is None + if dask_unavailable: + this_ds = manual_mfdataset(filelist, my_vars, my_vegtypes, time_slice) + else: + this_ds = xr.open_mfdataset( + sorted(filelist), + data_vars="minimal", + preprocess=mfdataset_preproc_closure, + compat="override", + coords="all", + concat_dim="time", + combine="nested", + chunks=chunks, + ) elif isinstance(filelist, str): this_ds = xr.open_dataset(filelist, chunks=chunks) this_ds = mfdataset_preproc(this_ds, my_vars, my_vegtypes, time_slice) From 96015dacbc7a22d57bcd242e358356f5c0cb028b Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 11:11:52 -0600 Subject: [PATCH 366/444] generate_gdd20_baseline: Can now specify -v/--variable GDDBX or GDDB20. --- .../crop_calendars/generate_gdd20_baseline.py | 64 +++++++++++++------ 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 5d4fac3aff..4b8e68e8f9 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -19,7 +19,6 @@ import ctsm.crop_calendars.cropcal_utils as utils from ctsm.crop_calendars.grid_one_variable import grid_one_variable -VAR_LIST_IN = ["GDD0X", "GDD8X", "GDD10X"] GRIDDING_VAR_LIST = ["patches1d_ixy", "patches1d_jxy", "lat", "lon"] MISSING_FILL = -1 # Something impossible to ensure that you can mark it as a missing value, to be # bilinear-interpolated @@ -88,6 +87,16 @@ def _parse_args(): type=int, required=False, ) + parser.add_argument( + "-v", + "--variable", + help=( + "Which type of variable should be processed?" + ), + required=False, + default="GDDBX", + choices=["GDDBX", "GDDB20"], + ) # Get arguments args = parser.parse_args(sys.argv[1:]) @@ -96,6 +105,12 @@ def _parse_args(): if os.path.exists(args.output_file) and not args.overwrite: raise FileExistsError("Output file exists but --overwrite is not specified") + # Get and check input files + args.input_files = args.input_files.split(" ") + for filename in args.input_files: + 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 @@ -137,7 +152,7 @@ def _get_cft_list(crop_list): return cft_str_list -def _get_gddn_for_cft(cft_str): +def _get_gddn_for_cft(cft_str, variable): """ Given a CFT name, return the GDDN variable it uses. @@ -149,6 +164,7 @@ def _get_gddn_for_cft(cft_str): """ gddn = None + gddn_str = None gdd0_list_str = ["wheat", "cotton", "rice"] if cft_str in _get_cft_list(gdd0_list_str): @@ -163,9 +179,9 @@ def _get_gddn_for_cft(cft_str): gddn = 10 if gddn is not None: - gddn = f"GDD{gddn}X" + gddn_str = variable.replace("B", str(gddn)) - return gddn + return gddn, gddn_str def _get_output_varname(cft_str): @@ -194,19 +210,28 @@ def _add_time_axis(da_in): return da_out -def generate_gdd20_baseline(input_files, output_file, author, time_slice): +def generate_gdd20_baseline(input_files, output_file, author, time_slice, variable): """ Generate stream_fldFileName_gdd20_baseline file from CTSM outputs """ - # Get input file list - input_files = input_files.split(sep=" ") + # Define variables to process + if variable == "GDDBX": + suffix = "X" + elif variable == "GDDB20": + suffix = "20" + else: + raise ValueError(f"-v/--variable {variable} not recoginzed") + var_list_in = [] + for base_temp in [0, 8, 10]: + var_list_in.append(f"GDD{base_temp}{suffix}") + # Get unique values and sort input_files = list(set(input_files)) input_files.sort() # Import history files and ensure they have lat/lon dims - ds_in = import_ds(input_files, VAR_LIST_IN + GRIDDING_VAR_LIST, time_slice=time_slice) + ds_in = import_ds(input_files, var_list_in + GRIDDING_VAR_LIST, time_slice=time_slice) if not all(x in ds_in.dims for x in ["lat", "lon"]): raise RuntimeError("Input files must have lat and lon dimensions") @@ -216,9 +241,9 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice): # Set up a dummy DataArray to use for crops without an assigned GDDN variable dummy_da = xr.DataArray( - data=MISSING_FILL * np.ones_like(ds_in[VAR_LIST_IN[0]].values), - dims=ds_in[VAR_LIST_IN[0]].dims, - coords=ds_in[VAR_LIST_IN[0]].coords, + data=MISSING_FILL * np.ones_like(ds_in[var_list_in[0]].values), + dims=ds_in[var_list_in[0]].dims, + coords=ds_in[var_list_in[0]].coords, ) dummy_da = _add_time_axis(dummy_da) @@ -239,25 +264,27 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice): print(f"{cft_str} ({cft_int})") # Which GDDN history variable does this crop use? E.g., GDD0, GDD10 - gddn = _get_gddn_for_cft(cft_str) + gddn, gddn_str = _get_gddn_for_cft(cft_str, variable) # Fill any missing values with MISSING_FILL. This will mean that gddmaturity in these cells # never changes. - if gddn is None: + if gddn_str is None: # Crop not handled yet? Fill it entirely with missing value this_da = dummy_da print(" dummy GDD20") else: # this_da = ds_in[gddn].fillna(MISSING_FILL) - this_da = ds_in[gddn] + this_da = ds_in[gddn_str] this_da = _add_time_axis(this_da) - print(f" {gddn}") + print(f" {gddn_str}") # Add attributes of output file - if gddn is None: + if (gddn is None) != (gddn_str is None): + raise RuntimeError("gddn and gddn_str must either both be None or both be not None") + if gddn_str is None: long_name = "Dummy GDD20" else: - long_name = gddn.replace("X", "20") + long_name = f"GDD{gddn}20" this_da.attrs["long_name"] = long_name + f" baseline for {cft_str}" this_da.attrs["units"] = "°C days" # this_da.attrs["_FillValue"] = MISSING_FILL @@ -287,5 +314,6 @@ def main(): args.input_files, args.output_file, args.author, - time_slice + time_slice, + args.variable, ) From 3cc1d0fafb3290c1b249d22f828429c92a3719c4 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 11:14:33 -0600 Subject: [PATCH 367/444] generate_gdd20_baseline: Satisfy pylint. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 4b8e68e8f9..d2f96965b7 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -160,7 +160,7 @@ def _get_gddn_for_cft(cft_str, variable): cft_str (str): E.g., "irrigated_temperate_corn" Returns: - str or None: Name of variable to use (e.g., "GDD8X"). If crop isn't yet handled, return None. + str or None: Name of variable to use (e.g., "GDD8X"). If crop not yet handled, return None. """ gddn = None @@ -249,8 +249,8 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab # Process all crops data_var_dict = {} - for v in GRIDDING_VAR_LIST: - data_var_dict[v] = ds_in[v] + for gridding_var in GRIDDING_VAR_LIST: + data_var_dict[gridding_var] = ds_in[gridding_var] ds_out = xr.Dataset( data_vars=data_var_dict, attrs={ From b1bbe15eb03a57a26eb010a850a285fd600dfe3b Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 11:27:10 -0600 Subject: [PATCH 368/444] generate_gdd20_baseline: Save input file list as attribute(s). --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index d2f96965b7..b03d1fd658 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -247,7 +247,7 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab ) dummy_da = _add_time_axis(dummy_da) - # Process all crops + # Set up output Dataset data_var_dict = {} for gridding_var in GRIDDING_VAR_LIST: data_var_dict[gridding_var] = ds_in[gridding_var] @@ -258,6 +258,14 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab "created": dt.datetime.now().astimezone().isoformat(), }, ) + all_files_in_same_dir = len(np.unique([os.path.dirname(file) for file in input_files])) == 1 + if all_files_in_same_dir: + ds_out.attrs["input_files_dir"] = os.path.dirname(input_files[0]) + ds_out.attrs["input_files"] = ", ".join([os.path.basename(file) for file in input_files]) + else: + ds_out.attrs["input_files"] = ", ".join(input_files) + + # Process all crops encoding_dict = {} for cft_str in utils.define_mgdcrop_list(): cft_int = utils.vegtype_str2int(cft_str)[0] From a703cb6549576c63cedde68756292fab630543a5 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 11:31:46 -0600 Subject: [PATCH 369/444] generate_gdd20_baseline: Save input year range as attribute. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index b03d1fd658..14e2d5974f 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -210,7 +210,7 @@ def _add_time_axis(da_in): return da_out -def generate_gdd20_baseline(input_files, output_file, author, time_slice, variable): +def generate_gdd20_baseline(input_files, output_file, author, time_slice, variable, year_args): """ Generate stream_fldFileName_gdd20_baseline file from CTSM outputs """ @@ -256,6 +256,7 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab attrs={ "author": author, "created": dt.datetime.now().astimezone().isoformat(), + "input_year_range": f"{year_args[0]}-{year_args[1]}", }, ) all_files_in_same_dir = len(np.unique([os.path.dirname(file) for file in input_files])) == 1 @@ -324,4 +325,5 @@ def main(): args.author, time_slice, args.variable, + [args.first_year, args.last_year], ) From 7a5e067dd09970d74708ed9c678f1de7d8f29af6 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 11:32:33 -0600 Subject: [PATCH 370/444] generate_gdd20_baseline: Save input variable type as attribute. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 14e2d5974f..a87a2edb79 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -257,6 +257,7 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab "author": author, "created": dt.datetime.now().astimezone().isoformat(), "input_year_range": f"{year_args[0]}-{year_args[1]}", + "input_variable": variable, }, ) all_files_in_same_dir = len(np.unique([os.path.dirname(file) for file in input_files])) == 1 From 25896e460ac556a5cef78201f55b8f04fc6ce154 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 11:34:19 -0600 Subject: [PATCH 371/444] generate_gdd20_baseline: Functionize setup_output_dataset(). --- .../crop_calendars/generate_gdd20_baseline.py | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index a87a2edb79..5d6809f7ff 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -210,6 +210,31 @@ def _add_time_axis(da_in): return da_out +def setup_output_dataset(input_files, author, variable, year_args, ds_in): + """ + Set up output Dataset + """ + data_var_dict = {} + for gridding_var in GRIDDING_VAR_LIST: + data_var_dict[gridding_var] = ds_in[gridding_var] + ds_out = xr.Dataset( + data_vars=data_var_dict, + attrs={ + "author": author, + "created": dt.datetime.now().astimezone().isoformat(), + "input_year_range": f"{year_args[0]}-{year_args[1]}", + "input_variable": variable, + }, + ) + all_files_in_same_dir = len(np.unique([os.path.dirname(file) for file in input_files])) == 1 + if all_files_in_same_dir: + ds_out.attrs["input_files_dir"] = os.path.dirname(input_files[0]) + ds_out.attrs["input_files"] = ", ".join([os.path.basename(file) for file in input_files]) + else: + ds_out.attrs["input_files"] = ", ".join(input_files) + return ds_out + + def generate_gdd20_baseline(input_files, output_file, author, time_slice, variable, year_args): """ Generate stream_fldFileName_gdd20_baseline file from CTSM outputs @@ -248,24 +273,7 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab dummy_da = _add_time_axis(dummy_da) # Set up output Dataset - data_var_dict = {} - for gridding_var in GRIDDING_VAR_LIST: - data_var_dict[gridding_var] = ds_in[gridding_var] - ds_out = xr.Dataset( - data_vars=data_var_dict, - attrs={ - "author": author, - "created": dt.datetime.now().astimezone().isoformat(), - "input_year_range": f"{year_args[0]}-{year_args[1]}", - "input_variable": variable, - }, - ) - all_files_in_same_dir = len(np.unique([os.path.dirname(file) for file in input_files])) == 1 - if all_files_in_same_dir: - ds_out.attrs["input_files_dir"] = os.path.dirname(input_files[0]) - ds_out.attrs["input_files"] = ", ".join([os.path.basename(file) for file in input_files]) - else: - ds_out.attrs["input_files"] = ", ".join(input_files) + ds_out = setup_output_dataset(input_files, author, variable, year_args, ds_in) # Process all crops encoding_dict = {} From f909d2da504328459dd8129df708e289dfe33de3 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 13:15:49 -0600 Subject: [PATCH 372/444] Fill all land cells with MISSING_RX_GDD_VAL. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 5d6809f7ff..c0c9adb30b 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -18,10 +18,9 @@ from ctsm.crop_calendars.import_ds import import_ds import ctsm.crop_calendars.cropcal_utils as utils from ctsm.crop_calendars.grid_one_variable import grid_one_variable +from ctsm.crop_calendars.cropcal_module import MISSING_RX_GDD_VAL GRIDDING_VAR_LIST = ["patches1d_ixy", "patches1d_jxy", "lat", "lon"] -MISSING_FILL = -1 # Something impossible to ensure that you can mark it as a missing value, to be -# bilinear-interpolated STREAM_YEAR = 2000 # The year specified for stream_yearFirst and stream_yearLast in the call of # shr_strdata_init_from_inline() for sdat_cropcal_gdd20_baseline @@ -266,7 +265,7 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab # Set up a dummy DataArray to use for crops without an assigned GDDN variable dummy_da = xr.DataArray( - data=MISSING_FILL * np.ones_like(ds_in[var_list_in[0]].values), + data=np.full_like(ds_in[var_list_in[0]].values, MISSING_RX_GDD_VAL), dims=ds_in[var_list_in[0]].dims, coords=ds_in[var_list_in[0]].coords, ) @@ -284,10 +283,10 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab # Which GDDN history variable does this crop use? E.g., GDD0, GDD10 gddn, gddn_str = _get_gddn_for_cft(cft_str, variable) - # Fill any missing values with MISSING_FILL. This will mean that gddmaturity in these cells + # Fill any missing values with MISSING_RX_GDD_VAL. This will mean that gddmaturity there # never changes. if gddn_str is None: - # Crop not handled yet? Fill it entirely with missing value + # Crop not handled yet? It's already filled with missing value this_da = dummy_da print(" dummy GDD20") else: @@ -295,6 +294,7 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab this_da = ds_in[gddn_str] this_da = _add_time_axis(this_da) print(f" {gddn_str}") + this_da = this_da.fillna(MISSING_RX_GDD_VAL) # Add attributes of output file if (gddn is None) != (gddn_str is None): @@ -305,7 +305,6 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab long_name = f"GDD{gddn}20" this_da.attrs["long_name"] = long_name + f" baseline for {cft_str}" this_da.attrs["units"] = "°C days" - # this_da.attrs["_FillValue"] = MISSING_FILL # Copy that to ds_out var_out = _get_output_varname(cft_str) From 8fa8506ceb753e6e1571f4b93adb4c43ea51d8d1 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 13:39:15 -0600 Subject: [PATCH 373/444] Set different gdd20 baseline file if using default gdd20 baseline seasons. --- bld/namelist_files/namelist_defaults_ctsm.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 3f8bc1f382..70ff048aa7 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1711,7 +1711,8 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.tweaked_latlons.nc -lnd/clm2/cropdata/calendars/processed/gdd20bl.copied_from.gdds_20230829_161011.v2.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/20230714_cropcals_pr2_1deg.actually2deg.1980-2009.from_GDDB20.interpd_halfdeg.tweaked_latlons.nc +lnd/clm2/cropdata/calendars/processed/gdd20bl.copied_from.gdds_20230829_161011.v2.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.tweaked_latlons.nc lnd/clm2/cropdata/calendars/processed/360x720_120830_ESMFmesh_c20210507_cdf5.tweaked_latlons.nc From 945c8bbd142d0c528cbddbafd529a790a88c2dd8 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 14:34:03 -0600 Subject: [PATCH 374/444] Add utility function to get list of managed crops WITH grasses. define_mgdcrop_list() had excluded foddergrass and switchgrass. New function define_mgdcrop_list_withgrasses includes them. Renamed the existing function to define_mgdcrop_list_nograsses for clarity. --- python/ctsm/crop_calendars/cropcal_module.py | 2 +- python/ctsm/crop_calendars/cropcal_utils.py | 11 ++++++++++- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 4 ++-- python/ctsm/crop_calendars/generate_gdds_functions.py | 4 ++-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/python/ctsm/crop_calendars/cropcal_module.py b/python/ctsm/crop_calendars/cropcal_module.py index b87d26816f..08754f8823 100644 --- a/python/ctsm/crop_calendars/cropcal_module.py +++ b/python/ctsm/crop_calendars/cropcal_module.py @@ -345,7 +345,7 @@ def import_output( my_vars, year_1=None, year_n=None, - my_vegtypes=utils.define_mgdcrop_list(), + my_vegtypes=utils.define_mgdcrop_list_nograsses(), sdates_rx_ds=None, gdds_rx_ds=None, verbose=False, diff --git a/python/ctsm/crop_calendars/cropcal_utils.py b/python/ctsm/crop_calendars/cropcal_utils.py index 00ed2413d2..2157dc87f4 100644 --- a/python/ctsm/crop_calendars/cropcal_utils.py +++ b/python/ctsm/crop_calendars/cropcal_utils.py @@ -207,7 +207,7 @@ def is_each_vegtype(this_vegtypelist, this_filter, this_method): return [is_this_vegtype(x, this_filter, this_method) for x in this_vegtypelist] -def define_mgdcrop_list(): +def define_mgdcrop_list_nograsses(): """ List (strings) of managed crops in CLM. """ @@ -216,6 +216,15 @@ def define_mgdcrop_list(): is_crop = is_each_vegtype(defined_pftlist, notcrop_list, "notok_contains") return [defined_pftlist[i] for i, x in enumerate(is_crop) if x] +def define_mgdcrop_list_withgrasses(): + """ + List (strings) of managed crops in CLM. + """ + notcrop_list = ["tree", "c3_arctic_grass", "c3_non-arctic_grass", "c4_grass", "shrub", "unmanaged", "not_vegetated"] + defined_pftlist = define_pftlist() + is_crop = is_each_vegtype(defined_pftlist, notcrop_list, "notok_contains") + return [defined_pftlist[i] for i, x in enumerate(is_crop) if x] + def vegtype_str2int(vegtype_str, vegtype_mainlist=None): """ diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index c0c9adb30b..64cfd804fa 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -144,7 +144,7 @@ def _get_cft_list(crop_list): "cotton", "irrigated_cotton"] """ - mgdcrop_list = utils.define_mgdcrop_list() + mgdcrop_list = utils.define_mgdcrop_list_nograsses() cft_str_list = [] for crop_str in crop_list: cft_str_list += [x for x in mgdcrop_list if crop_str in x] @@ -276,7 +276,7 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab # Process all crops encoding_dict = {} - for cft_str in utils.define_mgdcrop_list(): + for cft_str in utils.define_mgdcrop_list_nograsses(): cft_int = utils.vegtype_str2int(cft_str)[0] print(f"{cft_str} ({cft_int})") diff --git a/python/ctsm/crop_calendars/generate_gdds_functions.py b/python/ctsm/crop_calendars/generate_gdds_functions.py index 2658e1de87..83c167af00 100644 --- a/python/ctsm/crop_calendars/generate_gdds_functions.py +++ b/python/ctsm/crop_calendars/generate_gdds_functions.py @@ -282,9 +282,9 @@ def import_and_process_1yr( # Get list of crops to include if skip_crops is not None: - crops_to_read = [c for c in utils.define_mgdcrop_list() if c not in skip_crops] + crops_to_read = [c for c in utils.define_mgdcrop_list_nograsses() if c not in skip_crops] else: - crops_to_read = utils.define_mgdcrop_list() + crops_to_read = utils.define_mgdcrop_list_nograsses() print(h1_filelist) dates_ds = import_ds( From ec9f07f2a6cc5f79e6c207e8050db74ff2d857ea Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 14:36:41 -0600 Subject: [PATCH 375/444] generate_gdd20_baseline: Use MGDCROP_LIST constant. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 64cfd804fa..1de6b5a739 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -23,6 +23,7 @@ GRIDDING_VAR_LIST = ["patches1d_ixy", "patches1d_jxy", "lat", "lon"] STREAM_YEAR = 2000 # The year specified for stream_yearFirst and stream_yearLast in the call of # shr_strdata_init_from_inline() for sdat_cropcal_gdd20_baseline +MGDCROP_LIST = utils.define_mgdcrop_list_nograsses() def _parse_args(): @@ -144,10 +145,9 @@ def _get_cft_list(crop_list): "cotton", "irrigated_cotton"] """ - mgdcrop_list = utils.define_mgdcrop_list_nograsses() cft_str_list = [] for crop_str in crop_list: - cft_str_list += [x for x in mgdcrop_list if crop_str in x] + cft_str_list += [x for x in MGDCROP_LIST if crop_str in x] return cft_str_list @@ -276,7 +276,7 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab # Process all crops encoding_dict = {} - for cft_str in utils.define_mgdcrop_list_nograsses(): + for cft_str in MGDCROP_LIST: cft_int = utils.vegtype_str2int(cft_str)[0] print(f"{cft_str} ({cft_int})") From 669f227921e1bdf59157cf1da1c9b4e5176851bc Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 14:37:05 -0600 Subject: [PATCH 376/444] generate_gdd20_baseline: Include mgd grasses. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 1de6b5a739..effc8e54ec 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -23,7 +23,7 @@ GRIDDING_VAR_LIST = ["patches1d_ixy", "patches1d_jxy", "lat", "lon"] STREAM_YEAR = 2000 # The year specified for stream_yearFirst and stream_yearLast in the call of # shr_strdata_init_from_inline() for sdat_cropcal_gdd20_baseline -MGDCROP_LIST = utils.define_mgdcrop_list_nograsses() +MGDCROP_LIST = utils.define_mgdcrop_list_withgrasses() def _parse_args(): From a62460642403d827b58807cfe5961df0db026c71 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 18 Jul 2024 14:41:46 -0600 Subject: [PATCH 377/444] generate_gdd20_baseline: Include unmanaged crops. --- python/ctsm/crop_calendars/cropcal_utils.py | 8 ++++++++ python/ctsm/crop_calendars/generate_gdd20_baseline.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/cropcal_utils.py b/python/ctsm/crop_calendars/cropcal_utils.py index 2157dc87f4..1a80448c1b 100644 --- a/python/ctsm/crop_calendars/cropcal_utils.py +++ b/python/ctsm/crop_calendars/cropcal_utils.py @@ -206,6 +206,14 @@ def is_each_vegtype(this_vegtypelist, this_filter, this_method): return [is_this_vegtype(x, this_filter, this_method) for x in this_vegtypelist] +def define_crop_list(): + """ + List (strings) of managed crops in CLM. + """ + notcrop_list = ["tree", "c3_arctic_grass", "c3_non-arctic_grass", "c4_grass", "shrub", "not_vegetated"] + defined_pftlist = define_pftlist() + is_crop = is_each_vegtype(defined_pftlist, notcrop_list, "notok_contains") + return [defined_pftlist[i] for i, x in enumerate(is_crop) if x] def define_mgdcrop_list_nograsses(): """ diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index effc8e54ec..3d082d0fde 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -23,7 +23,7 @@ GRIDDING_VAR_LIST = ["patches1d_ixy", "patches1d_jxy", "lat", "lon"] STREAM_YEAR = 2000 # The year specified for stream_yearFirst and stream_yearLast in the call of # shr_strdata_init_from_inline() for sdat_cropcal_gdd20_baseline -MGDCROP_LIST = utils.define_mgdcrop_list_withgrasses() +MGDCROP_LIST = utils.define_crop_list() def _parse_args(): From c031e1c699be02a96123df5c0ed780f4c9ce73bc Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 18 Jul 2024 15:14:14 -0600 Subject: [PATCH 378/444] Update ntests in build-namelist_test.pl --- bld/unit_testers/build-namelist_test.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 16f6ba2a62..9b283af334 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 3309; +my $ntests = 3306; if ( defined($opts{'compare'}) ) { $ntests += 2045; From c2b6c43f44c0dc3b6b9ad65b5dc979951090c3da Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Thu, 18 Jul 2024 17:35:07 -0600 Subject: [PATCH 379/444] Draft ChangeLog/ChangeSum --- doc/ChangeLog | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++ doc/ChangeSum | 1 + 2 files changed, 145 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index 8cc3198fae..5f2896ebc9 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,148 @@ =============================================================== +Tag name: ctsm5.2.014 +Originator(s): chrislxj (Xingjie Lu, Northern Arizona U., xingjie.lu@nau.edu) +Date: Thu 18 Jul 2024 03:50:56 PM MDT +One-line Summary: use_matrixcn, use_soil_matrixcn come in but as default .false. + +Purpose and description of changes +---------------------------------- + + Currently set as default .false.: + - Add matrix module for vegetation and soil C and N cycle + - Add diagnostic variables C and N storage capacity in history files + - Add Sparse matrix module to increase the code efficiency + - Create spin-up switch, and be ready for matrix spin up development + + Additional contributors: Yuanyuan Huang, Zhenggang Du, and Yiqi Luo from + Professor Yiqi Luo's EcoLab at Northern Arizona University, now at Cornell U. + + In TSS/CGD/NCAR, contributors in the last year include slevis, ekluzek, wwieder. + Others may have been involved prior. I apologize for omissions. + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + Fixes #903 Bring CN-Matrix solution into CTSM + Fixes #2450 Cn-matrix testing in the aux_clm test-suites + Fixes #2621 matrixcn does not work with nrepr != 1 (number of crop reproductive pools) + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + use_matrixcn and use_soil_matrixcn ARE recommended for accelerating bgc spin-ups + and NOT recommended for + - transient simulations (e.g. IHist) + - simulations that use threading (e.g. see tests with P64x2) + - NWP compsets + +Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): + New: use_matrixcn, use_soil_matrixcn, hist_wrt_matrixcn_diag. + All three are default .false. at this time. + +Changes made to namelist defaults (e.g., changed parameter values): + Changed hillslope_fsat_equals_zero to default .false. when + use_hillslope = .false. as per issue #2652 + clm_accelerated_spinup can be set to off, on, sasu, the latter being + the setting that uses matrixcn + +Changes to the datasets (e.g., parameter, surface or initial files): + No. + +Changes to documentation: + None at this time. A description of the spinup procedure appears in + https://github.com/NCAR/LMWG_dev/issues/58 + +Substantial timing or memory changes: + ***Check PFS test in the test suite and look at timings + + +Notes of particular relevance for developers: +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + - Future changes to the bgc will likely require changes in both + matrix and non-matrix parts of the code. + - I have found matrixcn to be sensitive to changes in the subgrid + heterogeneity and other subtleties. For example, matrixcn simulations + have failed from using a finidat file from a different simulation (#2592), + from running in transient mode (#2592), from running with threading (#2619), + and from setting hillslope_fsat_equals_zero = .true. (issue #2652). + - We recommend using matrixcn to accelerate bgc spin-ups and not for + most (possibly any) other purposes. + +Changes to tests or testing: + Numerous new tests in aux_clm and in build-namelist_test.pl that can be + identified by searching "matr" + + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - PASS + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + derecho - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- IN PROG + izumi ------- IN PROG + + ctsm_sci + derecho ---- IN PROG + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes, roundoff + + Summarize any changes to answers, i.e., + - what code configurations: All + - what platforms/compilers: All + - nature of change: roundoff + use_matrixcn and use_soil_matrixcn are default .false.. We get + roundoff diffs due to order-of-operation changes in a few locations, + done to improve code readability and streamlining in the presence of matrix. + + Testing with the non-default use_matrixcn = .true. and use_soil_matrixcn = .true. + appears here: https://github.com/NCAR/LMWG_dev/issues/58 + + PR #640 associated with this tag explains how answers are expected to + change from non-matrix to matrix simulations. + +Other details +------------- +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/640 + +=============================================================== +=============================================================== Tag name: ctsm5.2.013 Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) glemieux (Gregory Lemieux, LBNL, glemieux@lbl.gov) diff --git a/doc/ChangeSum b/doc/ChangeSum index df8e6dcf6a..8579fbee98 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,6 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.2.014 chrislxj 07/18/2024 use_matrixcn, use_soil_matrixcn come in but as default .false. ctsm5.2.013 glemieux 07/18/2024 FATES Land Use V2 ctsm5.2.012 sacks 07/16/2024 Relax tolerance for truncating small snocan values in CanopyFluxes ctsm5.2.011 slevis 07/12/2024 Merge b4b-dev From 5aeb618ebffdb8ab49521d47aa2d04037f76aa6f Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 19 Jul 2024 11:53:37 -0600 Subject: [PATCH 380/444] Update ChangeLog/ChangeSum --- doc/ChangeLog | 57 +++++++++++++++++++++++++-------------------------- doc/ChangeSum | 2 +- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 5f2896ebc9..35ad747636 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,8 +1,8 @@ =============================================================== Tag name: ctsm5.2.014 Originator(s): chrislxj (Xingjie Lu, Northern Arizona U., xingjie.lu@nau.edu) -Date: Thu 18 Jul 2024 03:50:56 PM MDT -One-line Summary: use_matrixcn, use_soil_matrixcn come in but as default .false. +Date: Fri 19 Jul 2024 11:04:17 AM MDT +One-line Summary: use_matrixcn, use_soil_matrixcn come in as default .false. Purpose and description of changes ---------------------------------- @@ -16,8 +16,9 @@ Purpose and description of changes Additional contributors: Yuanyuan Huang, Zhenggang Du, and Yiqi Luo from Professor Yiqi Luo's EcoLab at Northern Arizona University, now at Cornell U. - In TSS/CGD/NCAR, contributors in the last year include slevis, ekluzek, wwieder. - Others may have been involved prior. I apologize for omissions. + In TSS/CGD/NCAR/UCAR, contributors in the last year include slevis, ekluzek, wwieder. + I apologize if I have omitted others who may have been involved prior. + Significant changes to scientifically-supported configurations -------------------------------------------------------------- @@ -45,12 +46,13 @@ List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: Fixes #2450 Cn-matrix testing in the aux_clm test-suites Fixes #2621 matrixcn does not work with nrepr != 1 (number of crop reproductive pools) + Notes of particular relevance for users --------------------------------------- Caveats for users (e.g., need to interpolate initial conditions): - use_matrixcn and use_soil_matrixcn ARE recommended for accelerating bgc spin-ups - and NOT recommended for + use_matrixcn and use_soil_matrixcn ARE recommended for accelerating bgc + spin-ups (keep reading for more info) and NOT recommended for - transient simulations (e.g. IHist) - simulations that use threading (e.g. see tests with P64x2) - NWP compsets @@ -60,21 +62,17 @@ Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): All three are default .false. at this time. Changes made to namelist defaults (e.g., changed parameter values): - Changed hillslope_fsat_equals_zero to default .false. when + - hillslope_fsat_equals_zero is now default .false. when use_hillslope = .false. as per issue #2652 - clm_accelerated_spinup can be set to off, on, sasu, the latter being - the setting that uses matrixcn - -Changes to the datasets (e.g., parameter, surface or initial files): - No. + - clm_accelerated_spinup can be set to on, sasu, off; matrixcn spin-up + is performed in that order (on, sasu, off); in the "on" phase, matrixcn + is not active, in the "sasu" phase matrixcn is active, and in the "off" + phase, matrixcn may be active Changes to documentation: None at this time. A description of the spinup procedure appears in https://github.com/NCAR/LMWG_dev/issues/58 -Substantial timing or memory changes: - ***Check PFS test in the test suite and look at timings - Notes of particular relevance for developers: --------------------------------------------- @@ -82,17 +80,17 @@ Notes of particular relevance for developers: Caveats for developers (e.g., code that is duplicated that requires double maintenance): - Future changes to the bgc will likely require changes in both matrix and non-matrix parts of the code. - - I have found matrixcn to be sensitive to changes in the subgrid - heterogeneity and other subtleties. For example, matrixcn simulations - have failed from using a finidat file from a different simulation (#2592), + - matrixcn seems sensitive to changes in subgrid heterogeneity and + other subtleties. For example, matrixcn simulations have failed from + using a finidat file from a different simulation (#2592), from running in transient mode (#2592), from running with threading (#2619), and from setting hillslope_fsat_equals_zero = .true. (issue #2652). - We recommend using matrixcn to accelerate bgc spin-ups and not for - most (possibly any) other purposes. + most (any?) other purposes. Changes to tests or testing: - Numerous new tests in aux_clm and in build-namelist_test.pl that can be - identified by searching "matr" + We introduced numerous new tests to the aux_clm and build-namelist_test.pl + test-suites that can be identified by searching "matrix" Testing summary: @@ -110,11 +108,11 @@ Testing summary: regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): - derecho ----- IN PROG - izumi ------- IN PROG + derecho ----- OK + izumi ------- OK ctsm_sci - derecho ---- IN PROG + derecho ---- OK Answer changes @@ -123,17 +121,18 @@ Answer changes Changes answers relative to baseline: Yes, roundoff Summarize any changes to answers, i.e., - - what code configurations: All + - what code configurations: Non-matrix - what platforms/compilers: All - nature of change: roundoff use_matrixcn and use_soil_matrixcn are default .false.. We get - roundoff diffs due to order-of-operation changes in a few locations, - done to improve code readability and streamlining in the presence of matrix. + roundoff diffs due to order-of-operation changes in a few sections + of code, which improve readability and streamlining of the code + in the presence of matrix. - Testing with the non-default use_matrixcn = .true. and use_soil_matrixcn = .true. + Testing with the non-default use_matrixcn and use_soil_matrixcn = .true. appears here: https://github.com/NCAR/LMWG_dev/issues/58 - PR #640 associated with this tag explains how answers are expected to + PR #640 explains how answers are expected to change from non-matrix to matrix simulations. Other details diff --git a/doc/ChangeSum b/doc/ChangeSum index 8579fbee98..21237cbac8 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,6 +1,6 @@ Tag Who Date Summary ============================================================================================================================ - ctsm5.2.014 chrislxj 07/18/2024 use_matrixcn, use_soil_matrixcn come in but as default .false. + ctsm5.2.014 chrislxj 07/19/2024 use_matrixcn, use_soil_matrixcn come in as default .false. ctsm5.2.013 glemieux 07/18/2024 FATES Land Use V2 ctsm5.2.012 sacks 07/16/2024 Relax tolerance for truncating small snocan values in CanopyFluxes ctsm5.2.011 slevis 07/12/2024 Merge b4b-dev From 63b3c3fdfa8e9d5aec763bd872a81a69b2832d8e Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 19 Jul 2024 17:19:36 -0600 Subject: [PATCH 381/444] Namelist corrections after an izumi test failed ERS_D.f19_g17.I1850Clm50BgcCrop.izumi_nag.clm-ciso_monthly_matrixcn_spinup failed during the build because a namelist variable needed renaming --- .../user_nl_mosart | 2 +- .../testmods_dirs/clm/rtmColdSSP/user_nl_rtm | 8 +++---- lilac/bld_templates/mosart_in | 22 +++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/ciso_monthly_matrixcn_spinup/user_nl_mosart b/cime_config/testdefs/testmods_dirs/clm/ciso_monthly_matrixcn_spinup/user_nl_mosart index 9e109fc131..82243d7d3d 100644 --- a/cime_config/testdefs/testmods_dirs/clm/ciso_monthly_matrixcn_spinup/user_nl_mosart +++ b/cime_config/testdefs/testmods_dirs/clm/ciso_monthly_matrixcn_spinup/user_nl_mosart @@ -1 +1 @@ -frivinp_rtm = '/dev/null' +frivinp = '/dev/null' diff --git a/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/user_nl_rtm b/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/user_nl_rtm index d1a0254a0b..e78d13a51c 100644 --- a/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/user_nl_rtm +++ b/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/user_nl_rtm @@ -1,4 +1,4 @@ -finidat_rtm = " " -rtmhist_mfilt = 1 -rtmhist_ndens = 2 -rtmhist_nhtfrq = 0 +finidat = " " +mfilt = 1 +ndens = 2 +nhtfrq = 0 diff --git a/lilac/bld_templates/mosart_in b/lilac/bld_templates/mosart_in index 091ec69285..0bc2242dda 100644 --- a/lilac/bld_templates/mosart_in +++ b/lilac/bld_templates/mosart_in @@ -4,18 +4,18 @@ delt_mosart = 1800 do_rtm = .true. do_rtmflood = .false. - finidat_rtm = " " - frivinp_rtm = "/glade/campaign/cesm/cesmdata/cseg/inputdata/rof/mosart/MOSART_routing_Global_0.5x0.5_c170601.nc" + finidat = " " + frivinp = "/glade/campaign/cesm/cesmdata/cseg/inputdata/rof/mosart/MOSART_routing_Global_0.5x0.5_c170601.nc" ice_runoff = .true. qgwl_runoff_option = "threshold" - rtmhist_fexcl1 = "" - rtmhist_fexcl2 = "" - rtmhist_fexcl3 = "" - rtmhist_fincl1 = "" - rtmhist_fincl2 = "" - rtmhist_fincl3 = "" - rtmhist_mfilt = 1 - rtmhist_ndens = 1 - rtmhist_nhtfrq = 0 + fexcl1 = "" + fexcl2 = "" + fexcl3 = "" + fincl1 = "" + fincl2 = "" + fincl3 = "" + mfilt = 1 + ndens = 1 + nhtfrq = 0 smat_option = "Xonly" / From a32a9eb121af3fcb7de1af94b5812f51eac49666 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Fri, 19 Jul 2024 18:42:31 -0600 Subject: [PATCH 382/444] Draft ChangeLog/ChangeSum (comments welcome) --- doc/ChangeLog | 130 +++++++++++++++++++++++++++++++++++++++++++++++++- doc/ChangeSum | 3 +- 2 files changed, 131 insertions(+), 2 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 35ad747636..785b26db9e 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,131 @@ =============================================================== +Tag name: ctsm5.2.015 +Originator(s): multiple (Samuel Levis,UCAR/TSS,303-665-1310, @mvertens, @jedwards4b, @billsacks, @Katetc) +Date: Fri 19 Jul 2024 06:02:22 PM MDT +One-line Summary: Update submodule tags to pass runoff from cism to rof + +Purpose and description of changes +---------------------------------- + + - Update MOSART, CMEPS, and CISM so CISM runoff goes to ROF rather than CTSM + - Update RTM with fix needed for Paleo LGM work + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + Fixes #2590 Update CMEPS/MOSART/CISM/RTM tags + Fixes https://github.com/ESCOMP/RTM/issues/50 Likely wrong RTM river flux to MOM6 within cesm2_3_beta17 + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + Issue https://github.com/ESCOMP/RTM/issues/50 + Likely wrong RTM river flux to MOM6 within cesm2_3_beta17 is now fixed with + https://github.com/ESCOMP/RTM/pull/51 + +Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): + Differences in namelist 'mosart_inparm': + missing variable: 'do_rtmflood' + missing variable: 'finidat_rtm' + missing variable: 'frivinp_rtm' + missing variable: 'rtmhist_fexcl1' + missing variable: 'rtmhist_fexcl2' + missing variable: 'rtmhist_fexcl3' + missing variable: 'rtmhist_fincl1' + missing variable: 'rtmhist_fincl2' + missing variable: 'rtmhist_fincl3' + missing variable: 'rtmhist_mfilt' + missing variable: 'rtmhist_ndens' + missing variable: 'rtmhist_nhtfrq' + found extra variable: 'budget_frq' + found extra variable: 'fexcl1' + found extra variable: 'fexcl2' + found extra variable: 'fexcl3' + found extra variable: 'fincl1' + found extra variable: 'fincl2' + found extra variable: 'fincl3' + found extra variable: 'finidat' + found extra variable: 'frivinp' + found extra variable: 'mfilt' + found extra variable: 'mosart_euler_calc' + found extra variable: 'mosart_tracers' + found extra variable: 'ndens' + found extra variable: 'nhtfrq' + found extra variable: 'use_halo_option' + +Changes to documentation: + Not that I am aware of + + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - PASS + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + derecho - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + ctsm_sci + derecho ---- OK (while in tag ctsm5.2.007; I did not repeat with the latest; see checklist in #2590) + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes + + Summarize any changes to answers, i.e., + - what code configurations: mosart and rtm + - what platforms/compilers: all + - nature of change: mosart roundoff; rtm larger than roundoff due to bug fix + + +Other details +------------- +List any git submodules updated (cime, rtm, mosart, cism, fates, etc.): + See .gitmodules: cism, rtm, mosart, ccs_config, cmeps + +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/2605 + https://github.com/ESCOMP/RTM/pull/51 + https://github.com/ESCOMP/MOSART/pull/94 + https://github.com/ESCOMP/CISM-wrapper/pull/100 + https://github.com/ESCOMP/CMEPS/pull/463 + https://github.com/ESMCI/ccs_config_cesm/pull/174 + +=============================================================== +=============================================================== Tag name: ctsm5.2.014 Originator(s): chrislxj (Xingjie Lu, Northern Arizona U., xingjie.lu@nau.edu) Date: Fri 19 Jul 2024 11:04:17 AM MDT @@ -51,7 +178,8 @@ Notes of particular relevance for users --------------------------------------- Caveats for users (e.g., need to interpolate initial conditions): - use_matrixcn and use_soil_matrixcn ARE recommended for accelerating bgc + use_matrixcn and use_soil_matrixcn ARE NOT available for clm4_5 + and ARE recommended for accelerating bgc spin-ups (keep reading for more info) and NOT recommended for - transient simulations (e.g. IHist) - simulations that use threading (e.g. see tests with P64x2) diff --git a/doc/ChangeSum b/doc/ChangeSum index 21237cbac8..5c7123b5e0 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,6 +1,7 @@ Tag Who Date Summary ============================================================================================================================ - ctsm5.2.014 chrislxj 07/19/2024 use_matrixcn, use_soil_matrixcn come in as default .false. + ctsm5.2.015 multiple 07/19/2024 Update submodule tags to pass runoff from cism to rof + ctsm5.2.014 multiple 07/19/2024 use_matrixcn, use_soil_matrixcn come in as default .false. ctsm5.2.013 glemieux 07/18/2024 FATES Land Use V2 ctsm5.2.012 sacks 07/16/2024 Relax tolerance for truncating small snocan values in CanopyFluxes ctsm5.2.011 slevis 07/12/2024 Merge b4b-dev From a4a9ede604eb36e1b1f6541fb1e40b712176ffa5 Mon Sep 17 00:00:00 2001 From: Samuel Levis Date: Mon, 22 Jul 2024 16:04:00 -0600 Subject: [PATCH 383/444] Update ChangeLog/ChangeSum --- doc/ChangeLog | 4 +++- doc/ChangeSum | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 785b26db9e..506b3d5ad0 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,7 +1,7 @@ =============================================================== Tag name: ctsm5.2.015 Originator(s): multiple (Samuel Levis,UCAR/TSS,303-665-1310, @mvertens, @jedwards4b, @billsacks, @Katetc) -Date: Fri 19 Jul 2024 06:02:22 PM MDT +Date: Mon 22 Jul 2024 12:46:17 PM MDT One-line Summary: Update submodule tags to pass runoff from cism to rof Purpose and description of changes @@ -110,6 +110,8 @@ Changes answers relative to baseline: Yes - what platforms/compilers: all - nature of change: mosart roundoff; rtm larger than roundoff due to bug fix + We are ignoring strange diffs from baseline in two tests in variable + FATES_TRANSITION_MATRIX_LULU as explained in issue #2656. Other details ------------- diff --git a/doc/ChangeSum b/doc/ChangeSum index 5c7123b5e0..9c6524b33d 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,6 +1,6 @@ Tag Who Date Summary ============================================================================================================================ - ctsm5.2.015 multiple 07/19/2024 Update submodule tags to pass runoff from cism to rof + ctsm5.2.015 multiple 07/22/2024 Update submodule tags to pass runoff from cism to rof ctsm5.2.014 multiple 07/19/2024 use_matrixcn, use_soil_matrixcn come in as default .false. ctsm5.2.013 glemieux 07/18/2024 FATES Land Use V2 ctsm5.2.012 sacks 07/16/2024 Relax tolerance for truncating small snocan values in CanopyFluxes From 753fda3ff0147837231a73c9c728dd9ce47b5997 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Tue, 23 Jul 2024 09:27:15 -0600 Subject: [PATCH 384/444] Format with black. --- python/ctsm/crop_calendars/cropcal_utils.py | 22 +++++++++++++++++-- .../crop_calendars/generate_gdd20_baseline.py | 12 +++------- .../crop_calendars/generate_gdds_functions.py | 17 ++++++++------ .../ctsm/crop_calendars/interpolate_gdds.py | 2 +- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/python/ctsm/crop_calendars/cropcal_utils.py b/python/ctsm/crop_calendars/cropcal_utils.py index 1a80448c1b..584046edee 100644 --- a/python/ctsm/crop_calendars/cropcal_utils.py +++ b/python/ctsm/crop_calendars/cropcal_utils.py @@ -206,15 +206,24 @@ def is_each_vegtype(this_vegtypelist, this_filter, this_method): return [is_this_vegtype(x, this_filter, this_method) for x in this_vegtypelist] + def define_crop_list(): """ List (strings) of managed crops in CLM. """ - notcrop_list = ["tree", "c3_arctic_grass", "c3_non-arctic_grass", "c4_grass", "shrub", "not_vegetated"] + notcrop_list = [ + "tree", + "c3_arctic_grass", + "c3_non-arctic_grass", + "c4_grass", + "shrub", + "not_vegetated", + ] defined_pftlist = define_pftlist() is_crop = is_each_vegtype(defined_pftlist, notcrop_list, "notok_contains") return [defined_pftlist[i] for i, x in enumerate(is_crop) if x] + def define_mgdcrop_list_nograsses(): """ List (strings) of managed crops in CLM. @@ -224,11 +233,20 @@ def define_mgdcrop_list_nograsses(): is_crop = is_each_vegtype(defined_pftlist, notcrop_list, "notok_contains") return [defined_pftlist[i] for i, x in enumerate(is_crop) if x] + def define_mgdcrop_list_withgrasses(): """ List (strings) of managed crops in CLM. """ - notcrop_list = ["tree", "c3_arctic_grass", "c3_non-arctic_grass", "c4_grass", "shrub", "unmanaged", "not_vegetated"] + notcrop_list = [ + "tree", + "c3_arctic_grass", + "c3_non-arctic_grass", + "c4_grass", + "shrub", + "unmanaged", + "not_vegetated", + ] defined_pftlist = define_pftlist() is_crop = is_each_vegtype(defined_pftlist, notcrop_list, "notok_contains") return [defined_pftlist[i] for i, x in enumerate(is_crop) if x] diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 3d082d0fde..06d3a9cd21 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -72,27 +72,21 @@ def _parse_args(): parser.add_argument( "-y1", "--first-year", - help=( - "First calendar year to include" - ), + help=("First calendar year to include"), type=int, required=False, ) parser.add_argument( "-yN", "--last-year", - help=( - "Last calendar year to include" - ), + help=("Last calendar year to include"), type=int, required=False, ) parser.add_argument( "-v", "--variable", - help=( - "Which type of variable should be processed?" - ), + help=("Which type of variable should be processed?"), required=False, default="GDDBX", choices=["GDDBX", "GDDB20"], diff --git a/python/ctsm/crop_calendars/generate_gdds_functions.py b/python/ctsm/crop_calendars/generate_gdds_functions.py index 83c167af00..50e2ac3d00 100644 --- a/python/ctsm/crop_calendars/generate_gdds_functions.py +++ b/python/ctsm/crop_calendars/generate_gdds_functions.py @@ -651,10 +651,7 @@ def import_and_process_1yr( ) if save_figs and np.any(np.isnan(gddharv_atharv_p)): if np.all(np.isnan(gddharv_atharv_p)): - log( - logger, - " ❗ All GDDHARV are NaN; should only affect figure" - ) + log(logger, " ❗ All GDDHARV are NaN; should only affect figure") check_gddharv = False else: log( @@ -744,9 +741,15 @@ def import_and_process_1yr( ) else: error(logger, "Unexpected NaN for last season's GDD accumulation.") - if save_figs and check_gddharv and np.any( - np.isnan( - gddharv_yp_list[var][year_index - 1, active_this_year_where_gs_lastyr_indices] + if ( + save_figs + and check_gddharv + and np.any( + np.isnan( + gddharv_yp_list[var][ + year_index - 1, active_this_year_where_gs_lastyr_indices + ] + ) ) ): if incorrectly_daily: diff --git a/python/ctsm/crop_calendars/interpolate_gdds.py b/python/ctsm/crop_calendars/interpolate_gdds.py index 809be98826..830df18c73 100755 --- a/python/ctsm/crop_calendars/interpolate_gdds.py +++ b/python/ctsm/crop_calendars/interpolate_gdds.py @@ -70,7 +70,7 @@ def _setup_process_args(): help="Interpolate variables whose names start with this string", type=str, required=False, - default="gdd1_" + default="gdd1_", ) parser.add_argument( "--overwrite", From c0a3556886e31c5c4bfc55ceccec0925e407b1f4 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Tue, 23 Jul 2024 09:27:53 -0600 Subject: [PATCH 385/444] Add previous commit to .git-blame-ignore-revs. --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 44a697c343..31f63ef8ae 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -48,3 +48,4 @@ aa04d1f7d86cc2503b98b7e2b2d84dbfff6c316b 9660667b1267dcd4150889f5f39db540158be74a 665cf86102e09b4c4c5a140700676dca23bc55a9 045d90f1d80f713eb3ae0ac58f6c2352937f1eb0 +753fda3ff0147837231a73c9c728dd9ce47b5997 From b11bc8923bbaa6edc6c60913c37c1ba7f906d2b6 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 24 Jul 2024 11:21:17 -0600 Subject: [PATCH 386/444] Update cism to work with this cmeps version --- .gitmodules | 2 +- components/cism | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 501708f587..810b43a266 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,7 +36,7 @@ fxDONOTUSEurl = https://github.com/NCAR/fates-release [submodule "cism"] path = components/cism url = https://github.com/ESCOMP/CISM-wrapper -fxtag = cismwrap_2_2_001 +fxtag = cismwrap_2_2_002 fxrequired = ToplevelRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/ESCOMP/CISM-wrapper diff --git a/components/cism b/components/cism index c05dd5c4fc..c84cc9f5b3 160000 --- a/components/cism +++ b/components/cism @@ -1 +1 @@ -Subproject commit c05dd5c4fc85327e76523aaea9cfe1e388748928 +Subproject commit c84cc9f5b3103766a35d0a7ddd5e9dbd7deae762 From 38656f9c9904a312b041afaf9d15ed2e95f3838a Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 24 Jul 2024 11:49:01 -0600 Subject: [PATCH 387/444] Get LILAC test working --- bld/env_run.xml | 1 + python/ctsm/lilac_make_runtime_inputs.py | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/bld/env_run.xml b/bld/env_run.xml index f3b7467168..cd865ad82c 100644 --- a/bld/env_run.xml +++ b/bld/env_run.xml @@ -9,6 +9,7 @@ Sample env_run.xml file that allows build-namelist to be run for testing in this --> + diff --git a/python/ctsm/lilac_make_runtime_inputs.py b/python/ctsm/lilac_make_runtime_inputs.py index 71f3c9bbe4..33b87c543e 100644 --- a/python/ctsm/lilac_make_runtime_inputs.py +++ b/python/ctsm/lilac_make_runtime_inputs.py @@ -47,6 +47,12 @@ TRUE,FALSE + + + logical + TRUE,FALSE + + """ From e438a907e1fa23934255a10dddcfee4601bcd20d Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Wed, 24 Jul 2024 12:14:39 -0600 Subject: [PATCH 388/444] Fix test number --- bld/unit_testers/build-namelist_test.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 198df535ad..1533e00d73 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 3311; +my $ntests = 3317; if ( defined($opts{'compare'}) ) { $ntests += 2052; From 71ca96d2d8e14fbbe9bc7686c2d905907b4d43d5 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:29:29 -0600 Subject: [PATCH 389/444] Delete an unused ncd_log. --- 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 bb579b8031..5ba64f9b1e 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -897,7 +897,7 @@ subroutine Restart(this, bounds, ncid, flag, is_simple_buildtemp, is_prog_buildt use shr_log_mod , only : errMsg => shr_log_errMsg use spmdMod , only : masterproc use abortutils , only : endrun - use ncdio_pio , only : file_desc_t, ncd_double, ncd_int, ncd_log + use ncdio_pio , only : file_desc_t, ncd_double, ncd_int use restUtilMod ! ! !ARGUMENTS: From ad2c7f3af389ad2b2b6464987a06d1200049a813 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:30:31 -0600 Subject: [PATCH 390/444] Delete a troubleshooting log message. --- bld/CLMBuildNamelist.pm | 1 - 1 file changed, 1 deletion(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index ad110b017e..5202717d74 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4200,7 +4200,6 @@ sub setup_logic_cropcal_streams { my $gdd20_season_end_file = $nl->get_value('stream_fldFileName_gdd20_season_end') ; if ( &string_is_undef_or_empty($gdd20_season_start_file) or &string_is_undef_or_empty($gdd20_season_end_file) ) { $log->message($gdd20_season_start_file); - $log->message('abcd'); $log->message($gdd20_season_end_file); $log->fatal_error("If stream_gdd20_seasons is true, gdd20 season start and end files must be provided." ); } From 592476f7c6ae5751b6360c372ed70ad4f94af0c7 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:34:29 -0600 Subject: [PATCH 391/444] Improve comments/error at "Handle invalid gdd20 season values." --- src/cpl/share_esmf/cropcalStreamMod.F90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index ef3bab03c5..d17ce1c259 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -793,9 +793,10 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Handle invalid gdd20 season values if (any(gdd20_season_starts(begp:endp) < 1._r8 .or. gdd20_season_ends(begp:endp) < 1._r8)) then - ! Fail if not allowing fallback to paramfile sowing windows + ! Fail if not allowing fallback to paramfile sowing windows. Only need to check for + ! values < 1 because values outside [1, 366] are set to -1 above. if ((.not. allow_invalid_gdd20_season_inputs) .and. any(gdd20_season_starts(begp:endp) < 1._r8 .and. patch%wtgcell(begp:endp) > 0._r8 .and. patch%itype(begp:endp) >= npcropmin)) then - write(iulog, *) 'At least one crop in one gridcell has invalid gdd20 season start date(s). To ignore and fall back to paramfile sowing windows, set allow_invalid_gdd20_season_inputs to .true.' + write(iulog, *) 'At least one crop in one gridcell has invalid gdd20 season start and/or end date(s). To ignore and fall back to paramfile sowing windows for such crop-gridcells, set allow_invalid_gdd20_season_inputs to .true.' write(iulog, *) 'Affected crops:' do ivt = npcropmin, mxpft do fp = 1, num_pcropp From 013028c4687f564953ef5443e159b02f00220297 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:35:49 -0600 Subject: [PATCH 392/444] Replace SSR with Sam Rabin. --- src/biogeochem/CNPhenologyMod.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index d1d3c85b21..159e688dbd 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -2699,7 +2699,7 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & did_rx_gdds = .true. if (adapt_cropcal_rx_cultivar_gdds .and. crop_inst%gdd20_baseline_patch(p) > min_gdd20_baseline) then gddmaturity(p) = gddmaturity(p) * gdd20 / crop_inst%gdd20_baseline_patch(p) - !TODO SSR: Set maximum and minimum gddmaturity + !TODO Sam Rabin: Set maximum and minimum gddmaturity end if else if (ivt(p) == nwwheat .or. ivt(p) == nirrig_wwheat) then gddmaturity(p) = hybgdd(ivt(p)) @@ -2716,11 +2716,11 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & ivt(p) == nmiscanthus .or. ivt(p) == nirrig_miscanthus .or. & ivt(p) == nswitchgrass .or. ivt(p) == nirrig_switchgrass) then gddmaturity(p) = max(950._r8, min(gdd20*0.85_r8, hybgdd(ivt(p)))) - if (do_plant_normal) then ! TODO SSR: Add ".and. .not. do_plant_prescribed"? + if (do_plant_normal) then ! TODO Sam Rabin: Add ".and. .not. do_plant_prescribed"? gddmaturity(p) = max(950._r8, min(gddmaturity(p)+150._r8, 1850._r8)) end if else - ! TODO SSR: Add more descriptive error message + ! TODO Sam Rabin: Add more descriptive error message call endrun(msg="Stopping") end if From 96c7c2d96cf39347cd6e259366f5d321971e75eb Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:37:30 -0600 Subject: [PATCH 393/444] import_ds.py: Delete a commented-out line. --- python/ctsm/crop_calendars/import_ds.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/ctsm/crop_calendars/import_ds.py b/python/ctsm/crop_calendars/import_ds.py index 0526d3c720..486757492f 100644 --- a/python/ctsm/crop_calendars/import_ds.py +++ b/python/ctsm/crop_calendars/import_ds.py @@ -59,7 +59,6 @@ def manual_mfdataset(filelist, my_vars, my_vegtypes, time_slice): compat="override", coords="all", dim="time", - # combine="nested", ) return ds_out From 1d9e93989c656c91b44389a307bf07602727bcfd Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:38:29 -0600 Subject: [PATCH 394/444] Improve a comment in run_sys_tests.py. --- python/ctsm/run_sys_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctsm/run_sys_tests.py b/python/ctsm/run_sys_tests.py index 9961fd325d..b3a3b78379 100644 --- a/python/ctsm/run_sys_tests.py +++ b/python/ctsm/run_sys_tests.py @@ -736,7 +736,7 @@ def _check_py_env(test_attributes): # whether import is possible. # pylint: disable=import-error disable - # Check requirements for using modify_fsurdat, if needed + # Check requirements for using modify_fsurdat Python module, if needed modify_fsurdat_users = ["FSURDATMODIFYCTSM", "RXCROPMATURITY"] if any(any(u in t for u in modify_fsurdat_users) for t in test_attributes): try: From 78d9f98060c62ec486b32ef20dd2b14718d3c428 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:40:49 -0600 Subject: [PATCH 395/444] Improve error messages in PlantCrop(). --- src/biogeochem/CNPhenologyMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index 159e688dbd..855a1476f8 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -2720,7 +2720,7 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & gddmaturity(p) = max(950._r8, min(gddmaturity(p)+150._r8, 1850._r8)) end if else - ! TODO Sam Rabin: Add more descriptive error message + write(iulog, *) 'ERROR: PlantCrop(): unrecognized ivt for GDD target: ',ivt(p) call endrun(msg="Stopping") end if @@ -2729,7 +2729,7 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & if (gddmaturity(p) < min_gddmaturity) then if (use_cropcal_rx_cultivar_gdds .or. generate_crop_gdds) then if (did_rx_gdds) then - write(iulog,*) 'Some patch with ivt ',ivt(p),' has rx gddmaturity',gddmaturity(p),'; using min_gddmaturity instead (',min_gddmaturity,')' + write(iulog,*) 'Some patch with ivt ',ivt(p),' has rx gddmaturity ',gddmaturity(p),'; using min_gddmaturity instead (',min_gddmaturity,')' end if gddmaturity(p) = min_gddmaturity else From d3e6cbf13c4347ad2e61bbd5841b1bb9a7363fb8 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:41:54 -0600 Subject: [PATCH 396/444] CropType: Fix a comment. --- src/biogeochem/CropType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeochem/CropType.F90 b/src/biogeochem/CropType.F90 index 77da895135..0f650a4a9f 100644 --- a/src/biogeochem/CropType.F90 +++ b/src/biogeochem/CropType.F90 @@ -54,7 +54,7 @@ module CropType real(r8), pointer :: rx_cultivar_gdds_thisyr_patch (:,:) ! all cultivar GDD targets for this patch this year (ddays) [patch, mxsowings] real(r8), pointer :: gdd20_baseline_patch (:) ! GDD20 baseline for this patch (ddays) [patch] real(r8), pointer :: gdd20_season_start_patch(:) ! gdd20 season start date for this patch (day of year) [patch]. Real to enable history field. - real(r8), pointer :: gdd20_season_end_patch (:) ! gdd20 season end date for this patch (day of year) [patch]/ Real to enable history field. + real(r8), pointer :: gdd20_season_end_patch (:) ! gdd20 season end date for this patch (day of year) [patch]. Real to enable history field. real(r8), pointer :: sdates_thisyr_patch (:,:) ! all actual sowing dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: swindow_starts_thisyr_patch(:,:) ! all sowing window start dates for this patch this year (day of year) [patch, mxsowings] real(r8), pointer :: swindow_ends_thisyr_patch (:,:) ! all sowing window end dates for this patch this year (day of year) [patch, mxsowings] From 6546a681b92f736e460a106b33b4523b290f1cbc Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:42:57 -0600 Subject: [PATCH 397/444] TemperatureType Restart(): Delete unused p. --- 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 5ba64f9b1e..787efa81a0 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -909,7 +909,7 @@ subroutine Restart(this, bounds, ncid, flag, is_simple_buildtemp, is_prog_buildt logical , intent(in) :: is_prog_buildtemp ! Prognostic building temp is being used ! ! !LOCAL VARIABLES: - integer :: j,c,p ! indices + integer :: j,c ! indices logical :: readvar ! determine if variable is on initial file integer :: idata !----------------------------------------------------------------------- From c96ce350ed85600c8525b655f3acbfd2f6831059 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:49:19 -0600 Subject: [PATCH 398/444] Delete unused sowingWindows testmod. --- .../testmods_dirs/clm/sowingWindows/include_user_mods | 1 - .../testdefs/testmods_dirs/clm/sowingWindows/user_nl_clm | 5 ----- 2 files changed, 6 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/sowingWindows/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/sowingWindows/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/sowingWindows/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/sowingWindows/include_user_mods deleted file mode 100644 index fe0e18cf88..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/sowingWindows/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../default diff --git a/cime_config/testdefs/testmods_dirs/clm/sowingWindows/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/sowingWindows/user_nl_clm deleted file mode 100644 index 7024e99b96..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/sowingWindows/user_nl_clm +++ /dev/null @@ -1,5 +0,0 @@ -stream_fldFileName_swindow_start = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc' -stream_fldFileName_swindow_end = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc' -stream_meshfile_cropcal = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.tweaked_latlons.nc' -stream_year_first_cropcal_swindows = 2000 -stream_year_last_cropcal_swindows = 2000 From b96ec9107fe8e5b02260689190cd79799f589938 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:52:49 -0600 Subject: [PATCH 399/444] check_rxboth_run.py: Improve error message. --- python/ctsm/crop_calendars/check_rxboth_run.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/check_rxboth_run.py b/python/ctsm/crop_calendars/check_rxboth_run.py index a1014b5e66..fa4affd220 100644 --- a/python/ctsm/crop_calendars/check_rxboth_run.py +++ b/python/ctsm/crop_calendars/check_rxboth_run.py @@ -156,7 +156,16 @@ def main(argv): any_bad = any_bad or gdds_not_obeyed if any_bad: - raise RuntimeError("Unexpected behavior in rxboth run") + msg = "\n ".join( + [ + "Unexpected behavior in rxboth run:", + f"any_bad_import_output: {any_bad_import_output}", + f"any_bad_check_const_vars: {any_bad_check_const_vars}", + f"sdate_not_obeyed: {sdate_not_obeyed}", + f"gdds_not_obeyed: {gdds_not_obeyed}", + ] + ) + raise RuntimeError(msg) if __name__ == "__main__": From 876e23bb4fe4c6274e5f328212b4377ae1dd9c1d Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 15:59:46 -0600 Subject: [PATCH 400/444] interpolate_gdds.py: Strict check for prefix match. --- python/ctsm/crop_calendars/interpolate_gdds.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/interpolate_gdds.py b/python/ctsm/crop_calendars/interpolate_gdds.py index 830df18c73..92bb112e3f 100755 --- a/python/ctsm/crop_calendars/interpolate_gdds.py +++ b/python/ctsm/crop_calendars/interpolate_gdds.py @@ -6,6 +6,7 @@ import sys import argparse import logging +import re import xarray as xr # -- add python/ctsm to path (needed if we want to run this stand-alone) @@ -121,7 +122,7 @@ def interpolate_gdds(args): if "lat" not in ds_in[var].dims and "lon" not in ds_in[var].dims: print(f"Skipping variable {var} with dimensions {ds_in[var].dims}") continue - elif args.variable_prefix not in var: + if not re.compile("^" + args.variable_prefix).match(var) print(f"Unexpected variable {var} on input file. Skipping.") continue if args.dry_run: From fecad299757de00f235217add67f70e60f7cda33 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 16:06:22 -0600 Subject: [PATCH 401/444] Delete unneeded cropAnnOutputMonthly testmod. --- cime_config/testdefs/testlist_clm.xml | 4 ++-- .../testmods_dirs/clm/cropAnnOutputMonthly/user_nl_clm | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/cropAnnOutputMonthly/user_nl_clm diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index c2926a25e7..e5a1ae7ef4 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3794,7 +3794,7 @@ - + @@ -3803,7 +3803,7 @@ - + diff --git a/cime_config/testdefs/testmods_dirs/clm/cropAnnOutputMonthly/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/cropAnnOutputMonthly/user_nl_clm deleted file mode 100644 index 1c47a2ebd1..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/cropAnnOutputMonthly/user_nl_clm +++ /dev/null @@ -1,3 +0,0 @@ -! These variables SHOULD only be saved annually in real runs, but for testing purposes it's fine to have them monthly. -! Modifies h2 history file defined in crop testmod. -hist_nhtfrq(3) = 0 From c94aeeab68a6f98188f0f94127b3685d2c89dd49 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 16:09:35 -0600 Subject: [PATCH 402/444] Add READMEs to testmods decStart and midDecStart. --- cime_config/testdefs/testmods_dirs/clm/decStart/README | 1 + cime_config/testdefs/testmods_dirs/clm/midDecStart/README | 1 + 2 files changed, 2 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/decStart/README create mode 100644 cime_config/testdefs/testmods_dirs/clm/midDecStart/README diff --git a/cime_config/testdefs/testmods_dirs/clm/decStart/README b/cime_config/testdefs/testmods_dirs/clm/decStart/README new file mode 100644 index 0000000000..7cdab6abfd --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/decStart/README @@ -0,0 +1 @@ +Use midDecStart instead of decStart if you want ERP/ERS/etc. tests longer than 2 days to be able to have the split in December instead of January (i.e., before rather than after new year). \ No newline at end of file diff --git a/cime_config/testdefs/testmods_dirs/clm/midDecStart/README b/cime_config/testdefs/testmods_dirs/clm/midDecStart/README new file mode 100644 index 0000000000..7cdab6abfd --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/midDecStart/README @@ -0,0 +1 @@ +Use midDecStart instead of decStart if you want ERP/ERS/etc. tests longer than 2 days to be able to have the split in December instead of January (i.e., before rather than after new year). \ No newline at end of file From 833d4f67e888c747cfb2c35d8ae8354974987061 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 16:11:48 -0600 Subject: [PATCH 403/444] import_output(): Bugfix in call of check_v0_le_v1(). --- python/ctsm/crop_calendars/cropcal_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/cropcal_module.py b/python/ctsm/crop_calendars/cropcal_module.py index 08754f8823..927bdc9100 100644 --- a/python/ctsm/crop_calendars/cropcal_module.py +++ b/python/ctsm/crop_calendars/cropcal_module.py @@ -425,7 +425,7 @@ def import_output( # Check that e.g., GDDACCUM <= HUI for var_list in [["GDDACCUM", "HUI"], ["SYEARS", "HYEARS"]]: if all(v in this_ds_gs for v in var_list): - any_bad = check_v0_le_v1( + any_bad = any_bad or check_v0_le_v1( this_ds_gs, var_list, both_nan_ok=True, throw_error=throw_errors ) From 56523e4cbb4969e9648adb2601c40d847cb9d408 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 16:15:28 -0600 Subject: [PATCH 404/444] Remove 1-degree RXCROPMATURITY test from rxcropmaturity, crop_calendars suites. --- cime_config/testdefs/testlist_clm.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index e5a1ae7ef4..5d3fbeb11a 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3663,8 +3663,6 @@ - - From d06e8642a180190fea9f31c0a6af042758c31b81 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 16:18:38 -0600 Subject: [PATCH 405/444] Remove unneeded RxCropCalsAdaptFlush testmod. --- .../testmods_dirs/clm/RxCropCalsAdaptFlush/include_user_mods | 1 - .../testdefs/testmods_dirs/clm/RxCropCalsAdaptFlush/user_nl_clm | 2 -- 2 files changed, 3 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptFlush/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptFlush/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptFlush/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptFlush/include_user_mods deleted file mode 100644 index af5fe8591e..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptFlush/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../RxCropCalsAdapt diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptFlush/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptFlush/user_nl_clm deleted file mode 100644 index 4c6af0f6d2..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptFlush/user_nl_clm +++ /dev/null @@ -1,2 +0,0 @@ - -flush_gdd20 = .true. From a2bf12483a8fd1f33488b6df09ffe2b291aa2f43 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 16:21:18 -0600 Subject: [PATCH 406/444] generate_gdd20_baseline.py: Add a clarifying comment. --- python/ctsm/crop_calendars/generate_gdd20_baseline.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/ctsm/crop_calendars/generate_gdd20_baseline.py b/python/ctsm/crop_calendars/generate_gdd20_baseline.py index 06d3a9cd21..13668fc850 100644 --- a/python/ctsm/crop_calendars/generate_gdd20_baseline.py +++ b/python/ctsm/crop_calendars/generate_gdd20_baseline.py @@ -284,8 +284,7 @@ def generate_gdd20_baseline(input_files, output_file, author, time_slice, variab this_da = dummy_da print(" dummy GDD20") else: - # this_da = ds_in[gddn].fillna(MISSING_FILL) - this_da = ds_in[gddn_str] + this_da = ds_in[gddn_str] # Already did ds_in.mean(dim="time") above this_da = _add_time_axis(this_da) print(f" {gddn_str}") this_da = this_da.fillna(MISSING_RX_GDD_VAL) From c9ff0ee33410b82462fbf4fc876b4130811e13cc Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 16:24:14 -0600 Subject: [PATCH 407/444] PlantCrop(): Resolve (dismiss) a TODO. --- src/biogeochem/CNPhenologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index 855a1476f8..1fb13d32eb 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -2716,7 +2716,7 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & ivt(p) == nmiscanthus .or. ivt(p) == nirrig_miscanthus .or. & ivt(p) == nswitchgrass .or. ivt(p) == nirrig_switchgrass) then gddmaturity(p) = max(950._r8, min(gdd20*0.85_r8, hybgdd(ivt(p)))) - if (do_plant_normal) then ! TODO Sam Rabin: Add ".and. .not. do_plant_prescribed"? + if (do_plant_normal) then gddmaturity(p) = max(950._r8, min(gddmaturity(p)+150._r8, 1850._r8)) end if else From bc055919bd68719b53d6563d1f7a37976ec11c44 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 16:47:49 -0600 Subject: [PATCH 408/444] Improve flush_gdd20 restart logic. Previously, TemperatureType%flush_gdd20 would get set to true upon restart unless it was read and false. This change makes it so that: - If TemperatureType%flush_gdd20 isn't read from the restart file, it falls back to the flush_gdd20 from clm_varctl. - If TemperatureType%flush_gdd20 IS read from the restart file, it is set to true if it's true on the restart file OR if the flush_gdd20 from clm_varctl is true. --- src/biogeophys/TemperatureType.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 787efa81a0..98f6d0f638 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -1148,10 +1148,10 @@ subroutine Restart(this, bounds, ncid, flag, is_simple_buildtemp, is_prog_buildt long_name='Flag indicating that GDD20 values need to be flushed', & units='none', interpinic_flag='copy', readvar=readvar, data=idata) if (flag == 'read') then - if (readvar .and. idata == 0) then - this%flush_gdd20 = .false. + if (readvar) then + this%flush_gdd20 = flush_gdd20 .or. idata == 1 else - this%flush_gdd20 = .true. + this%flush_gdd20 = flush_gdd20 end if end if end if From d298aef9438d0b13bf37ccd162e1f5a303f6e4b4 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 16:53:54 -0600 Subject: [PATCH 409/444] Do not use flush_gdd20 from clm_varctl in flush decision. Not directly, at least. Instead, rely on TemperatureType%flush_gdd20 having been set correctly. --- src/biogeophys/TemperatureType.F90 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 98f6d0f638..4929b24307 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -169,6 +169,9 @@ subroutine Init(this, bounds, & em_perroad_lun(bounds%begl:bounds%endl), & is_simple_buildtemp, is_prog_buildtemp) + ! Finish up + this%flush_gdd20 = flush_gdd20 + end subroutine Init !------------------------------------------------------------------------ @@ -1693,13 +1696,13 @@ subroutine UpdateAccVars (this, bounds, crop_inst) ! Accumulate and extract running 20-year means if (is_end_curr_year()) then ! Flush, if needed - if (flush_gdd20 .or. this%flush_gdd20) then + if (this%flush_gdd20) then write(iulog, *) 'Flushing GDD20 variables' call markreset_accum_field('GDD020') call markreset_accum_field('GDD820') call markreset_accum_field('GDD1020') this%flush_gdd20 = .false. - flush_gdd20 = .false. + flush_gdd20 = .false. ! Shouldn't be necessary, because flush_gdd20 shouldn't be considered after Init and Restart. But just in case... end if call update_accum_field ('GDD020', this%gdd0_patch, nstep) call extract_accum_field ('GDD020', this%gdd020_patch, nstep) From 827632e12b1f55253c8c75b999f4d8abd6f87b7a Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 18:08:09 -0600 Subject: [PATCH 410/444] Actually don't use TemperatureType%flush_gdd20 at all. Having that alongside flush_gdd20 from clm_varctl means that they can disagree when restarting, and it's not obvious which should win. Note that the user being able to request a flush at all is dangerous. If they start a run with it true, they might continue that run without setting it to false. Instead, the restart decision should be made by the model---if a gridcell has different prescribed gdd20 season from what its restart file says, then that gridcell should be flushed. --- src/biogeophys/TemperatureType.F90 | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 4929b24307..71722d84fb 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -95,7 +95,6 @@ module TemperatureType real(r8), pointer :: gdd020_patch (:) ! patch 20-year average of gdd0 (ddays) real(r8), pointer :: gdd820_patch (:) ! patch 20-year average of gdd8 (ddays) real(r8), pointer :: gdd1020_patch (:) ! patch 20-year average of gdd10 (ddays) - logical :: flush_gdd20 = .false. ! whether accumulated GDD20s need to be flushed ! Heat content real(r8), pointer :: beta_col (:) ! coefficient of convective velocity [-] @@ -169,9 +168,6 @@ subroutine Init(this, bounds, & em_perroad_lun(bounds%begl:bounds%endl), & is_simple_buildtemp, is_prog_buildtemp) - ! Finish up - this%flush_gdd20 = flush_gdd20 - end subroutine Init !------------------------------------------------------------------------ @@ -1139,26 +1135,6 @@ subroutine Restart(this, bounds, ncid, flag, is_simple_buildtemp, is_prog_buildt end if end if - if (use_crop) then - if (flag == 'write') then - if (this%flush_gdd20) then - idata = 1 - else - idata = 0 - end if - end if - call restartvar(ncid=ncid, flag=flag, varname='flush_gdd20', xtype=ncd_int, & - long_name='Flag indicating that GDD20 values need to be flushed', & - units='none', interpinic_flag='copy', readvar=readvar, data=idata) - if (flag == 'read') then - if (readvar) then - this%flush_gdd20 = flush_gdd20 .or. idata == 1 - else - this%flush_gdd20 = flush_gdd20 - end if - end if - end if - end subroutine Restart @@ -1696,13 +1672,12 @@ subroutine UpdateAccVars (this, bounds, crop_inst) ! Accumulate and extract running 20-year means if (is_end_curr_year()) then ! Flush, if needed - if (this%flush_gdd20) then + if (flush_gdd20) then write(iulog, *) 'Flushing GDD20 variables' call markreset_accum_field('GDD020') call markreset_accum_field('GDD820') call markreset_accum_field('GDD1020') - this%flush_gdd20 = .false. - flush_gdd20 = .false. ! Shouldn't be necessary, because flush_gdd20 shouldn't be considered after Init and Restart. But just in case... + flush_gdd20 = .false. end if call update_accum_field ('GDD020', this%gdd0_patch, nstep) call extract_accum_field ('GDD020', this%gdd020_patch, nstep) From 4ab30a5ddb9ac54cba659abc8682f1152e8eb844 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 18:20:21 -0600 Subject: [PATCH 411/444] crop_calendars Python stuff now includes crop grasses. --- python/ctsm/crop_calendars/cropcal_module.py | 2 +- python/ctsm/crop_calendars/generate_gdds_functions.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ctsm/crop_calendars/cropcal_module.py b/python/ctsm/crop_calendars/cropcal_module.py index 927bdc9100..719d352665 100644 --- a/python/ctsm/crop_calendars/cropcal_module.py +++ b/python/ctsm/crop_calendars/cropcal_module.py @@ -345,7 +345,7 @@ def import_output( my_vars, year_1=None, year_n=None, - my_vegtypes=utils.define_mgdcrop_list_nograsses(), + my_vegtypes=utils.define_mgdcrop_list_withgrasses(), sdates_rx_ds=None, gdds_rx_ds=None, verbose=False, diff --git a/python/ctsm/crop_calendars/generate_gdds_functions.py b/python/ctsm/crop_calendars/generate_gdds_functions.py index 50e2ac3d00..14bd6b2e40 100644 --- a/python/ctsm/crop_calendars/generate_gdds_functions.py +++ b/python/ctsm/crop_calendars/generate_gdds_functions.py @@ -282,9 +282,9 @@ def import_and_process_1yr( # Get list of crops to include if skip_crops is not None: - crops_to_read = [c for c in utils.define_mgdcrop_list_nograsses() if c not in skip_crops] + crops_to_read = [c for c in utils.define_mgdcrop_list_withgrasses() if c not in skip_crops] else: - crops_to_read = utils.define_mgdcrop_list_nograsses() + crops_to_read = utils.define_mgdcrop_list_withgrasses() print(h1_filelist) dates_ds = import_ds( From aeb4182302dc63bc88a3c8a5186233901f310f37 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 18:22:58 -0600 Subject: [PATCH 412/444] interpolate_gdds.py: Syntax fix. --- python/ctsm/crop_calendars/interpolate_gdds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctsm/crop_calendars/interpolate_gdds.py b/python/ctsm/crop_calendars/interpolate_gdds.py index 92bb112e3f..123d40af38 100755 --- a/python/ctsm/crop_calendars/interpolate_gdds.py +++ b/python/ctsm/crop_calendars/interpolate_gdds.py @@ -122,7 +122,7 @@ def interpolate_gdds(args): if "lat" not in ds_in[var].dims and "lon" not in ds_in[var].dims: print(f"Skipping variable {var} with dimensions {ds_in[var].dims}") continue - if not re.compile("^" + args.variable_prefix).match(var) + if not re.compile("^" + args.variable_prefix).match(var): print(f"Unexpected variable {var} on input file. Skipping.") continue if args.dry_run: From 929ec5d6c43a4234e35b060b02223888466554fc Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 23:08:27 -0600 Subject: [PATCH 413/444] Skip switchgrass in RXCROPMATURITY. --- cime_config/SystemTests/rxcropmaturity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/SystemTests/rxcropmaturity.py b/cime_config/SystemTests/rxcropmaturity.py index 46ed8f8be3..965398821f 100644 --- a/cime_config/SystemTests/rxcropmaturity.py +++ b/cime_config/SystemTests/rxcropmaturity.py @@ -438,7 +438,7 @@ def _run_generate_gdds(self, case_gddgen): f"--sdates-file {sdates_file}", f"--hdates-file {hdates_file}", f"--output-dir generate_gdds_out", - f"--skip-crops miscanthus,irrigated_miscanthus", + f"--skip-crops miscanthus,irrigated_miscanthus,switchgrass,irrigated_switchgrass", ] ) stu.run_python_script( From b70c156fed30f835a8b32cbca4d82dcbfe4888b2 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jul 2024 23:16:00 -0600 Subject: [PATCH 414/444] Manually specify sowing date file for GddGen testmod. --- cime_config/testdefs/testmods_dirs/clm/GddGen/user_nl_clm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cime_config/testdefs/testmods_dirs/clm/GddGen/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/GddGen/user_nl_clm index 87cdd5d5b5..cfde517fd9 100644 --- a/cime_config/testdefs/testmods_dirs/clm/GddGen/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/GddGen/user_nl_clm @@ -1,4 +1,6 @@ cropcals_rx = .true. +stream_fldFileName_swindow_start = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.tweaked_latlons.nc' +stream_fldFileName_swindow_end = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-hcru_hcru_mt13.2000-2000.20230728_165845.tweaked_latlons.nc' stream_fldFileName_cultivar_gdds = '' generate_crop_gdds = .true. use_mxmat = .false. From 7400d5bb153bd64be3eeb7f560e85128d736ed5c Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 05:14:01 -0600 Subject: [PATCH 415/444] Add izumi_nag.clm-RxCropCalsAdaptGGCMI test to expected fails. SMS_P128x1_Lm25.f10_f10_mg37.IHistClm60BgcCrop.izumi_nag.clm-RxCropCalsAdaptGGCMI --- cime_config/testdefs/ExpectedTestFails.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 03eb6a157d..e5e1410d1e 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -170,6 +170,13 @@ + + + FAIL + #2659 + + + From 388c7ed45e9561206a88efeecdb6faec054522d1 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 05:55:45 -0600 Subject: [PATCH 416/444] Move stream_gdd20_seasons to cropCalStreamMod. --- bld/namelist_files/namelist_definition_ctsm.xml | 2 +- src/biogeophys/TemperatureType.F90 | 7 +++++-- src/cpl/share_esmf/cropcalStreamMod.F90 | 5 ++++- src/main/clm_varctl.F90 | 1 - src/main/controlMod.F90 | 4 +--- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 31ce220d9c..a24f59339a 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1839,7 +1839,7 @@ Filename of input stream data for baseline GDD20 values + group="cropcal_streams" valid_values="" > Set this to true to read gdd20 accumulation season start and end dates from stream files, rather than using hard-coded hemisphere-specific "warm seasons." diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 71722d84fb..707218cc27 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -8,7 +8,7 @@ module TemperatureType use decompMod , only : bounds_type use abortutils , only : endrun use clm_varctl , only : use_cndv, iulog, use_luna, use_crop, use_biomass_heat_storage - use clm_varctl , only : stream_gdd20_seasons, flush_gdd20 + use clm_varctl , only : flush_gdd20 use clm_varpar , only : nlevsno, nlevgrnd, nlevlak, nlevurb, nlevmaxurbgrnd use clm_varcon , only : spval, ispval use GridcellType , only : grc @@ -1401,6 +1401,7 @@ subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, d real(r8) :: lat ! latitude integer :: gdd20_season_start, gdd20_season_end integer :: jday ! Julian day of year (1, ..., 366) + logical :: stream_gdd20_seasons_tt ! Local derivation of this to avoid circular dependency associate( & gdd20_season_starts => crop_inst%gdd20_season_start_patch, & @@ -1432,6 +1433,8 @@ subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, d end if write(field_name, format_string) "GDD",basetemp_int + stream_gdd20_seasons_tt = any(gdd20_season_starts(begp:endp) > 0.5_r8) .and. any(gdd20_season_starts(begp:endp) < 366.5_r8) + do p = begp,endp ! Avoid unnecessary calculations over inactive points @@ -1447,7 +1450,7 @@ subroutine UpdateAccVars_CropGDDs(this, rbufslp, begp, endp, month, day, secs, d ((month > 9 .or. month < 4) .and. lat < 0._r8) ! Replace with read-in gdd20 accumulation season, if needed and valid ! (If these aren't being read in or they're invalid, they'll be -1) - if (stream_gdd20_seasons .and. patch%itype(p) >= npcropmin) then + if (stream_gdd20_seasons_tt .and. patch%itype(p) >= npcropmin) then gdd20_season_start = int(gdd20_season_starts(p)) gdd20_season_end = int(gdd20_season_ends(p)) if (gdd20_season_start >= 1 .and. gdd20_season_end >= 1) then diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index d17ce1c259..85218a0e1c 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -16,7 +16,6 @@ module cropcalStreamMod use clm_varctl , only : iulog use clm_varctl , only : use_cropcal_rx_swindows, use_cropcal_rx_cultivar_gdds, use_cropcal_streams use clm_varctl , only : adapt_cropcal_rx_cultivar_gdds - use clm_varctl , only : stream_gdd20_seasons use clm_varpar , only : mxpft use clm_varpar , only : mxsowings use perf_mod , only : t_startf, t_stopf @@ -53,6 +52,7 @@ module cropcalStreamMod character(len=CL) :: stream_fldFileName_gdd20_baseline ! GDD20 baseline stream filename to read logical :: cropcals_rx ! Used only for setting input files in namelist; does nothing in code, but needs to be here so namelist read doesn't crash logical :: cropcals_rx_adapt ! Used only for setting input files in namelist; does nothing in code, but needs to be here so namelist read doesn't crash + logical :: stream_gdd20_seasons ! Read start and end dates for gdd20 seasons from streams instead of using hemisphere-specific values logical :: allow_invalid_gdd20_season_inputs ! Fall back on hemisphere "warm periods" in cases of invalid values in stream_fldFileName_gdd20_season_start and _end? character(len=CL) :: stream_fldFileName_gdd20_season_start ! Stream filename to read for start of gdd20 season character(len=CL) :: stream_fldFileName_gdd20_season_end ! Stream filename to read for end of gdd20 season @@ -113,6 +113,7 @@ subroutine cropcal_init(bounds) stream_meshfile_cropcal, & cropcals_rx, & cropcals_rx_adapt, & + stream_gdd20_seasons, & allow_invalid_gdd20_season_inputs, & stream_fldFileName_gdd20_season_start, & stream_fldFileName_gdd20_season_end @@ -130,6 +131,7 @@ subroutine cropcal_init(bounds) stream_fldFileName_swindow_end = '' stream_fldFileName_cultivar_gdds = '' stream_fldFileName_gdd20_baseline = '' + stream_gdd20_seasons = .false. allow_invalid_gdd20_season_inputs = .false. stream_fldFileName_gdd20_season_start = '' stream_fldFileName_gdd20_season_end = '' @@ -173,6 +175,7 @@ subroutine cropcal_init(bounds) call shr_mpi_bcast(stream_fldFileName_cultivar_gdds, mpicom) call shr_mpi_bcast(stream_fldFileName_gdd20_baseline, mpicom) call shr_mpi_bcast(stream_meshfile_cropcal , mpicom) + call shr_mpi_bcast(stream_gdd20_seasons, mpicom) call shr_mpi_bcast(allow_invalid_gdd20_season_inputs, mpicom) call shr_mpi_bcast(stream_fldFileName_gdd20_season_start, mpicom) call shr_mpi_bcast(stream_fldFileName_gdd20_season_end, mpicom) diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index a1ca2fd3f7..678f386f23 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -392,7 +392,6 @@ module clm_varctl logical, public :: use_cropcal_rx_swindows = .false. logical, public :: use_cropcal_rx_cultivar_gdds = .false. logical, public :: adapt_cropcal_rx_cultivar_gdds = .false. - logical, public :: stream_gdd20_seasons = .false. logical, public :: flush_gdd20 = .false. !---------------------------------------------------------- diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 98e0d1afac..634128798b 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -302,7 +302,7 @@ subroutine control_init(dtime) use_lch4, use_nitrif_denitrif, use_extralakelayers, & use_vichydro, use_cn, use_cndv, use_crop, use_fertilizer, & use_grainproduct, use_snicar_frc, use_vancouver, use_mexicocity, use_noio, & - use_nguardrail, crop_residue_removal_frac, stream_gdd20_seasons, flush_gdd20 + use_nguardrail, crop_residue_removal_frac, flush_gdd20 ! SNICAR namelist /clm_inparm/ & @@ -711,7 +711,6 @@ subroutine control_spmd() call mpi_bcast (use_cndv, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_nguardrail, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_crop, 1, MPI_LOGICAL, 0, mpicom, ier) - call mpi_bcast (stream_gdd20_seasons, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (flush_gdd20, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fertilizer, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_grainproduct, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -985,7 +984,6 @@ subroutine control_print () write(iulog,*) ' use_cn = ', use_cn write(iulog,*) ' use_cndv = ', use_cndv write(iulog,*) ' use_crop = ', use_crop - write(iulog,*) ' stream_gdd20_seasons = ', stream_gdd20_seasons write(iulog,*) ' flush_gdd20 = ', flush_gdd20 write(iulog,*) ' use_fertilizer = ', use_fertilizer write(iulog,*) ' use_grainproduct = ', use_grainproduct From 0d4a300112f16ee35332af5e72e8016ea1990c8a Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 14:21:40 -0600 Subject: [PATCH 417/444] Fix setting of stream_fldFileName_gdd20_baseline. --- bld/CLMBuildNamelist.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 232b15c3b1..c2d23ce962 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4247,7 +4247,7 @@ sub setup_logic_cropcal_streams { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_swindow_end'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_cultivar_gdds'); if ( &value_is_true($cropcals_rx_adapt) ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_gdd20_baseline'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_gdd20_baseline', 'stream_gdd20_seasons'=>$stream_gdd20_seasons); } } From 649547c5015e59ab582436c8c1bcfc39e296dd8f Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 16:21:16 -0600 Subject: [PATCH 418/444] Don't specify PE layout for SMS crop_calendars tests. --- cime_config/testdefs/testlist_clm.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index b8e3dd2f31..ecdeeb659d 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3560,7 +3560,7 @@ - + @@ -3578,7 +3578,7 @@ - + From 26ce0bbb0ac7835f11251c0585eec778b4a79859 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 16:04:00 -0600 Subject: [PATCH 419/444] Add izumi versions of most derecho crop_calendars tests. --- cime_config/testdefs/testlist_clm.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index ecdeeb659d..18e66d4d64 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3563,6 +3563,7 @@ + @@ -3581,6 +3582,7 @@ + @@ -3593,6 +3595,7 @@ + @@ -3603,6 +3606,7 @@ + @@ -3613,6 +3617,7 @@ + @@ -3622,6 +3627,7 @@ + From ae4af6b53cf0e525cd125a1eea97472ad2c72799 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 16:26:14 -0600 Subject: [PATCH 420/444] Fix PE layouts of izumi crop_calendars tests. --- cime_config/testdefs/testlist_clm.xml | 30 +++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 18e66d4d64..edbfd3c4eb 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3579,6 +3579,15 @@ + + + + + + + + + @@ -3595,18 +3604,25 @@ - + + + + + + + + + - @@ -3614,6 +3630,16 @@ + + + + + + + + + + From e757d3df5154d3671129a26d9afab667f337591f Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 14:54:24 -0600 Subject: [PATCH 421/444] Add oldCropCals testmod and two aux_clm tests that use it. --- cime_config/testdefs/testlist_clm.xml | 27 +++++++++++++++++++ .../testmods_dirs/clm/oldCropCals/user_nl_clm | 3 +++ 2 files changed, 30 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/oldCropCals/user_nl_clm diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index edbfd3c4eb..ffaf4edc29 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3660,5 +3660,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cime_config/testdefs/testmods_dirs/clm/oldCropCals/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/oldCropCals/user_nl_clm new file mode 100644 index 0000000000..5885f6f2a0 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/oldCropCals/user_nl_clm @@ -0,0 +1,3 @@ +cropcals_rx = .false. +cropcals_rx_adapt = .false. +stream_gdd20_seasons = .false. \ No newline at end of file From 7070abcd9272cc4b0f55d086321ea6968f1d2e83 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 16:29:34 -0600 Subject: [PATCH 422/444] Add cropcals_rx(_adapt) in some testmods; rename RxCropCals to RxCropCalsNoAdapt. --- cime_config/testdefs/testlist_clm.xml | 2 +- cime_config/testdefs/testmods_dirs/clm/GddGen/include_user_mods | 1 + cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm | 2 -- .../testmods_dirs/clm/RxCropCalsAdapt/include_user_mods | 2 +- .../clm/{RxCropCals => RxCropCalsNoAdapt}/include_user_mods | 0 .../testdefs/testmods_dirs/clm/RxCropCalsNoAdapt/user_nl_clm | 2 ++ 6 files changed, 5 insertions(+), 4 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm rename cime_config/testdefs/testmods_dirs/clm/{RxCropCals => RxCropCalsNoAdapt}/include_user_mods (100%) create mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCalsNoAdapt/user_nl_clm diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index ffaf4edc29..cca879604d 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3560,7 +3560,7 @@ - + diff --git a/cime_config/testdefs/testmods_dirs/clm/GddGen/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/GddGen/include_user_mods index 02ec13743f..4d75082583 100644 --- a/cime_config/testdefs/testmods_dirs/clm/GddGen/include_user_mods +++ b/cime_config/testdefs/testmods_dirs/clm/GddGen/include_user_mods @@ -1 +1,2 @@ ../cropMonthOutput +../oldCropCals \ No newline at end of file diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm deleted file mode 100644 index 8a0b4a91be..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm +++ /dev/null @@ -1,2 +0,0 @@ - -cropcals_rx = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods index 88c9694365..4f46c0ce95 100644 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods @@ -1 +1 @@ -../RxCropCals +../RxCropCalsNoAdapt diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCals/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsNoAdapt/include_user_mods similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/RxCropCals/include_user_mods rename to cime_config/testdefs/testmods_dirs/clm/RxCropCalsNoAdapt/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsNoAdapt/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsNoAdapt/user_nl_clm new file mode 100644 index 0000000000..625960b389 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsNoAdapt/user_nl_clm @@ -0,0 +1,2 @@ +cropcals_rx = .true. +cropcals_rx_adapt = .false. From f0a221f0a68c0aac10cf0c449406c1dcd27a6294 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 15:38:20 -0600 Subject: [PATCH 423/444] Rework RxCropCalsAdaptGGCMI to not require RxCropCalsAdapt. The latter will be deleted in the next commit. --- .../testmods_dirs/clm/RxCropCalsAdaptGGCMI/include_user_mods | 2 +- .../testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/include_user_mods index af5fe8591e..23ea3745e6 100644 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/include_user_mods +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/include_user_mods @@ -1 +1 @@ -../RxCropCalsAdapt +../crop diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm index dd4ac3117c..fdf5a86c26 100644 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdaptGGCMI/user_nl_clm @@ -1,4 +1,5 @@ - +cropcals_rx = .false. +cropcals_rx_adapt = .true. stream_gdd20_seasons = .true. flush_gdd20 = .true. !TODO SSR: Try without this once you have half-degree inputs From 5dabe6287e9ad843003f08122cf58327aaf356b3 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 16:31:07 -0600 Subject: [PATCH 424/444] Delete RxCropCalsAdapt test. --- cime_config/testdefs/testlist_clm.xml | 18 ------------------ .../clm/RxCropCalsAdapt/include_user_mods | 1 - .../clm/RxCropCalsAdapt/user_nl_clm | 3 --- 3 files changed, 22 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index cca879604d..4e5574932e 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3570,24 +3570,6 @@ - - - - - - - - - - - - - - - - - - diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods deleted file mode 100644 index 4f46c0ce95..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../RxCropCalsNoAdapt diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm deleted file mode 100644 index 709c7221e0..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm +++ /dev/null @@ -1,3 +0,0 @@ - -cropcals_rx = .false. -cropcals_rx_adapt = .true. From ca6b608ce59eb9043297d4452a5d0107eb5b8e82 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 15:52:10 -0600 Subject: [PATCH 425/444] Add 'cropcals_rx_adapt = .false.' to RXCROPMATURITYSHARED. --- cime_config/SystemTests/rxcropmaturity.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cime_config/SystemTests/rxcropmaturity.py b/cime_config/SystemTests/rxcropmaturity.py index b1de55836b..fb254c408f 100644 --- a/cime_config/SystemTests/rxcropmaturity.py +++ b/cime_config/SystemTests/rxcropmaturity.py @@ -402,6 +402,7 @@ def _run_check_rxboth_run(self, skip_gen): def _modify_user_nl_allruns(self): nl_additions = [ "cropcals_rx = .true.", + "cropcals_rx_adapt = .false.", "stream_meshfile_cropcal = '{}'".format(self._case.get_value("LND_DOMAIN_MESH")), "stream_fldFileName_swindow_start = '{}'".format(self._sdatefile), "stream_fldFileName_swindow_end = '{}'".format(self._sdatefile), From 904e6b2f99164165a4a197436f4b583148bdc087 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 18:22:36 -0600 Subject: [PATCH 426/444] Change a test name in ExpectedTestFails.xml. --- cime_config/testdefs/ExpectedTestFails.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 9b653d8e0b..d5e3e4e378 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -163,7 +163,7 @@ - + FAIL #2659 From a3d8158c65dcff4cabc1a9e3dd86fe762050f7f3 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 20:01:54 -0600 Subject: [PATCH 427/444] Turn on cropcals_rx_adapt by default for physics other than clm4_5, clm5_0, and clm5_1. --- bld/namelist_files/namelist_defaults_ctsm.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 706b4dd26d..5f336dabf8 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -2199,7 +2199,10 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c .false. -.false. +.true. +.false. +.false. +.false. .false. .false. 2000 From dcdd587848f18f2087543966856f6b0373a64adb Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 22:36:49 -0600 Subject: [PATCH 428/444] Remove most Izumi crop_calendars tests. --- cime_config/testdefs/testlist_clm.xml | 32 --------------------------- 1 file changed, 32 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 4e5574932e..efeb011844 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3563,7 +3563,6 @@ - @@ -3573,7 +3572,6 @@ - @@ -3592,15 +3590,6 @@ - - - - - - - - - @@ -3612,20 +3601,9 @@ - - - - - - - - - - - @@ -3635,7 +3613,6 @@ - @@ -3660,14 +3637,5 @@ - - - - - - - - - From af02bca9e98661c1f9450cf7602c96dc3aab2b15 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Thu, 25 Jul 2024 23:17:56 -0700 Subject: [PATCH 429/444] Update ChangeLog and ChangeSum. --- doc/ChangeLog | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++ doc/ChangeSum | 1 + 2 files changed, 138 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index 506b3d5ad0..501a67720f 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,141 @@ =============================================================== +Tag name: ctsm5.2.016 +Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) +Date: Thu Jul 25 22:39:39 MST 2024 +One-line Summary: Enable new crop calendars for clm60 compsets + +Purpose and description of changes +---------------------------------- + +This commit switches clm60 compsets (really, any compset other than clm45, clm50, and clm51) to use: +- Per-gridcell and -crop sowing windows derived from the GGCMI phase 3b group II static growing seasons +- Per-gridcell and -crop maturity requirements derived from those same growing seasons, over the 1980-2009 growing seasons +- Code to adjust those prescribed maturity requirements based on recent climate + + +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.) + +[X] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[?] ctsm5_0-nwp: Probably? Haven't tested, but didn't exclude that setup. + +[ ] clm4_5 + + +Bugs fixed +---------- + +List of CTSM issues fixed (include CTSM Issue # and description): +- Fixes ESCOMP/CTSM#2584: Reset accumulators to initval instead of 0 (https://github.com/ESCOMP/CTSM/issues/2584) + +Notes of particular relevance for users +--------------------------------------- +[Remove any lines that don't apply. Remove entire section if nothing applies.] + +Caveats for users (e.g., need to interpolate initial conditions): + +Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): +- Add cropcals_rx, default false. +- Add cropcals_rx_adapt, default true. This is what changes default behavior. +- Rename stream_year_first_cropcal to stream_year_first_cropcal_swindows +- Rename stream_year_last_cropcal to stream_year_last_cropcal_swindows +- Rename model_year_align_cropcal to model_year_align_cropcal_swindows +- Add stream_year_first_cropcal_cultivar_gdds +- Add stream_year_last_cropcal_cultivar_gdds +- Add model_year_align_cropcal_cultivar_gdds +- Add stream_fldFileName_gdd20_baseline +- Add stream_gdd20_seasons (experimental) +- Add flush_gdd20 (experimental) +- Add stream_fldFileName_gdd20_season_start (experimental) +- Add stream_fldFileName_gdd20_season_end (experimental) +- Add allow_invalid_gdd20_season_inputs + +Changes to the datasets (e.g., parameter, surface or initial files): +- Many new default and optional stream files added. + +Changes to documentation: +- None yet. + +Notes of particular relevance for developers: +--------------------------------------------- + +Caveats for developers: +- tools/contrib/tweak_latlons.py: This is a script I made to avoid the "ambiguous nearest neighbor" issue described in the discussion at https://github.com/orgs/esmf-org/discussions/261. It's hopefully just a temporary thing as we wait for ESMF to fix that bug. If they end up deciding not to, then this should be moved into python/ctsm/ and fully tested. +- Unit and system testing needs to be added for generate_gdd20_baseline.py. +- RXCROPMATURITY SystemTest should be updated to also call generate_gdd20_baseline.py. + +Changes to tests or testing: +- Adds testmods: + - midDecStart: Like decStart, except starts Dec. 15 instead of 30. Useful for ERP/ERS tests where you want the split in December. + - GddGen + - oldCropCals: To recreate previous crop calendars + - RxCropCalsAdaptGGCMI (experimental) + - RxCropCalsNoAdapt + - StreamGDD20Seasons (experimental) +- Removes sowingWindows testmod +- Adds and changes various tests related to crop calendars + +Note that testmods marked "experimental" are fine to be marked as expected failures, if needed. + + +Testing summary: +---------------- + +[Remove any lines that don't apply.] + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + (any machine) - + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- + izumi ------- + +Answer changes +-------------- + +Changes answers relative to baseline: + + Summarize any changes to answers, i.e., + - what code configurations: crop-enabled compsets with clm60 (or more specifically, other than clm45, clm50, clm51) + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): new climate + + Probably? At least, there can be large regional shifts in crop growing season. Results are similar to those for the Prescribed Calendars setup in Rabin et al. (2023; https://gmd.copernicus.org/articles/16/7253/2023/gmd-16-7253-2023.html). + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - None + + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +- ESCOMP/CTSM#2560: Allow prescribed gddmaturity to vary based on recent climate (initial work, v2) (https://github.com/ESCOMP/CTSM/pull/2560) +- ESCOMP/CTSM#2585: Allow "manual" resets of all accumulator types (https://github.com/ESCOMP/CTSM/pull/2585) +- ESCOMP/CTSM#2593: Optionally base GDD20 on per-gridcell windows, not per-hemisphere (https://github.com/ESCOMP/CTSM/pull/2593) +- ESCOMP/CTSM#2661: Merge ctsm5.2.015 into scale-maturity-reqs (https://github.com/ESCOMP/CTSM/pull/2661) +- ESCOMP/CTSM#2664: Enable new crop calendars for clm60 compsets (https://github.com/ESCOMP/CTSM/pull/2664) +- ESCOMP/CTSM#2665: Merge new crop calendars into master (https://github.com/ESCOMP/CTSM/pull/2665) + +=============================================================== +=============================================================== Tag name: ctsm5.2.015 Originator(s): multiple (Samuel Levis,UCAR/TSS,303-665-1310, @mvertens, @jedwards4b, @billsacks, @Katetc) Date: Mon 22 Jul 2024 12:46:17 PM MDT diff --git a/doc/ChangeSum b/doc/ChangeSum index 9c6524b33d..f043ab8b34 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,6 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.2.016 samrabin 07/25/2024 Enable new crop calendars for clm60 compsets ctsm5.2.015 multiple 07/22/2024 Update submodule tags to pass runoff from cism to rof ctsm5.2.014 multiple 07/19/2024 use_matrixcn, use_soil_matrixcn come in as default .false. ctsm5.2.013 glemieux 07/18/2024 FATES Land Use V2 From 542f7080432e76073ea2734be0ed50393e9a6bb8 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jul 2024 01:40:34 -0600 Subject: [PATCH 430/444] Wrap cropcal subroutine calls in use_crop. Avoids issue with undefined pointer to crop_inst%rx_swindow_starts_thisyr_patch and probably other arrays. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 1 + src/main/clm_driver.F90 | 4 ++-- src/main/clm_initializeMod.F90 | 26 +++++++++++++------------ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 85218a0e1c..a39ba40754 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -14,6 +14,7 @@ module cropcalStreamMod use decompMod , only : bounds_type use abortutils , only : endrun use clm_varctl , only : iulog + use clm_varctl , only : use_crop use clm_varctl , only : use_cropcal_rx_swindows, use_cropcal_rx_cultivar_gdds, use_cropcal_streams use clm_varctl , only : adapt_cropcal_rx_cultivar_gdds use clm_varpar , only : mxpft diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 01c0ec409e..53b1e55f7c 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -475,7 +475,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! When crop calendar streams are being used ! NOTE: This call needs to happen outside loops over nclumps (as streams are not threadsafe) - if (use_cropcal_streams .and. is_beg_curr_year()) then + if (use_crop .and. use_cropcal_streams .and. is_beg_curr_year()) then call cropcal_advance( bounds_proc ) end if @@ -1073,7 +1073,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro frictionvel_inst, photosyns_inst, drydepvel_inst) call t_stopf('depvel') - if (use_cropcal_streams .and. is_beg_curr_year()) then + if (use_crop .and. use_cropcal_streams .and. is_beg_curr_year()) then ! ============================================================================ ! Update crop calendars ! ============================================================================ diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index e8f70bdef8..0c0570c577 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -659,19 +659,21 @@ subroutine initialize2(ni,nj) end if ! Initialize crop calendars - call t_startf('init_cropcal') - call cropcal_init(bounds_proc) - if (use_cropcal_streams) then - call cropcal_advance( bounds_proc ) - !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) - do nc = 1,nclumps - call get_clump_bounds(nc, bounds_clump) - call cropcal_interp(bounds_clump, filter_inactive_and_active(nc)%num_pcropp, & - filter_inactive_and_active(nc)%pcropp, .true., crop_inst) - end do - !$OMP END PARALLEL DO + if (use_crop) then + call t_startf('init_cropcal') + call cropcal_init(bounds_proc) + if (use_cropcal_streams) then + call cropcal_advance( bounds_proc ) + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) + do nc = 1,nclumps + call get_clump_bounds(nc, bounds_clump) + call cropcal_interp(bounds_clump, filter_inactive_and_active(nc)%num_pcropp, & + filter_inactive_and_active(nc)%pcropp, .true., crop_inst) + end do + !$OMP END PARALLEL DO + end if + call t_stopf('init_cropcal') end if - call t_stopf('init_cropcal') ! Initialize active history fields. ! This is only done if not a restart run. If a restart run, then this From 126ce292f1380e96ff22750ec4cd0dc1a518e8d6 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jul 2024 07:49:53 -0600 Subject: [PATCH 431/444] Allocate first dim on dataptr2d_*_start/end arrays with begp:endp. Instead of just :. Hopefully will eliminate too-high index errors in threading tests. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index a39ba40754..3fdf1ba06c 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -545,9 +545,9 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Read prescribed sowing window start dates from input files allocate(dataptr2d_swindow_start(lsize, ncft)) - dataptr2d_swindow_start(:,:) = -1._r8 + dataptr2d_swindow_start(begp:endp,:) = -1._r8 allocate(dataptr2d_swindow_end (lsize, ncft)) - dataptr2d_swindow_end(:,:) = -1._r8 + dataptr2d_swindow_end(begp:endp,:) = -1._r8 if (use_cropcal_rx_swindows) then ! Starting with npcropmin will skip generic crops do n = 1, ncft @@ -742,9 +742,9 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Read prescribed gdd20 season start dates from input files allocate(dataptr2d_gdd20_season_start(lsize, ncft)) - dataptr2d_gdd20_season_start(:,:) = -1._r8 + dataptr2d_gdd20_season_start(begp:endp,:) = -1._r8 allocate(dataptr2d_gdd20_season_end (lsize, ncft)) - dataptr2d_gdd20_season_end(:,:) = -1._r8 + dataptr2d_gdd20_season_end(begp:endp,:) = -1._r8 if (stream_gdd20_seasons) then ! Starting with npcropmin will skip generic crops do n = 1, ncft From b7a8fb58e2186d9d6b9dcd20b8b6c57301bfcd8e Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jul 2024 08:14:51 -0600 Subject: [PATCH 432/444] Allocate 2d arrays with begp:endp, not lsize. Hopefully will eliminate too-high index errors in threading tests. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 3fdf1ba06c..36c6c78f22 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -544,9 +544,9 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) dayspyr = get_curr_days_per_year() ! Read prescribed sowing window start dates from input files - allocate(dataptr2d_swindow_start(lsize, ncft)) + allocate(dataptr2d_swindow_start(begp:endp, ncft)) dataptr2d_swindow_start(begp:endp,:) = -1._r8 - allocate(dataptr2d_swindow_end (lsize, ncft)) + allocate(dataptr2d_swindow_end (begp:endp, ncft)) dataptr2d_swindow_end(begp:endp,:) = -1._r8 if (use_cropcal_rx_swindows) then ! Starting with npcropmin will skip generic crops @@ -631,7 +631,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) deallocate(dataptr2d_swindow_start) deallocate(dataptr2d_swindow_end) - allocate(dataptr2d_cultivar_gdds(lsize, ncft)) + allocate(dataptr2d_cultivar_gdds(begp:endp, ncft)) if (use_cropcal_rx_cultivar_gdds) then ! Read prescribed cultivar GDDs from input files ! Starting with npcropmin will skip generic crops @@ -688,7 +688,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) deallocate(dataptr2d_cultivar_gdds) - allocate(dataptr2d_gdd20_baseline(lsize, ncft)) + allocate(dataptr2d_gdd20_baseline(begp:endp, ncft)) if (adapt_cropcal_rx_cultivar_gdds) then ! Read GDD20 baselines from input files ! Starting with npcropmin will skip generic crops @@ -741,9 +741,9 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Read prescribed gdd20 season start dates from input files - allocate(dataptr2d_gdd20_season_start(lsize, ncft)) + allocate(dataptr2d_gdd20_season_start(begp:endp, ncft)) dataptr2d_gdd20_season_start(begp:endp,:) = -1._r8 - allocate(dataptr2d_gdd20_season_end (lsize, ncft)) + allocate(dataptr2d_gdd20_season_end (begp:endp, ncft)) dataptr2d_gdd20_season_end(begp:endp,:) = -1._r8 if (stream_gdd20_seasons) then ! Starting with npcropmin will skip generic crops From 63b66b66944e0bacf55da5e87f48a1a860ca9211 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jul 2024 08:22:57 -0600 Subject: [PATCH 433/444] Add ERP_D_Ld10_P64x2.f10_f10_mg37.IHistClm60BgcCrop.derecho_intel.clm-default to crop_calendars suite. --- cime_config/testdefs/testlist_clm.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index efeb011844..bb421c8e9e 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -1016,6 +1016,7 @@ + From 7e04126d66429ee7419441538447bb3a3cc4b448 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jul 2024 08:26:32 -0600 Subject: [PATCH 434/444] dataptr2d arrays' first dim is gridcell, not patch. Hopefully will eliminate too-high index errors in threading tests. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 36c6c78f22..d19c74ad37 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -544,10 +544,10 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) dayspyr = get_curr_days_per_year() ! Read prescribed sowing window start dates from input files - allocate(dataptr2d_swindow_start(begp:endp, ncft)) - dataptr2d_swindow_start(begp:endp,:) = -1._r8 - allocate(dataptr2d_swindow_end (begp:endp, ncft)) - dataptr2d_swindow_end(begp:endp,:) = -1._r8 + allocate(dataptr2d_swindow_start(bounds%begg:bounds%endg, ncft)) + dataptr2d_swindow_start(bounds%begg:bounds%endg,:) = -1._r8 + allocate(dataptr2d_swindow_end (bounds%begg:bounds%endg, ncft)) + dataptr2d_swindow_end(bounds%begg:bounds%endg,:) = -1._r8 if (use_cropcal_rx_swindows) then ! Starting with npcropmin will skip generic crops do n = 1, ncft @@ -563,7 +563,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) end if ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize ! So an explicit loop is required here - do g = 1,lsize + do g = bounds%begg, bounds%endg ! If read-in value is invalid, set to -1. Will be handled later in this subroutine. if (dataptr1d_swindow_start(g) <= 0 .or. dataptr1d_swindow_start(g) > dayspyr & @@ -631,7 +631,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) deallocate(dataptr2d_swindow_start) deallocate(dataptr2d_swindow_end) - allocate(dataptr2d_cultivar_gdds(begp:endp, ncft)) + allocate(dataptr2d_cultivar_gdds(bounds%begg:bounds%endg, ncft)) if (use_cropcal_rx_cultivar_gdds) then ! Read prescribed cultivar GDDs from input files ! Starting with npcropmin will skip generic crops @@ -688,7 +688,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) deallocate(dataptr2d_cultivar_gdds) - allocate(dataptr2d_gdd20_baseline(begp:endp, ncft)) + allocate(dataptr2d_gdd20_baseline(bounds%begg:bounds%endg, ncft)) if (adapt_cropcal_rx_cultivar_gdds) then ! Read GDD20 baselines from input files ! Starting with npcropmin will skip generic crops @@ -741,10 +741,10 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Read prescribed gdd20 season start dates from input files - allocate(dataptr2d_gdd20_season_start(begp:endp, ncft)) - dataptr2d_gdd20_season_start(begp:endp,:) = -1._r8 - allocate(dataptr2d_gdd20_season_end (begp:endp, ncft)) - dataptr2d_gdd20_season_end(begp:endp,:) = -1._r8 + allocate(dataptr2d_gdd20_season_start(bounds%begg:bounds%endg, ncft)) + dataptr2d_gdd20_season_start(bounds%begg:bounds%endg,:) = -1._r8 + allocate(dataptr2d_gdd20_season_end (bounds%begg:bounds%endg, ncft)) + dataptr2d_gdd20_season_end(bounds%begg:bounds%endg,:) = -1._r8 if (stream_gdd20_seasons) then ! Starting with npcropmin will skip generic crops do n = 1, ncft From d47b28a5e3e44b66a11fc8055d57f24c02d8bbbc Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jul 2024 08:36:47 -0600 Subject: [PATCH 435/444] Use begg and endg instead of lsize. Hopefully will eliminate too-high index errors in threading tests. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index d19c74ad37..02cfc5e67a 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -507,7 +507,6 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) integer :: nc, fp integer :: dayspyr integer :: n, g - integer :: lsize integer :: rc integer :: begp, endp real(r8), pointer :: dataptr1d_swindow_start(:) @@ -536,7 +535,6 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Get pointer for stream data that is time and spatially interpolate to model time and grid ! Place all data from each type into a temporary 2d array - lsize = bounds%endg - bounds%begg + 1 begp = bounds%begp endp = bounds%endp @@ -644,7 +642,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize ! So an explicit loop is required here - do g = 1,lsize + do g = bounds%begg, bounds%endg ! If read-in value is invalid, have PlantCrop() set gddmaturity to PFT-default value. if (dataptr1d_cultivar_gdds(g) < 0 .or. dataptr1d_cultivar_gdds(g) > 1000000._r8) then @@ -672,8 +670,8 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! vegetated pft ig = g_to_ig(patch%gridcell(p)) - if (ig > lsize) then - write(iulog,'(a,i0,a,i0,a)') 'ig (',ig,') > lsize (',lsize,')' + if (ig < bounds%begg .or. ig > bounds%endg) then + write(iulog,'(a,i0,a,i0,a)') 'ig (',ig,') < begg (',bounds%begg,') or > endg (',bounds%endg,')' call ESMF_Finalize(endflag=ESMF_END_ABORT) end if @@ -701,7 +699,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize ! So an explicit loop is required here - do g = 1,lsize + do g = bounds%begg, bounds%endg dataptr2d_gdd20_baseline(g,n) = dataptr1d_gdd20_baseline(g) end do end do @@ -723,8 +721,8 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! vegetated pft ig = g_to_ig(patch%gridcell(p)) - if (ig > lsize) then - write(iulog,'(a,i0,a,i0,a)') 'ig (',ig,') > lsize (',lsize,')' + if (ig < bounds%begg .or. ig > bounds%endg) then + write(iulog,'(a,i0,a,i0,a)') 'ig (',ig,') < begg (',bounds%begg,') or > endg (',bounds%endg,')' call ESMF_Finalize(endflag=ESMF_END_ABORT) end if @@ -760,7 +758,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) end if ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize ! So an explicit loop is required here - do g = 1,lsize + do g = bounds%begg, bounds%endg ! If read-in value is invalid, set to -1. Will be handled later in this subroutine. if (dataptr1d_gdd20_season_start(g) <= 0 .or. dataptr1d_gdd20_season_start(g) > 366 & From 2156c7206c61a131d3a4a6da69940acafb3d1dcf Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jul 2024 08:40:18 -0600 Subject: [PATCH 436/444] Use begg/endg instead of referring to bounds%. --- src/cpl/share_esmf/cropcalStreamMod.F90 | 51 ++++++++++++++----------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index 02cfc5e67a..5587641c21 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -422,6 +422,7 @@ subroutine cropcal_advance( bounds ) ! ! !LOCAL VARIABLES: integer :: g, ig ! Indices + integer :: begg, endg ! gridcell bounds integer :: year ! year (0, ...) for nstep+1 integer :: mon ! month (1, ..., 12) for nstep+1 integer :: day ! day of month (1, ..., 31) for nstep+1 @@ -430,6 +431,9 @@ subroutine cropcal_advance( bounds ) integer :: rc !----------------------------------------------------------------------- + begg = bounds%begg + endg = bounds%endg + call get_curr_date(year, mon, day, sec) mcdate = year*10000 + mon*100 + day if (use_cropcal_rx_swindows) then @@ -471,9 +475,9 @@ subroutine cropcal_advance( bounds ) end if if ( .not. allocated(g_to_ig) )then - allocate (g_to_ig(bounds%begg:bounds%endg) ) + allocate (g_to_ig(begg:endg) ) ig = 0 - do g = bounds%begg,bounds%endg + do g = begg,endg ig = ig+1 g_to_ig(g) = ig end do @@ -508,6 +512,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) integer :: dayspyr integer :: n, g integer :: rc + integer :: begg, endg integer :: begp, endp real(r8), pointer :: dataptr1d_swindow_start(:) real(r8), pointer :: dataptr1d_swindow_end (:) @@ -530,8 +535,10 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) gdd20_season_ends => crop_inst%gdd20_season_end_patch & ) - SHR_ASSERT_FL( (lbound(g_to_ig,1) <= bounds%begg ), sourcefile, __LINE__) - SHR_ASSERT_FL( (ubound(g_to_ig,1) >= bounds%endg ), sourcefile, __LINE__) + begg = bounds%begg + endg = bounds%endg + SHR_ASSERT_FL( (lbound(g_to_ig,1) <= begg ), sourcefile, __LINE__) + SHR_ASSERT_FL( (ubound(g_to_ig,1) >= endg ), sourcefile, __LINE__) ! Get pointer for stream data that is time and spatially interpolate to model time and grid ! Place all data from each type into a temporary 2d array @@ -542,10 +549,10 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) dayspyr = get_curr_days_per_year() ! Read prescribed sowing window start dates from input files - allocate(dataptr2d_swindow_start(bounds%begg:bounds%endg, ncft)) - dataptr2d_swindow_start(bounds%begg:bounds%endg,:) = -1._r8 - allocate(dataptr2d_swindow_end (bounds%begg:bounds%endg, ncft)) - dataptr2d_swindow_end(bounds%begg:bounds%endg,:) = -1._r8 + allocate(dataptr2d_swindow_start(begg:endg, ncft)) + dataptr2d_swindow_start(begg:endg,:) = -1._r8 + allocate(dataptr2d_swindow_end (begg:endg, ncft)) + dataptr2d_swindow_end(begg:endg,:) = -1._r8 if (use_cropcal_rx_swindows) then ! Starting with npcropmin will skip generic crops do n = 1, ncft @@ -561,7 +568,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) end if ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize ! So an explicit loop is required here - do g = bounds%begg, bounds%endg + do g = begg, endg ! If read-in value is invalid, set to -1. Will be handled later in this subroutine. if (dataptr1d_swindow_start(g) <= 0 .or. dataptr1d_swindow_start(g) > dayspyr & @@ -629,7 +636,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) deallocate(dataptr2d_swindow_start) deallocate(dataptr2d_swindow_end) - allocate(dataptr2d_cultivar_gdds(bounds%begg:bounds%endg, ncft)) + allocate(dataptr2d_cultivar_gdds(begg:endg, ncft)) if (use_cropcal_rx_cultivar_gdds) then ! Read prescribed cultivar GDDs from input files ! Starting with npcropmin will skip generic crops @@ -642,7 +649,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize ! So an explicit loop is required here - do g = bounds%begg, bounds%endg + do g = begg, endg ! If read-in value is invalid, have PlantCrop() set gddmaturity to PFT-default value. if (dataptr1d_cultivar_gdds(g) < 0 .or. dataptr1d_cultivar_gdds(g) > 1000000._r8) then @@ -670,8 +677,8 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! vegetated pft ig = g_to_ig(patch%gridcell(p)) - if (ig < bounds%begg .or. ig > bounds%endg) then - write(iulog,'(a,i0,a,i0,a)') 'ig (',ig,') < begg (',bounds%begg,') or > endg (',bounds%endg,')' + if (ig < begg .or. ig > endg) then + write(iulog,'(a,i0,a,i0,a)') 'ig (',ig,') < begg (',begg,') or > endg (',endg,')' call ESMF_Finalize(endflag=ESMF_END_ABORT) end if @@ -686,7 +693,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) deallocate(dataptr2d_cultivar_gdds) - allocate(dataptr2d_gdd20_baseline(bounds%begg:bounds%endg, ncft)) + allocate(dataptr2d_gdd20_baseline(begg:endg, ncft)) if (adapt_cropcal_rx_cultivar_gdds) then ! Read GDD20 baselines from input files ! Starting with npcropmin will skip generic crops @@ -699,7 +706,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize ! So an explicit loop is required here - do g = bounds%begg, bounds%endg + do g = begg, endg dataptr2d_gdd20_baseline(g,n) = dataptr1d_gdd20_baseline(g) end do end do @@ -721,8 +728,8 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! vegetated pft ig = g_to_ig(patch%gridcell(p)) - if (ig < bounds%begg .or. ig > bounds%endg) then - write(iulog,'(a,i0,a,i0,a)') 'ig (',ig,') < begg (',bounds%begg,') or > endg (',bounds%endg,')' + if (ig < begg .or. ig > endg) then + write(iulog,'(a,i0,a,i0,a)') 'ig (',ig,') < begg (',begg,') or > endg (',endg,')' call ESMF_Finalize(endflag=ESMF_END_ABORT) end if @@ -739,10 +746,10 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) ! Read prescribed gdd20 season start dates from input files - allocate(dataptr2d_gdd20_season_start(bounds%begg:bounds%endg, ncft)) - dataptr2d_gdd20_season_start(bounds%begg:bounds%endg,:) = -1._r8 - allocate(dataptr2d_gdd20_season_end (bounds%begg:bounds%endg, ncft)) - dataptr2d_gdd20_season_end(bounds%begg:bounds%endg,:) = -1._r8 + allocate(dataptr2d_gdd20_season_start(begg:endg, ncft)) + dataptr2d_gdd20_season_start(begg:endg,:) = -1._r8 + allocate(dataptr2d_gdd20_season_end (begg:endg, ncft)) + dataptr2d_gdd20_season_end(begg:endg,:) = -1._r8 if (stream_gdd20_seasons) then ! Starting with npcropmin will skip generic crops do n = 1, ncft @@ -758,7 +765,7 @@ subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, init, crop_inst) end if ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize ! So an explicit loop is required here - do g = bounds%begg, bounds%endg + do g = begg, endg ! If read-in value is invalid, set to -1. Will be handled later in this subroutine. if (dataptr1d_gdd20_season_start(g) <= 0 .or. dataptr1d_gdd20_season_start(g) > 366 & From b1aed3f36e79cb8eaf278f1a72be77de88ad1c64 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jul 2024 09:12:57 -0600 Subject: [PATCH 437/444] Update ChangeLog and ChangeSum. --- doc/ChangeLog | 13 ++++++------- doc/ChangeSum | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 501a67720f..88c322e990 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,7 +1,7 @@ =============================================================== Tag name: ctsm5.2.016 Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) -Date: Thu Jul 25 22:39:39 MST 2024 +Date: Fri 26 Jul 2024 09:11:52 AM MDT One-line Summary: Enable new crop calendars for clm60 compsets Purpose and description of changes @@ -89,22 +89,21 @@ Note that testmods marked "experimental" are fine to be marked as expected failu Testing summary: ---------------- -[Remove any lines that don't apply.] - [PASS means all tests PASS; OK means tests PASS other than expected fails.] build-namelist tests (if CLMBuildNamelist.pm has changed): - derecho - + derecho - FAIL + 1x1_cidadinhoBR tests only. That's fine. Filed Issue #2666: 1x1_cidadinhoBR tests fail in build-namelist_test.pl (https://github.com/ESCOMP/CTSM/issues/2666). python testing (if python code has changed; see instructions in python/README.md; document testing done): - (any machine) - + derecho - PASS regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): - derecho ----- - izumi ------- + derecho ----- OK + izumi ------- OK Answer changes -------------- diff --git a/doc/ChangeSum b/doc/ChangeSum index f043ab8b34..edc9e4cada 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,6 +1,6 @@ Tag Who Date Summary ============================================================================================================================ - ctsm5.2.016 samrabin 07/25/2024 Enable new crop calendars for clm60 compsets + ctsm5.2.016 samrabin 07/26/2024 Enable new crop calendars for clm60 compsets ctsm5.2.015 multiple 07/22/2024 Update submodule tags to pass runoff from cism to rof ctsm5.2.014 multiple 07/19/2024 use_matrixcn, use_soil_matrixcn come in as default .false. ctsm5.2.013 glemieux 07/18/2024 FATES Land Use V2 From 66e28d184b6d68f55c8ac2bf3d26b5d46399e7bb Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jul 2024 12:12:23 -0600 Subject: [PATCH 438/444] Changes one Izumi test from f19 to 10x15 resolution. - Was: ERS_D.f19_g17.I1850Clm50BgcCrop.izumi_nag.clm-ciso_monthly_matrixcn_spinup - Now: ERS_D.f10_f10_mg37.I1850Clm50BgcCrop.izumi_nag.clm-ciso_monthly_matrixcn_spinup Fixes ESCOMP/CTSM#2667: Change out a f19 resolution test on Izumi for f10 (https://github.com/ESCOMP/CTSM/issues/2667) --- cime_config/testdefs/testlist_clm.xml | 8 ++++++++ doc/ChangeLog | 9 +++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index bb421c8e9e..951e0d8d5b 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -863,6 +863,14 @@ + + + + + + + + diff --git a/doc/ChangeLog b/doc/ChangeLog index 88c322e990..0057567561 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,7 +1,7 @@ =============================================================== Tag name: ctsm5.2.016 Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) -Date: Fri 26 Jul 2024 09:11:52 AM MDT +Date: Fri Jul 26 12:20:46 MDT 2024 One-line Summary: Enable new crop calendars for clm60 compsets Purpose and description of changes @@ -35,12 +35,10 @@ Bugs fixed List of CTSM issues fixed (include CTSM Issue # and description): - Fixes ESCOMP/CTSM#2584: Reset accumulators to initval instead of 0 (https://github.com/ESCOMP/CTSM/issues/2584) +- Fixes ESCOMP/CTSM#2667: Change out a f19 resolution test on Izumi for f10 (https://github.com/ESCOMP/CTSM/issues/2667) Notes of particular relevance for users --------------------------------------- -[Remove any lines that don't apply. Remove entire section if nothing applies.] - -Caveats for users (e.g., need to interpolate initial conditions): Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): - Add cropcals_rx, default false. @@ -82,6 +80,9 @@ Changes to tests or testing: - StreamGDD20Seasons (experimental) - Removes sowingWindows testmod - Adds and changes various tests related to crop calendars +- Changes one Izumi test from f19 to 10x15 resolution: + - Was: ERS_D.f19_g17.I1850Clm50BgcCrop.izumi_nag.clm-ciso_monthly_matrixcn_spinup + - Now: ERS_D.f10_f10_mg37.I1850Clm50BgcCrop.izumi_nag.clm-ciso_monthly_matrixcn_spinup Note that testmods marked "experimental" are fine to be marked as expected failures, if needed. From 2422cef7f1e0ef1cc184eb51c0f973f2125396e9 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Sat, 27 Jul 2024 17:15:10 -0600 Subject: [PATCH 439/444] Update date on Change files --- doc/ChangeLog | 2 +- doc/ChangeSum | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 0057567561..79d640242d 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,7 +1,7 @@ =============================================================== Tag name: ctsm5.2.016 Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) -Date: Fri Jul 26 12:20:46 MDT 2024 +Date: Sat 27 Jul 2024 05:13:08 PM MDT One-line Summary: Enable new crop calendars for clm60 compsets Purpose and description of changes diff --git a/doc/ChangeSum b/doc/ChangeSum index edc9e4cada..382e5cf7cb 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,6 +1,6 @@ Tag Who Date Summary ============================================================================================================================ - ctsm5.2.016 samrabin 07/26/2024 Enable new crop calendars for clm60 compsets + ctsm5.2.016 samrabin 07/27/2024 Enable new crop calendars for clm60 compsets ctsm5.2.015 multiple 07/22/2024 Update submodule tags to pass runoff from cism to rof ctsm5.2.014 multiple 07/19/2024 use_matrixcn, use_soil_matrixcn come in as default .false. ctsm5.2.013 glemieux 07/18/2024 FATES Land Use V2 From 0f9fee7ea3b3f6732e2f0dd7bf75f7f6536b3cfa Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Mon, 29 Jul 2024 11:42:44 -0600 Subject: [PATCH 440/444] LILAC needs to read and handle the drv_flds_in file as dust emission settings are required and it's namelist must be read --- cime_config/SystemTests/lilacsmoke.py | 2 +- python/ctsm/lilac_make_runtime_inputs.py | 1 - src/CMakeLists.txt | 1 + src/cpl/lilac/lnd_comp_esmf.F90 | 5 +++++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cime_config/SystemTests/lilacsmoke.py b/cime_config/SystemTests/lilacsmoke.py index 1287301ba2..5bdbb31ec1 100644 --- a/cime_config/SystemTests/lilacsmoke.py +++ b/cime_config/SystemTests/lilacsmoke.py @@ -38,7 +38,7 @@ logger = logging.getLogger(__name__) -_LILAC_RUNTIME_FILES = ["lnd_in", "lnd_modelio.nml", "lilac_in"] +_LILAC_RUNTIME_FILES = ["lnd_in", "lnd_modelio.nml", "drv_flds_in", "lilac_in"] class LILACSMOKE(SystemTestsCommon): diff --git a/python/ctsm/lilac_make_runtime_inputs.py b/python/ctsm/lilac_make_runtime_inputs.py index 33b87c543e..e751f6c931 100644 --- a/python/ctsm/lilac_make_runtime_inputs.py +++ b/python/ctsm/lilac_make_runtime_inputs.py @@ -307,7 +307,6 @@ def buildnml(cime_path, rundir): # remove temporary files in rundir os.remove(os.path.join(rundir, "config_cache.xml")) os.remove(os.path.join(rundir, "env_lilac.xml")) - os.remove(os.path.join(rundir, "drv_flds_in")) os.remove(infile) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9388e65bc2..5b0f6c9b1b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -107,5 +107,6 @@ add_subdirectory(${CLM_ROOT}/src/init_interp/test clm_init_interp_test) add_subdirectory(${CLM_ROOT}/src/self_tests/test clm_self_tests_test) # Add driver unit test directories +# (these should be moved to the appropriate submodule) add_subdirectory(${CLM_ROOT}/src/drv_test drv_test) diff --git a/src/cpl/lilac/lnd_comp_esmf.F90 b/src/cpl/lilac/lnd_comp_esmf.F90 index 298aa730c0..6c8bb2a491 100644 --- a/src/cpl/lilac/lnd_comp_esmf.F90 +++ b/src/cpl/lilac/lnd_comp_esmf.F90 @@ -114,6 +114,8 @@ subroutine lnd_init(comp, import_state, export_state, clock, rc) use ESMF , only : ESMF_StateAdd use ESMF , only : operator(==) + use shr_dust_emis_mod , only : shr_dust_emis_readnl + ! input/output variables type(ESMF_GridComp) :: comp ! CLM gridded component type(ESMF_State) :: import_state ! CLM import state @@ -270,6 +272,9 @@ subroutine lnd_init(comp, import_state, export_state, clock, rc) ! Fill in the value for model_meshfile in lnd_comp_shr used by the stream routines in share_esmf/ model_meshfile = trim(lnd_mesh_filename) + ! Reading in the drv_flds_in namelist is required for dust emissions + call shr_dust_emis_readnl( mpicom, "drv_flds_in") + !---------------------- ! Obtain caseid and start type from attributes in import state !---------------------- From 17c748bad564c560cf305549b744c7c82c13b5c5 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Mon, 29 Jul 2024 17:06:26 -0600 Subject: [PATCH 441/444] Fix 1x1_cidadinhoBR tests by specifying 2000_control for it and 1850_control for smallville --- bld/unit_testers/build-namelist_test.pl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index c92f428d82..d6291c94de 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -1532,7 +1532,11 @@ sub cat_and_create_namelistinfile { # Check for crop resolutions my @crop1850_res = ( "1x1_smallvilleIA", "1x1_cidadinhoBR" ); foreach my $res ( @crop1850_res ) { - $options = "-bgc bgc -crop -res $res -use_case 1850_control -envxml_dir ."; + my $use_case = "1850_control"; + if ( $res =~ /1x1_cidadinhoBR/ ) { + $use_case = "2000_control"; + } + $options = "-bgc bgc -crop -res $res -use_case $use_case -envxml_dir ."; &make_env_run(); eval{ system( "$bldnml $options > $tempfile 2>&1 " ); }; is( $@, '', "$options" ); From 4d4fe83b759c972c9f4e8d0ad9422d1cd36c7693 Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Jul 2024 08:38:44 -0600 Subject: [PATCH 442/444] Fix test numbers --- bld/unit_testers/build-namelist_test.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index d6291c94de..5bccb3b77c 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,10 +163,10 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 3317; +my $ntests = 3329; if ( defined($opts{'compare'}) ) { - $ntests += 2052; + $ntests += 1999; } plan( tests=>$ntests ); From cdb36a0f681d02a2c5720940c169a559783a3e9b Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Jul 2024 08:39:36 -0600 Subject: [PATCH 443/444] Update change files --- doc/ChangeLog | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++ doc/ChangeSum | 1 + 2 files changed, 116 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index 79d640242d..8c01174329 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,119 @@ =============================================================== +Tag name: ctsm5.2.017 +Originator(s): erik (Erik Kluzek,UCAR/TSS,303-497-1326) +Date: Tue 30 Jul 2024 08:39:20 AM MDT +One-line Summary: Dust emissions control moved to cmeps + +Purpose and description of changes +---------------------------------- + +Remove the dust emissions namelist items from CTSM and use the namelist in the drv_flds_in for CMEPS. + +This updates CTSM to use the namelist control in CMEPS (in ESCOMP/CMEPS#429). So the CMEPS external needs to be updated, and the +namelist control in CTSM changed to use CMEPS rather than the internal CTSM control settings and the CTSM ones removed. + +The new XML variable: + + LND_SETS_DUST_EMIS_DRV_FLDS + +controls whether dust emission settings are set by CTSM or by CAM. Only one or the other can set them, and it's required so when CAM +and CTSM are running together they need to know which one will select. + +This required some changes for LILAC. The drv_flds_in namelist file is now required for LILAC, and read for dust emissions +(and dust emissions only) at the LILAC lnd_comp_esmf.F90 level. + +Add a unit test for the CMEPS code to make sure it's working correctly. This validates the code both for CAM and CTSM. + +Fix the cidinahoBR test in the build-namelist unit tester. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- + +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + + Fixes #2376 -- Update CTSM with CMEPS that controls dust emission options + Fixes #2150 -- Ability to flip between different dust emission methods + Fixes #2524 -- Add option to NOT set dust emission settings when coupled to CAM + Fixes #2666 -- cidinahoBR test in build-namelist + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + dust_emis_method can NOT be set to Leung_2023 -- yet. + See below about LND_SETS_DUST_EMIS_DRV_FLDS + +Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): + CTSM namelist items moved to the dust_emis_inparm namelist in drv_flds_in: + zender_soil_erod_source and dust_emis_method + + New logical XML variable: + LND_SETS_DUST_EMIS_DRV_FLDS + If TRUE CTSM sets the dust emission namelist, otherwise CAM will (when coupled to CAM) + If you are NOT coupled to CAM and LND_SETS_DUST_EMIS_DRV_FLDS==FALSE, the model will abort + trying to read the dust_emis_inparm namelist in drv_flds_in. + +Notes of particular relevance for developers: +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + Added a PF unit test for CMEPS dust emission code. This should be moved to CMEPS, but still run here. + Control design in DustEmisFactory, uses a Functional Programming design pattern with pure functions + from CMEPS for CTSM to know the drv_flds_in settings. Design notes were added in that regard. + +Testing summary: Regular +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - PASS (1006 are different because of the namelist changes) + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + derecho - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + +Answer changes +-------------- + +Changes answers relative to baseline: No bit-for-bit + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +(https://github.com/ESCOMP/ctsm/pull) + #2545 -- Dust emission control moved to CMEPS + +=============================================================== +=============================================================== Tag name: ctsm5.2.016 Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) Date: Sat 27 Jul 2024 05:13:08 PM MDT diff --git a/doc/ChangeSum b/doc/ChangeSum index 382e5cf7cb..15a67bcf04 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,6 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.2.017 erik 07/30/2024 Dust emissions control moved to cmeps ctsm5.2.016 samrabin 07/27/2024 Enable new crop calendars for clm60 compsets ctsm5.2.015 multiple 07/22/2024 Update submodule tags to pass runoff from cism to rof ctsm5.2.014 multiple 07/19/2024 use_matrixcn, use_soil_matrixcn come in as default .false. From f28ecdb5cbd3ab3ab28ffd149ef54761055e926e Mon Sep 17 00:00:00 2001 From: Erik Kluzek Date: Tue, 30 Jul 2024 08:44:59 -0600 Subject: [PATCH 444/444] Add note about the fails compared to baselines --- doc/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index 8c01174329..aeb7b2972f 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -105,6 +105,12 @@ Answer changes Changes answers relative to baseline: No bit-for-bit + The following tests compared different to baseline because of reproducability issues: + ERP_P64x2_Lm13.f10_f10_mg37.IHistClm60Bgc.derecho_intel.clm-monthly--clm-matrixcnOn_ignore_warnings + SMS_D.1x1_brazil.I2000Clm60FatesSpCruRsGs.derecho_gnu.clm-FatesColdDryDepSatPhen + SMS_D.1x1_brazil.I2000Clm60FatesSpCruRsGs.derecho_gnu.clm-FatesColdMeganSatPhen + The CN-MATRIX issue is because of #2619 and FATES because of #2656 + Other details -------------