From 8771e50aa004afd616013a2246e90da57d15eb72 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 19 Sep 2023 15:50:39 -0700 Subject: [PATCH] Add fates landuse x pft API code Adds luh2 harvest data read to fates landuse module This will enables the use of the raw LUH2 harvest data when running with fates in land use mode + wood harvest mode --- components/elm/bld/ELMBuildNamelist.pm | 122 ++++++-- .../bld/namelist_files/namelist_defaults.xml | 20 +- .../namelist_files/namelist_definition.xml | 38 ++- .../testmods_dirs/elm/fates/user_nl_elm | 2 +- .../testmods_dirs/elm/fates_eca/user_nl_elm | 2 +- .../testmods_dirs/elm/fates_long/user_nl_elm | 2 +- .../testmods_dirs/elm/fates_rd/user_nl_elm | 2 +- .../dyn_subgrid/dynFATESLandUseChangeMod.F90 | 135 +++++++-- .../elm/src/dyn_subgrid/dynHarvestMod.F90 | 3 + .../src/dyn_subgrid/dynSubgridDriverMod.F90 | 22 +- components/elm/src/main/controlMod.F90 | 15 +- components/elm/src/main/elm_instMod.F90 | 4 +- components/elm/src/main/elm_varctl.F90 | 5 +- .../elm/src/main/elmfates_interfaceMod.F90 | 273 ++++++++++++++---- 14 files changed, 504 insertions(+), 141 deletions(-) diff --git a/components/elm/bld/ELMBuildNamelist.pm b/components/elm/bld/ELMBuildNamelist.pm index 67347728e0fd..05e19b9bbb4a 100755 --- a/components/elm/bld/ELMBuildNamelist.pm +++ b/components/elm/bld/ELMBuildNamelist.pm @@ -808,12 +808,28 @@ 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 = ( "fates_spitfire_mode", + "fates_harvest_mode", + "fates_history_dimlevel", + "fates_inventory_ctrl_filename", + "fates_seeddisp_cadence", + "use_century_decomp", + "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_parteh_mode", + "use_fates_planthydro", + "use_fates_potentialveg", + "use_fates_sp", + "use_fates_tree_damage", + "use_snicar_ad", + "use_vertsoilc", + "fluh_timeseries"); foreach my $var ( @list ) { if ( defined($nl->get_value($var)) ) { $nl_flags->{$var} = $nl->get_value($var); @@ -841,17 +857,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 +893,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_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 = "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 +2832,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 +3400,28 @@ 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_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, 'flandusepftdat', 'phys'=>$nl_flags->{'phys'}); + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_harvest_mode', 'use_fates'=>$nl_flags->{'use_fates'} ); + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_history_dimlevel', '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, 'fates_parteh_mode', '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, 'fates_spitfire_mode', '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_nocomp', '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_fixed_biogeog', '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_planthydro', '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_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_lupft', 'use_fates'=>$nl_flags->{'use_fates'}); + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_potentialveg', 'use_fates'=>$nl_flags->{'use_fates'}); + # 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,9 +3441,37 @@ 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)) ) { + $var = "flandusepftdat"; + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, + 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, nofail=>1 ); + my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); + if ( ! defined($nl->get_value($var)) ) { + fatal_error("$var is required when use_fates_lupft is set" ); + } elsif ( ! -f "$fname" ) { + fatal_error("$fname does NOT point to a valid filename" ); + } + # make sure that nocomp and fbg mode are enabled as well as use_fates_luh + #my @list = ( "use_fates_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)) ) { @@ -3436,6 +3487,29 @@ sub setup_logic_fates { } } } + # check that fates landuse is on and harvest mode is off when potential veg switch is true + my $var = "use_potentialveg"; + if ( defined($nl->get_value($var)) ) { + if ( &value_is_true($nl->get_value($var)) ) { + if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { + fatal_error("use_fates_luh must be true when $var is true" ); + } + if ( $nl->get_value('fates_harvest_mode') ne "no_harvest") { + fatal_error("fates_harvest_mode must be off when $var 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 + if ( $nl->get_value($var) eq "luhdata_area" || $nl->get_value($var) eq "luhdata_mass" ) { + # Make sure that use_fates_luh is true when using raw fates luh2 harvest data + if ( ! &value_is_true($nl->get_value('use_fates_luh')) ) { + fatal_error("use_fates_luh is required to be true when $var is greater than 2" ); + } + } + } } } diff --git a/components/elm/bld/namelist_files/namelist_defaults.xml b/components/elm/bld/namelist_files/namelist_defaults.xml index 2fe8b19aaa87..6459605ff4dc 100644 --- a/components/elm/bld/namelist_files/namelist_defaults.xml +++ b/components/elm/bld/namelist_files/namelist_defaults.xml @@ -587,10 +587,12 @@ 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.73.0_api.36.0.0/fates_landuse_pft_map_4x5_240206.nc @@ -2177,25 +2179,25 @@ 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. +.false. .false. - "/dev/null" .true. .false. .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 a6d4e9eff3c0..c597d164661d 100644 --- a/components/elm/bld/namelist_files/namelist_definition.xml +++ b/components/elm/bld/namelist_files/namelist_definition.xml @@ -308,6 +308,18 @@ 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) + surfdata_file: 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) + + Switch deciding which nutrient model to use in FATES. @@ -339,11 +351,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 +389,26 @@ 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. +This is enabled by default if fates_harvest_mode is set to use the raw LUH2 harvest +data (fates_harvest_mode >= 3) or if use_fates_lupft is true. (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.) + +If TRUE, enable use of fates land use x pft mapping data file. +(Only valid for use_fates = true and is incompatible with transient runs currently.) + + + +If TRUE, ignore the land-use state vector and transitions, and assert that all lands +are primary, and that there is no harvest. + + @@ -408,6 +429,11 @@ output level is not enabled. (Only relevant if FATES is on) + +Full pathname of fates landuse x pft data map. + + 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_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..3d1b9ec50d61 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=13), public, parameter :: fates_harvest_no_logging = 'no_harvest' + character(len=13), public, parameter :: fates_harvest_logging_only = 'event_code' + character(len=13), public, parameter :: fates_harvest_clmlanduse = 'surfdata_file' + character(len=13), public, parameter :: fates_harvest_luh_area = 'luhdata_area' + character(len=13), public, parameter :: fates_harvest_luh_mass = 'luhdata_mass' + + ! Define landuse harvest unit integer representation + integer, public, parameter :: landuse_harvest_area_units = 1 + 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..6914e4d70c38 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_clmlanduse ! ! !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_clmlanduse) 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_clmlanduse 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_clmlanduse) 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/main/controlMod.F90 b/components/elm/src/main/controlMod.F90 index 8f763a9ebd4d..1e200ce045c0 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, & @@ -802,9 +805,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) @@ -812,6 +816,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), & @@ -1217,9 +1223,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, *) ' flandusepftdat = ', 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 @@ -1231,6 +1238,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 b8afca87e241..6e41290d9c7c 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 7fa580b19f28..39740277e1ce 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 520197de5765..0c67c0e82262 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_clmlanduse + 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 @@ -389,12 +403,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. @@ -440,7 +456,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') @@ -464,7 +480,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 @@ -507,26 +523,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_clmlanduse) 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 @@ -535,10 +555,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 @@ -690,7 +718,7 @@ end subroutine ELMFatesTimesteps ! ==================================================================================== - subroutine init(this, bounds_proc ) + subroutine init(this, bounds_proc, flandusepftdat) ! --------------------------------------------------------------------------------- ! This initializes the hlm_fates_interface_type @@ -722,6 +750,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 @@ -740,6 +769,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 @@ -765,6 +797,12 @@ 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) call GetLandusePFTData(bounds_proc, flandusepftdat, & + landuse_pft_map, landuse_bareground) + + nclumps = get_proc_clumps() + !$OMP PARALLEL DO PRIVATE (nc,bounds_clump,nmaxcol,s,c,l,g,collist,pi,pf,ft) do nc = 1,nclumps @@ -883,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 @@ -912,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. @@ -935,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 ! =================================================================================== @@ -1047,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"//& @@ -1067,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 @@ -1152,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_clmlanduse) 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 @@ -1913,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 @@ -2016,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, & @@ -3609,6 +3673,111 @@ 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) + + ! Check that sums equal to unity + + end subroutine GetLandusePFTData end module ELMFatesInterfaceMod