diff --git a/cime_config/tests.py b/cime_config/tests.py index 37af54e8c88f..6bbb8581ce24 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -436,21 +436,30 @@ }, #fates testmod coverage + "fates_landuse" : { + "time" : "00:40:00", + "tests" : ( + "ERS_Ld60.f45_g37.IELMFATES.elm-fates_cold_logging", + "ERS_D_Ld30.f45_g37.IELMFATES.elm-fates_cold_landuse", + "ERS_D_Ld30.f45_g37.IELMFATES.elm-fates_cold_luh2", + "ERS_D_Ld30.f45_g37.IELMFATES.elm-fates_cold_luh2harvestarea", + "ERS_D_Ld30.f45_g37.IELMFATES.elm-fates_cold_luh2harvestmass", + ) + }, + #fates testmod coverage "fates" : { - "inherit" : ("fates_long_tests", "fates_elm_developer"), + "inherit" : ("fates_long_tests", "fates_elm_developer", "fates_landuse"), "tests" : ( "ERP_Ld15.ne4pg2_ne4pg2.IELMFATES.elm-fates_cold_allvars", "ERP_Ld3.f09_g16.IELMFATES.elm-fates_cold", "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", "ERS_Ld30.f45_g37.IELMFATES.elm-fates_cold_nocomp_fixedbiogeo", "ERS_Ld60.f45_g37.IELMFATES.elm-fates", - "ERS_Ld60.f45_g37.IELMFATES.elm-fates_cold_logging", "ERS_Ld60.f45_g37.IELMFATES.elm-fates_cold_nofire", "ERS_Ld60.f45_g37.IELMFATES.elm-fates_cold_st3", "ERS_Ld60.f45_g37.IELMFATES.elm-fates_cold_pphys", diff --git a/components/elm/bld/ELMBuildNamelist.pm b/components/elm/bld/ELMBuildNamelist.pm index 67347728e0fd..68afd92e132d 100755 --- a/components/elm/bld/ELMBuildNamelist.pm +++ b/components/elm/bld/ELMBuildNamelist.pm @@ -808,12 +808,29 @@ sub setup_cmdl_fates_mode { # The following variables may be set by the user and are compatible with use_fates # no need to set defaults, covered in a different routine - my @list = ( "fates_spitfire_mode", "use_vertsoilc", "use_century_decomp", "fates_seeddisp_cadence", - "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_luh", - "fluh_timeseries","fates_history_dimlevel"); + my @list = ( "flandusepftdat", + "fluh_timeseries", + "fates_harvest_mode", + "fates_history_dimlevel", + "fates_inventory_ctrl_filename", + "fates_parteh_mode", + "fates_seeddisp_cadence", + "fates_spitfire_mode", + "use_fates_cohort_age_tracking", + "use_fates_ed_st3", + "use_fates_ed_prescribed_phys", + "use_fates_fixed_biogeog", + "use_fates_inventory_init", + "use_fates_luh", + "use_fates_lupft", + "use_fates_nocomp", + "use_fates_planthydro", + "use_fates_potentialveg", + "use_fates_sp", + "use_fates_tree_damage", + "use_century_decomp", + "use_snicar_ad", + "use_vertsoilc"); foreach my $var ( @list ) { if ( defined($nl->get_value($var)) ) { $nl_flags->{$var} = $nl->get_value($var); @@ -841,17 +858,17 @@ 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_cohort_age_tracking"; + $var = "fates_harvest_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_fixed_biogeog"; + $var = "use_fates_cohort_age_tracking"; 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_logging"; + $var = "use_fates_fixed_biogeog"; if ( defined($nl->get_value($var)) ) { - fatal_error("$var is being set, but can ONLY be set when -bgc fates option is used.\n"); + fatal_error("$var is being set, but can ONLY be set when -bgc fates option is used.\n"); } $var = "fates_parteh_mode"; if ( defined($nl->get_value($var)) ) { @@ -877,6 +894,14 @@ 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_lupft"; + 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_potentialveg"; + 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"); @@ -2812,8 +2837,8 @@ sub setup_logic_do_harvest { if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) { $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 CN (use_cn == true) or when using FATES (use_fates == true)"; + elsif (!( value_is_true($nl->get_value('use_cn')))) { + $cannot_be_true = "$var can only be set to true when running with CN (use_cn == true)"; } if ($cannot_be_true) { @@ -3380,25 +3405,42 @@ sub setup_logic_fates { my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( value_is_true( $nl_flags->{'use_fates'}) ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_spitfire_mode', 'use_fates'=>$nl_flags->{'use_fates'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_fixed_biogeog', 'use_fates'=>$nl_flags->{'use_fates'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_logging', 'use_fates'=>$nl_flags->{'use_fates'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_planthydro', 'use_fates'=>$nl_flags->{'use_fates'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_parteh_mode', 'use_fates'=>$nl_flags->{'use_fates'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_ed_st3', 'use_fates'=>$nl_flags->{'use_fates'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_ed_prescribed_phys', 'use_fates'=>$nl_flags->{'use_fates'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_inventory_init', 'use_fates'=>$nl_flags->{'use_fates'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_inventory_ctrl_filename','use_fates'=>$nl_flags->{'use_fates'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_cohort_age_tracking','use_fates'=>$nl_flags->{'use_fates'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_sp', 'use_fates'=>$nl_flags->{'use_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'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_history_dimlevel','use_fates'=>$nl_flags->{'use_fates'}); - + + # add other fates modes whose defaults don't depend on other modes + my @list = ( "fates_harvest_mode", + "fates_history_dimlevel", + "fates_inventory_ctrl_filename", + "fates_parteh_mode", + "fates_seeddisp_cadence", + "fates_spitfire_mode", + "use_fates_cohort_age_tracking", + "use_fates_ed_st3", + "use_fates_ed_prescribed_phys", + "use_fates_inventory_init", + "use_fates_lupft", + "use_fates_planthydro", + "use_fates_potentialveg", + "use_fates_sp", + "use_fates_tree_damage"); + + foreach my $var (@list) { + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,'use_fates'=>$nl_flags->{'use_fates'}); + } + + # Add defaults for fates modes that depend on previously set fates modes. See namelist defaults file for list. + add_default($test_files, $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'=>remove_leading_and_trailing_quotes($nl->get_value('fates_harvest_mode')) ); + add_default($test_files, $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->get_value('use_fates_sp') ); + add_default($test_files, $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->get_value('use_fates_sp') ); + # 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"; @@ -3418,21 +3460,104 @@ sub setup_logic_fates { if (&value_is_true( $nl->get_value('use_fates_planthydro') )) { fatal_error('fates sp mode is currently not supported to work with fates hydro'); } + # FATES landuse can not be active with fates sp mode is active + if ( &value_is_true($nl->get_value('use_fates_luh')) ) { + fatal_error("use_fates_luh is can NOT be true when use_fates_sp is true" ); + } + } + } + # 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)) ) { + my @list = ( "use_fates_luh", "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 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)) ) { - $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 ); + $var = "use_fates_potentialveg"; + 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, + '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)) ) { + fatal_error("$var is required when use_fates_luh is set" ); + } elsif ( ! -f "$fname" ) { + 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($test_files, $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)) ) { + fatal_error("$var is required when use_fates_luh and use_fates_fixed_biogeog is set" ); + } elsif ( ! -f "$fname" ) { + 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')) ) { + fatal_error("use_fates_luh must be true when $var is true" ); + } + my $var = remove_leading_and_trailing_quotes($nl->get_value('fates_harvest_mode')); + if ( $var ne 'no_harvest') { + fatal_error("fates_harvest_mode set to $var. It must set to no_harvest when use_fates_potential_veg is true." ); + } + # it is ok for fluh_timeseries to be defined as long as the string is empty + my $var = "fluh_timeseries"; + if ( defined($nl->get_value($var)) ) { + if (! string_is_undef_or_empty($nl->get_value($var))) { + fatal_error("fluh_timeseries can not be set when use_fates_potentialveg is true" ); + } + } + } + } + + # Check fates_harvest_mode compatibility + my $var = "fates_harvest_mode"; + if ( defined($nl->get_value($var)) ) { + # using fates_harvest mode with raw luh2 harvest data + 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')) ) { + fatal_error("use_fates_luh is required to be true when $var is luhdata_mass or luhdata_area" ); + } + } 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 + # 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)) ) { - fatal_error("$var is required when use_fates_luh is set" ); + fatal_error("$var is required when fates_harvest_mode is landuse_timeseries" ); } elsif ( ! -f "$fname" ) { - fatal_error("$fname does NOT point to a valid filename" ); + fatal_error("$var 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 2fe8b19aaa87..316292219861 100644 --- a/components/elm/bld/namelist_files/namelist_defaults.xml +++ b/components/elm/bld/namelist_files/namelist_defaults.xml @@ -134,7 +134,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 lnd/clm2/paramdata/CNP_parameters_c131108.nc @@ -587,10 +587,15 @@ 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 +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.77.0_api.36.0.0/fates_landuse_pft_map_4x5_240206.nc @@ -2177,25 +2182,31 @@ this mask will have smb calculated over the entire global land surface 0 -.false. -.false. +no_harvest +2,2 + "/dev/null" +1 +0 .false. .false. .false. .false. -.false. .false. .false. -.false. -1 -0 +.false. +.false. +.true. +.true. +.true. +.true. +.false. .false. - "/dev/null" .true. +.true. .false. .true. +.true. .false. -2,2 .true. .true. .false. diff --git a/components/elm/bld/namelist_files/namelist_definition.xml b/components/elm/bld/namelist_files/namelist_definition.xml index 16bca299ddd7..74e1967fc529 100644 --- a/components/elm/bld/namelist_files/namelist_definition.xml +++ b/components/elm/bld/namelist_files/namelist_definition.xml @@ -308,6 +308,20 @@ Allowed values are: 5 : use gross domestic production and population datasets to simulate anthropogenic fire supression + +Set FATES harvesting mode by setting fates_harvest_mode +Allowed values are: + no_harvest : no fates harvesting of any kind + event_code : fates logging via fates logging event codes only (via fates parameter file) + landuse_timeseries: fates harvest driven by HLM 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) +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. + + Switch deciding which nutrient model to use in FATES. @@ -339,11 +353,6 @@ Toggle to turn on FATES no competition mode (only relevant if FATES is being use 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 being used). - - Toggle to turn on plant hydraulics (only relevant if FATES is on). @@ -382,12 +391,29 @@ Full pathname to the inventory initialization control file. + group="elm_inparm" valid_values="" value=".false."> 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.) +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.) + +If TRUE, enable use of fates land use x pft mapping data file. 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.) + + + +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. The option +should be set to true for the spin-up case and false for the transient case. + + @@ -408,6 +434,18 @@ output level is not enabled. (Only relevant if FATES is on) + +Full pathname of fates landuse x pft 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 (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) + + 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 cd078b90950c..575517b98fd2 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,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/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 index 098d4fd33a38..94067cfefeba 100644 --- 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 @@ -1,2 +1,2 @@ flanduse_timeseries = '$DIN_LOC_ROOT/lnd/clm2/surfdata_map/landuse.timeseries_4x5_hist_simyr1850-2015_200311.nc' -do_harvest = .true. +fates_harvest_mode = 'landuse_timeseries' diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_logging/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_logging/user_nl_elm index 3b74a4fd3798..d2079d9e4386 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_logging/user_nl_elm +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_logging/user_nl_elm @@ -1 +1 @@ -use_fates_logging= .true. +fates_harvest_mode = 'event_code' diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/README b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/README new file mode 100644 index 000000000000..79d6511d1728 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2/README @@ -0,0 +1,2 @@ +Currently the FATES LUH2 category of test mods currently only supports +4x5 grid resolutions. 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 index 854c21407f1a..3f089bcf49d2 100644 --- 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 @@ -1 +1,5 @@ use_fates_luh = .true. +use_fates_nocomp = .true. +use_fates_fixed_biogeog = .true. +use_fates_sp = .false. +use_fates_potentialveg = .false. diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestarea/include_user_mods b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestarea/include_user_mods new file mode 100644 index 000000000000..9474118e0370 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestarea/include_user_mods @@ -0,0 +1 @@ +../fates_cold_luh2 diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestarea/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestarea/user_nl_elm new file mode 100644 index 000000000000..426b41b49e59 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestarea/user_nl_elm @@ -0,0 +1 @@ +fates_harvest_mode = 'luhdata_area' diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestmass/include_user_mods b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestmass/include_user_mods new file mode 100644 index 000000000000..9474118e0370 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestmass/include_user_mods @@ -0,0 +1 @@ +../fates_cold_luh2 diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestmass/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestmass/user_nl_elm new file mode 100644 index 000000000000..7b6bc24f5a79 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_luh2harvestmass/user_nl_elm @@ -0,0 +1 @@ +fates_harvest_mode = 'luhdata_mass' 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 8dfdff1ab8eb..bd31fbbc4b68 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 @@ -21,7 +21,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/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 4812969a278b..e8e22f163b05 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,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/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 1e72d72d5712..263e4b5fad7c 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 @@ -21,7 +21,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/components/elm/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 b/components/elm/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 index 53be7987182e..04f76767f546 100644 --- a/components/elm/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 +++ b/components/elm/src/dyn_subgrid/dynFATESLandUseChangeMod.F90 @@ -9,6 +9,7 @@ module dynFATESLandUseChangeMod ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc use decompMod , only : bounds_type, BOUNDS_LEVEL_PROC use abortutils , only : endrun use dynFileMod , only : dyn_file_type @@ -22,12 +23,36 @@ module dynFATESLandUseChangeMod real(r8), allocatable, public :: landuse_transitions(:,:) real(r8), allocatable, public :: landuse_states(:,:) + real(r8), allocatable, public :: landuse_harvest(:,:) 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 + 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_hlmlanduse = '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 + integer, public, parameter :: landuse_harvest_mass_units = 2 + integer, public :: landuse_harvest_units 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', & ! forested primary land @@ -69,8 +94,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 @@ -84,14 +110,15 @@ subroutine dynFatesLandUseInit(bounds, landuse_filename) ! Initialize data structures for land use information. ! !USES: - use elm_varctl , only : use_fates_luh + use elm_varctl , only : use_fates_luh, fates_harvest_mode + use elm_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 ! !ARGUMENTS: - type(bounds_type), intent(in) :: bounds ! proc-level bounds - character(len=*) , intent(in) :: landuse_filename ! name of file containing land use information + type(bounds_type), intent(in) :: bounds ! proc-level bounds + character(len=*) , intent(in) :: landuse_filename ! name of file containing landuse timeseries information (fates luh2) ! !LOCAL VARIABLES integer :: varnum, i ! counter for harvest variables @@ -114,37 +141,71 @@ 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 defaut landuse_states = 0._r8 landuse_transitions = 0._r8 + landuse_harvest = 0._r8 + + ! 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) + + ! 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 + + ! Since fates needs state data during initialization, make sure to call + ! the interpolation routine at the start + call dynFatesLandUseInterp(bounds,init_state=.true.) - 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 @@ -152,6 +213,7 @@ end subroutine dynFatesLandUseInit subroutine dynFatesLandUseInterp(bounds, init_state) use dynTimeInfoMod , only : time_info_type + use elm_varctl , only : fates_harvest_mode ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds ! proc-level bounds @@ -171,13 +233,14 @@ subroutine dynFatesLandUseInterp(bounds, init_state) 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) + ! Get the data for the current year + call dynFatesLandUse_file%time_info%set_current_year_get_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 ! Right now we don't account for the topounits allocate(this_data(bounds%begg:bounds%endg)) @@ -189,9 +252,17 @@ 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 (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) + end do + end if deallocate(this_data) end if end subroutine dynFatesLandUseInterp + end module dynFATESLandUseChangeMod diff --git a/components/elm/src/dyn_subgrid/dynHarvestMod.F90 b/components/elm/src/dyn_subgrid/dynHarvestMod.F90 index b30643e9757d..5256f415efe2 100644 --- a/components/elm/src/dyn_subgrid/dynHarvestMod.F90 +++ b/components/elm/src/dyn_subgrid/dynHarvestMod.F90 @@ -188,6 +188,9 @@ subroutine dynHarvest_interp_harvest_types(bounds) end do deallocate(this_data) end if + + ! FATES does not make use of the get_do_harvest mechanism. Make sure this is always false for fates runs. + if (use_fates) do_harvest = .false. end if end subroutine dynHarvest_interp_harvest_types diff --git a/components/elm/src/dyn_subgrid/dynSubgridDriverMod.F90 b/components/elm/src/dyn_subgrid/dynSubgridDriverMod.F90 index 8ac0cf4c45e7..7335d47fb099 100644 --- a/components/elm/src/dyn_subgrid/dynSubgridDriverMod.F90 +++ b/components/elm/src/dyn_subgrid/dynSubgridDriverMod.F90 @@ -71,11 +71,13 @@ subroutine dynSubgrid_init(bounds, glc2lnd_vars, crop_vars) ! clumps - so this routine needs to be called from outside any loops over clumps. ! ! !USES: - use decompMod , only : bounds_type, BOUNDS_LEVEL_PROC - use decompMod , only : get_proc_clumps, get_clump_bounds - use dynpftFileMod , only : dynpft_init - use dynHarvestMod , only : dynHarvest_init - use dynpftFileMod , only : dynpft_interp + use decompMod , only : bounds_type, BOUNDS_LEVEL_PROC + use decompMod , only : get_proc_clumps, get_clump_bounds + use dynpftFileMod , only : dynpft_init + use dynHarvestMod , only : dynHarvest_init + use dynpftFileMod , only : dynpft_interp + use elm_varctl , only : fates_harvest_mode + use dynFATESLandUseChangeMod , only : fates_harvest_hlmlanduse ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds ! processor-level bounds @@ -103,7 +105,7 @@ subroutine dynSubgrid_init(bounds, glc2lnd_vars, crop_vars) end if ! Initialize stuff for harvest (currently shares the flanduse_timeseries file) - if (get_do_harvest()) then + if (get_do_harvest() .or. fates_harvest_mode == fates_harvest_hlmlanduse) then call dynHarvest_init(bounds, harvest_filename=get_flanduse_timeseries()) end if @@ -154,7 +156,8 @@ subroutine dynSubgrid_driver(bounds_proc, & ! ! !USES: use elm_varctl , only : use_cn, create_glacier_mec_landunit - use elm_varctl , only : use_fates, use_fates_luh + use elm_varctl , only : use_fates, use_fates_luh, fates_harvest_mode + use elm_varctl , only : use_fates_potentialveg use decompMod , only : bounds_type, get_proc_clumps, get_clump_bounds use decompMod , only : BOUNDS_LEVEL_PROC use dynInitColumnsMod , only : initialize_new_columns @@ -164,6 +167,7 @@ subroutine dynSubgrid_driver(bounds_proc, & use dynHarvestMod , only : dynHarvest_interp_harvest_types use dynFATESLandUseChangeMod, only : dynFatesLandUseInterp + use dynFATESLandUseChangeMod , only : fates_harvest_hlmlanduse use dynEDMod , only : dyn_ED use reweightMod , only : reweight_wrapup @@ -244,11 +248,11 @@ subroutine dynSubgrid_driver(bounds_proc, & call dyncrop_interp(bounds_proc,crop_vars) end if - if (get_do_harvest()) then + if (get_do_harvest() .or. fates_harvest_mode == fates_harvest_hlmlanduse) then call dynHarvest_interp_harvest_types(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 diff --git a/components/elm/src/external_models/fates b/components/elm/src/external_models/fates index b8e4eee5ed46..1982b0032c3c 160000 --- a/components/elm/src/external_models/fates +++ b/components/elm/src/external_models/fates @@ -1 +1 @@ -Subproject commit b8e4eee5ed46daf5c9e710e9ebbe6d20464adbc8 +Subproject commit 1982b0032c3cab6278892eccb85f643114ffb1af diff --git a/components/elm/src/main/controlMod.F90 b/components/elm/src/main/controlMod.F90 index 02c3ccf0867f..24bb855ff61a 100755 --- a/components/elm/src/main/controlMod.F90 +++ b/components/elm/src/main/controlMod.F90 @@ -250,7 +250,7 @@ subroutine control_init( ) namelist /elm_inparm / use_c13, use_c14 namelist /elm_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, & @@ -260,7 +260,10 @@ subroutine control_init( ) use_fates_nocomp, & use_fates_sp, & use_fates_luh, & + use_fates_lupft, & + use_fates_potentialveg, & fluh_timeseries, & + flandusepftdat, & fates_parteh_mode, & fates_seeddisp_cadence, & use_fates_tree_damage, & @@ -804,9 +807,10 @@ subroutine control_spmd() call mpi_bcast (fates_spitfire_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 (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 (flandusepftdat, len(flandusepftdat) , MPI_CHARACTER, 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) call mpi_bcast (use_fates_ed_st3, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -814,6 +818,8 @@ 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_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), & @@ -1220,9 +1226,10 @@ 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, *) ' fluh_timeseries = ', fluh_timeseries + write(iulog, *) ' fluh_timeseries = ', trim(fluh_timeseries) + write(iulog, *) ' flandusepftdat = ', trim(flandusepftdat) 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 @@ -1234,6 +1241,8 @@ 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, *) ' 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_instMod.F90 b/components/elm/src/main/elm_instMod.F90 index 90b576c320d6..ca74dda6ccf4 100644 --- a/components/elm/src/main/elm_instMod.F90 +++ b/components/elm/src/main/elm_instMod.F90 @@ -145,6 +145,8 @@ subroutine elm_inst_biogeochem(bounds_proc) ! initialize biogeochemical variables use elm_varcon , only : c13ratio, c14ratio use histFileMod , only : hist_printflds + use elm_varctl , only : flandusepftdat + implicit none type(bounds_type), intent(in) :: bounds_proc @@ -245,7 +247,7 @@ subroutine elm_inst_biogeochem(bounds_proc) ! Initialize the Functionaly Assembled Terrestrial Ecosystem Simulator (FATES) if (use_fates) then - call alm_fates%init(bounds_proc) + call alm_fates%init(bounds_proc, flandusepftdat) end if call hist_printflds() diff --git a/components/elm/src/main/elm_varctl.F90 b/components/elm/src/main/elm_varctl.F90 index b9ddd4b24397..46b0d3c65a41 100644 --- a/components/elm/src/main/elm_varctl.F90 +++ b/components/elm/src/main/elm_varctl.F90 @@ -221,8 +221,8 @@ module elm_varctl logical, public :: use_fates = .false. ! true => use ED integer, public :: fates_spitfire_mode = 0 ! 0 for no fire; 1 for constant ignitions + character(len=13), public :: fates_harvest_mode = '' ! five different harvest modes; see namelist_definitions logical, public :: use_fates_fixed_biogeog = .false. ! true => use fixed biogeography mode - logical, public :: use_fates_logging = .false. ! true => turn on logging module 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_tree_damage = .false. ! true => turn on tree damage module @@ -232,7 +232,10 @@ module elm_varctl 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 + logical, public :: use_fates_lupft = .false. ! true => FATES land use x pft mode + logical, public :: use_fates_potentialveg = .false. ! true => FATES potential veg only character(len=256), public :: fluh_timeseries = '' ! filename for land use harmonization 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 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 1b9d6c1ba490..a20444d67582 100644 --- a/components/elm/src/main/elmfates_interfaceMod.F90 +++ b/components/elm/src/main/elmfates_interfaceMod.F90 @@ -44,18 +44,21 @@ module ELMFatesInterfaceMod use elm_varctl , only : use_fates use elm_varctl , only : use_vertsoilc use elm_varctl , only : fates_spitfire_mode + use elm_varctl , only : fates_harvest_mode use elm_varctl , only : fates_parteh_mode use elm_varctl , only : fates_seeddisp_cadence use elm_varctl , only : use_fates_planthydro use elm_varctl , only : use_fates_cohort_age_tracking use elm_varctl , only : use_fates_ed_st3 use elm_varctl , only : use_fates_ed_prescribed_phys - use elm_varctl , only : use_fates_logging use elm_varctl , only : use_fates_inventory_init 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_lupft + use elm_varctl , only : use_fates_potentialveg + use elm_varctl , only : flandusepftdat use elm_varctl , only : use_fates_tree_damage use elm_varctl , only : nsrest, nsrBranch use elm_varctl , only : fates_inventory_ctrl_filename @@ -172,14 +175,23 @@ module ELMFatesInterfaceMod use dynHarvestMod , only : num_harvest_vars, harvest_varnames, wood_harvest_units 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 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_transition_vars + use dynFATESLandUseChangeMod, only : num_landuse_state_vars + use dynFATESLandUseChangeMod, only : num_landuse_harvest_vars + use dynFATESLandUseChangeMod, only : landuse_transitions + use dynFATESLandUseChangeMod, only : landuse_states + use dynFATESLandUseChangeMod, only : landuse_harvest + use dynFATESLandUseChangeMod, only : landuse_transition_varnames + use dynFATESLandUseChangeMod, only : landuse_state_varnames + use dynFATESLandUseChangeMod, only : landuse_harvest_varnames + use dynFATESLandUseChangeMod, only : landuse_harvest_units + use dynFATESLandUseChangeMod, only : fates_harvest_no_logging + use dynFATESLandUseChangeMod, only : fates_harvest_hlmlanduse + use dynFATESLandUseChangeMod, only : fates_harvest_luh_area + use dynFATESLandUseChangeMod, only : fates_harvest_luh_mass use FatesInterfaceTypesMod , only : bc_in_type, bc_out_type @@ -282,6 +294,8 @@ module ELMFatesInterfaceMod character(len=*), parameter, private :: sourcefile = & __FILE__ + integer, parameter :: num_landuse_pft_vars = 4 + public :: ELMFatesGlobals1 public :: ELMFatesGlobals2 public :: ELMFatesTimesteps @@ -388,12 +402,14 @@ subroutine ELMFatesGlobals2() integer :: pass_inventory_init integer :: pass_is_restart integer :: pass_cohort_age_tracking - integer :: pass_num_lu_harvest_types + integer :: pass_num_lu_harvest_cats integer :: pass_lu_harvest 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 ! ---------------------------------------------------------------------------------- ! FATES lightning definitions ! 1 : use a global constant lightning rate found in fates_params. @@ -439,7 +455,7 @@ subroutine ELMFatesGlobals2() end if call set_fates_ctrlparms('use_tree_damage',ival=pass_tree_damage) - if((trim(nu_com).eq.'ECA') .or. (trim(nu_com).eq.'MIC')) then + if((trim(nu_com)=='ECA') .or. (trim(nu_com)=='MIC')) then call set_fates_ctrlparms('nu_com',cval='ECA') else call set_fates_ctrlparms('nu_com',cval='RD') @@ -463,7 +479,7 @@ subroutine ELMFatesGlobals2() call set_fates_ctrlparms('nitrogen_spec',ival=1) call set_fates_ctrlparms('phosphorus_spec',ival=1) - if(is_restart() .or. nsrest .eq. nsrBranch) then + if(is_restart() .or. nsrest == nsrBranch) then pass_is_restart = 1 else pass_is_restart = 0 @@ -506,26 +522,30 @@ subroutine ELMFatesGlobals2() call set_fates_ctrlparms('sf_successful_ignitions_def',ival=successful_ignitions) call set_fates_ctrlparms('sf_anthro_ignitions_def',ival=anthro_ignitions) - ! check fates logging namelist value first because hlm harvest overrides it - if(use_fates_logging) then - pass_logging = 1 - else - pass_logging = 0 + ! FATES logging and harvest modes + pass_logging = 0 + pass_lu_harvest = 0 + pass_num_lu_harvest_cats = 0 + 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 (trim(fates_harvest_mode) == fates_harvest_hlmlanduse) then + pass_num_lu_harvest_cats = num_harvest_vars + pass_lu_harvest = 1 + + ! LUH2 landuse timeseries driven harvest rates + 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 - if(get_do_harvest()) then - pass_logging = 1 - pass_num_lu_harvest_types = num_harvest_vars - pass_lu_harvest = 1 - else - 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('num_lu_harvest_cats',ival=pass_num_lu_harvest_cats) call set_fates_ctrlparms('use_logging',ival=pass_logging) - if (use_fates_luh) then + 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 @@ -534,10 +554,18 @@ subroutine ELMFatesGlobals2() 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(use_fates_ed_st3) then pass_ed_st3 = 1 else @@ -689,7 +717,7 @@ end subroutine ELMFatesTimesteps ! ==================================================================================== - subroutine init(this, bounds_proc ) + subroutine init(this, bounds_proc, flandusepftdat) ! --------------------------------------------------------------------------------- ! This initializes the hlm_fates_interface_type @@ -721,6 +749,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 @@ -739,6 +768,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 @@ -764,6 +796,13 @@ subroutine init(this, bounds_proc ) write(iulog,*) 'alm_fates%init(): allocating for ',nclumps,' threads' end if + ! Retrieve the landuse x pft static data if the optional switch has been set + if (use_fates_fixed_biogeog .and. use_fates_luh) then + call GetLandusePFTData(bounds_proc, flandusepftdat, landuse_pft_map, landuse_bareground) + end if + + nclumps = get_proc_clumps() + !$OMP PARALLEL DO PRIVATE (nc,bounds_clump,nmaxcol,s,c,l,g,collist,pi,pf,ft) do nc = 1,nclumps @@ -882,17 +921,25 @@ subroutine init(this, bounds_proc ) endif endif - ! initialize static layers for reduced complexity FATES versions from HLM - 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,t,m) - end do + if (use_fates_fixed_biogeog) then + ! Transfer the landuse x pft data to fates via bc_in if landuse mode engaged + 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 + 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,t,m) + end do - if(abs(sum(this%fates(nc)%bc_in(s)%pft_areafrac(surfpft_lb:surfpft_ub))-1.0_r8).gt.1.0e-9)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__)) - endif + if(abs(sum(this%fates(nc)%bc_in(s)%pft_areafrac(surfpft_lb:surfpft_ub))-1.0_r8).gt.1.0e-9)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 @@ -911,7 +958,6 @@ subroutine init(this, bounds_proc ) call endrun(msg=errMsg(sourcefile, __LINE__)) end if - ! Set patch itypes on natural veg columns to nonsense ! This will force a crash if the model outside of FATES tries to think ! of the patch as a PFT. @@ -934,6 +980,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 (use_fates_fixed_biogeog .and. use_fates_luh) then + deallocate(landuse_pft_map) + deallocate(landuse_bareground) + end if + end subroutine init ! =================================================================================== @@ -1046,7 +1098,7 @@ subroutine dynamics_driv(this, bounds_clump, top_as_inst, & lnfm24 = this%fates_fire_data_method%GetLight24() end if - if (fates_spitfire_mode .eq. anthro_suppression) then + if (fates_spitfire_mode == anthro_suppression) then allocate(gdp_lf_col(bounds_clump%begc:bounds_clump%endc), stat=ier) if (ier /= 0) then call endrun(msg="allocation error for gdp"//& @@ -1066,13 +1118,13 @@ subroutine dynamics_driv(this, bounds_clump, top_as_inst, & this%fates(nc)%bc_in(s)%lightning24(ifp) = lnfm24(g) * 24._r8 ! #/km2/hr to #/km2/day - if (fates_spitfire_mode .ge. anthro_ignitions) then + if (fates_spitfire_mode >= anthro_ignitions) then this%fates(nc)%bc_in(s)%pop_density(ifp) = this%fates_fire_data_method%forc_hdm(g) end if end do ! ifp - if (fates_spitfire_mode .eq. anthro_suppression) then + if (fates_spitfire_mode == anthro_suppression) then ! Placeholder for future fates use of gdp - comment out before integration !this%fates(nc)%bc_in(s)%gdp = gdp_lf_col(c) ! k US$/capita(g) end if @@ -1151,10 +1203,15 @@ subroutine dynamics_driv(this, bounds_clump, top_as_inst, & ! for now there is one veg column per gridcell, so store all harvest data in each site ! this will eventually change ! the harvest data are zero if today is before the start of the harvest time series - if (get_do_harvest()) then + if (trim(fates_harvest_mode) == fates_harvest_hlmlanduse) then this%fates(nc)%bc_in(s)%hlm_harvest_rates = harvest_rates(:,g) this%fates(nc)%bc_in(s)%hlm_harvest_catnames = harvest_varnames this%fates(nc)%bc_in(s)%hlm_harvest_units = wood_harvest_units + 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 end if this%fates(nc)%bc_in(s)%site_area=col_pp%wtgcell(c)*grc_pp%area(g)*m2_per_km2 @@ -1912,7 +1969,6 @@ end subroutine restart subroutine init_coldstart(this, canopystate_inst, soilstate_inst, frictionvel_inst) - ! Arguments class(hlm_fates_interface_type), intent(inout) :: this type(canopystate_type) , intent(inout) :: canopystate_inst @@ -2015,17 +2071,26 @@ 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) + ! Transfer initial values to fates + if (use_fates_luh) then + do s = 1,this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + g = col_pp%gridcell(c) + + 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 + + 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 + end if - 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 + end do + end if ! Initialize patches call init_patches(this%fates(nc)%nsites, this%fates(nc)%sites, & @@ -3608,6 +3673,109 @@ 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 elm_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) + + end subroutine GetLandusePFTData end module ELMFatesInterfaceMod