diff --git a/cime_config/tests.py b/cime_config/tests.py index 5e94f9c30073..f75032ef3349 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -415,6 +415,7 @@ "ERP_D_Ld3.f19_g16.IELMFATES.elm-fates_cold", "ERS_D_Ld3_PS.f09_g16.IELMFATES.elm-fates_cold", "ERS_D_Ld5.f45_g37.IELMFATES.elm-fates_cold", + "ERS_D_Ld30.f45_g37.IELMFATES.elm-fates_cold_landuse", "ERS_Ld30.f45_g37.IELMFATES.elm-fates_satphen", "ERS_Ld30.f45_g37.IELMFATES.elm-fates_cold_fixedbiogeo", "ERS_Ld30.f45_g37.IELMFATES.elm-fates_cold_nocomp", diff --git a/components/elm/bld/ELMBuildNamelist.pm b/components/elm/bld/ELMBuildNamelist.pm index 4e5818e6963b..c6214323525b 100755 --- a/components/elm/bld/ELMBuildNamelist.pm +++ b/components/elm/bld/ELMBuildNamelist.pm @@ -797,7 +797,8 @@ sub setup_cmdl_fates_mode { "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys", "use_fates_inventory_init", "use_fates_fixed_biogeog", "use_fates_nocomp","use_fates_sp", "fates_inventory_ctrl_filename","use_fates_logging", "use_fates_tree_damage", - "use_fates_parteh_mode","use_fates_cohort_age_tracking","use_snicar_ad"); + "use_fates_parteh_mode","use_fates_cohort_age_tracking","use_snicar_ad", "use_fates_luh", + "fluh_timeseries"); foreach my $var ( @list ) { if ( defined($nl->get_value($var)) ) { $nl_flags->{$var} = $nl->get_value($var); @@ -857,6 +858,10 @@ sub setup_cmdl_fates_mode { if ( defined($nl->get_value($var)) ) { fatal_error("$var is being set, but can ONLY be set when -bgc fates option is used.\n"); } + $var = "use_fates_luh"; + if ( defined($nl->get_value($var)) ) { + fatal_error("$var is being set, but can ONLY be set when -bgc fates option is used.\n"); + } $var = "fates_inventory_ctrl_filename"; if ( defined($nl->get_value($var)) ) { fatal_error("$var is being set, but can ONLY be set when -bgc fates option is used.\n"); @@ -3292,8 +3297,43 @@ sub setup_logic_fates { add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_nocomp', 'use_fates'=>$nl_flags->{'use_fates'}); add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_tree_damage', 'use_fates'=>$nl_flags->{'use_fates'}); add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_seeddisp_cadence', 'use_fates'=>$nl_flags->{'use_fates'}); + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_luh', 'use_fates'=>$nl_flags->{'use_fates'}); add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_paramfile', 'phys'=>$nl_flags->{'phys'}); - + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fluh_timeseries', 'phys'=>$nl_flags->{'phys'}); + + # For FATES SP mode make sure no-competion, and fixed-biogeography are also set + # And also check for other settings that can't be trigged on as well + my $var = "use_fates_sp"; + if ( defined($nl->get_value($var)) ) { + if ( &value_is_true($nl->get_value($var)) ) { + my @list = ( "use_fates_nocomp", "use_fates_fixed_biogeog" ); + foreach my $var ( @list ) { + if ( ! &value_is_true($nl->get_value($var)) ) { + fatal_error("$var is required when FATES SP is on (use_fates_sp)" ); + } + } + # spit-fire can't be on with FATES SP mode is active + if ( $nl->get_value('fates_spitfire_mode') > 0 ) { + fatal_error('fates_spitfire_mode can NOT be set to greater than 0 when use_fates_sp is true'); + } + } + } + # check that fates landuse change mode has the necessary luh2 landuse timeseries data + my $var = "use_fates_luh"; + if ( defined($nl->get_value($var)) ) { + if ( &value_is_true($nl->get_value($var)) ) { + $var = "fluh_timeseries"; + add_default($test_files, $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)) ) { + fatal_error("$var is required when use_fates_luh is set" ); + } elsif ( ! -f "$fname" ) { + fatal_error("$fname does NOT point to a valid filename" ); + } + } + } } } diff --git a/components/elm/bld/namelist_files/namelist_defaults.xml b/components/elm/bld/namelist_files/namelist_defaults.xml index 4f02fc9df8ac..d267252fd3a6 100644 --- a/components/elm/bld/namelist_files/namelist_defaults.xml +++ b/components/elm/bld/namelist_files/namelist_defaults.xml @@ -127,7 +127,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). -lnd/clm2/paramdata/fates_params_api25.5.0_12pft_c230710.nc +lnd/clm2/paramdata/fates_params_api.32.0.0_12pft_c231215.nc lnd/clm2/paramdata/CNP_parameters_c131108.nc @@ -565,6 +565,11 @@ lnd/clm2/surfdata_map/surfdata_conusx4v1_simyr2000_c160503.nc lnd/clm2/surfdata_map/surfdata.pftdyn_ne30np4_rcp2.6_simyr1850-2100_c130524.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 + + @@ -2136,6 +2141,7 @@ this mask will have smb calculated over the entire global land surface .false. .false. .false. +.false. 1 0 .false. diff --git a/components/elm/bld/namelist_files/namelist_definition.xml b/components/elm/bld/namelist_files/namelist_definition.xml index 1353f8b84b64..45a419edb99a 100644 --- a/components/elm/bld/namelist_files/namelist_definition.xml +++ b/components/elm/bld/namelist_files/namelist_definition.xml @@ -381,6 +381,21 @@ Toggle to turn on inventory initialization(only relevant if FATES is being used) Full pathname to the inventory initialization control file. + + +If TRUE, enable use of land use state and transition data from luh_timeseries file. +(Only valid for fates land use change runs, where there is a luh_timeseries file.) +(Also, only valid for use_fates = true and is incompatible with transient runs currently.) + + + + +Full pathname of unified land use harmonization data file. This causes the land-use +types to vary over time. + + Toggle to turn on if Kennedy et al plant hydraulics model is used. diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates/user_nl_elm index 9b07b504564b..cd078b90950c 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates/user_nl_elm +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates/user_nl_elm @@ -16,10 +16,8 @@ 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_DISTURBANCE_RATE_P2P', 'FATES_DISTURBANCE_RATE_P2S', -'FATES_DISTURBANCE_RATE_S2S', 'FATES_DISTURBANCE_RATE_FIRE', +'FATES_HARVEST_CARBON_FLUX', 'FATES_DISTURBANCE_RATE_FIRE', 'FATES_DISTURBANCE_RATE_LOGGING', 'FATES_DISTURBANCE_RATE_TREEFALL', -'FATES_DISTURBANCE_RATE_POTENTIAL', 'FATES_HARVEST_CARBON_FLUX', 'FATES_STOMATAL_COND', 'FATES_LBLAYER_COND', 'FATES_NPP', 'FATES_GPP', 'FATES_AUTORESP', 'FATES_GROWTH_RESP', 'FATES_MAINT_RESP', 'FATES_GPP_CANOPY', 'FATES_AUTORESP_CANOPY', 'FATES_GPP_USTORY', 'FATES_AUTORESP_USTORY', @@ -28,4 +26,5 @@ hist_fincl1 = 'FATES_NCOHORTS', 'FATES_TRIMMING', 'FATES_AREA_PLANTS', 'FATES_NEP', 'FATES_HET_RESP', 'FATES_FIRE_CLOSS', 'FATES_FIRE_FLUX_EL', 'FATES_CBALANCE_ERROR', 'FATES_ERROR_EL', 'FATES_LEAF_ALLOC', 'FATES_SEED_ALLOC', 'FATES_STEM_ALLOC', 'FATES_FROOT_ALLOC', -'FATES_CROOT_ALLOC', 'FATES_STORE_ALLOC' +'FATES_CROOT_ALLOC', 'FATES_STORE_ALLOC', +'FATES_PATCHAREA_LU', 'FATES_DISTURBANCE_RATE_MATRIX_LULU' diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_landuse/include_user_mods b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_landuse/include_user_mods new file mode 100644 index 000000000000..45e8af32d22a --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_landuse/include_user_mods @@ -0,0 +1 @@ +../fates_cold diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_landuse/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_landuse/user_nl_elm new file mode 100644 index 000000000000..098d4fd33a38 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_landuse/user_nl_elm @@ -0,0 +1,2 @@ +flanduse_timeseries = '$DIN_LOC_ROOT/lnd/clm2/surfdata_map/landuse.timeseries_4x5_hist_simyr1850-2015_200311.nc' +do_harvest = .true. diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/include_user_mods b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/include_user_mods new file mode 100644 index 000000000000..45e8af32d22a --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/include_user_mods @@ -0,0 +1 @@ +../fates_cold diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/shell_commands b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/shell_commands new file mode 100644 index 000000000000..e02188057ce6 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/shell_commands @@ -0,0 +1 @@ +./xmlchange TEST_MEMLEAK_TOLERANCE=0.2 diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/user_nl_elm new file mode 100644 index 000000000000..854c21407f1a --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/user_nl_elm @@ -0,0 +1 @@ +use_fates_luh = .true. diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_eca/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_eca/user_nl_elm index 407d0dcecf2a..8dc47347ed88 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_eca/user_nl_elm +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_eca/user_nl_elm @@ -19,10 +19,8 @@ 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_DISTURBANCE_RATE_P2P', 'FATES_DISTURBANCE_RATE_P2S', -'FATES_DISTURBANCE_RATE_S2S', 'FATES_DISTURBANCE_RATE_FIRE', +'FATES_HARVEST_CARBON_FLUX', 'FATES_DISTURBANCE_RATE_FIRE', 'FATES_DISTURBANCE_RATE_LOGGING', 'FATES_DISTURBANCE_RATE_TREEFALL', -'FATES_DISTURBANCE_RATE_POTENTIAL', 'FATES_HARVEST_CARBON_FLUX', 'FATES_STOMATAL_COND', 'FATES_LBLAYER_COND', 'FATES_NPP', 'FATES_GPP', 'FATES_AUTORESP', 'FATES_GROWTH_RESP', 'FATES_MAINT_RESP', 'FATES_GPP_CANOPY', 'FATES_AUTORESP_CANOPY', 'FATES_GPP_USTORY', 'FATES_AUTORESP_USTORY', diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_long/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_long/user_nl_elm index 9b07b504564b..4812969a278b 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_long/user_nl_elm +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_long/user_nl_elm @@ -16,10 +16,8 @@ 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_DISTURBANCE_RATE_P2P', 'FATES_DISTURBANCE_RATE_P2S', -'FATES_DISTURBANCE_RATE_S2S', 'FATES_DISTURBANCE_RATE_FIRE', +'FATES_HARVEST_CARBON_FLUX', 'FATES_DISTURBANCE_RATE_FIRE', 'FATES_DISTURBANCE_RATE_LOGGING', 'FATES_DISTURBANCE_RATE_TREEFALL', -'FATES_DISTURBANCE_RATE_POTENTIAL', 'FATES_HARVEST_CARBON_FLUX', 'FATES_STOMATAL_COND', 'FATES_LBLAYER_COND', 'FATES_NPP', 'FATES_GPP', 'FATES_AUTORESP', 'FATES_GROWTH_RESP', 'FATES_MAINT_RESP', 'FATES_GPP_CANOPY', 'FATES_AUTORESP_CANOPY', 'FATES_GPP_USTORY', 'FATES_AUTORESP_USTORY', diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_rd/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_rd/user_nl_elm index 30a0dbb88cb0..92bfa49d87ce 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_rd/user_nl_elm +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_rd/user_nl_elm @@ -19,10 +19,8 @@ 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_DISTURBANCE_RATE_P2P', 'FATES_DISTURBANCE_RATE_P2S', -'FATES_DISTURBANCE_RATE_S2S', 'FATES_DISTURBANCE_RATE_FIRE', +'FATES_HARVEST_CARBON_FLUX', 'FATES_DISTURBANCE_RATE_FIRE', 'FATES_DISTURBANCE_RATE_LOGGING', 'FATES_DISTURBANCE_RATE_TREEFALL', -'FATES_DISTURBANCE_RATE_POTENTIAL', 'FATES_HARVEST_CARBON_FLUX', 'FATES_STOMATAL_COND', 'FATES_LBLAYER_COND', 'FATES_NPP', 'FATES_GPP', 'FATES_AUTORESP', 'FATES_GROWTH_RESP', 'FATES_MAINT_RESP', 'FATES_GPP_CANOPY', 'FATES_AUTORESP_CANOPY', 'FATES_GPP_USTORY', 'FATES_AUTORESP_USTORY', diff --git a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 index 2b3666b5157f..073c836c19bc 100644 --- a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 @@ -754,13 +754,16 @@ subroutine SurfaceAlbedo(bounds, & ws(p) = esai(p) / max( elai(p)+esai(p), mpe ) end do - do ib = 1, numrad - do fp = 1,num_vegsol - p = filter_vegsol(fp) - rho(p,ib) = max( rhol(veg_pp%itype(p),ib)*wl(p) + rhos(veg_pp%itype(p),ib)*ws(p), mpe ) - tau(p,ib) = max( taul(veg_pp%itype(p),ib)*wl(p) + taus(veg_pp%itype(p),ib)*ws(p), mpe ) + ! rho and tau are not needed if fates is on + if (.not. use_fates) then + do ib = 1, numrad + do fp = 1,num_vegsol + p = filter_vegsol(fp) + rho(p,ib) = max( rhol(veg_pp%itype(p),ib)*wl(p) + rhos(veg_pp%itype(p),ib)*ws(p), mpe ) + tau(p,ib) = max( taul(veg_pp%itype(p),ib)*wl(p) + taus(veg_pp%itype(p),ib)*ws(p), mpe ) + end do end do - end do + end if ! Diagnose number of canopy layers for radiative transfer, in increments of dincmax. ! Add to number of layers so long as cumulative leaf+stem area does not exceed total diff --git a/components/elm/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 b/components/elm/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 new file mode 100644 index 000000000000..53be7987182e --- /dev/null +++ b/components/elm/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 @@ -0,0 +1,197 @@ +module dynFATESLandUseChangeMod + +#include "shr_assert.h" + + !--------------------------------------------------------------------------- + ! !DESCRIPTION: + ! Handle reading of the land use harmonization (LUH2) dataset + + ! !USES: + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use decompMod , only : bounds_type, BOUNDS_LEVEL_PROC + use abortutils , only : endrun + use dynFileMod , only : dyn_file_type + use dynVarTimeUninterpMod , only : dyn_var_time_uninterp_type + use elm_varcon , only : grlnd + use elm_varctl , only : iulog + + implicit none + + private + + real(r8), allocatable, public :: landuse_transitions(:,:) + real(r8), allocatable, public :: landuse_states(:,:) + + integer, public, parameter :: num_landuse_transition_vars = 108 + integer, public, parameter :: num_landuse_state_vars = 12 + + type(dyn_file_type), target :: dynFatesLandUse_file + + ! Land use name arrays + character(len=5), public, parameter :: landuse_state_varnames(num_landuse_state_vars) = & + [character(len=5) :: 'primf', & ! forested primary land + 'primn', & ! non-forested primary land + 'secdf', & ! potentially forested secondary land + 'secdn', & ! potentially non-forested secondary land + 'pastr', & ! managed pasture + 'range', & ! rangeland + 'urban', & ! urban land + 'c3ann', & ! C3 annual crops + 'c4ann', & ! C4 annual crops + 'c3per', & ! C3 perennial crops + 'c4per', & ! C4 perennial crops + 'c3nfx'] ! C3 nitrogen-fixing crops + + character(len=14), public, parameter :: landuse_transition_varnames(num_landuse_transition_vars) = & + [character(len=14) :: 'primf_to_secdn','primf_to_pastr','primf_to_range','primf_to_urban', & + 'primf_to_c3ann','primf_to_c4ann','primf_to_c3per','primf_to_c4per','primf_to_c3nfx', & + 'primn_to_secdf','primn_to_pastr','primn_to_range','primn_to_urban', & + 'primn_to_c3ann','primn_to_c4ann','primn_to_c3per','primn_to_c4per','primn_to_c3nfx', & + 'secdf_to_secdn','secdf_to_pastr','secdf_to_range','secdf_to_urban', & + 'secdf_to_c3ann','secdf_to_c4ann','secdf_to_c3per','secdf_to_c4per','secdf_to_c3nfx', & + 'secdn_to_secdf','secdn_to_pastr','secdn_to_range','secdn_to_urban', & + 'secdn_to_c3ann','secdn_to_c4ann','secdn_to_c3per','secdn_to_c4per','secdn_to_c3nfx', & + 'pastr_to_secdf','pastr_to_secdn','pastr_to_range','pastr_to_urban', & + 'pastr_to_c3ann','pastr_to_c4ann','pastr_to_c3per','pastr_to_c4per','pastr_to_c3nfx', & + 'range_to_secdf','range_to_secdn','range_to_pastr','range_to_urban', & + 'range_to_c3ann','range_to_c4ann','range_to_c3per','range_to_c4per','range_to_c3nfx', & + 'urban_to_secdf','urban_to_secdn','urban_to_pastr','urban_to_range', & + 'urban_to_c3ann','urban_to_c4ann','urban_to_c3per','urban_to_c4per','urban_to_c3nfx', & + 'c3ann_to_c4ann','c3ann_to_c3per','c3ann_to_c4per','c3ann_to_c3nfx', & + 'c3ann_to_secdf','c3ann_to_secdn','c3ann_to_pastr','c3ann_to_range','c3ann_to_urban', & + 'c4ann_to_c3ann','c4ann_to_c3per','c4ann_to_c4per','c4ann_to_c3nfx', & + 'c4ann_to_secdf','c4ann_to_secdn','c4ann_to_pastr','c4ann_to_range','c4ann_to_urban', & + 'c3per_to_c3ann','c3per_to_c4ann','c3per_to_c4per','c3per_to_c3nfx', & + 'c3per_to_secdf','c3per_to_secdn','c3per_to_pastr','c3per_to_range','c3per_to_urban', & + 'c4per_to_c3ann','c4per_to_c4ann','c4per_to_c3per','c4per_to_c3nfx', & + 'c4per_to_secdf','c4per_to_secdn','c4per_to_pastr','c4per_to_range','c4per_to_urban', & + '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 + + public :: dynFatesLandUseInit + public :: dynFatesLandUseInterp + +contains + + !----------------------------------------------------------------------- + subroutine dynFatesLandUseInit(bounds, landuse_filename) + + ! !DESCRIPTION: + ! Initialize data structures for land use information. + + ! !USES: + use elm_varctl , only : use_fates_luh + 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 + + ! !LOCAL VARIABLES + integer :: varnum, i ! counter for harvest variables + integer :: landuse_shape(1) ! land use shape + integer :: num_points ! number of spatial points + integer :: ier ! error code + real(r8), allocatable :: this_data(:) ! data for a single harvest variable + ! + character(len=*), parameter :: subname = 'dynFatesLandUseInit' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL(bounds%level == BOUNDS_LEVEL_PROC, subname // ': argument must be PROC-level bounds') + + ! Allocate and initialize the land use arrays + allocate(landuse_states(num_landuse_state_vars,bounds%begg:bounds%endg),stat=ier) + if (ier /= 0) then + call endrun(msg=' allocation error for landuse_states'//errMsg(__FILE__, __LINE__)) + end if + allocate(landuse_transitions(num_landuse_transition_vars,bounds%begg:bounds%endg),stat=ier) + if (ier /= 0) then + call endrun(msg=' allocation error for landuse_transitions'//errMsg(__FILE__, __LINE__)) + end if + + landuse_states = 0._r8 + landuse_transitions = 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 + dynFatesLandUse_file = dyn_file_type(landuse_filename, YEAR_POSITION_END_OF_TIMESTEP) + + ! Get initial land use data + 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 + 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.) + + end subroutine dynFatesLandUseInit + + + !----------------------------------------------------------------------- + subroutine dynFatesLandUseInterp(bounds, init_state) + + use dynTimeInfoMod , only : time_info_type + + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds ! proc-level bounds + logical, optional, intent(in) :: init_state ! fates needs state for initialization + + ! !LOCAL VARIABLES: + integer :: varnum + integer :: i + logical :: init_flag + real(r8), allocatable :: this_data(:) + character(len=*), parameter :: subname = 'dynFatesLandUseInterp' + !----------------------------------------------------------------------- + SHR_ASSERT_ALL(bounds%level == BOUNDS_LEVEL_PROC, subname // ': argument must be PROC-level bounds') + + init_flag = .false. + if (present(init_state)) then + init_flag = init_state + end if + + ! input land use data for current year are stored in year+1 in the file + call dynFatesLandUse_file%time_info%set_current_year_get_year(1) + + 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 + else + ! Right now we don't account for the topounits + allocate(this_data(bounds%begg:bounds%endg)) + do varnum = 1, num_landuse_transition_vars + call landuse_transition_vars(varnum)%get_current_data(this_data) + landuse_transitions(varnum,bounds%begg:bounds%endg) = this_data(bounds%begg:bounds%endg) + end do + do varnum = 1, num_landuse_state_vars + 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 + deallocate(this_data) + end if + + end subroutine dynFatesLandUseInterp + +end module dynFATESLandUseChangeMod diff --git a/components/elm/src/dyn_subgrid/dynSubgridDriverMod.F90 b/components/elm/src/dyn_subgrid/dynSubgridDriverMod.F90 index 479ee5ab5518..8ac0cf4c45e7 100644 --- a/components/elm/src/dyn_subgrid/dynSubgridDriverMod.F90 +++ b/components/elm/src/dyn_subgrid/dynSubgridDriverMod.F90 @@ -153,7 +153,8 @@ subroutine dynSubgrid_driver(bounds_proc, & ! OUTSIDE any loops over clumps in the driver. ! ! !USES: - use elm_varctl , only : use_cn, create_glacier_mec_landunit, use_fates + use elm_varctl , only : use_cn, create_glacier_mec_landunit + use elm_varctl , only : use_fates, use_fates_luh use decompMod , only : bounds_type, get_proc_clumps, get_clump_bounds use decompMod , only : BOUNDS_LEVEL_PROC use dynInitColumnsMod , only : initialize_new_columns @@ -161,6 +162,9 @@ subroutine dynSubgrid_driver(bounds_proc, & use dynConsBiogeochemMod , only : dyn_cnbal_patch, dyn_cnbal_column use dynpftFileMod , only : dynpft_interp use dynHarvestMod , only : dynHarvest_interp_harvest_types + + use dynFATESLandUseChangeMod, only : dynFatesLandUseInterp + use dynEDMod , only : dyn_ED use reweightMod , only : reweight_wrapup use subgridWeightsMod , only : compute_higher_order_weights, set_subgrid_diagnostic_fields @@ -244,6 +248,10 @@ subroutine dynSubgrid_driver(bounds_proc, & call dynHarvest_interp_harvest_types(bounds_proc) end if + if (use_fates_luh) then + call dynFatesLandUseInterp(bounds_proc) + end if + ! ========================================================================== ! Do everything else related to land cover change ! ========================================================================== diff --git a/components/elm/src/external_models/fates b/components/elm/src/external_models/fates index 0b105bec7a90..698a8df848ec 160000 --- a/components/elm/src/external_models/fates +++ b/components/elm/src/external_models/fates @@ -1 +1 @@ -Subproject commit 0b105bec7a90c5e02d1098f9bbdcf255f358aaa4 +Subproject commit 698a8df848ecdb81aa72fee6c86be2c41b2545e9 diff --git a/components/elm/src/main/controlMod.F90 b/components/elm/src/main/controlMod.F90 index 51e0b2898417..3b8c08be31bd 100755 --- a/components/elm/src/main/controlMod.F90 +++ b/components/elm/src/main/controlMod.F90 @@ -259,6 +259,8 @@ subroutine control_init( ) use_fates_fixed_biogeog, & use_fates_nocomp, & use_fates_sp, & + use_fates_luh, & + fluh_timeseries, & fates_parteh_mode, & fates_seeddisp_cadence, & use_fates_tree_damage @@ -800,6 +802,7 @@ subroutine control_spmd() call mpi_bcast (fates_spitfire_mode, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (fates_paramfile, len(fates_paramfile) , MPI_CHARACTER, 0, mpicom, ier) + call mpi_bcast (fluh_timeseries, len(fluh_timeseries) , MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (use_fates_logging, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_planthydro, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_cohort_age_tracking, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -807,6 +810,7 @@ subroutine control_spmd() call mpi_bcast (use_fates_fixed_biogeog, 1, MPI_LOGICAL, 0, mpicom, ier) 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_ed_prescribed_phys, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_inventory_init, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (fates_inventory_ctrl_filename, len(fates_inventory_ctrl_filename), & @@ -1213,6 +1217,7 @@ subroutine control_print () write(iulog, *) ' fates_spitfire_mode = ', fates_spitfire_mode write(iulog, *) ' use_fates_logging = ', use_fates_logging write(iulog, *) ' fates_paramfile = ', fates_paramfile + write(iulog, *) ' fluh_timeseries = ', fluh_timeseries write(iulog, *) ' use_fates_planthydro = ', use_fates_planthydro write(iulog, *) ' use_fates_tree_damage = ', use_fates_tree_damage write(iulog, *) ' use_fates_cohort_age_tracking = ',use_fates_cohort_age_tracking @@ -1223,6 +1228,7 @@ subroutine control_print () write(iulog, *) ' use_fates_fixed_biogeog = ', use_fates_fixed_biogeog 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, *) ' fates_inventory_ctrl_filename = ',fates_inventory_ctrl_filename write(iulog, *) ' fates_seeddisp_cadence = ', fates_seeddisp_cadence write(iulog, *) ' fates_seeddisp_cadence: 0, 1, 2, 3 => off, daily, monthly, or yearly dispersal' diff --git a/components/elm/src/main/elm_initializeMod.F90 b/components/elm/src/main/elm_initializeMod.F90 index 2a8079692379..86e72030b946 100755 --- a/components/elm/src/main/elm_initializeMod.F90 +++ b/components/elm/src/main/elm_initializeMod.F90 @@ -12,8 +12,8 @@ module elm_initializeMod use elm_varctl , only : nsrest, nsrStartup, nsrContinue, nsrBranch use elm_varctl , only : create_glacier_mec_landunit, iulog use elm_varctl , only : use_lch4, use_cn, use_voc, use_c13, use_c14 - use elm_varctl , only : use_fates, use_betr, use_fates_sp, use_fan - use elm_varsur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, wt_glc_mec, topo_glc_mec,firrig,f_surf,f_grd + use elm_varctl , only : use_fates, use_betr, use_fates_sp, use_fan, use_fates_luh + use elm_varsur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, wt_glc_mec, topo_glc_mec,firrig,f_surf,f_grd use elm_varsur , only : fert_cft, fert_p_cft use elm_varsur , only : wt_tunit, elv_tunit, slp_tunit,asp_tunit,num_tunit_per_grd use perf_mod , only : t_startf, t_stopf @@ -468,6 +468,7 @@ subroutine initialize2( ) use elm_time_manager , only : get_curr_date, get_nstep, advance_timestep use elm_time_manager , only : timemgr_init, timemgr_restart_io, timemgr_restart use controlMod , only : nlfilename + use controlMod , only : fluh_timeseries use decompMod , only : get_proc_clumps, get_proc_bounds, get_clump_bounds, bounds_type use domainMod , only : ldomain use initInterpMod , only : initInterp @@ -508,6 +509,7 @@ subroutine initialize2( ) use ELMFatesInterfaceMod , only: ELMFatesTimesteps use FATESFireFactoryMod , only : scalar_lightning use FanStreamMod , only : fanstream_init, fanstream_interp + use dynFATESLandUseChangeMod, only : dynFatesLandUseInit ! ! !ARGUMENTS implicit none @@ -734,6 +736,11 @@ subroutine initialize2( ) call dynSubgrid_init(bounds_proc, glc2lnd_vars, crop_vars) call t_stopf('init_dyn_subgrid') + ! Initialize fates LUH2 usage + if (use_fates_luh) then + call dynFatesLandUseInit(bounds_proc, fluh_timeseries) + end if + ! ------------------------------------------------------------------------ ! Initialize modules (after time-manager initialization in most cases) ! ------------------------------------------------------------------------ diff --git a/components/elm/src/main/elm_varctl.F90 b/components/elm/src/main/elm_varctl.F90 index e1d26775a5dc..d5a61da8fdbf 100644 --- a/components/elm/src/main/elm_varctl.F90 +++ b/components/elm/src/main/elm_varctl.F90 @@ -229,8 +229,10 @@ module elm_varctl logical, public :: use_fates_ed_st3 = .false. ! true => static stand structure logical, public :: use_fates_ed_prescribed_phys = .false. ! true => prescribed physiology logical, public :: use_fates_inventory_init = .false. ! true => initialize fates from inventory - logical, public :: use_fates_nocomp = .false. ! true => use no comopetition mode - logical, public :: use_fates_sp = .false. ! true => use FATES satellite phenology mode + logical, public :: use_fates_nocomp = .false. ! true => no competition mode + logical, public :: use_fates_sp = .false. ! true => FATES satellite phenology mode + logical, public :: use_fates_luh = .false. ! true => FATES land use transitions mode + character(len=256), public :: fluh_timeseries = '' ! filename for land use harmonization data character(len=256), public :: fates_inventory_ctrl_filename = '' ! filename for inventory control integer, public :: fates_parteh_mode = -9 ! 1 => carbon only ! 2 => C+N+P (not enabled yet) diff --git a/components/elm/src/main/elmfates_interfaceMod.F90 b/components/elm/src/main/elmfates_interfaceMod.F90 index a7aec9e85933..edcdd01f1ede 100644 --- a/components/elm/src/main/elmfates_interfaceMod.F90 +++ b/components/elm/src/main/elmfates_interfaceMod.F90 @@ -55,6 +55,7 @@ module ELMFatesInterfaceMod use elm_varctl , only : use_fates_fixed_biogeog use elm_varctl , only : use_fates_nocomp use elm_varctl , only : use_fates_sp + use elm_varctl , only : use_fates_luh use elm_varctl , only : use_fates_tree_damage use elm_varctl , only : nsrest, nsrBranch use elm_varctl , only : fates_inventory_ctrl_filename @@ -73,7 +74,8 @@ module ELMFatesInterfaceMod use elm_varpar , only : nlevdecomp_full use elm_varpar , only : i_met_lit, i_cel_lit, i_lig_lit use elm_varpar , only : surfpft_lb, surfpft_ub - use elm_varpar , only : natpft_size, cft_size + use elm_varpar , only : natpft_size, max_patch_per_col, maxpatch_urb + use elm_varpar , only : numcft, maxpatch_urb use PhotosynthesisType , only : photosyns_type Use TopounitDataType , only : topounit_atmospheric_flux, topounit_atmospheric_state use atm2lndType , only : atm2lnd_type @@ -134,6 +136,7 @@ module ELMFatesInterfaceMod use FatesInterfaceMod , only : DetermineGridCellNeighbors use FatesHistoryInterfaceMod, only : fates_hist use FatesRestartInterfaceMod, only : fates_restart_interface_type + use FatesInterfaceTypesMod, only : hlm_num_luh2_states use PRTGenericMod , only : num_elements use FatesPatchMod , only : fates_patch_type @@ -166,14 +169,17 @@ module ELMFatesInterfaceMod anthro_ignitions, anthro_suppression use dynHarvestMod , only : num_harvest_vars, harvest_varnames, wood_harvest_units - use dynHarvestMod , only : harvest_rates ! these are dynamic in space and time - + use dynHarvestMod , only : harvest_rates ! these are dynamic in space and time + use dynSubgridControlMod , only : get_do_harvest ! this gets the namelist value use FatesConstantsMod , only : hlm_harvest_area_fraction use FatesConstantsMod , only : hlm_harvest_carbon - use dynSubgridControlMod, only : get_do_harvest ! this gets the namelist value + 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 FatesInterfaceTypesMod , only : bc_in_type, bc_out_type + use FatesInterfaceTypesMod , only : bc_in_type, bc_out_type use ELMFatesParamInterfaceMod, only : fates_param_reader_ctsm_impl use FatesParametersInterface, only : fates_param_reader_type @@ -351,7 +357,7 @@ subroutine ELMFatesGlobals1() call SetFatesGlobalElements1(use_fates,natpft_size,0,var_reader) natpft_size = fates_maxPatchesPerSite - + max_patch_per_col= max(natpft_size, numcft, maxpatch_urb) return end subroutine ELMFatesGlobals1 @@ -382,7 +388,9 @@ subroutine ELMFatesGlobals2() integer :: pass_num_lu_harvest_types integer :: pass_lu_harvest integer :: pass_tree_damage - + integer :: pass_use_luh + integer :: pass_num_luh_states + integer :: pass_num_luh_transitions ! ---------------------------------------------------------------------------------- ! FATES lightning definitions ! 1 : use a global constant lightning rate found in fates_params. @@ -507,11 +515,23 @@ subroutine ELMFatesGlobals2() pass_lu_harvest = 0 pass_num_lu_harvest_types = 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_types) 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 + 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_ed_st3) then pass_ed_st3 = 1 else @@ -747,7 +767,9 @@ subroutine init(this, bounds_proc ) ndecomp = 1 end if - call allocate_bcin(this%fates(nc)%bc_in(s),col_pp%nlevbed(c),ndecomp,num_harvest_vars,surfpft_lb,surfpft_ub) + call allocate_bcin(this%fates(nc)%bc_in(s), col_pp%nlevbed(c), ndecomp, & + num_harvest_vars, num_landuse_state_vars, num_landuse_transition_vars, & + surfpft_lb, surfpft_ub) call allocate_bcout(this%fates(nc)%bc_out(s),col_pp%nlevbed(c),ndecomp) call zero_bcs(this%fates(nc),s) @@ -870,7 +892,7 @@ subroutine dynamics_driv(this, bounds_clump, top_as_inst, & top_af_inst, atm2lnd_inst, soilstate_inst, & canopystate_inst, frictionvel_inst, soil_water_retention_curve ) - use FatesConstantsMod , only : m2_per_km2 + use FatesConstantsMod , only : m2_per_km2 ! This wrapper is called daily from clm_driver ! This wrapper calls ed_driver, which is the daily dynamics component of FATES @@ -889,7 +911,7 @@ subroutine dynamics_driv(this, bounds_clump, top_as_inst, & class(soil_water_retention_curve_type), intent(in) :: soil_water_retention_curve ! !LOCAL VARIABLES: - integer :: s ! site index + integer :: s, i ! site index integer :: c ! column index (HLM) integer :: j ! Soil layer index integer :: t ! topounit index (HLM) @@ -905,6 +927,8 @@ subroutine dynamics_driv(this, bounds_clump, top_as_inst, & real(r8), pointer :: lnfm24(:) ! 24-hour averaged lightning data real(r8), pointer :: gdp_lf_col(:) ! gdp data + logical :: do_landuse_update ! local flag to pass transitions update to fates + !----------------------------------------------------------------------- @@ -1048,6 +1072,13 @@ subroutine dynamics_driv(this, bounds_clump, top_as_inst, & end if this%fates(nc)%bc_in(s)%site_area=col_pp%wtgcell(c)*grc_pp%area(g)*m2_per_km2 + if (use_fates_luh) then + this%fates(nc)%bc_in(s)%hlm_luh_states = landuse_states(:,g) + 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 + end if + end do ! Nutrient uptake fluxes have been accumulating with each short @@ -1805,11 +1836,12 @@ subroutine init_coldstart(this, canopystate_inst, soilstate_inst, frictionvel_in real(r8) :: vol_ice real(r8) :: eff_porosity integer :: nlevsoil - integer :: j + integer :: j, i integer :: s - integer :: c + integer :: c, g integer :: p ! HLM patch index integer :: ft ! plant functional type + logical :: do_landuse_update ! local flag to pass transitions update to fates ! Set the FATES global time and date variables call GetAndSetTime @@ -1859,7 +1891,6 @@ subroutine init_coldstart(this, canopystate_inst, soilstate_inst, frictionvel_in if (use_fates_planthydro) then do s = 1,this%fates(nc)%nsites - c = this%f2hmap(nc)%fcolumn(s) nlevsoil = this%fates(nc)%bc_in(s)%nlevsoil @@ -1893,9 +1924,23 @@ subroutine init_coldstart(this, canopystate_inst, soilstate_inst, frictionvel_in call HydrSiteColdStart(this%fates(nc)%sites,this%fates(nc)%bc_in) end if + do s = 1,this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + g = col_pp%gridcell(c) + + if (use_fates_luh) then + this%fates(nc)%bc_in(s)%hlm_luh_states = landuse_states(:,g) + 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 + end if + end do + + ! Initialize patches call init_patches(this%fates(nc)%nsites, this%fates(nc)%sites, & this%fates(nc)%bc_in) + do s = 1,this%fates(nc)%nsites c = this%f2hmap(nc)%fcolumn(s) @@ -2946,6 +2991,7 @@ subroutine init_history_io(this,bounds_proc) use FatesIOVariableKindMod, only : site_coage_r8, site_coage_pft_r8 use FatesIOVariableKindMod, only : site_can_r8, site_cnlf_r8, site_cnlfpft_r8 use FatesIOVariableKindMod, only : site_cdpf_r8, site_cdsc_r8, site_cdam_r8 + use FatesIOVariableKindMod, only : site_landuse_r8, site_lulu_r8 use FatesIODimensionsMod, only : fates_bounds_type @@ -3044,7 +3090,8 @@ subroutine init_history_io(this,bounds_proc) site_can_r8,site_cnlf_r8, site_cnlfpft_r8, site_scag_r8, & site_scagpft_r8, site_agepft_r8, site_elem_r8, site_elpft_r8, & site_elcwd_r8, site_elage_r8, site_coage_r8, site_coage_pft_r8, & - site_agefuel_r8,site_cdsc_r8, site_cdpf_r8, site_cdam_r8) + site_agefuel_r8,site_cdsc_r8, site_cdpf_r8, site_cdam_r8, & + site_landuse_r8, site_lulu_r8) d_index = fates_hist%dim_kinds(dk_index)%dim2_index dim2name = fates_hist%dim_bounds(d_index)%name @@ -3311,6 +3358,7 @@ subroutine hlm_bounds_to_fates_bounds(hlm, fates) use EDParamsMod, only : nclmax_fates => nclmax use FatesInterfaceTypesMod, only : numpft_fates => numpft use FatesInterfaceTypesMod, only : nlevcoage + use FatesConstantsMod, only : n_landuse_cats implicit none @@ -3395,6 +3443,12 @@ subroutine hlm_bounds_to_fates_bounds(hlm, fates) fates%agefuel_begin = 1 fates%agefuel_end = nlevage_fates * nfsc_fates + fates%landuse_begin = 1 + fates%landuse_end = n_landuse_cats + + fates%lulu_begin = 1 + fates%lulu_end = n_landuse_cats * n_landuse_cats + end subroutine hlm_bounds_to_fates_bounds ! ====================================================================================== diff --git a/components/elm/src/main/histFileMod.F90 b/components/elm/src/main/histFileMod.F90 index 6e89d15ff192..c11eafe96f45 100644 --- a/components/elm/src/main/histFileMod.F90 +++ b/components/elm/src/main/histFileMod.F90 @@ -28,12 +28,13 @@ module histFileMod use FatesInterfaceTypesMod , only : nlevheight_fates => nlevheight use FatesInterfaceTypesMod , only : nlevdamage_fates => nlevdamage use FatesInterfaceTypesMod , only : nlevcoage - use FatesLitterMod , only : nfsc_fates => nfsc - use FatesLitterMod , only : ncwd_fates => ncwd + use FatesLitterMod , only : nfsc_fates => nfsc + use FatesConstantsMod , only : n_landuse_cats + use FatesLitterMod , only : ncwd_fates => ncwd use FatesInterfaceTypesMod , only : numpft_fates => numpft use PRTGenericMod , only : nelements_fates => num_elements - use TopounitType , only : top_pp - use topounit_varcon , only: max_topounits, has_topounit + use TopounitType , only : top_pp + use topounit_varcon , only: max_topounits, has_topounit ! implicit none @@ -1951,6 +1952,8 @@ subroutine htape_create (t, histrest) call ncd_defdim(lnfid, 'fates_levelcwd', nelements_fates * ncwd_fates, dimid) call ncd_defdim(lnfid, 'fates_levelage', nelements_fates * nlevage_fates, dimid) call ncd_defdim(lnfid, 'fates_levagefuel', nlevage_fates * nfsc_fates, dimid) + call ncd_defdim(lnfid, 'fates_levlanduse', n_landuse_cats, dimid) + call ncd_defdim(lnfid, 'fates_levlulu', n_landuse_cats * n_landuse_cats, dimid) end if if ( .not. lhistrest )then @@ -2353,6 +2356,7 @@ subroutine htape_timeconst(t, mode) use FatesInterfaceTypesMod, only : fates_hdim_camap_levcapf use FatesInterfaceTypesMod, only : fates_hdim_levage use FatesInterfaceTypesMod, only : fates_hdim_levpft + use FatesInterfaceTypesMod, only : fates_hdim_levlanduse use FatesInterfaceTypesMod, only : fates_hdim_scmap_levscag use FatesInterfaceTypesMod, only : fates_hdim_agmap_levscag use FatesInterfaceTypesMod, only : fates_hdim_levfuel @@ -2463,6 +2467,8 @@ subroutine htape_timeconst(t, mode) long_name='FATES patch age (yr)', ncid=nfid(t)) call ncd_defvar(varname='fates_levpft',xtype=ncd_int, dim1name='fates_levpft', & long_name='FATES pft number', ncid=nfid(t)) + call ncd_defvar(varname='fates_levlanduse',xtype=ncd_int, dim1name='fates_levlanduse', & + long_name='FATES land use label', ncid=nfid(t)) call ncd_defvar(varname='fates_levfuel',xtype=ncd_int, dim1name='fates_levfuel', & long_name='FATES fuel index', ncid=nfid(t)) call ncd_defvar(varname='fates_levcwdsc',xtype=ncd_int, dim1name='fates_levcwdsc', & @@ -2548,6 +2554,7 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='fates_scmap_levscpf',data=fates_hdim_scmap_levscpf, ncid=nfid(t), flag='write') call ncd_io(varname='fates_levage',data=fates_hdim_levage, ncid=nfid(t), flag='write') call ncd_io(varname='fates_levpft',data=fates_hdim_levpft, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_levlanduse',data=fates_hdim_levlanduse, ncid=nfid(t), flag='write') call ncd_io(varname='fates_levfuel',data=fates_hdim_levfuel, ncid=nfid(t), flag='write') call ncd_io(varname='fates_levcwdsc',data=fates_hdim_levcwdsc, ncid=nfid(t), flag='write') call ncd_io(varname='fates_levcan',data=fates_hdim_levcan, ncid=nfid(t), flag='write') @@ -4828,6 +4835,10 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, num2d = nlevcoage*numpft_fates case ('fates_levpft') num2d = numpft_fates + case ('fates_levlanduse') + num2d = n_landuse_cats + case ('fates_levlulu') + num2d = n_landuse_cats * n_landuse_cats case ('fates_levage') num2d = nlevage_fates case ('fates_levfuel')