diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index a3795e4c6b..e14ce11599 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,4 +1,5 @@ # Ran python directory through black python formatter +d229b5c6689efc4c2a6cef077515c4ccd5c18ff6 4cd83cb3ee6d85eb909403487abf5eeaf4d98911 0aa2957c1f8603c63fa30b11295c06cfddff44a5 2cdb380febb274478e84cd90945aee93f29fa2e6 @@ -7,3 +8,14 @@ e44dc469439e02e9ee582dab274d890ebdfab104 b88e1cd1b28e3609684c79a2ec0e88f26cfc362b 51c102c5df2e0ef971b5f8eeeb477567899af63a 7dacad70e74e2ec97f6492d4e7a3cb5dd498bcd7 +b771971e3299c4fa56534b93421f7a2b9c7282fd +9de88bb57ea9855da408cbec1dc8acb9079eda47 +8bc4688e52ea23ef688e283698f70a44388373eb +0a5a9e803b56ec1bbd6232eff1c99dbbeef25eb7 +810cb346f05ac1aabfff931ab1a2b7b584add241 +5933b0018f8e29413e30dda9b906370d147bad45 +# Ran SystemTests and python/ctsm through black python formatter +5364ad66eaceb55dde2d3d598fe4ce37ac83a93c +8056ae649c1b37f5e10aaaac79005d6e3a8b2380 +540b256d1f3382f4619d7b0877c32d54ce5c40b6 +8a168bb0895f4f2421608dd2589398e13a6663e6 diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index 438b48e918..3759fa84c3 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -16,6 +16,22 @@ jobs: # Use options and version identical to the conda environment # Using pyproject.toml makes sure this testing is consistent with our python directory testing options: "--check --config python/pyproject.toml" - src: "./python" + src: "./python" # Version should be coordinated with the ctsm_pylib conda environment under the python directory version: "22.3.0" + # Actions identical to above for each directory and source file we need to check (arrays aren't allowed for src: field) + - uses: psf/black@stable + with: + options: "--check --config python/pyproject.toml" + src: "./cime_config/SystemTests" + version: "22.3.0" + - uses: psf/black@stable + with: + options: "--check --config python/pyproject.toml" + src: "./cime_config/buildlib" + version: "22.3.0" + - uses: psf/black@stable + with: + options: "--check --config python/pyproject.toml" + src: "./cime_config/buildnml" + version: "22.3.0" diff --git a/Externals.cfg b/Externals.cfg index dc85604283..02f64c0210 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -34,7 +34,7 @@ hash = 34723c2 required = True [ccs_config] -tag = ccs_config_cesm0.0.64 +tag = ccs_config_cesm0.0.65 protocol = git repo_url = https://github.com/ESMCI/ccs_config_cesm.git local_path = ccs_config @@ -44,7 +44,7 @@ required = True local_path = cime protocol = git repo_url = https://github.com/ESMCI/cime -tag = cime6.0.108 +tag = cime6.0.125 required = True [cmeps] diff --git a/Externals_CLM.cfg b/Externals_CLM.cfg index c3d00db726..14ba14d8b4 100644 --- a/Externals_CLM.cfg +++ b/Externals_CLM.cfg @@ -2,7 +2,7 @@ local_path = src/fates protocol = git repo_url = https://github.com/NGEET/fates -tag = sci.1.66.1_api.25.5.0 +tag = sci.1.67.2_api.27.0.0 required = True [externals_description] diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 0b11707023..e5bda4680d 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -91,11 +91,13 @@ OPTIONS This toggles off the namelist variable: use_cn bgc = Carbon Nitrogen with methane, nitrification, vertical soil C, CENTURY or MIMICS decomposition - This toggles on the namelist variables: + This toggles on the namelist variables: use_cn, use_lch4, use_nitrif_denitrif - fates = FATES/Ecosystem Demography with below ground BGC - This toggles on the namelist variables: - use_fates + fates = FATES/Ecosystem Demography with below ground BGC + CENTURY or MIMICS decomposition + This toggles on the namelist variables: + use_fates. use_lch4 and use_nitrif_denitrif are optional + (Only for CLM4.5/CLM5.0) -[no-]chk_res Also check [do NOT check] to make sure the resolution and land-mask is valid. @@ -763,26 +765,12 @@ 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 = ( "use_lch4" ); - foreach my $var ( @list ) { - if ( defined($nl->get_value($var)) ) { - $nl_flags->{$var} = $nl->get_value($var); - $val = $nl_flags->{$var}; - my $group = $definition->get_group_name($var); - $nl->set_variable_value($group, $var, $val); - if ( ! $definition->is_valid_value( $var, $val ) ) { - my @valid_values = $definition->get_valid_values( $var ); - $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); - } - } - } } else { # dis-allow fates specific namelist items with non-fates runs my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys", - "use_fates_cohort_age_tracking", - "use_fates_inventory_init","use_fates_fixed_biogeog","use_fates_nocomp","use_fates_sp","fates_inventory_ctrl_filename","use_fates_logging","fates_parteh_mode","use_fates_tree_damage" ); + "use_fates_cohort_age_tracking","use_fates_inventory_init","use_fates_fixed_biogeog", + "use_fates_nocomp","use_fates_sp","fates_inventory_ctrl_filename","use_fates_logging", + "fates_parteh_mode","use_fates_tree_damage" ); # dis-allow fates specific namelist items with non-fates runs foreach my $var ( @list ) { if ( defined($nl->get_value($var)) ) { @@ -1593,6 +1581,7 @@ sub process_namelist_inline_logic { setup_logic_supplemental_nitrogen($opts, $nl_flags, $definition, $defaults, $nl); setup_logic_snowpack($opts, $nl_flags, $definition, $defaults, $nl); setup_logic_fates($opts, $nl_flags, $definition, $defaults, $nl); + setup_logic_z0param($opts, $nl_flags, $definition, $defaults, $nl); setup_logic_misc($opts, $nl_flags, $definition, $defaults, $nl); ######################################### @@ -1626,9 +1615,9 @@ sub process_namelist_inline_logic { setup_logic_urban($opts, $nl_flags, $definition, $defaults, $nl); ############################### - # namelist group: crop # + # namelist group: crop_inparm # ############################### - setup_logic_crop($opts, $nl_flags, $definition, $defaults, $nl); + setup_logic_crop_inparm($opts, $nl_flags, $definition, $defaults, $nl); ############################### # namelist group: ch4par_in # @@ -1696,6 +1685,11 @@ sub process_namelist_inline_logic { ################################## setup_logic_lai_streams($opts, $nl_flags, $definition, $defaults, $nl); + ################################## + # namelist group: cropcal_streams # + ################################## + setup_logic_cropcal_streams($opts, $nl_flags, $definition, $defaults, $nl); + ########################################## # namelist group: soil_moisture_streams # ########################################## @@ -1789,6 +1783,11 @@ sub process_namelist_inline_logic { # namelist group: clm_initinterp_inparm # ######################################### setup_logic_initinterp($opts, $nl_flags, $definition, $defaults, $nl); + + ############################### + # namelist group: exice_streams # + ############################### + setup_logic_exice($opts, $nl_flags, $definition, $defaults, $nl); } #------------------------------------------------------------------------------- @@ -2150,7 +2149,7 @@ sub setup_logic_urban { #------------------------------------------------------------------------------- -sub setup_logic_crop { +sub setup_logic_crop_inparm { my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; if ( &value_is_true($nl->get_value('use_crop')) ) { @@ -2193,6 +2192,7 @@ sub setup_logic_soilstate { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'organic_frac_squared' ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_bedrock', 'use_fates'=>$nl_flags->{'use_fates'}, 'vichydro'=>$nl_flags->{'vichydro'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_excess_ice'); # excess ice flag should be read before stream vars my $var1 = "soil_layerstruct_predefined"; my $var2 = "soil_layerstruct_userdefined"; @@ -2980,24 +2980,30 @@ sub setup_logic_supplemental_nitrogen { my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; if ( $nl_flags->{'bgc_mode'} ne "sp" && $nl_flags->{'bgc_mode'} ne "fates" && &value_is_true($nl_flags->{'use_crop'}) ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, - 'suplnitro', 'use_cn'=>$nl_flags->{'use_cn'}, 'use_crop'=>$nl_flags->{'use_crop'}); - } + # If this is non-fates, non-sp and crop is active + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + 'suplnitro', 'use_cn'=>$nl_flags->{'use_cn'}, 'use_crop'=>$nl_flags->{'use_crop'}); + } elsif ( $nl_flags->{'bgc_mode'} eq "fates" && not &value_is_true( $nl_flags->{'use_fates_sp'}) ) { + # Or... if its fates but not fates-sp + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + 'suplnitro', 'use_fates'=>$nl_flags->{'use_fates'}); + } + # # Error checking for suplnitro # my $suplnitro = $nl->get_value('suplnitro'); if ( defined($suplnitro) ) { if ( $nl_flags->{'bgc_mode'} eq "sp" ) { - $log->fatal_error("supplemental Nitrogen (suplnitro) is set, but neither CN nor CNDV is active!"); + $log->fatal_error("supplemental Nitrogen (suplnitro) is set, but neither CN nor CNDV nor FATES is active!"); } if ( ! &value_is_true($nl_flags->{'use_crop'}) && $suplnitro =~ /PROG_CROP_ONLY/i ) { $log->fatal_error("supplemental Nitrogen is set to run over prognostic crops, but prognostic crop is NOT active!"); } if ( $suplnitro =~ /ALL/i ) { - if ( $nl_flags->{'bgc_spinup'} eq "on" ) { + if ( $nl_flags->{'bgc_spinup'} eq "on" && $nl_flags->{'bgc_mode'} ne "fates" ) { $log->warning("There is no need to use a bgc_spinup mode when supplemental Nitrogen is on for all PFT's, as these modes spinup Nitrogen" ); } } @@ -3307,6 +3313,12 @@ sub setup_logic_luna { 'use_cn'=>$nl_flags->{'use_cn'} ); } $nl_flags->{'use_luna'} = $nl->get_value('use_luna'); + + # LUNA can NOT be on with FATES + if ( &value_is_true( $nl_flags->{'use_luna'} ) && &value_is_true( $nl_flags->{'use_fates'} )) { + $log->fatal_error("Cannot turn use_luna to true when bgc=fates" ); + } + my $vcmax_opt= $nl->get_value('vcmax_opt'); # lnc_opt only applies if luna is on or for vcmax_opt=3/4 if ( &value_is_true( $nl_flags->{'use_luna'} ) || $vcmax_opt == 3 || $vcmax_opt == 4 ) { @@ -3499,18 +3511,18 @@ sub setup_logic_nitrogen_deposition { my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; # - # Nitrogen deposition for bgc=CN + # Nitrogen deposition for bgc=CN or fates # - if ( $nl_flags->{'bgc_mode'} =~/bgc/ ) { + if ( ($nl_flags->{'bgc_mode'} =~/bgc/) ) { # or ($nl_flags->{'bgc_mode'} =~/fates/) ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndepmapalgo', 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, 'hgrid'=>$nl_flags->{'res'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndep_taxmode', 'phys'=>$nl_flags->{'phys'}, - 'use_cn'=>$nl_flags->{'use_cn'}, - 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'} ); + 'use_cn'=>$nl_flags->{'use_cn'}, + 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'} ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndep_varlist', 'phys'=>$nl_flags->{'phys'}, - 'use_cn'=>$nl_flags->{'use_cn'}, - 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'} ); + 'use_cn'=>$nl_flags->{'use_cn'}, + 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'} ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_ndep', 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); @@ -3898,8 +3910,7 @@ sub setup_logic_lai_streams { if ( &value_is_true($nl_flags->{'use_crop'}) && &value_is_true($nl->get_value('use_lai_streams')) ) { $log->fatal_error("turning use_lai_streams on is incompatable with use_crop set to true."); } - if ( $nl_flags->{'bgc_mode'} eq "sp" ) { - + if ( $nl_flags->{'bgc_mode'} eq "sp" || ($nl_flags->{'bgc_mode'} eq "fates" && &value_is_true($nl->get_value('use_fates_sp')) )) { if ( &value_is_true($nl->get_value('use_lai_streams')) ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_lai_streams'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lai_mapalgo', @@ -3925,21 +3936,73 @@ sub setup_logic_lai_streams { } } } else { - # If bgc is CN/CNDV then make sure none of the LAI settings are set - if ( defined($nl->get_value('stream_year_first_lai')) || - defined($nl->get_value('stream_year_last_lai')) || - defined($nl->get_value('model_year_align_lai')) || - defined($nl->get_value('lai_tintalgo' )) || + # If bgc is BGC/BGCDV then make sure none of the LAI settings are set + if ( &value_is_true($nl->get_value('use_lai_streams'))) { + $log->fatal_error("When not in SP mode use_lai_streams cannot be .true.\n" . + "(eg. don't use this option with BGC or non-SP FATES), \n" . + "Update compset to use SP)"); + } + if ( defined($nl->get_value('stream_year_first_lai')) || + defined($nl->get_value('stream_year_last_lai')) || + defined($nl->get_value('model_year_align_lai')) || + defined($nl->get_value('lai_tintalgo' )) || defined($nl->get_value('stream_fldfilename_lai')) ) { - $log->fatal_error("When bgc is NOT SP none of the following can be set: stream_year_first_lai,\n" . + $log->fatal_error("When not in SP mode none of the following can be set: stream_year_first_lai,\n" . "stream_year_last_lai, model_year_align_lai, lai_tintalgo nor\n" . - "stream_fldfilename_lai (eg. don't use this option with BGC,CN,CNDV nor BGDCV)."); + "stream_fldfilename_lai (eg. don't use this option with BGC or FATES-SP)."); } } } #------------------------------------------------------------------------------- +sub setup_logic_cropcal_streams { + my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; + + # Set first and last stream years + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_cropcal', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_cropcal', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + + # Set align year, if first and last years are different + if ( $nl->get_value('stream_year_first_cropcal') != + $nl->get_value('stream_year_last_cropcal') ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + 'model_year_align_cropcal', 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + } + + # Set up other crop calendar parameters + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'generate_crop_gdds'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_mxmat'); + + # Option checks + my $generate_crop_gdds = $nl->get_value('generate_crop_gdds') ; + my $use_mxmat = $nl->get_value('use_mxmat') ; + my $sdate_file = $nl->get_value('stream_fldFileName_sdate') ; + my $gdd_file = $nl->get_value('stream_fldFileName_cultivar_gdds') ; + my $mesh_file = $nl->get_value('stream_meshfile_cropcal') ; + if ( $generate_crop_gdds eq '.true.' ) { + if ( $use_mxmat eq '.true.' ) { + $log->fatal_error("If generate_crop_gdds is true, you must also set use_mxmat to false" ); + } + if ( $sdate_file eq '' ) { + $log->fatal_error("If generate_crop_gdds is true, you must specify stream_fldFileName_sdate") + } + if ( $gdd_file ne '' ) { + $log->fatal_error("If generate_crop_gdds is true, do not specify stream_fldFileName_cultivar_gdds") + } + } + if ( $mesh_file eq '' and ( $sdate_file ne '' or $gdd_file ne '' ) ) { + $log->fatal_error("If prescribing crop sowing dates and/or maturity requirements, you must specify stream_meshfile_cropcal") + } +} + +#------------------------------------------------------------------------------- + sub setup_logic_soilwater_movement { my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; @@ -4239,6 +4302,13 @@ sub setup_logic_fates { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'}, 'use_fates_sp'=>$nl_flags->{'use_fates_sp'} ); } + my $suplnitro = $nl->get_value('suplnitro'); + my $parteh_mode = $nl->get_value('fates_parteh_mode'); + if ( ($parteh_mode == 1) && ($suplnitro !~ /ALL/) && not &value_is_true( $nl_flags->{'use_fates_sp'}) ) { + $log->fatal_error("supplemental Nitrogen (suplnitro) is NOT set to ALL, FATES is on, " . + "but and FATES-SP is not active, but fates_parteh_mode is 1, so Nitrogen is not active" . + "Change suplnitro back to ALL"); + } # # For FATES SP mode make sure no-competetiion, and fixed-biogeography are also set # And also check for other settings that can't be trigged on as well @@ -4273,6 +4343,76 @@ sub setup_logic_fates { } } +#------------------------------------------------------------------------------- +sub setup_logic_exice { + # + # excess ice streams + # + my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; + my $use_exice = $nl->get_value( 'use_excess_ice' ); + my $use_exice_streams = $nl->get_value( 'use_excess_ice_streams' ); + # IF excess ice streams is on + if (defined($use_exice_streams) && value_is_true($use_exice_streams)) { + # Can only be true if excess ice is also on, otherwise fail + if (defined($use_exice) && not value_is_true($use_exice)) { + $log->fatal_error("use_excess_ice_streams can NOT be TRUE when use_excess_ice is FALSE" ); + } + # Otherwise if ice streams are off + } else { + my @list = ( "stream_meshfile_exice", "stream_fldfilename_exice" ); + # fail is excess ice streams files are set + foreach my $var ( @list ) { + if ( defined($nl->get_value($var)) ) { + $log->fatal_error("$var should NOT be set when use_excess_ice_streams=FALSE" ); + } + } + # mapalgo can only be none, if excess ice streams are off + my $map_algo = $nl->get_value("stream_mapalgo_exice"); + if ( defined($map_algo) && ($map_algo ne "none") ) { + $log->fatal_error("stream_mapalgo_exice can ONLY be none when use_excess_ice_streams=FALSE" ); + } + } + # If excess ice is on + if (defined($use_exice) && value_is_true($use_exice)) { + # IF nuopc driver and excess ice streams are on get the stream defaults + if (defined($use_exice_streams) && value_is_true($use_exice_streams)) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_exice'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_mapalgo_exice'); + # If excess ice streams on, but NOT the NUOPC driver fail + if ( not $opts->{'driver'} eq "nuopc" ) { + $log->fatal_error("nuopc driver is required when use_excess_ice_streams is set to true" ); + # NUOPC driver needs a mesh file + } else { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_exice'); + } + } + } + + +} # end exice streams + +#------------------------------------------------------------------------------- + +sub setup_logic_z0param { + # + # Set default z0 paramterization + # + my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; + + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'z0param_method'); + + my $z0param_method = remove_leading_and_trailing_quotes($nl->get_value('z0param_method' )); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_z0m_snowmelt', + 'z0param_method'=>$z0param_method ); + + my $use_z0m_snowmelt = $nl->get_value( 'use_z0m_snowmelt' ); + + if ( $z0param_method eq "ZengWang2007" && defined($use_z0m_snowmelt) && value_is_true($use_z0m_snowmelt)) { + $log->fatal_error("use_z0m_snowmelt must be .false. when z0param_method = $z0param_method.\n $@"); + } + +} + #------------------------------------------------------------------------------- sub setup_logic_misc { @@ -4292,7 +4432,7 @@ sub setup_logic_misc { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'for_testing_use_second_grain_pool'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'for_testing_use_repr_structure_pool'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'for_testing_no_crop_seed_replenishment'); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hist_master_list_file'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hist_fields_list_file'); } #------------------------------------------------------------------------------- @@ -4317,6 +4457,7 @@ sub write_output_files { @groups = qw(clm_inparm ndepdyn_nml popd_streams urbantv_streams light_streams soil_moisture_streams lai_streams atm2lnd_inparm lnd2atm_inparm clm_canopyhydrology_inparm cnphenology + cropcal_streams clm_soilhydrology_inparm dynamic_subgrid cnvegcarbonstate finidat_consistency_checks dynpft_consistency_checks clm_initinterp_inparm century_soilbgcdecompcascade @@ -4324,7 +4465,7 @@ sub write_output_files { soilwater_movement_inparm rooting_profile_inparm soil_resis_inparm bgc_shared canopyfluxes_inparm aerosol clmu_inparm clm_soilstate_inparm clm_nitrogen clm_snowhydrology_inparm hillslope_hydrology_inparm hillslope_properties_inparm - cnprecision_inparm clm_glacier_behavior crop irrigation_inparm + cnprecision_inparm clm_glacier_behavior crop_inparm irrigation_inparm surfacealbedo_inparm water_tracers_inparm); #@groups = qw(clm_inparm clm_canopyhydrology_inparm clm_soilhydrology_inparm @@ -4344,6 +4485,7 @@ sub write_output_files { push @groups, "nitrif_inparm"; push @groups, "lifire_inparm"; push @groups, "ch4finundated"; + push @groups, "exice_streams"; push @groups, "soilbgc_decomp"; push @groups, "clm_canopy_inparm"; if (remove_leading_and_trailing_quotes($nl->get_value('snow_cover_fraction_method')) eq 'SwensonLawrence2012') { diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index dfaea90ee9..a889821a46 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -67,8 +67,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. .false. - -.false. + +.false. .true. @@ -146,7 +146,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). NONE -NONE +ALL 0.50,0.30 @@ -213,7 +213,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 2.0d00 2.0d00 0.5d00 -0.5d00 +0.5d00 +2.0d00 .true. @@ -324,6 +325,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 40 3 + .true. 1.0 @@ -495,6 +497,15 @@ attributes from the config_cache.xml file (with keys converted to upper-case). lnd/clm2/paramdata/fates_params_api.25.5.0_12pft_c230628.nc + + + + +ZengWang2007 + +.true. +.false. + @@ -510,6 +521,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .true. .false. .false. +.false. .true. @@ -562,6 +574,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). DependsOnLat .false. Constant +.false. +.true. .false. @@ -1138,6 +1152,8 @@ lnd/clm2/surfdata_map/release-clm5.0.30/surfdata_C24_hist_78pfts_CMIP6_simyr2000 lnd/clm2/surfdata_map/release-clm5.0.18/surfdata_0.9x1.25_hist_78pfts_CMIP6_simyr2000_c190214.nc lnd/clm2/surfdata_map/release-clm5.0.18/surfdata_1.9x2.5_hist_78pfts_CMIP6_simyr2000_c190304.nc + +lnd/clm2/surfdata_map/release-clm5.0.18/surfdata_360x720cru_78pfts_CMIP6_simyr2000_c170824.nc lnd/clm2/surfdata_map/release-clm5.0.24/surfdata_0.125x0.125_hist_78pfts_CMIP6_simyr2005_c190624.nc @@ -1677,6 +1693,11 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 nn nn + +1850 +2100 +1850 + none @@ -2718,4 +2739,14 @@ use_crop=".true.">lnd/clm2/surfdata_map/ctsm5.1.dev052/landuse.timeseries_mpasa1 general + + + + +.false. + +lnd/clm2/paramdata/exice_init_0.125x0.125_c20220516.nc +lnd/clm2/paramdata/exice_init_0.125x0.125_ESMFmesh_cdf5_c20220802.nc +bilinear + diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 04deb185d5..0b4db69ee0 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -799,9 +799,9 @@ SNICAR (SNow, ICe, and Aerosol Radiative model) optical data file name SNICAR (SNow, ICe, and Aerosol Radiative model) snow aging data file name - -If TRUE, write master field list to separate file for documentation purposes +If TRUE, write list of all output fields to separate file for documentation purposes + group="crop_inparm" valid_values="constant,varytropicsbylat" value="constant"> Type of mapping to use for base temperature for prognostic crop model constant = Just use baset from the PFT parameter file varytropicsbylat = Vary the tropics by latitude + group="crop_inparm" valid_values="" value="0.4d00"> Only used when baset_mapping == varytropicsbylat Slope with latitude in degrees to vary tropical baset by + group="crop_inparm" valid_values="" value="12.0d00"> Only used when baset_mapping == varytropicsbylat Intercept at zero latitude to add to baset from the PFT parameter file @@ -1164,6 +1164,16 @@ Phenology onset depends on the vegetation type (only used when CN is on) + +Set to .true. in order to override crop harvesting logic and to instead harvest the day before the next sowing date. Used to generate growing-degree day outputs that can be used with an external script to generate new GDD requirement ("cultivar") files. + + + +Set to .false. in order to ignore crop PFT parameter for maximum growing season length (mxmat). Must be set to .false. when generate_crop_gdds is .true. + + Method for determining what the minimum critical day length for seasonal decidious leaf offset depends on @@ -1840,6 +1850,41 @@ Mapping method from LAI input file to the model resolution copy = copy using the same indices + + + + + + +First year to loop over for crop calendar data + + + +Last year to loop over for crop calendar data + + + +Simulation year that aligns with stream_year_first_cropcal value + + + +Filename of input stream data for sowing dates + + + +Filename of input stream data for cultivar growing degree-day targets + + + +Filename of input stream data for crop calendar inputs + + @@ -2778,6 +2823,24 @@ the related bulk quantities. If .true., run with water isotopes + + + + + +Parameterization/parameters to use for surface roughness +ZengWang2007: Zeng and Wang 2007 +Meier2022: Meier et al. in prep. 2022 + + + +If FALSE use constant snow z0m +If TRUE use parameterization of snow z0m as a function of accumulated +snow melt of Brock et al. (2006) + + @@ -2832,4 +2895,38 @@ use case.) + + + + +If TRUE turn on the excess ice physics, (Lee et al., 2014; Cai et al., 2020) + + + +If TRUE and use_excess_ice is TRUE, use the excess ice stream to determine the initial values of the excess ice field +if FALSE and use_excess_ice is TRUE, expect excess ice to come from the initial conditions or restart file +Expect to be FALSE is use_excess_ice is FALSE + + + +Filename of input stream data for excess ice data + + + +mesh filename of input stream data for excess ice + + + +Mapping method from excess ice input stream data to the model resolution + bilinear = bilinear interpolation + nn = nearest neighbor + none = no interpolation + + + diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index fdfc53093a..72796a4d12 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,9 +163,10 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 1975; +my $ntests = 1999; + if ( defined($opts{'compare'}) ) { - $ntests += 1344; + $ntests += 1353; } plan( tests=>$ntests ); @@ -323,6 +324,8 @@ sub cat_and_create_namelistinfile { "-res 0.9x1.25 -structure fast", "-res 0.9x1.25 -namelist '&a irrigate=.true./'", "-res 0.9x1.25 -verbose", "-res 0.9x1.25 -ssp_rcp SSP1-2.6", "-res 0.9x1.25 -test", "-res 0.9x1.25 -sim_year 1850", "-res 0.9x1.25 -namelist '&a use_lai_streams=.true.,use_soil_moisture_streams=.true./'", + "-res 0.9x1.25 -namelist '&a use_excess_ice=.true. use_excess_ice_streams=.true./'", + "-res 0.9x1.25 -namelist '&a use_excess_ice=.true. use_excess_ice_streams=.false./'", "-res 0.9x1.25 -use_case 1850_control", "-res 1x1pt_US-UMB -clm_usr_name 1x1pt_US-UMB -namelist '&a fsurdat=\"/dev/null\"/'", "-res 1x1_brazil", @@ -337,6 +340,10 @@ sub cat_and_create_namelistinfile { my $base_options = "-envxml_dir . -driver $driver"; if ( $driver eq "mct" ) { $base_options = "$base_options -lnd_frac $DOMFILE"; + # Skip the MCT test for excess ice streams + if ( $options =~ /use_excess_ice_streams=.true./ ) { + next; + } } else { $base_options = "$base_options -namelist '&a force_send_to_atm = .false./'"; } @@ -524,8 +531,33 @@ sub cat_and_create_namelistinfile { GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, - "soilm_stream wo use" =>{ options=>"-res 0.9x1.25 -envxml_dir .", - namelst=>"use_soil_moisture_streams = .false.,stream_fldfilename_soilm='missing_file'", + "soilm_stream off w file" =>{ options=>"-res 0.9x1.25 -envxml_dir .", + namelst=>"use_soil_moisture_streams = .false.,stream_fldfilename_soilm='file_provided_when_off'", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "exice_stream off w file" =>{ options=>"-res 0.9x1.25 -envxml_dir .", + namelst=>"use_excess_ice=.true., use_excess_ice_streams = .false.,stream_fldfilename_exice='file_provided_when_off'", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "exice_stream off w mesh" =>{ options=>"-res 0.9x1.25 -envxml_dir .", + namelst=>"use_excess_ice=.true., use_excess_ice_streams = .false.,stream_meshfile_exice='file_provided_when_off'", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "exice off, but stream on" =>{ options=>"-res 0.9x1.25 -envxml_dir .", + namelst=>"use_excess_ice=.false., use_excess_ice_streams = .true.,stream_fldfilename_exice='file_provided', stream_meshfile_exice='file_provided'", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "exice stream off, but setmap"=>{ options=>"-res 0.9x1.25 -envxml_dir .", + namelst=>"use_excess_ice=.true., use_excess_ice_streams = .false.,stream_mapalgo_exice='bilinear'", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "exice stream on, but mct" =>{ options=>"--res 0.9x1.25 --envxml_dir . --driver mct --lnd_frac $DOMFILE ", + namelst=>"use_excess_ice=.true., use_excess_ice_streams=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, @@ -969,6 +1001,21 @@ sub cat_and_create_namelistinfile { GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_1", }, + "useFATESWluna" =>{ options=>"--bgc fates --envxml_dir . --no-megan", + namelst=>"use_luna=TRUE", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_1", + }, + "useFATESWfun" =>{ options=>"--bgc fates --envxml_dir . --no-megan", + namelst=>"use_fun=TRUE", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_1", + }, + "useFATESWOsuplnitro" =>{ options=>"--bgc fates --envxml_dir . --no-megan", + namelst=>"suplnitro='NONE'", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_1", + }, "FireNoneButBGCfireon" =>{ options=>"-bgc bgc -envxml_dir . -light_res none", namelst=>"fire_method='li2021gswpfrc'", GLC_TWO_WAY_COUPLING=>"FALSE", @@ -1164,6 +1211,26 @@ sub cat_and_create_namelistinfile { GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm5_0", }, + "fates_non_sp_laistreams" =>{ options=>"--envxml_dir . --bgc fates", + namelst=>"use_lai_streams=.true., use_fates_sp=.false.", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "bgc_non_sp_laistreams" =>{ options=>"--envxml_dir . -bgc bgc", + namelst=>"use_lai_streams=.true.", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "bgc_laistreams_input" =>{ options=>"--envxml_dir . --bgc bgc", + namelst=>"stream_year_first_lai=1999", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, + "crop_laistreams_input" =>{ options=>"--envxml_dir . --bgc sp --crop", + namelst=>"use_lai_streams=.true.", + GLC_TWO_WAY_COUPLING=>"FALSE", + phys=>"clm5_0", + }, ); foreach my $key ( keys(%failtest) ) { print( "$key\n" ); diff --git a/cime_config/SystemTests/fsurdatmodifyctsm.py b/cime_config/SystemTests/fsurdatmodifyctsm.py index 70dfa7c434..03e437d5c4 100644 --- a/cime_config/SystemTests/fsurdatmodifyctsm.py +++ b/cime_config/SystemTests/fsurdatmodifyctsm.py @@ -5,11 +5,18 @@ import os import re -import subprocess from CIME.SystemTests.system_tests_common import SystemTestsCommon from CIME.XML.standard_module_setup import * from CIME.SystemTests.test_utils.user_nl_utils import append_to_user_nl_files +# For calling fsurdat_modifier +from argparse import Namespace + +_CTSM_PYTHON = os.path.join( + os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir, "python" +) +sys.path.insert(1, _CTSM_PYTHON) + logger = logging.getLogger(__name__) @@ -66,36 +73,18 @@ def _create_config_file(self): cfg_out.write(line) def _run_modify_fsurdat(self): - tool_path = os.path.join(self._ctsm_root, "tools/modify_input_files/fsurdat_modifier") + fsurdat_modifier_args = Namespace( + cfg_path=self._cfg_file_path, + debug=False, + fsurdat_in="UNSET", + fsurdat_out="UNSET", + overwrite=False, + silent=False, + verbose=False, + ) + from ctsm.modify_input_files.fsurdat_modifier import fsurdat_modifier - self._case.load_env(reset=True) - conda_env = ". " + self._get_caseroot() + "/.env_mach_specific.sh; " - # Preprend the commands to get the conda environment for python first - conda_env += self._get_conda_env() - # Source the env - try: - subprocess.run( - conda_env + "python3 " + tool_path + " " + self._cfg_file_path, - shell=True, - check=True, - ) - except subprocess.CalledProcessError as error: - print("ERROR while getting the conda environment and/or ") - print("running the fsurdat_modifier tool: ") - print("(1) If your ctsm_pylib environment is out of date or you ") - print("have not created the ctsm_pylib environment, yet, you may ") - print("get past this error by running ./py_env_create ") - print("in your ctsm directory and trying this test again. ") - print("(2) If conda is not available, install and load conda, ") - print("run ./py_env_create, and then try this test again. ") - print("(3) If (1) and (2) are not the issue, then you may be ") - print("getting an error within the fsurdat_modifier tool itself. ") - print("Default error message: ") - print(error.output) - raise - except: - print("ERROR trying to run fsurdat_modifier tool.") - raise + fsurdat_modifier(fsurdat_modifier_args) def _modify_user_nl(self): append_to_user_nl_files( @@ -103,24 +92,3 @@ def _modify_user_nl(self): component="clm", contents="fsurdat = '{}'".format(self._fsurdat_out), ) - - def _get_conda_env(self): - # - # Add specific commands needed on different machines to get conda available - # Use semicolon here since it's OK to fail - # - # Execute the module unload/load when "which conda" fails - # eg on cheyenne - try: - subprocess.run("which conda", shell=True, check=True) - conda_env = " " - except subprocess.CalledProcessError: - # Remove python and add conda to environment for cheyennne - conda_env = "module unload python; module load conda;" - - # Activate the python environment - conda_env += " conda activate ctsm_pylib" - # End above to get to actual command - conda_env += " && " - - return conda_env diff --git a/cime_config/SystemTests/lreprstruct.py b/cime_config/SystemTests/lreprstruct.py index f8a3300e56..a03fb1815b 100644 --- a/cime_config/SystemTests/lreprstruct.py +++ b/cime_config/SystemTests/lreprstruct.py @@ -49,6 +49,20 @@ def _case_one_setup(self): contents="for_testing_use_repr_structure_pool=.true.", ) + # Replace any GRAIN outputs with the same outputs for REPRODUCTIVE1 and REPRODUCTIVE2 + user_nl_clm_path = os.path.join(self._get_caseroot(), "user_nl_clm") + with open(user_nl_clm_path) as f: + user_nl_clm_text = f.read() + for grain_output in re.findall("GRAIN\w*", user_nl_clm_text): + user_nl_clm_text = user_nl_clm_text.replace( + grain_output, + grain_output.replace("GRAIN", "REPRODUCTIVE1") + + "', '" + + grain_output.replace("GRAIN", "REPRODUCTIVE2"), + ) + with open(user_nl_clm_path, "w") as f: + f.write(user_nl_clm_text) + def _case_two_setup(self): # This is needed in the nearly-standard case to prevent grain from being used to # replenish crop seed deficits, thus making grain act like the reproductive diff --git a/cime_config/SystemTests/rxcropmaturity.py b/cime_config/SystemTests/rxcropmaturity.py new file mode 100644 index 0000000000..b3b43cff07 --- /dev/null +++ b/cime_config/SystemTests/rxcropmaturity.py @@ -0,0 +1,442 @@ +""" +CTSM-specific test that first performs a GDD-generating run, then calls +Python code to generate the maturity requirement file. This is then used +in a sowing+maturity forced run, which finally is tested to ensure +correct behavior. + +Currently only supports 0.9x1.25, 1.9x2.5, and 10x15 resolutions. Eventually, +this test should be able to generate its own files at whatever resolution it's +called at. Well, really, the ultimate goal would be to give CLM the files +at the original resolution (for GGCMI phase 3, 0.5°) and have the stream +code do the interpolation. However, that wouldn't act on harvest dates +(which are needed for generate_gdds.py). I could have Python interpolate +those, but this would cause a potential inconsistency. +""" + +import os +import re +import systemtest_utils as stu +import subprocess +from CIME.SystemTests.system_tests_common import SystemTestsCommon +from CIME.XML.standard_module_setup import * +from CIME.SystemTests.test_utils.user_nl_utils import append_to_user_nl_files +import shutil, glob + +logger = logging.getLogger(__name__) + + +class RXCROPMATURITY(SystemTestsCommon): + def __init__(self, case): + # initialize an object interface to the SMS system test + SystemTestsCommon.__init__(self, case) + + # Ensure run length is at least 5 years. Minimum to produce one complete growing season (i.e., two complete calendar years) actually 4 years, but that only gets you 1 season usable for GDD generation, so you can't check for season-to-season consistency. + stop_n = self._case.get_value("STOP_N") + stop_option = self._case.get_value("STOP_OPTION") + stop_n_orig = stop_n + stop_option_orig = stop_option + if "nsecond" in stop_option: + stop_n /= 60 + stop_option = "nminutes" + if "nminute" in stop_option: + stop_n /= 60 + stop_option = "nhours" + if "nhour" in stop_option: + stop_n /= 24 + stop_option = "ndays" + if "nday" in stop_option: + stop_n /= 365 + stop_option = "nyears" + if "nmonth" in stop_option: + stop_n /= 12 + stop_option = "nyears" + error_message = None + if "nyear" not in stop_option: + error_message = ( + f"STOP_OPTION ({stop_option_orig}) must be nsecond(s), nminute(s), " + + "nhour(s), nday(s), nmonth(s), or nyear(s)" + ) + elif stop_n < 5: + error_message = ( + "RXCROPMATURITY must be run for at least 5 years; you requested " + + f"{stop_n_orig} {stop_option_orig[1:]}" + ) + if error_message is not None: + logger.error(error_message) + raise RuntimeError(error_message) + + # Get the number of complete years that will be run + self._run_Nyears = int(stop_n) + + # Only allow RXCROPMATURITY to be called with test cropMonthOutput + casebaseid = self._case.get_value("CASEBASEID") + if casebaseid.split("-")[-1] != "cropMonthOutput": + error_message = ( + "Only call RXCROPMATURITY with test cropMonthOutput " + + "to avoid potentially huge sets of daily outputs." + ) + logger.error(error_message) + raise RuntimeError(error_message) + + # Get files with prescribed sowing and harvest dates + self._get_rx_dates() + + # Which conda environment should we use? + self._get_conda_env() + + def run_phase(self): + # Modeling this after the SSP test, we create a clone to be the case whose outputs we don't + # want to be saved as baseline. + + # ------------------------------------------------------------------- + # (1) Set up GDD-generating run + # ------------------------------------------------------------------- + # Create clone to be GDD-Generating case + logger.info("RXCROPMATURITY log: cloning setup") + case_rxboth = self._case + caseroot = self._case.get_value("CASEROOT") + clone_path = f"{caseroot}.gddgen" + self._path_gddgen = clone_path + if os.path.exists(self._path_gddgen): + shutil.rmtree(self._path_gddgen) + logger.info("RXCROPMATURITY log: cloning") + case_gddgen = self._case.create_clone(clone_path, keepexe=True) + logger.info("RXCROPMATURITY log: done cloning") + + os.chdir(self._path_gddgen) + self._set_active_case(case_gddgen) + + # Set up stuff that applies to both tests + self._setup_all() + + # Add stuff specific to GDD-Generating run + logger.info("RXCROPMATURITY log: modify user_nl files: generate GDDs") + self._append_to_user_nl_clm( + [ + "generate_crop_gdds = .true.", + "use_mxmat = .false.", + " ", + "! (h2) Daily outputs for GDD generation and figure-making", + "hist_fincl3 = 'GDDACCUM', 'GDDHARV'", + "hist_nhtfrq(3) = -24", + "hist_mfilt(3) = 365", + "hist_type1d_pertape(3) = 'PFTS'", + "hist_dov2xy(3) = .false.", + ] + ) + + # If flanduse_timeseries is defined, we need to make a static version for this test. This + # should have every crop in most of the world. + self._get_flanduse_timeseries_in(case_gddgen) + if self._flanduse_timeseries_in is not None: + + # Download files from the server, if needed + case_gddgen.check_all_input_data() + + # Make custom version of surface file + logger.info("RXCROPMATURITY log: run fsurdat_modifier") + self._run_fsurdat_modifier() + + # ------------------------------------------------------------------- + # (2) Perform GDD-generating run and generate prescribed GDDs file + # ------------------------------------------------------------------- + logger.info("RXCROPMATURITY log: Start GDD-Generating run") + + # As per SSP test: + # "No history files expected, set suffix=None to avoid compare error" + # We *do* expect history files here, but anyway. This works. + self._skip_pnl = False + self.run_indv(suffix=None, st_archive=True) + + self._run_generate_gdds(case_gddgen) + + # ------------------------------------------------------------------- + # (3) Set up and perform Prescribed Calendars run + # ------------------------------------------------------------------- + os.chdir(caseroot) + self._set_active_case(case_rxboth) + + # Set up stuff that applies to both tests + self._setup_all() + + # Add stuff specific to Prescribed Calendars run + logger.info("RXCROPMATURITY log: modify user_nl files: Prescribed Calendars") + self._append_to_user_nl_clm( + [ + "generate_crop_gdds = .false.", + f"stream_fldFileName_cultivar_gdds = '{self._gdds_file}'", + ] + ) + + self.run_indv() + + # ------------------------------------------------------------------- + # (4) Check Prescribed Calendars run + # ------------------------------------------------------------------- + logger.info("RXCROPMATURITY log: output check: Prescribed Calendars") + self._run_check_rxboth_run() + + # Get sowing and harvest dates for this resolution. + def _get_rx_dates(self): + # Eventually, I want to remove these hard-coded resolutions so that this test can generate + # its own sowing and harvest date files at whatever resolution is requested. + lnd_grid = self._case.get_value("LND_GRID") + input_data_root = self._case.get_value("DIN_LOC_ROOT") + processed_crop_dates_dir = f"{input_data_root}/lnd/clm2/cropdata/calendars/processed" + if lnd_grid == "10x15": + self._sdatefile = os.path.join( + processed_crop_dates_dir, + "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f10_f10_mg37.2000-2000.20230330_165301.nc", + ) + self._hdatefile = os.path.join( + processed_crop_dates_dir, + "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f10_f10_mg37.2000-2000.20230330_165301.nc", + ) + elif lnd_grid == "1.9x2.5": + self._sdatefile = os.path.join( + processed_crop_dates_dir, + "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f19_g17.2000-2000.20230102_175625.nc", + ) + self._hdatefile = os.path.join( + processed_crop_dates_dir, + "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f19_g17.2000-2000.20230102_175625.nc", + ) + elif lnd_grid == "0.9x1.25": + self._sdatefile = os.path.join( + processed_crop_dates_dir, + "sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f09_g17.2000-2000.20230520_134417.nc", + ) + self._hdatefile = os.path.join( + processed_crop_dates_dir, + "hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f09_g17.2000-2000.20230520_134418.nc", + ) + else: + error_message = "ERROR: RXCROPMATURITY currently only supports 0.9x1.25, 1.9x2.5, and 10x15 resolutions" + logger.error(error_message) + raise RuntimeError(error_message) + + # Ensure files exist + error_message = None + if not os.path.exists(self._sdatefile): + error_message = f"ERROR: Sowing date file not found: {self._sdatefile}" + elif not os.path.exists(self._hdatefile): + error_message = f"ERROR: Harvest date file not found: {self._sdatefile}" + if error_message is not None: + logger.error(error_message) + raise RuntimeError(error_message) + + def _setup_all(self): + logger.info("RXCROPMATURITY log: _setup_all start") + + # Get some info + self._ctsm_root = self._case.get_value("COMP_ROOT_DIR_LND") + run_startdate = self._case.get_value("RUN_STARTDATE") + self._run_startyear = int(run_startdate.split("-")[0]) + + # Set sowing dates file (and other crop calendar settings) for all runs + logger.info("RXCROPMATURITY log: modify user_nl files: all tests") + self._modify_user_nl_allruns() + logger.info("RXCROPMATURITY log: _setup_all done") + + # Make a surface dataset that has every crop in every gridcell + def _run_fsurdat_modifier(self): + + # fsurdat should be defined. Where is it? + self._fsurdat_in = None + with open(self._lnd_in_path, "r") as lnd_in: + for line in lnd_in: + fsurdat_in = re.match(r" *fsurdat *= *'(.*)'", line) + if fsurdat_in: + self._fsurdat_in = fsurdat_in.group(1) + break + if self._fsurdat_in is None: + error_message = "fsurdat not defined" + logger.error(error_message) + raise RuntimeError(error_message) + + # Where we will save the fsurdat version for this test + path, ext = os.path.splitext(self._fsurdat_in) + dir_in, filename_in_noext = os.path.split(path) + self._fsurdat_out = os.path.join( + self._path_gddgen, f"{filename_in_noext}.all_crops_everywhere{ext}" + ) + + # Make fsurdat for this test, if not already done + if not os.path.exists(self._fsurdat_out): + tool_path = os.path.join( + self._ctsm_root, + "tools", + "modify_input_files", + "fsurdat_modifier", + ) + + # Create configuration file for fsurdat_modifier + self._cfg_path = os.path.join( + self._path_gddgen, + "modify_fsurdat_allcropseverywhere.cfg", + ) + self._create_config_file_evenlysplitcrop() + + command = f"python3 {tool_path} {self._cfg_path} " + stu.run_python_script( + self._get_caseroot(), + self._this_conda_env, + command, + tool_path, + ) + + # Modify namelist + logger.info("RXCROPMATURITY log: modify user_nl files: new fsurdat") + self._append_to_user_nl_clm( + [ + "fsurdat = '{}'".format(self._fsurdat_out), + "do_transient_crops = .false.", + "flanduse_timeseries = ''", + "use_init_interp = .true.", + ] + ) + + def _create_config_file_evenlysplitcrop(self): + """ + Open the new and the template .cfg files + Loop line by line through the template .cfg file + When string matches, replace that line's content + """ + cfg_template_path = os.path.join( + self._ctsm_root, "tools/modify_input_files/modify_fsurdat_template.cfg" + ) + + with open(self._cfg_path, "w", encoding="utf-8") as cfg_out: + # Copy template, replacing some lines + with open(cfg_template_path, "r", encoding="utf-8") as cfg_in: + for line in cfg_in: + if re.match(r" *evenly_split_cropland *=", line): + line = f"evenly_split_cropland = True" + elif re.match(r" *fsurdat_in *=", line): + line = f"fsurdat_in = {self._fsurdat_in}" + elif re.match(r" *fsurdat_out *=", line): + line = f"fsurdat_out = {self._fsurdat_out}" + elif re.match(r" *process_subgrid_section *=", line): + line = f"process_subgrid_section = True" + cfg_out.write(line) + + # Add new lines + cfg_out.write("\n") + cfg_out.write("[modify_fsurdat_subgrid_fractions]\n") + cfg_out.write("PCT_CROP = 100.0\n") + cfg_out.write("PCT_NATVEG = 0.0\n") + cfg_out.write("PCT_GLACIER = 0.0\n") + cfg_out.write("PCT_WETLAND = 0.0\n") + cfg_out.write("PCT_LAKE = 0.0\n") + cfg_out.write("PCT_URBAN = 0.0 0.0 0.0\n") + + def _run_check_rxboth_run(self): + + output_dir = os.path.join(self._get_caseroot(), "run") + first_usable_year = self._run_startyear + 2 + last_usable_year = self._run_startyear + self._run_Nyears - 2 + + tool_path = os.path.join( + self._ctsm_root, "python", "ctsm", "crop_calendars", "check_rxboth_run.py" + ) + command = ( + f"python3 {tool_path} " + + f"--directory {output_dir} " + + f"-y1 {first_usable_year} " + + f"-yN {last_usable_year} " + + f"--rx-sdates-file {self._sdatefile} " + + f"--rx-gdds-file {self._gdds_file} " + ) + stu.run_python_script( + self._get_caseroot(), + self._this_conda_env, + command, + tool_path, + ) + + def _modify_user_nl_allruns(self): + nl_additions = [ + "stream_meshfile_cropcal = '{}'".format(self._case.get_value("LND_DOMAIN_MESH")), + "stream_fldFileName_sdate = '{}'".format(self._sdatefile), + "stream_year_first_cropcal = 2000", + "stream_year_last_cropcal = 2000", + "model_year_align_cropcal = 2000", + " ", + "! (h1) Annual outputs on sowing or harvest axis", + "hist_fincl2 = 'GRAINC_TO_FOOD_PERHARV', 'GRAINC_TO_FOOD_ANN', 'SDATES', 'SDATES_PERHARV', 'SYEARS_PERHARV', 'HDATES', 'GDDHARV_PERHARV', 'GDDACCUM_PERHARV', 'HUI_PERHARV', 'SOWING_REASON_PERHARV', 'HARVEST_REASON_PERHARV'", + "hist_nhtfrq(2) = 17520", + "hist_mfilt(2) = 999", + "hist_type1d_pertape(2) = 'PFTS'", + "hist_dov2xy(2) = .false.", + ] + self._append_to_user_nl_clm(nl_additions) + + def _run_generate_gdds(self, case_gddgen): + self._generate_gdds_dir = os.path.join(self._path_gddgen, "generate_gdds_out") + os.makedirs(self._generate_gdds_dir) + + # Get arguments to generate_gdds.py + dout_sr = case_gddgen.get_value("DOUT_S_ROOT") + input_dir = os.path.join(dout_sr, "lnd", "hist") + first_season = self._run_startyear + 2 + last_season = self._run_startyear + self._run_Nyears - 2 + sdates_file = self._sdatefile + hdates_file = self._hdatefile + + # It'd be much nicer to call generate_gdds.main(), but I can't import generate_gdds. + tool_path = os.path.join( + self._ctsm_root, "python", "ctsm", "crop_calendars", "generate_gdds.py" + ) + command = " ".join( + [ + f"python3 {tool_path}", + f"--input-dir {input_dir}", + f"--first-season {first_season}", + f"--last-season {last_season}", + f"--sdates-file {sdates_file}", + f"--hdates-file {hdates_file}", + f"--output-dir generate_gdds_out", + f"--skip-crops miscanthus,irrigated_miscanthus", + ] + ) + stu.run_python_script( + self._get_caseroot(), + self._this_conda_env, + command, + tool_path, + ) + + # Where were the prescribed maturity requirements saved? + generated_gdd_files = glob.glob(os.path.join(self._generate_gdds_dir, "gdds_*.nc")) + if len(generated_gdd_files) != 1: + error_message = f"ERROR: Expected one matching prescribed maturity requirements file; found {len(generated_gdd_files)}: {generated_gdd_files}" + logger.error(error_message) + raise RuntimeError(error_message) + self._gdds_file = generated_gdd_files[0] + + def _get_conda_env(self): + conda_setup_commands = stu.cmds_to_setup_conda(self._get_caseroot()) + + # If npl conda environment is available, use that (It has dask, which + # enables chunking, which makes reading daily 1-degree netCDF files + # much more efficient. + if "npl " in os.popen(conda_setup_commands + "conda env list").read(): + self._this_conda_env = "npl" + else: + self._this_conda_env = "ctsm_pylib" + + def _append_to_user_nl_clm(self, additions): + caseroot = self._get_caseroot() + append_to_user_nl_files(caseroot=caseroot, component="clm", contents=additions) + + # Is flanduse_timeseries defined? If so, where is it? + def _get_flanduse_timeseries_in(self, case): + case.create_namelists(component="lnd") + self._lnd_in_path = os.path.join(self._path_gddgen, "CaseDocs", "lnd_in") + self._flanduse_timeseries_in = None + with open(self._lnd_in_path, "r") as lnd_in: + for line in lnd_in: + flanduse_timeseries_in = re.match(r" *flanduse_timeseries *= *'(.*)'", line) + if flanduse_timeseries_in: + self._flanduse_timeseries_in = flanduse_timeseries_in.group(1) + break diff --git a/cime_config/SystemTests/systemtest_utils.py b/cime_config/SystemTests/systemtest_utils.py new file mode 100644 index 0000000000..c5ac986abd --- /dev/null +++ b/cime_config/SystemTests/systemtest_utils.py @@ -0,0 +1,86 @@ +""" +Reduce code duplication by putting reused functions here. +""" + +import os, subprocess + + +def cmds_to_setup_conda(caseroot): + # Add specific commands needed on different machines to get conda available + # Use semicolon here since it's OK to fail + # + conda_setup_commands = ". " + caseroot + "/.env_mach_specific.sh; " + # Setting CONDA_PREFIX to empty ensures that this works even if called from + # a shell with a conda environment activated + conda_setup_commands += "CONDA_PREFIX=; " + # Execute the module unload/load when "which conda" fails + # eg on cheyenne + try: + subprocess.run("which conda", shell=True, check=True) + except subprocess.CalledProcessError: + # Remove python and add conda to environment for cheyennne + unload_python_load_conda = "module unload python; module load conda;" + # Make sure that adding this actually loads conda + subprocess.run(unload_python_load_conda + "which conda", shell=True, check=True) + # Save + conda_setup_commands += " " + unload_python_load_conda + + return conda_setup_commands + + +def cmds_to_run_via_conda(caseroot, conda_run_call, command): + # Run in the specified conda environment + conda_setup_commands = cmds_to_setup_conda(caseroot) + conda_setup_commands += " " + conda_run_call + + # Finish with Python script call + command = conda_setup_commands + " " + command + print(f"command: {command}") + + return command + + +def run_python_script(caseroot, this_conda_env, command_in, tool_path): + + # First, try with "conda run -n" + command = cmds_to_run_via_conda(caseroot, f"conda run -n {this_conda_env}", command_in) + + # Run with logfile + tool_name = os.path.split(tool_path)[-1] + try: + with open(tool_name + ".log", "w") as f: + subprocess.run( + command, shell=True, check=True, text=True, stdout=f, stderr=subprocess.STDOUT + ) + except subprocess.CalledProcessError as error: + # Retry with the original "conda activate" method + command = cmds_to_run_via_conda( + caseroot, + f"conda activate {this_conda_env} && ", + command_in, + ) + try: + with open(tool_name + ".log2", "w") as f: + subprocess.run( + command, shell=True, check=True, text=True, stdout=f, stderr=subprocess.STDOUT + ) + except subprocess.CalledProcessError as error: + print("ERROR while getting the conda environment and/or ") + print(f"running the {tool_name} tool: ") + print(f"(1) If your {this_conda_env} environment is out of date or you ") + print(f"have not created the {this_conda_env} environment, yet, you may ") + print("get past this error by running ./py_env_create ") + print("in your ctsm directory and trying this test again. ") + print("(2) If conda is not available, install and load conda, ") + print("run ./py_env_create, and then try this test again. ") + print("(3) If (1) and (2) are not the issue, then you may be ") + print(f"getting an error within {tool_name} itself. ") + print("Default error message: ") + print(error.output) + raise + except: + print(f"ERROR trying to run {tool_name}.") + raise + except: + print(f"ERROR trying to run {tool_name}.") + raise diff --git a/cime_config/config_compsets.xml b/cime_config/config_compsets.xml index 61931c94ba..aaa5c68394 100644 --- a/cime_config/config_compsets.xml +++ b/cime_config/config_compsets.xml @@ -205,6 +205,10 @@ I2000Clm45BgcCropQianRs 2000_DATM%QIA_CLM45%BGC-CROP_SICE_SOCN_SROF_SGLC_SWAV + + I2000Clm50FatesQian + 2000_DATM%QIA_CLM50%FATES_SICE_SOCN_MOSART_SGLC_SWAV + I2000Clm50BgcCruRs diff --git a/cime_config/config_tests.xml b/cime_config/config_tests.xml index 0307ee7ef5..536f79aeec 100644 --- a/cime_config/config_tests.xml +++ b/cime_config/config_tests.xml @@ -113,6 +113,16 @@ This defines various CTSM-specific system tests $STOP_N + + Generate prescribed maturity requirements, then test with them + 1 + FALSE + FALSE + never + $STOP_OPTION + $STOP_N + + - FAIL @@ -44,6 +43,20 @@ + + + FAIL + #1733 + + + + + + FAIL + #1733 + + + diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index b887e570f6..6cef2f35f1 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -17,6 +17,15 @@ + + + + + + + + + @@ -133,16 +142,6 @@ - - - - - - - - - - @@ -168,40 +167,40 @@ - + - + - - + + - + - - + + - + - + - + - + - + @@ -489,15 +488,6 @@ - - - - - - - - - @@ -630,16 +620,6 @@ - - - - - - - - - - @@ -968,16 +948,6 @@ - - - - - - - - - - @@ -1037,7 +1007,7 @@ - + @@ -1175,31 +1145,53 @@ - + - + - + + + + + + + + + + - + - + + + + + - - + + + + + + + + + + + @@ -1456,16 +1448,6 @@ - - - - - - - - - - @@ -1492,15 +1474,6 @@ - - - - - - - - - @@ -1539,16 +1512,6 @@ - - - - - - - - - - @@ -1621,17 +1584,6 @@ - - - - - - - - - - - @@ -1963,15 +1915,6 @@ - - - - - - - - - @@ -2381,17 +2324,16 @@ - @@ -2647,4 +2589,15 @@ + + + + + + + + + + + diff --git a/cime_config/testdefs/testmods_dirs/clm/ExcessIceStartup_output_sp_exice/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/ExcessIceStartup_output_sp_exice/include_user_mods new file mode 100644 index 0000000000..6d8de3732a --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/ExcessIceStartup_output_sp_exice/include_user_mods @@ -0,0 +1,2 @@ +../monthly +../../../../usermods_dirs/output_sp_exice diff --git a/cime_config/testdefs/testmods_dirs/clm/ExcessIceStartup_output_sp_exice/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/ExcessIceStartup_output_sp_exice/user_nl_clm new file mode 100644 index 0000000000..e479af9449 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/ExcessIceStartup_output_sp_exice/user_nl_clm @@ -0,0 +1,3 @@ + use_excess_ice = .true. + finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.I1850Clm50Sp.0003-01-01.0.9x1.25_gx1v7_exice_simyr1850_c221205.nc' + use_init_interp = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/ExcessIceStreams/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/ExcessIceStreams/include_user_mods new file mode 100644 index 0000000000..fe0e18cf88 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/ExcessIceStreams/include_user_mods @@ -0,0 +1 @@ +../default diff --git a/cime_config/testdefs/testmods_dirs/clm/ExcessIceStreams/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/ExcessIceStreams/user_nl_clm new file mode 100644 index 0000000000..f61ca32a79 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/ExcessIceStreams/user_nl_clm @@ -0,0 +1,2 @@ + use_excess_ice = .true. + use_excess_ice_streams = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdCH4Off/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdCH4Off/user_nl_clm index 4d7617fed4..9f977ac5ce 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdCH4Off/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdCH4Off/user_nl_clm @@ -1,2 +1,2 @@ use_lch4 = .false. -hist_master_list_file = .true. +hist_fields_list_file = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdSatPhen_prescribed/README b/cime_config/testdefs/testmods_dirs/clm/FatesColdSatPhen_prescribed/README deleted file mode 100644 index a1c8f04632..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdSatPhen_prescribed/README +++ /dev/null @@ -1,3 +0,0 @@ -This testmod currently does NOT work, because of issue #1722 - -See https://github.com/ESCOMP/CTSM/issues/1722 diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdSatPhen_prescribed/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdSatPhen_prescribed/include_user_mods index d111d05911..33ca1de12e 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdSatPhen_prescribed/include_user_mods +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdSatPhen_prescribed/include_user_mods @@ -1,2 +1 @@ ../FatesColdSatPhen -../prescribed diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdSatPhen_prescribed/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdSatPhen_prescribed/user_nl_clm new file mode 100644 index 0000000000..59a4137be7 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdSatPhen_prescribed/user_nl_clm @@ -0,0 +1,3 @@ +use_lai_streams = .true. +lai_tintalgo = 'lower' ! set time interpolation to use lower value, so can compare more directly to input dataset + \ No newline at end of file diff --git a/cime_config/testdefs/testmods_dirs/clm/Meier2022_surf_rough/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/Meier2022_surf_rough/include_user_mods new file mode 100644 index 0000000000..fe0e18cf88 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Meier2022_surf_rough/include_user_mods @@ -0,0 +1 @@ +../default diff --git a/cime_config/testdefs/testmods_dirs/clm/Meier2022_surf_rough/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Meier2022_surf_rough/user_nl_clm new file mode 100644 index 0000000000..01df79ecba --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Meier2022_surf_rough/user_nl_clm @@ -0,0 +1,4 @@ +z0param_method = 'Meier2022' +use_z0m_snowmelt = .true. +paramfile = '$DIN_LOC_ROOT/lnd/clm2/paramdata/ctsm51_params.RMz0.c220304.nc' + diff --git a/cime_config/testdefs/testmods_dirs/clm/SaveHistFieldList/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/SaveHistFieldList/user_nl_clm new file mode 100644 index 0000000000..4791cd28b2 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/SaveHistFieldList/user_nl_clm @@ -0,0 +1 @@ +hist_fields_list_file = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/crop/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/crop/user_nl_clm index 4add705be3..dc22a973b2 100644 --- a/cime_config/testdefs/testmods_dirs/clm/crop/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/crop/user_nl_clm @@ -7,3 +7,11 @@ ! This is in the crop testmods because this field is mainly useful in transient crop runs ! This is on history tape 2 because this field is not meaningful at the gridcell level hist_fincl2 += 'DYN_COL_SOIL_ADJUSTMENTS_C' + + +! Annual crop variables on per-sowing/per-harvest axes, per PFT. +hist_fincl3 = 'SDATES', 'SDATES_PERHARV', 'SYEARS_PERHARV', 'HDATES', 'GRAINC_TO_FOOD_PERHARV', 'GRAINC_TO_FOOD_ANN', 'HDATES', 'GDDHARV_PERHARV', 'GDDACCUM_PERHARV', 'HUI_PERHARV', 'SOWING_REASON_PERHARV', 'HARVEST_REASON_PERHARV' +hist_nhtfrq(3) = 17520 +hist_mfilt(3) = 1 +hist_type1d_pertape(3) = 'PFTS' +hist_dov2xy(3) = .false. diff --git a/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm index dfe718a7b4..ae4284da6b 100644 --- a/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm @@ -1,6 +1,2 @@ - hist_nhtfrq = 0,-240,-8760 + hist_nhtfrq = 0,-240,17520 hist_mfilt = 1,1,1 - - ! Add an annual output file with these crop-specific variables, which exercise some special logic: - hist_fincl3 = 'SDATES', 'HDATES' - hist_dov2xy(3) = .false. diff --git a/cime_config/testdefs/testmods_dirs/clm/datm_bias_correct_cruv7/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/datm_bias_correct_cruv7/user_nl_clm deleted file mode 100644 index c7cfe279ee..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/datm_bias_correct_cruv7/user_nl_clm +++ /dev/null @@ -1 +0,0 @@ -use_lai_streams = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/extra_outputs/README b/cime_config/testdefs/testmods_dirs/clm/extra_outputs/README index 03bc956b6f..574d7cc204 100644 --- a/cime_config/testdefs/testmods_dirs/clm/extra_outputs/README +++ b/cime_config/testdefs/testmods_dirs/clm/extra_outputs/README @@ -1,4 +1,4 @@ This test mod turns on extra diagnostic fields -It also outputs an optional text file containing a table of the -history fields master list +It also outputs an optional text file containing a table of all +the possible history fields diff --git a/cime_config/testdefs/testmods_dirs/clm/extra_outputs/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/extra_outputs/user_nl_clm index 6dc5225f1d..dad8a7e843 100644 --- a/cime_config/testdefs/testmods_dirs/clm/extra_outputs/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/extra_outputs/user_nl_clm @@ -1,5 +1,5 @@ calc_human_stress_indices = 'ALL' -hist_master_list_file = .true. +hist_fields_list_file = .true. hist_fincl1 += 'GSSUN:L43200', 'GSSHA:L43200', 'FSDSND:L43200', 'FSRND:L43200', 'FSRSFND:L43200', 'SSRE_FSRND:L43200', 'FSDSVD:L43200', 'FSDSVI:L43200', diff --git a/cime_config/usermods_dirs/newton_krylov_spinup/user_nl_clm b/cime_config/usermods_dirs/newton_krylov_spinup/user_nl_clm index 318105a043..75513be601 100644 --- a/cime_config/usermods_dirs/newton_krylov_spinup/user_nl_clm +++ b/cime_config/usermods_dirs/newton_krylov_spinup/user_nl_clm @@ -1,8 +1,8 @@ hist_dov2xy = .true.,.false. hist_nhtfrq = 0,-175200 hist_mfilt = 1,1 -hist_fincl2 = 'FPI_vr', 'K_PAS_SOM', 'K_SLO_SOM', 'K_ACT_SOM', - 'K_CWD', 'K_CEL_LIT', 'K_LIG_LIT', 'K_MET_LIT', +hist_fincl2 = 'FPI_vr', 'K_SOM_PAS', 'K_SOM_SLO', 'K_SOM_ACT', + 'K_CWD', 'K_LIT_CEL', 'K_LIT_LIG', 'K_LIT_MET', 'CWD_PATHFRAC_L2_vr', 'CWD_RESP_FRAC_L2_vr', 'CWD_PATHFRAC_L3_vr', 'CWD_RESP_FRAC_L3_vr', 'L1_PATHFRAC_S1_vr', 'L1_RESP_FRAC_S1_vr', diff --git a/cime_config/usermods_dirs/output_bgc/user_nl_clm b/cime_config/usermods_dirs/output_bgc/user_nl_clm index f7aaa09911..a7c5d098db 100644 --- a/cime_config/usermods_dirs/output_bgc/user_nl_clm +++ b/cime_config/usermods_dirs/output_bgc/user_nl_clm @@ -3,8 +3,8 @@ !---------------------------------------------------------------------------------- ! h0 stream (monthly average, gridcell-level) -hist_fexcl1 += 'ACT_SOMC_vr', 'ACT_SOMN_vr', 'SLO_SOMC_vr', 'SLO_SOMN_vr', 'PAS_SOMC_vr', 'PAS_SOMN_vr', 'SOILC_vr','SOILN_vr', 'CWDC_vr', 'MET_LITC_vr', 'CEL_LITC_vr', 'LIG_LITC_vr', 'MET_LITN_vr', 'CEL_LITN_vr', 'LIG_LITN_vr', 'CWDN_vr', 'SMIN_NO3_vr', 'CONC_O2_UNSAT', 'CONC_O2_SAT','SMIN_NH4_vr','SMINN_vr' -hist_fincl1 += 'LEAFC_TO_LITTER', 'FROOTC_TO_LITTER','MET_LITC_TO_ACT_SOMC','MET_LITN_TO_ACT_SOMN','CEL_LITC_TO_ACT_SOMC', 'CEL_LITN_TO_ACT_SOMN','LIG_LITC_TO_SLO_SOMC','LIG_LITN_TO_SLO_SOMN','DWT_WOOD_PRODUCTC_GAIN_PATCH' +hist_fexcl1 += 'SOM_ACT_C_vr', 'SOM_ACT_N_vr', 'SOM_SLO_C_vr', 'SOM_SLO_N_vr', 'SOM_PAS_C_vr', 'SOM_PAS_N_vr', 'SOILC_vr','SOILN_vr', 'CWD_C_vr', 'LIT_MET_C_vr', 'LIT_CEL_C_vr', 'LIT_LIG_C_vr', 'LIT_MET_N_vr', 'LIT_CEL_N_vr', 'LIT_LIG_N_vr', 'CWD_N_vr', 'SMIN_NO3_vr', 'CONC_O2_UNSAT', 'CONC_O2_SAT','SMIN_NH4_vr','SMINN_vr' +hist_fincl1 += 'LEAFC_TO_LITTER', 'FROOTC_TO_LITTER','LIT_MET_C_TO_SOM_ACT_C','LIT_MET_N_TO_SOM_ACT_N','LIT_CEL_C_TO_SOM_ACT_C', 'LIT_CEL_N_TO_SOM_ACT_N','LIT_LIG_C_TO_SOM_SLO_C','LIT_LIG_N_TO_SOM_SLO_N','DWT_WOOD_PRODUCTC_GAIN_PATCH' ! h1 stream (monthly average, finest sub-grid) hist_fincl2 += 'GPP', 'NPP', 'AGNPP', 'TOTVEGC', 'NPP_NUPTAKE', 'AR', 'HR', 'HTOP' @@ -14,7 +14,7 @@ hist_fincl2 += 'GPP', 'NPP', 'AGNPP', 'TOTVEGC', 'NPP_NUPTAKE', 'AR', 'HR', 'HTO hist_fincl3 += 'GPP', 'NPP', 'AR', 'HR', 'DWT_CONV_CFLUX_PATCH', 'WOOD_HARVESTC', 'DWT_WOOD_PRODUCTC_GAIN_PATCH', 'SLASH_HARVESTC', 'COL_FIRE_CLOSS', 'FROOTC:I', 'HTOP' ! h3 stream (yearly average, gridcell-level) -hist_fincl4 += 'SOILC_vr', 'SOILN_vr', 'CWDC_vr', 'MET_LITC_vr', 'CEL_LITC_vr', 'LIG_LITC_vr', 'MET_LITN_vr', 'CEL_LITN_vr', 'LIG_LITN_vr','CWDN_vr', 'TOTLITC:I', 'TOT_WOODPRODC:I', 'TOTSOMC:I','TOTVEGC:I' +hist_fincl4 += 'SOILC_vr', 'SOILN_vr', 'CWD_C_vr', 'LIT_MET_C_vr', 'LIT_CEL_C_vr', 'LIT_LIG_C_vr', 'LIT_MET_N_vr', 'LIT_CEL_N_vr', 'LIT_LIG_N_vr','CWD_N_vr', 'TOTLITC:I', 'TOT_WOODPRODC:I', 'TOTSOMC:I','TOTVEGC:I' ! h4 stream (yearly average, landunit-level) hist_fincl5 += 'TOTSOMC:I', 'TOTSOMC_1m:I', 'TOTECOSYSC:I', 'TOTVEGC:I', 'WOODC:I', 'TOTLITC:I', 'LIVECROOTC:I', 'DEADCROOTC:I', 'FROOTC:I' diff --git a/cime_config/usermods_dirs/output_sp_exice/include_user_mods b/cime_config/usermods_dirs/output_sp_exice/include_user_mods new file mode 100644 index 0000000000..786fa907a9 --- /dev/null +++ b/cime_config/usermods_dirs/output_sp_exice/include_user_mods @@ -0,0 +1,2 @@ +../_includes/output_base +../output_sp diff --git a/cime_config/usermods_dirs/output_sp_exice/user_nl_clm b/cime_config/usermods_dirs/output_sp_exice/user_nl_clm new file mode 100644 index 0000000000..48e680df67 --- /dev/null +++ b/cime_config/usermods_dirs/output_sp_exice/user_nl_clm @@ -0,0 +1,8 @@ +!---------------------------------------------------------------------------------- +! Settings from output_sp_exice +!---------------------------------------------------------------------------------- + +! h3 stream (yearly average, gridcell-level) +! Eyr +hist_fincl4 += 'EXCESS_ICE' + diff --git a/doc/.ChangeLog_template b/doc/.ChangeLog_template index 63f4628bad..9f4f64c587 100644 --- a/doc/.ChangeLog_template +++ b/doc/.ChangeLog_template @@ -33,13 +33,8 @@ Bugs fixed or introduced CTSM issues fixed (include CTSM Issue #): -Externals issues fixed (include issue #): - Known bugs introduced in this tag (include issue #): -Known bugs found since the previous tag (include issue #): - - Notes of particular relevance for users --------------------------------------- [Remove any lines that don't apply. Remove entire section if nothing applies.] @@ -150,7 +145,9 @@ Changes answers relative to baseline: - nature of change (roundoff; larger than roundoff/same climate; new climate): If bitwise differences were observed, how did you show they were no worse - than roundoff? + than roundoff? Roundoff differences means one or more lines of code change results + only by roundoff level (because order of operation changes for example). Roundoff + changes to state fields usually grow to greater than roundoff as the simulation progresses. If this tag changes climate describe the run(s) done to evaluate the new climate (put details of the simulations in the experiment database) diff --git a/doc/ChangeLog b/doc/ChangeLog index 2651e0d2a0..8e8a99b868 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,976 @@ +=============================================================== +Tag name: ctsm5.1.dev142 +Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) +Date: Tue Sep 19 11:30:22 MDT 2023 +One-line Summary: Merge 5 bit-for-bit pull requests + +Purpose and description of changes +---------------------------------- + +Merge 5 bit-for-bit pull requests; see "Other details." + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed or introduced +------------------------ +CTSM issues fixed (include CTSM Issue #): +* Add unit test for making fsurdat with all crops everywhere (#2079) +* Rework master_list_(no)?fates.rst? (#2083) +* conda run -n can fail if a conda environment is already active (#2109) +* conda fails to load for SystemTests (#2111) + + +Notes of particular relevance for developers: +--------------------------------------------- +Changes to tests or testing: +* FSURDATMODIFYCTSM system test should now work for everyone. + + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + cheyenne - PASS + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + cheyenne - PASS + clm_pymods test suite on cheyenne - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + cheyenne ---- OK + izumi ------- OK + + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +* Add system and unit tests for making fsurdat with all crops everywhere (#2081) +* Rework master_list* files etc. (#2087) +* Fixes to methane Tech Note (#2091) +* Add is_doy_in_interval() function (#2158) +* Avoid using subprocess.run() in FSURDATMODIFYCTSM (#2125) + +=============================================================== +=============================================================== +Tag name: ctsm5.1.dev141 +Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310) +Date: Wed Sep 13 13:58:04 MDT 2023 +One-line Summary: Change small snocan to zero + +Purpose and description of changes +---------------------------------- + + Issues #2041 and #2048 discuss and resolve a test failure in the ctsm5.2 + branch. The failure goes away when we reset small snocan to zero. + + Bill Sacks recommended merging this change in ctsm5.1 and then updating + the ctsm5.2 branch to the latest ctsm5.1. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed or introduced +------------------------ +CTSM issues fixed (include CTSM Issue #): + Fixes #2041 + Fixes #2048 + + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + cheyenne ---- OK + izumi ------- OK + + +Answer changes +-------------- + +Changes answers relative to baseline: + Yes + + Summarize any changes to answers, i.e., + - what code configurations: All + - what platforms/compilers: All + - nature of change: roundoff + + The answer changes are expected to be roundoff-level because the code change + just truncates roundoff-level greater-than-zero states to exactly zero for + snocan that most likely needed to be zero anyway. + + The answer changes grow to greater than roundoff, but the + cprnc.out file from a 20-year izumi test-suite case does not contain + differences of concerning magnitude. + +Other details +------------- +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/2053 + +=============================================================== +=============================================================== +Tag name: ctsm5.1.dev140 +Originator(s): afoster (Adrianna Foster) +Date: Tue Sep 12 14:47:06 MDT 2023 +One-line Summary: add lai_streams capability for FATES + +Purpose and description of changes +---------------------------------- + +Removed checks in clm_driver and CLMBuildNamelist.pm so that now FATES can run when use_lai_streams=.true. + +I also had to modify the init in cpl/share_esmf/laiStreamMod to allocate the g_to_ig array in the lai_init method (rather than in the lai_advance method. This was required because SatellitePhenology is called in clim_initializedMod in FATES cases (here). This happens before lai_advance is ever called so at that point the g_to_ig array was not yet allocated. Moving the allocation/initialization to the lai_init method fixes this. + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + +Bugs fixed or introduced +------------------------ + +CTSM issues fixed (include CTSM Issue #): #1722 - Should be able to use lai streams with FATES-SP mode + +Notes of particular relevance for developers: +--------------------------------------------- + +build-namelist tests (if CLMBuildNamelist.pm has changed): added tests to make sure use_lai_streams failed correctly + +Changes to tests or testing: Added a test for lai_streams with FATES + +Testing summary: +---------------- + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + cheyenne ---- OK + izumi ------- OK + + fates tests: (give name of baseline if different from CTSM tagname, normally fates baselines are fates--) + cheyenne ---- OK + izumi ------- OK + + +Answer changes +-------------- + +Changes answers relative to baseline: None + +Other details +------------- + +List any externals directories updated (cime, rtm, mosart, cism, fates, etc.): fates + +Pull Requests that document the changes (include PR ids): #2054 +(https://github.com/ESCOMP/ctsm/pull) + +=============================================================== +=============================================================== +Tag name: ctsm5.1.dev139 +Originator(s): slevis (Samuel Levis) +Date: Fri Aug 25 16:47:45 MDT 2023 +One-line Summary: Fix problems uncovered by nag -nan tests + +Purpose and description of changes +---------------------------------- + + Fix problems uncovered by adding the -nan compilation flag for the Nag + compiler. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed or introduced +------------------------ +CTSM issues fixed (include CTSM Issue #): + Makes progress on issue #1994 (same title) + + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + cheyenne ---- OK + izumi ------- PASS + + +Answer changes +-------------- + +Changes answers relative to baseline: No + + +Other details +------------- +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/2051 + +=============================================================== +=============================================================== +Tag name: ctsm5.1.dev138 +Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310) +Date: Fri Aug 25 14:44:22 MDT 2023 +One-line Summary: Refactor max_patch_per_col and maxsoil_patches loops + +Purpose and description of changes +---------------------------------- + +Refactor such loops for clearer and more efficient code, as recommended in +issue #2025. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed or introduced +------------------------ +CTSM issues fixed (include CTSM Issue #): +Fixes #2025 "Refactor loops that use max_patch_per_col?" + +Testing summary: +---------------- + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + cheyenne ---- OK + izumi ------- OK + +Answer changes +-------------- +Changes answers relative to baseline: No + + +Other details +------------- +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/2056 + +=============================================================== +=============================================================== +Tag name: ctsm5.1.dev137 +Originator(s): Ronny Meier, slevis (Samuel Levis,UCAR/TSS,303-665-1310) +Date: Tue Aug 22 14:34:53 MDT 2023 +One-line Summary: Surface roughness modifications + +Purpose and description of changes +---------------------------------- + +Surface roughness (z0) modifications that appear in this publication: +https://doi.org/10.5194/gmd-15-2365-2022 + +When changing the namelist input z0param_method from ZengWang2007 (default) +to Meier2022 the following modifications are activated: + +- A new parameterization of the vegetation surface roughness based on +Raupach (1992) with optimized parameters to match the data collected in +Hu et al. (2020) for different types of vegetation. This requires several new +PFT-specific input parameters in the parameter file. +- A spatially explicit z0m input field for bare soil based on the data of +Prigent et al. (2005). This may be activated specifically by the user through +the namelist input use_z0mg_2d. This requires a new input variable in the +fsurdat file. +- The parameterization of z0m for snow based on accumulated snow melt as +proposed in Brock et al. (2006). This may be activated specifically by the +user through the namelist input use_z0m_snowmelt. +- The parameterization of Yang et al. (2008) for z0h and z0q over bare soil, +snow, and glaciers. +- The study in GMD also proposes new globally constant values for the +z0m of bare soil, snow, and ice. To "activate" those the parameter file needs +to be changed at the moment. The original and modified parameter files and +fsurdat files will be shared by ftp. + +Open issues/questions (discussed with @ekluzek, @dlawrenncar, @olyson): + +- How to incorporate the data of Prigent et al. (2005) in the surfdata +generation. I will write an email about this to Catherine Prigent. +- One statement marked in CanopyFluxesMod should probably be changed when +using Meier2022 (i.e., Yang et al. (2008) formulation should be used instead +of Zeng and Dickinson (1998)). +- At the moment one needs to change the parameter file to switch between the +original and proposed globally constant z0m values for bare soil, snow, and +ice. This is obviously not very user friendly and prone to mistakes. +- The introduction of Yang et al. (2008) frequently results in z0h and z0q +larger than z0m. This is only rarely observed in the field and in contradiction +to the theory that z0h and z0q should be smaller because heat and water vapor +need to be transported through molecular diffusion in the surface sublayer. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed or introduced +------------------------ +CTSM issues fixed (include CTSM Issue #): +Fixes #1316 +Fixes #1596 + +Notes of particular relevance for users +--------------------------------------- +Details already discussed in the description above. + +Notes of particular relevance for developers: +--------------------------------------------- +Changes to tests or testing: +New tests are in place for this new code. + +Testing summary: +---------------- + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + cheyenne ---- OK + izumi ------- OK + +Answer changes +-------------- +Changes answers relative to baseline: + No, unless user chooses to run in non-default Meier2022 mode. + +Other details +------------- +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/2045 + +=============================================================== +=============================================================== +Tag name: ctsm5.1.dev136 +Originator(s): jedwards (Jim Edwards), sacks (Bill Sacks) +Date: Tue Aug 22 13:10:28 MDT 2023 +One-line Summary: Change order of history fields to improve performance on derecho + +Purpose and description of changes +---------------------------------- + +Instead of just ordering history fields alphabetically, order them first +by the name of their level dimension (with fields without a level +dimension appearing first), then alphabetically within a given level +dimension. This changed ordering gives a significant performance +improvement especially noticeable on lustre file systems such as on +derecho. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Notes of particular relevance for users +--------------------------------------- +Caveats for users (e.g., need to interpolate initial conditions): +- History fields will now appear in a different order from tools like + ncdump, etc. + +Testing summary: +---------------- + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + cheyenne ---- OK + izumi ------- OK + + In addition to expected fails, the test + FSURDATMODIFYCTSM_D_Mmpi-serial_Ld1.5x5_amazon.I2000Clm50SpRs.cheyenne_intel + also failed as in https://github.com/ESCOMP/CTSM/issues/2111 + +Answer changes +-------------- + +Changes answers relative to baseline: NO + +Other details +------------- +Pull Requests that document the changes (include PR ids): +https://github.com/ESCOMP/CTSM/pull/2114 + +=============================================================== +=============================================================== +Tag name: ctsm5.1.dev135 +Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310) +Date: Mon Aug 21 15:06:35 MDT 2023 +One-line Summary: Rename hist fields to track them down more easily + +Purpose and description of changes +---------------------------------- + + Renaming history fields to make easier to find in lists, e.g. when + using ncview. For example, litter fields like MET_LIT and STR_LIT + will be LIT_MET and LIT_STR. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed or introduced +------------------------ +CTSM issues fixed (include CTSM Issue #): + Fixes #2095 + + +Testing summary: +---------------- +[Remove any lines that don't apply.] + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + cheyenne ---- OK + izumi ------- OK + + any other testing (give details below): + Sam L. ran the LMWG diag. pkg and found only one plot affected by this + PR's changes. In particular, set 6 CWD_C, which was CWDC + + +Answer changes +-------------- + +Changes answers relative to baseline: + No. Field lists differ. In some tests, the namelists differ. + + +Other details +------------- +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/2106 + +=============================================================== +=============================================================== +Tag name: ctsm5.1.dev134 +Originator(s): rgknox (Ryan Knox,LBNL EESA), erik (Erik Kluzek,UCAR/TSS,303-497-1326) +Date: Wed Aug 16 17:20:27 MDT 2023 +One-line Summary: Migration of FATES to share normal soil BGC call sequence and functionality + +Purpose and description of changes +---------------------------------- + +This set of changes enables the normal soil biogeochemistry that is used for CN, to be used for FATES as well. FATES had been using a simplified subset of soil biogeochemistry in its own module. This change required coordination of litter flux and methane boundary conditions from FATES to CLM. CNVEG datastructures were given trivial allocation (of size one on index zero) to prevent inappropriate use of CNVEG datastructures while FATES is active. Note that now the carbon balance checking for the soil is now active when FATES is active. Various accomodations have also been put in place to enable nitrogen cycling between the two models. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed or introduced +------------------------ +Surprisingly, nvhpc tests are now working, but it may just be coincidental. All existing aux_clm tests are passing. Tests without FATES are b4b, with roundoff differences in just TOTCOLC and TOTCOLN. + +CTSM issues fixed (include CTSM Issue #): + We think #1879 -- "AD spinup issues for FATES", is fixed but haven't proved it + #2112 -- black check on SystemTest file + +Notes of particular relevance for users +--------------------------------------- +A CLM-FATES simulation will turn on nitrogen supplementation, this enables sufficient immobilization and decomposition. Until FATES and CLM can handle fully coupled nitrogen exchange, which would include root uptake of the mineralized aqueous forms (NH4 and NO3), N limitations in the soil are meaningless when FATES is on. + +Caveats for users (e.g., need to interpolate initial conditions): + FATES MUST have suplnitro='ALL' now (was NONE). When fates_parteh_mode>=1 other settings are allowed. + More checking for use_luna and suplnitro is added for FATES in the build-namelist + +Changes made to namelist defaults (e.g., changed parameter values): FATES runs now supplement N + suplnitro set to ALL for FATES + use_luna set to .false. for FATES and clm4_5 physics + +Notes of particular relevance for developers: +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + We should update defaults for suplnitro, when Nitrogen nutrients are allowed in FATES + The black checdk github action has to duplicate actions for each source file or directory + We should move to using the Makefile in the python directory when we figure it out + +Testing summary: +---------------- + +aux_clm test run on cheyenne and izumi. See: + +izumi: OK /scratch/cluster/rgknox/tests_0814-095624iz +cheyenne: OK /glade/scratch/rgknox/tests_0814-134713ch + + +Answer changes +-------------- + +Changes answers relative to baseline: Two diganostic fields (TOTCOLC and TOTCOLN) + +Baseline changes will be reported for many tests, all tests were combed to identify RMS diffs, all non-FATES tests had at most, roundoff level (-) + cheyenne ---- OK + izumi ------- OK + +If the tag used for baseline comparisons was NOT the previous tag, note that here: + + Note that the previous ctsm5.1.dev132 tag was generated using FATES tagname + sci.1.66.1_api.25.5.0. This api update includes intermediate FATES science + tags that are non-b4b, so aux_clm FATES tests result in DIFFs as expected. + +Answer changes +-------------- + +Changes answers relative to baseline: Yes, but only for aux_clm fates tests. + +Other details +------------- + +List any externals directories updated (cime, rtm, mosart, cism, fates, etc.): + + sci.1.66.1_api.25.5.0 -> sci.1.67.1_api.26.0.0 + ccs_config_cesm0.0.64 -> ccs_config_cesm0.0.65 + +Pull Requests that document the changes (include PR ids): +(https://github.com/ESCOMP/ctsm/pull) + + https://github.com/ESCOMP/CTSM/pull/2000 -- refactor + https://github.com/ESCOMP/CTSM/pull/2089 -- Change template update + https://github.com/NGEET/fates/pull/1024 -- FATES refactor + +=============================================================== +=============================================================== +Tag name: ctsm5.1.dev132 +Originator(s): mvdebolskiy (NORCE, Bergen, Norway), slevis (Samuel Levis,UCAR/TSS,303-665-1310) +Date: Fri Aug 4 17:52:45 MDT 2023 +One-line Summary: Add parameterization to allow excess ice in soil and subsidence + +Purpose and description of changes +---------------------------------- + +As described in PR #1787: + +Parameterization for excess ice described in Lee et al. (2014): +http://dx.doi.org/10.1088/1748-9326/9/12/124006 + +This code is a modified version of code provided by Lei Cai: +https://github.com/lca041/ctsm/tree/clm5.0.dev92_exice + +Works only for the nuopc driver. + +Files changed: +bld/CLMBuildNamelist.pm, bld/namelist_files/namelist_defaults_ctsm.xml, bld/namelist_files/namelist_definitionss_ctsm.xml -- added namelist options; +src/main/clm_varctl.F90, src/main/controlMod.F90 -- added option to switch excess ice physics and read namelist option; +src/biogeophys/WaterStateType.F90 -- added prognostic excess ice variable and a history field; +src/biogeophys/WaterStateBulkType.F90, src/main/clm_instMod.F90, -- added arguments to soubrutiens for proper initialization; +src/biogeophys/TemperatureType.F90 -- initial soil temperature set to 268.15 K at the cold start (possibly redundant because #1460 is closed) +src/biogeophys/WaterDiagnosticBulkType.F90 -- added two diagnostic excess ice variables and two history fields; +src/biogeophys/SoilTemperatureMod.F90 -- added main excess ice calculations; +src/biogeophys/TotalWaterAndHeatMod.F90 -- added excess ice to total water for balance checks; +src/biogeophys/SoilHydrologyMod.F90 -- added excess ice for ice fraction calculation; + +New files: +src/cpl/share_esmf/ExcessIceStreamType.F90 -- routines to read dataset with initial excess ice concentration + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed or introduced +------------------------ +CTSM issues fixed (include CTSM Issue #): + Fixes #1229 -- excess ice + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + Excess ice can EITHER be turned on by using the stream file, OR a restart file that has excess ice on it. + Since, excess ice is expected to melt as time goes on, the use of a restart file is preferred. + But, use of a restart file requires a simulation that was spun up to that point. + +Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): + New namelist options added: + - use_excess_ice (logical, in clm_inparm) default = .false.; turns on excess ice physics + - stream_meshfile_exice, stream_fldfilename_exice, stream_mapalgo_exice (char, in exice_streams) + meshfile, stream file, spatial interpolation algorithm for initial values of excess ice + defaults - lnd/clm2/paramdata/exice_init_0.125x0.125_ESMFmesh_c20220516.nc, + lnd/clm2/paramdata/exice_init_0.125x0.125_c20220516.nc + and bilinear + Dataset interpolated to 0.125x0.125 degrees grid from Brown et al. (1997) can be found here: + https://drive.google.com/file/d/1mA457Oa52zG_MtLGB7KHuUYQvsS2-P5o/view?usp=sharing + Dataset used only in cold start or hybrid runs (or starting with finidat) that do not have excess ice + + +Notes of particular relevance for developers: +--------------------------------------------- +Changes to tests or testing: + New tests in place for this new code + +Testing summary: +---------------- +[Remove any lines that don't apply.] + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + cheyenne - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + heyenne ---- OK + izumi ------- OK + + any other testing (give details below): + +If the tag used for baseline comparisons was NOT the previous tag, note that here: + + +Answer changes +-------------- + +Changes answers relative to baseline: No + + +Other details +------------- +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/1787 + +=============================================================== +=============================================================== +Tag name: ctsm5.1.dev131 +Originator(s): samrabin (Sam Rabin,UCAR/TSS) +Date: Thu Jul 27 14:24:07 MDT 2023 +One-line Summary: Enable prescribed crop calendars. + +Purpose and description of changes +---------------------------------- + +This branch enables CLM to read in externally-prescribed crop sowing dates and "cultivar" maturity requirements (growing +degree-days, GDDs). This has so far only been tested with static values, and the results indicate that yield performance is +worsened. However, this capability is required by the GGCMI phase 3 / ISIMIP3 Agriculture protocol. + +Briefly, the way this works is that an offline run is first performed with prescribed sowing dates and 364-day seasons. +Instantaneous GDD accumulation is saved daily. A Python script then cross-references those daily outputs with a map of mean sowing +dates to determine the mean accumulated GDDs in the growing season, saving the result as a file for use as prescribed maturity +requirements. + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + +Bugs fixed or introduced +------------------------ + +CTSM issues fixed (include CTSM Issue #): + Resolves #281 -- Clean up CropPhenology logic + Resolves #519 -- Read in crop planting and harvest dates + Fixes #2042 -- Issue running SystemTests due to "conda activate" error + + Some on #1649 -- Additional "annual" (per growing season) crop outputs + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users: + Untested but theoretically possible: + * Time-varying inputs + * Running at any resolution other than one matching the crop calendar inputs + +Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): + Adds optional namelist variables: + * stream_fldfilename_sdate: Filename of input stream data for sowing dates + * stream_fldfilename_cultivar_gdds: Filename of input stream data for cultivar growing degree-day targets + * stream_meshfile_cropcal: Filename of input stream data for crop calendar inputs + * stream_year_first_cropcal: First year to loop over for crop calendar data + * stream_year_last_cropcal: Last year to loop over for crop calendar data + * model_year_align_cropcal: Simulation year that aligns with stream_year_first_cropcal value + * generate_crop_gdds: Set to .true. in order to override crop harvesting logic and to instead harvest the day before the next sowing date. Used to generate growing-degree day outputs that can be used with an external script to generate new GDD requirement ("cultivar") files. + * use_mxmat: Set to .false. in order to ignore crop PFT parameter for maximum growing season length (mxmat). Must be set to .false. when generate_crop_gdds is .true. + +Notes of particular relevance for developers: +--------------------------------------------- + +Changes to tests or testing: + * Adds RXCROPMATURITY SystemTest, with an example added to ctsm_sci test suite. + * Removes 12 MCT tests from testlist_clm.xml, as discussed in CTSM SE standup 2023-06-26. + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + cheyenne - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + cheyenne ---- OK + izumi ------- OK + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + cheyenne - PASS + +Answer changes +-------------- + +Changes answers relative to baseline: YES for Clm45BgcCrop compsets only + + Summarize any changes to answers, i.e., + - what code configurations: Clm45BgcCrop + - what platforms/compilers: Cheyenne intel and gnu, Izumi intel and nag + - nature of change (roundoff; larger than roundoff/same climate; new climate): roundoff + + 5 tests in aux_clm showed true DIFFs (i.e., not just field list differences / new output files): + - SMS_D_Ly6_Mmpi-serial.1x1_smallvilleIA.IHistClm45BgcCropQianRs.izumi_intel.clm-cropMonthOutput + - ERP_D_P36x2_Ld3.f10_f10_mg37.I2000Clm45BgcCrop.cheyenne_gnu.clm-no_subgrid_fluxes + - LGRAIN2_Ly2_P72x1.f10_f10_mg37.I1850Clm45BgcCrop.cheyenne_gnu.clm-ciso--clm-cropMonthOutput + - ERS_Ly5_P72x1.f10_f10_mg37.IHistClm45BgcCrop.cheyenne_intel.clm-cropMonthOutput + - SMS_D_Ld1_P48x1.f10_f10_mg37.I2000Clm45BgcCrop.izumi_nag.clm-oldhyd + + The first four were likely due to an order-of-operations change in CNOffsetLitterfall(), as they resolve with the patch at + https://github.com/samsrabin/CTSM/commit/c30320cbd6583bccbcc290ffe536e8500e6ec358 + + The last is resolved with an additional patch that removes all my changes to CNOffsetLitterfall()---changes which *should* only + affect new diagnostic variables: + https://github.com/samsrabin/CTSM/commit/e025f555e74584c63d50f27c4df38326fa64bc4f + +Other details +------------- +List any externals directories updated (cime, rtm, mosart, cism, fates, etc.): cime + cime: cime6.0.108 -> cime6.0.125 + +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/CTSM/pull/1863 + +=============================================================== + =============================================================== Tag name: ctsm5.1.dev130 Originator(s): glemieux (Greg Lemieux,LBL/NGEET,510-486-5049) diff --git a/doc/ChangeSum b/doc/ChangeSum index a3f748b0d0..e11f439658 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,17 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.1.dev142 samrabin 09/19/2023 Merge 5 bit-for-bit pull requests + ctsm5.1.dev141 slevis 09/13/2023 Change small snocan to zero + ctsm5.1.dev140 afoster 09/12/2023 add lai_streams capability for FATES + ctsm5.1.dev139 slevis 08/28/2023 Fix problems uncovered by nag -nan tests + ctsm5.1.dev138 slevis 08/25/2023 Refactor max_patch_per_col and maxsoil_patches loops + ctsm5.1.dev137 slevis 08/23/2023 Surface roughness modifications + ctsm5.1.dev136 multiple 08/22/2023 Change order of history fields to improve performance on derecho + ctsm5.1.dev135 slevis 08/21/2023 Rename hist fields to track them down more easily + ctsm5.1.dev134 rgknox 08/16/2023 Migration of FATES to share normal soil BGC call sequence and functionality + ctsm5.1.dev133 glemieux 08/09/2023 FATES API update to facilitate fates refactor + ctsm5.1.dev132 slevis 08/04/2023 Add parameterization to allow excess ice in soil and subsidence + ctsm5.1.dev131 samrabin 07/27/2023 Enable prescribed crop calendars ctsm5.1.dev130 glemieux 07/09/2023 FATES parameter file and test definition update ctsm5.1.dev129 erik 06/22/2023 NEON fixes for TOOL and user-mods, add SP for NEON, some history file updates, black refactor for buildlib/buildnml ctsm5.1.dev128 glemieux 06/01/2023 Update FATES tests to double precision diff --git a/doc/README.CHECKLIST.master_tags b/doc/README.CHECKLIST.master_tags index 31c09895be..ed7794130b 100644 --- a/doc/README.CHECKLIST.master_tags +++ b/doc/README.CHECKLIST.master_tags @@ -55,6 +55,14 @@ https://github.com/ESCOMP/ctsm/wiki/CTSM-development-workflow ---- THE FOLLOWING CAN ONLY BE DONE BY INTEGRATORS ---- +NOTE (especially for new integrators): Be sure to follow the recommended +git setup in +. +Especially note that you should never use something like `git merge +escomp/master` to merge the upstream master branch into your local copy: +instead, you should always use `git pull` with the recommended +configuration settings (or `git merge --ff-only`) for that scenario. + (7) Merge the PR to master when review is approved (8) Compare master to branch show that they are identical @@ -65,7 +73,10 @@ This should show no diffs (9) Make an annotated tag on master -(10) Push master and tag to ESCOMP/ctsm +(10) Push tag to ESCOMP/ctsm + +(10a) Push to master (if needed because you changed something in master after PR was merged, or +if you did step 7 above using git commands that require this step) (11) Update the CTSM upcoming tags project, if necessary (https://github.com/ESCOMP/ctsm/projects/6) diff --git a/doc/source/tech_note/Methane/CLM50_Tech_Note_Methane.rst b/doc/source/tech_note/Methane/CLM50_Tech_Note_Methane.rst index 7c89f857e3..875689558b 100644 --- a/doc/source/tech_note/Methane/CLM50_Tech_Note_Methane.rst +++ b/doc/source/tech_note/Methane/CLM50_Tech_Note_Methane.rst @@ -66,7 +66,7 @@ phases:\ :math:`R = \epsilon _{a} +K_{H} \epsilon _{w}`, with porosity, and partitioning coefficient for the species of interest, respectively, and :math:`C` represents CH\ :sub:`4` or O\ :sub:`2` concentration with respect to water volume (mol m\ :sup:`-3`). -An analogous version of equation is concurrently solved for +An analogous version of equation :eq:`24.1` is concurrently solved for O\ :sub:`2`, but with the following differences relative to CH\ :sub:`4`: *P* = *E* = 0 (i.e., no production or ebullition), and the oxidation sink includes the O\ :sub:`2` demanded by @@ -74,7 +74,7 @@ methanotrophs, heterotroph decomposers, nitrifiers, and autotrophic root respiration. As currently implemented, each gridcell contains an inundated and a -non-inundated fraction. Therefore, equation is solved four times for +non-inundated fraction. Therefore, equation :eq:`24.1` is solved four times for each gridcell and time step: in the inundated and non-inundated fractions, and for CH\ :sub:`4` and O\ :sub:`2`. If desired, the CH\ :sub:`4` and O\ :sub:`2` mass balance equation is @@ -173,9 +173,9 @@ anoxic microsites above the water table, we apply the Arah and Stephen \varphi =\frac{1}{1+\eta C_{O_{2} } } . -Here, :math:`\phi` is the factor by which production is inhibited +Here, :math:`\varphi` is the factor by which production is inhibited above the water table (compared to production as calculated in equation -, :math:`C_{O_{2}}` (mol m\ :sup:`-3`) is the bulk soil oxygen +:eq:`24.2`, :math:`C_{O_{2}}` (mol m\ :sup:`-3`) is the bulk soil oxygen concentration, and :math:`\eta` = 400 mol m\ :sup:`-3`. The O\ :sub:`2` required to facilitate the vertically resolved @@ -259,8 +259,8 @@ aqueous CH\ :sub:`4` concentration, and *p* is pressure. The local pressure is calculated as the sum of the ambient pressure, water pressure down to the local depth, and pressure from surface ponding (if applicable). When the CH\ :sub:`4` partial pressure -exceeds 15% of the local pressure (Baird et al. 2004; Strack et al. -2006; Wania et al. 2010), bubbling occurs to remove CH\ :sub:`4` +exceeds 15% of the local pressure (:ref:`Baird et al. 2004`; :ref:`Strack et al. +2006`; :ref:`Wania et al. 2010`), bubbling occurs to remove CH\ :sub:`4` to below this value, modified by the fraction of CH\ :sub:`4` in the bubbles [taken as 57%; (:ref:`Kellner et al. 2006`; :ref:`Wania et al. 2010`)]. @@ -286,14 +286,14 @@ The diffusive transport through aerenchyma (*A*, mol m\ :sup:`-2` s\ :sup:`-1`) A=\frac{C\left(z\right)-C_{a} }{{\raise0.7ex\hbox{$ r_{L} z $}\!\mathord{\left/ {\vphantom {r_{L} z D}} \right. \kern-\nulldelimiterspace}\!\lower0.7ex\hbox{$ D $}} +r_{a} } pT\rho _{r} , -where *D* is the free-air gas diffusion coefficient (m:sup:`2` s\ :sup:`-1`); *C(z)* (mol m\ :sup:`-3`) is the gaseous +where *D* is the free-air gas diffusion coefficient (m\ :sup:`2` s\ :sup:`-1`); *C(z)* (mol m\ :sup:`-3`) is the gaseous concentration at depth *z* (m); :math:`r_{L}` is the ratio of root length to depth; *p* is the porosity (-); *T* is specific aerenchyma -area (m:sup:`2` m\ :sup:`-2`); :math:`{r}_{a}` is the +area (m\ :sup:`2` m\ :sup:`-2`); :math:`{r}_{a}` is the aerodynamic resistance between the surface and the atmospheric reference -height (s m:sup:`-1`); and :math:`\rho _{r}` is the rooting +height (s m\ :sup:`-1`); and :math:`\rho _{r}` is the rooting density as a function of depth (-). The gaseous concentration is -calculated with Henry’s law as described in equation . +calculated with Henry’s law as described in equation :eq:`24.7`. Based on the ranges reported in :ref:`Colmer (2003)`, we have chosen baseline aerenchyma porosity values of 0.3 for grass and crop PFTs and 0.1 for @@ -310,7 +310,7 @@ m\ :sup:`-2` s\ :sup:`-1`); *R* is the aerenchyma radius belowground fraction of annual NPP; and the 0.22 factor represents the amount of C per tiller. O\ :sub:`2` can also diffuse in from the atmosphere to the soil layer via the reverse of the same pathway, with -the same representation as Equation but with the gas diffusivity of +the same representation as Equation :eq:`24.8` but with the gas diffusivity of oxygen. CLM also simulates the direct emission of CH\ :sub:`4` from leaves @@ -358,7 +358,7 @@ potential and :math:`{P}_{c} = -2.4 \times {10}^{5}` mm. Reactive Transport Solution -------------------------------- -The solution to equation is solved in several sequential steps: resolve +The solution to equation :eq:`24.11` is solved in several sequential steps: resolve competition for CH\ :sub:`4` and O\ :sub:`2` (section :numref:`Competition for CH4and O2`); add the ebullition flux into the layer directly above the water @@ -416,7 +416,7 @@ Aqueous and Gaseous Diffusion For gaseous diffusion, we adopted the temperature dependence of molecular free-air diffusion coefficients (:math:`{D}_{0}` -(m:sup:`2` s\ :sup:`-1`)) as described by +(m\ :sup:`2` s\ :sup:`-1`)) as described by :ref:`Lerman (1979) ` and applied by :ref:`Wania et al. (2010)` (:numref:`Table Temperature dependence of aqueous and gaseous diffusion`). @@ -426,7 +426,7 @@ molecular free-air diffusion coefficients (:math:`{D}_{0}` .. table:: Temperature dependence of aqueous and gaseous diffusion coefficients for CH\ :sub:`4` and O\ :sub:`2` +----------------------------------------------------------+----------------------------------------------------------+--------------------------------------------------------+ - | :math:`{D}_{0}` (m\ :sup:`2` s\ :sup:`-1`) | CH\ :sub:`4` | O\ :sub:`2` | + | :math:`{D}_{0}` (cm\ :sup:`2` s\ :sup:`-1`) | CH\ :sub:`4` | O\ :sub:`2` | +==========================================================+==========================================================+========================================================+ | Aqueous | 0.9798 + 0.02986\ *T* + 0.0004381\ *T*\ :sup:`2` | 1.172+ 0.03443\ *T* + 0.0005048\ *T*\ :sup:`2` | +----------------------------------------------------------+----------------------------------------------------------+--------------------------------------------------------+ @@ -437,7 +437,7 @@ Gaseous diffusivity in soils also depends on the molecular diffusivity, soil structure, porosity, and organic matter content. :ref:`Moldrup et al. (2003)`, using observations across a range of unsaturated mineral soils, showed that the relationship between -effective diffusivity (:math:`D_{e}` (m:sup:`2` s\ :sup:`-1`)) and soil +effective diffusivity (:math:`D_{e}` (m\ :sup:`2` s\ :sup:`-1`)) and soil properties can be represented as: .. math:: @@ -457,8 +457,8 @@ measurements more closely in unsaturated peat soils: D_{e} =D_{0} \frac{\theta _{a} ^{{\raise0.7ex\hbox{$ 10 $}\!\mathord{\left/ {\vphantom {10 3}} \right. \kern-\nulldelimiterspace}\!\lower0.7ex\hbox{$ 3 $}} } }{\theta _{s} ^{2} } -In CLM, we applied equation for soils with zero organic matter content -and equation for soils with more than 130 kg m\ :sup:`-3` organic +In CLM, we applied equation :eq:`24.12` for soils with zero organic matter content +and equation :eq:`24.13` for soils with more than 130 kg m\ :sup:`-3` organic matter content. A linear interpolation between these two limits is applied for soils with SOM content below 130 kg m\ :sup:`-3`. For aqueous diffusion in the saturated part of the soil column, we applied @@ -518,10 +518,10 @@ a zero flux gradient at the bottom of the soil column. Crank-Nicholson Solution ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Equation is solved using a Crank-Nicholson solution -(:ref:`Press et al. 1992`), +Equation :eq:`24.1` is solved using a Crank-Nicholson solution +(:ref:`Press et al., 1992`), which combines fully explicit and implicit representations of the mass -balance. The fully explicit decomposition of equation can be written as +balance. The fully explicit decomposition of equation :eq:`24.1` can be written as .. math:: :label: 24.15 @@ -535,11 +535,11 @@ and :math:`S_{j}^{n}` is the net source at time step *n* and position *j*, i.e., :math:`S_{j}^{n} =P\left(j,n\right)-E\left(j,n\right)-A\left(j,n\right)-O\left(j,n\right)`. The diffusivity coefficients are calculated as harmonic means of values -from the adjacent cells. Equation is solved for gaseous and aqueous +from the adjacent cells. Equation :eq:`24.15` is solved for gaseous and aqueous concentrations above and below the water table, respectively. The *R* term ensure the total mass balance in both phases is properly accounted for. An analogous relationship can be generated for the fully implicit -case by replacing *n* by *n+1* on the *C* and *S* terms of equation . +case by replacing *n* by *n+1* on the *C* and *S* terms of equation :eq:`24.15`. Using an average of the fully implicit and fully explicit relationships gives: @@ -548,14 +548,14 @@ gives: \begin{array}{l} {-\frac{1}{2\Delta x_{j} } \frac{D_{m1}^{} }{\Delta x_{m1}^{} } C_{j-1}^{n+1} +\left[\frac{R_{j}^{n+1} }{\Delta t} +\frac{1}{2\Delta x_{j} } \left(\frac{D_{p1}^{} }{\Delta x_{p1}^{} } +\frac{D_{m1}^{} }{\Delta x_{m1}^{} } \right)\right]C_{j}^{n+1} -\frac{1}{2\Delta x_{j} } \frac{D_{p1}^{} }{\Delta x_{p1}^{} } C_{j+1}^{n+1} =} \\ {\frac{R_{j}^{n} }{\Delta t} +\frac{1}{2\Delta x_{j} } \left[\frac{D_{p1}^{} }{\Delta x_{p1}^{} } \left(C_{j+1}^{n} -C_{j}^{n} \right)-\frac{D_{m1}^{} }{\Delta x_{m1}^{} } \left(C_{j}^{n} -C_{j-1}^{n} \right)\right]+\frac{1}{2} \left[S_{j}^{n} +S_{j}^{n+1} \right]} \end{array}, -Equation is solved with a standard tridiagonal solver, i.e.: +Equation :eq:`24.16` is solved with a standard tridiagonal solver, i.e.: .. math:: :label: 24.17 aC_{j-1}^{n+1} +bC_{j}^{n+1} +cC_{j+1}^{n+1} =r, -with coefficients specified in equation . +with coefficients specified in equation :eq:`24.16`. Two methane balance checks are performed at each timestep to insure that the diffusion solution and the time-varying aggregation over inundated @@ -599,7 +599,7 @@ Inundated Fraction Prediction ---------------------------------- A simplified dynamic representation of spatial inundation -based on recent work by :ref:`Prigent et al. (2007)` is used. Prigent et al. (2007) described a +based on recent work by :ref:`Prigent et al. (2007)` is used. :ref:`Prigent et al. (2007)` described a multi-satellite approach to estimate the global monthly inundated fraction (:math:`{F}_{i}`) over an equal area grid (0.25 :math:`\circ` \ :math:`\times`\ 0.25\ :math:`\circ` at the equator) diff --git a/doc/source/tech_note/References/CLM50_Tech_Note_References.rst b/doc/source/tech_note/References/CLM50_Tech_Note_References.rst index 4bd7a2cf9b..46b835a76d 100644 --- a/doc/source/tech_note/References/CLM50_Tech_Note_References.rst +++ b/doc/source/tech_note/References/CLM50_Tech_Note_References.rst @@ -223,6 +223,13 @@ Geosci. Model Dev., 7, 2193-2222, doi:10.5194/gmd-7-2193-2014. Botta, A et al., 2000. A global prognostic scheme of leaf onset using satellite data. Global Change Biology 6.7, pp. 709-725. +.. _Brownetal1997: + +Brown J., Ferrians O. J. Jr, Heginbottom J. A. and Melnikov E. S. 1997. + Circum-Arctic Map of Permafrost and Ground-Ice Conditions +(Boulder, CO: National Snow and Ice Data Center) version 2, +DOI: 10.3133/cp45 + .. _Brun1989: Brun, E. 1989. Investigation of wet-snow metamorphism in respect of @@ -1085,6 +1092,12 @@ Climate 25:3071-3095. DOI:10.1175/JCLI-D-11-00256.1. Lehner, B. and Döll, P., 2004. Development and validation of a global database of lakes, reservoirs and wetlands, J. Hydrol., 296, 1–22. +.. _Leeetal2014: + +Lee, H., Swenson, S.C., Slater A.G. and Lawrence D.M., 2014. Effects +of excess ground ice on projections of permafrost in a warming climate. +Environmental Research Letters 9:12 124006. DOI: 10.1088/1748-9326/9/12/124006 + .. _Lehneretal2008: Lehner, B., Verdin, K. and Jarvis, A., 2008. New global hydrograhy diff --git a/doc/source/tech_note/Soil_Snow_Temperatures/CLM50_Tech_Note_Soil_Snow_Temperatures.rst b/doc/source/tech_note/Soil_Snow_Temperatures/CLM50_Tech_Note_Soil_Snow_Temperatures.rst index 72040a1514..ab10547339 100644 --- a/doc/source/tech_note/Soil_Snow_Temperatures/CLM50_Tech_Note_Soil_Snow_Temperatures.rst +++ b/doc/source/tech_note/Soil_Snow_Temperatures/CLM50_Tech_Note_Soil_Snow_Temperatures.rst @@ -979,3 +979,50 @@ the top layer is a blend of ice and soil heat capacity c_{1} =c_{1}^{*} +\frac{C_{ice} W_{sno} }{\Delta z_{1} } where :math:`c_{1}^{*}` is calculated from :eq:`6.89` or :eq:`6.92`. + + +.. _Excess Ground Ice: + +Excess Ground Ice +------------------------------------ + +An optional parameterization of excess ground ice melt and respective subsidence based on (:ref:`Lee et al., (2014) `). +Initial excess ground ice concentrations for soil columns are derived from (:ref:`Brown et al., (1997) `). +When the excess ground ice is present in the soil column, soil depth for a given layer (:math:`z_{i}`) +is adjusted by the amount of excess ice in the column: + +.. math:: + :label: 6.94 + + z_{i}^{'}=\Sigma_{j=1}^{i} \ z_{j}^{'}+\frac{w_{exice,\, j}}{\rho_{ice} } + +where :math:`w_{exice,\,j}` is excess ground ice amount (kg m :sup:`-2`) in layer :math:`j` +and :math:`\rho_{ice}` is the density of ice (kg m :sup:`-3`). +After adjustment of layer depths have been made, all of the soil temperature equations (from :eq:`6.80` to :eq:`6.89`) +are calculted based on the adjusted depths. Thermal properties are additionally adjusted (:eq:`6.8` and :eq:`6.8`) in the following way: + +.. math:: + :label: 6.95 + + \begin{array}{lr} + \theta_{sat}^{'} =\frac{\theta _{liq} }{\theta _{liq} +\theta _{ice} +\theta_{exice}}{\theta_{sat}} \\ + \lambda _{sat}^{'} =\lambda _{s}^{1-\theta _{sat}^{'} } \lambda _{liq}^{\frac{\theta _{liq} }{\theta _{liq} +\theta _{ice} +\theta_{exice}} \theta _{sat}^{'} } \lambda _{ice}^{\theta _{sat}^{'} \left(1-\frac{\theta _{liq} }{\theta _{liq} +\theta _{ice} +\theta_{exice}} \right)} \\ + c_{i}^{'} =c_{s,\, i} \left(1-\theta _{sat,\, i}^{'} \right)+\frac{w_{ice,\, i} +w_{exice,\,j}}{\Delta z_{i}^{'} } C_{ice} +\frac{w_{liq,\, i} }{\Delta z_{i}^{'} } C_{liq} + \end{array} + +Soil subsidence at the timestep :math:`n+1` (:math:`z_{exice}^{n+1}`, m) is then calculated as: + +.. math:: + :label: 6.96 + + z_{exice}^{n+1}=\Sigma_{i=1}^{N_{levgrnd}} \ z_{j}^{',\ ,n+1}-z_{j}^{',\ ,n } + +With regards to hydraulic counductivity, excess ground ice is treated the same way normal soil +ice is treated in :numref:`Frozen Soils and Perched Water Table`. +When a soil layer thaws, excess ground ice is only allowed +to melt when no normals soil ice is present in the layer. +When a soil layer refreezes, liquid soil water can only turn into normal soil ice, thus, no new of excess ice can be created but only melted. +The excess liquid soil moisture from excess ice melt is distributed within the soil column according +to :numref:`Lateral Sub-surface Runoff`. + + diff --git a/doc/source/users_guide/setting-up-and-running-a-case/README_history_fields_files b/doc/source/users_guide/setting-up-and-running-a-case/README_history_fields_files new file mode 100644 index 0000000000..c611c19ae2 --- /dev/null +++ b/doc/source/users_guide/setting-up-and-running-a-case/README_history_fields_files @@ -0,0 +1,11 @@ +2021/9/8 slevis +2023/8/15 samsrabin + +The files history_fields_nofates.rst and history_fields_fates.rst each contain a +table of the history fields, active and inactive, available in the CTSM cases +that get generated by these tests: +SMS_Ld1.f10_f10_mg37.I1850Clm50BgcCrop.cheyenne_intel.clm-SaveHistFieldList +SMS_Ld1.f10_f10_mg37.I2000Clm50FatesCru.cheyenne_intel.clm-SaveHistFieldList + +To reproduce these .rst files, run the above tests and the files +will appear in the corresponding run directories. diff --git a/doc/source/users_guide/setting-up-and-running-a-case/README_master_list_files b/doc/source/users_guide/setting-up-and-running-a-case/README_master_list_files deleted file mode 100644 index 61f8ef44d4..0000000000 --- a/doc/source/users_guide/setting-up-and-running-a-case/README_master_list_files +++ /dev/null @@ -1,10 +0,0 @@ -2021/9/8 slevis - -The files master_list_nofates.rst and master_list_fates.rst each contain a -table of the history fields, active and inactive, available in the CTSM cases -that get generated by these tests: -ERP_P36x2_D_Ld3.f10_f10_mg37.I1850Clm50BgcCrop.cheyenne_gnu.clm-extra_outputs -ERS_Ld9.f10_f10_mg37.I2000Clm50FatesCru.cheyenne_intel.clm-FatesColdDefCH4 - -To reproduce these .rst files, run the above tests and the files -will appear in the corresponding run directories. diff --git a/doc/source/users_guide/setting-up-and-running-a-case/customizing-the-clm-namelist.rst b/doc/source/users_guide/setting-up-and-running-a-case/customizing-the-clm-namelist.rst index 47274d8480..064d3f5979 100644 --- a/doc/source/users_guide/setting-up-and-running-a-case/customizing-the-clm-namelist.rst +++ b/doc/source/users_guide/setting-up-and-running-a-case/customizing-the-clm-namelist.rst @@ -43,12 +43,12 @@ Included in the table are the following pieces of information: Table 1-3. CLM History Fields from a BgcCrop case ------------------------------------------------- -For Table from a BgcCrop case, please see :doc:`master_list_nofates`. +For Table from a BgcCrop case, please see :doc:`history_fields_nofates`. Table 1-4. CLM History Fields from a Fates case ----------------------------------------------- -For Table from a Fates case, please see :doc:`master_list_fates`. +For Table from a Fates case, please see :doc:`history_fields_fates`. --------------------------------------------- diff --git a/doc/source/users_guide/setting-up-and-running-a-case/history_fields_fates.rst b/doc/source/users_guide/setting-up-and-running-a-case/history_fields_fates.rst new file mode 100644 index 0000000000..ea7c23d22a --- /dev/null +++ b/doc/source/users_guide/setting-up-and-running-a-case/history_fields_fates.rst @@ -0,0 +1,1087 @@ +============================= +CTSM History Fields (fates) +============================= + +CAUTION: Not all variables are relevant / present for all CTSM cases. +Key flags used in this CTSM case: +use_cn = F +use_crop = F +use_fates = T + +=================================== ================ ============================================================================================== ================================================================= ======= +CTSM History Fields +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Variable Name Level Dim. Long Description Units Active? +=================================== ================ ============================================================================================== ================================================================= ======= +A5TMIN - 5-day running mean of min 2-m temperature K F +ACTUAL_IMMOB - actual N immobilization gN/m^2/s T +AGLB - Aboveground leaf biomass kg/m^2 F +AGSB - Aboveground stem biomass kg/m^2 F +ALT - current active layer thickness m F +ALTMAX - maximum annual active layer thickness m F +ALTMAX_LASTYEAR - maximum prior year active layer thickness m F +ATM_O3 - atmospheric ozone partial pressure mol/mol F +ATM_TOPO - atmospheric surface height m T +AnnET - Annual ET mm/s F +BCDEP - total BC deposition (dry+wet) from atmosphere kg/m^2/s T +BTRAN - transpiration beta factor unitless T +BTRANMN - daily minimum of transpiration beta factor unitless T +CH4PROD - Gridcell total production of CH4 gC/m2/s T +CH4_EBUL_TOTAL_SAT - ebullition surface CH4 flux; (+ to atm) mol/m2/s F +CH4_EBUL_TOTAL_UNSAT - ebullition surface CH4 flux; (+ to atm) mol/m2/s F +CH4_SURF_AERE_SAT - aerenchyma surface CH4 flux for inundated area; (+ to atm) mol/m2/s T +CH4_SURF_AERE_UNSAT - aerenchyma surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T +CH4_SURF_DIFF_SAT - diffusive surface CH4 flux for inundated / lake area; (+ to atm) mol/m2/s T +CH4_SURF_DIFF_UNSAT - diffusive surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T +CH4_SURF_EBUL_SAT - ebullition surface CH4 flux for inundated / lake area; (+ to atm) mol/m2/s T +CH4_SURF_EBUL_UNSAT - ebullition surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T +COL_CTRUNC - column-level sink for C truncation gC/m^2 F +COL_NTRUNC - column-level sink for N truncation gN/m^2 F +COSZEN - cosine of solar zenith angle none F +CROPPROD1C - 1-yr crop product (grain+biofuel) C gC/m^2 T +CROPPROD1C_LOSS - loss from 1-yr crop product pool gC/m^2/s T +CROPPROD1N - 1-yr crop product (grain+biofuel) N gN/m^2 T +CROPPROD1N_LOSS - loss from 1-yr crop product pool gN/m^2/s T +CWDC_HR - cwd C heterotrophic respiration gC/m^2/s T +DENIT - total rate of denitrification gN/m^2/s T +DGNETDT - derivative of net ground heat flux wrt soil temp W/m^2/K F +DISPLA - displacement height (vegetated landunits only) m F +DPVLTRB1 - turbulent deposition velocity 1 m/s F +DPVLTRB2 - turbulent deposition velocity 2 m/s F +DPVLTRB3 - turbulent deposition velocity 3 m/s F +DPVLTRB4 - turbulent deposition velocity 4 m/s F +DSL - dry surface layer thickness mm T +DSTDEP - total dust deposition (dry+wet) from atmosphere kg/m^2/s T +DSTFLXT - total surface dust emission kg/m2/s T +DWT_CROPPROD1C_GAIN - landcover change-driven addition to 1-year crop product pool gC/m^2/s T +DWT_CROPPROD1N_GAIN - landcover change-driven addition to 1-year crop product pool gN/m^2/s T +DWT_PROD100C_GAIN - landcover change-driven addition to 100-yr wood product pool gC/m^2/s F +DWT_PROD100N_GAIN - landcover change-driven addition to 100-yr wood product pool gN/m^2/s F +DWT_PROD10C_GAIN - landcover change-driven addition to 10-yr wood product pool gC/m^2/s F +DWT_PROD10N_GAIN - landcover change-driven addition to 10-yr wood product pool gN/m^2/s F +DWT_WOODPRODC_GAIN - landcover change-driven addition to wood product pools gC/m^2/s T +DWT_WOODPRODN_GAIN - landcover change-driven addition to wood product pools gN/m^2/s T +DYN_COL_ADJUSTMENTS_CH4 - Adjustments in ch4 due to dynamic column areas; only makes sense at the column level: should n gC/m^2 F +DYN_COL_SOIL_ADJUSTMENTS_C - Adjustments in soil carbon due to dynamic column areas; only makes sense at the column level: gC/m^2 F +DYN_COL_SOIL_ADJUSTMENTS_N - Adjustments in soil nitrogen due to dynamic column areas; only makes sense at the column level gN/m^2 F +DYN_COL_SOIL_ADJUSTMENTS_NH4 - Adjustments in soil NH4 due to dynamic column areas; only makes sense at the column level: sho gN/m^2 F +DYN_COL_SOIL_ADJUSTMENTS_NO3 - Adjustments in soil NO3 due to dynamic column areas; only makes sense at the column level: sho gN/m^2 F +EFLXBUILD - building heat flux from change in interior building air temperature W/m^2 T +EFLX_DYNBAL - dynamic land cover change conversion energy flux W/m^2 T +EFLX_GNET - net heat flux into ground W/m^2 F +EFLX_GRND_LAKE - net heat flux into lake/snow surface, excluding light transmission W/m^2 T +EFLX_LH_TOT - total latent heat flux [+ to atm] W/m^2 T +EFLX_LH_TOT_ICE - total latent heat flux [+ to atm] (ice landunits only) W/m^2 F +EFLX_LH_TOT_R - Rural total evaporation W/m^2 T +EFLX_LH_TOT_U - Urban total evaporation W/m^2 F +EFLX_SOIL_GRND - soil heat flux [+ into soil] W/m^2 F +ELAI - exposed one-sided leaf area index m^2/m^2 T +ERRH2O - total water conservation error mm T +ERRH2OSNO - imbalance in snow depth (liquid water) mm T +ERRSEB - surface energy conservation error W/m^2 T +ERRSOI - soil/lake energy conservation error W/m^2 T +ERRSOL - solar radiation conservation error W/m^2 T +ESAI - exposed one-sided stem area index m^2/m^2 T +FATES_AR - autotrophic respiration gC/m^2/s T +FATES_AREA_PLANTS - area occupied by all plants per m2 land area m2 m-2 T +FATES_AREA_TREES - area occupied by woody plants per m2 land area m2 m-2 T +FATES_AR_CANOPY - autotrophic respiration of canopy plants gC/m^2/s T +FATES_AR_UNDERSTORY - autotrophic respiration of understory plants gC/m^2/s T +FATES_AUTORESP - autotrophic respiration in kg carbon per m2 per second kg m-2 s-1 T +FATES_AUTORESP_CANOPY - autotrophic respiration of canopy plants in kg carbon per m2 per second kg m-2 s-1 T +FATES_AUTORESP_SECONDARY - autotrophic respiration in kg carbon per m2 per second, secondary patches kg m-2 s-1 T +FATES_AUTORESP_USTORY - autotrophic respiration of understory plants in kg carbon per m2 per second kg m-2 s-1 T +FATES_BA_WEIGHTED_HEIGHT - basal area-weighted mean height of woody plants m T +FATES_BURNFRAC - burned area fraction per second s-1 T +FATES_CANOPY_SPREAD - scaling factor (0-1) between tree basal area and canopy area T +FATES_CANOPY_VEGC - biomass of canopy plants in kg carbon per m2 land area kg m-2 T +FATES_CA_WEIGHTED_HEIGHT - crown area-weighted mean height of canopy plants m T +FATES_CBALANCE_ERROR - total carbon error in kg carbon per second kg s-1 T +FATES_COLD_STATUS - site-level cold status, 0=not cold-dec, 1=too cold for leaves, 2=not too cold T +FATES_CROOTMAINTAR - live coarse root maintenance autotrophic respiration in kg carbon per m2 per second kg m-2 s-1 T +FATES_CROOT_ALLOC - allocation to coarse roots in kg carbon per m2 per second kg m-2 s-1 T +FATES_DAYSINCE_COLDLEAFOFF - site-level days elapsed since cold leaf drop days T +FATES_DAYSINCE_COLDLEAFON - site-level days elapsed since cold leaf flush days T +FATES_DEMOTION_CARBONFLUX - demotion-associated biomass carbon flux from canopy to understory in kg carbon per m2 per seco kg m-2 s-1 T +FATES_DISTURBANCE_RATE_FIRE - disturbance rate from fire m2 m-2 yr-1 T +FATES_DISTURBANCE_RATE_LOGGING - disturbance rate from logging m2 m-2 yr-1 T +FATES_DISTURBANCE_RATE_P2P - disturbance rate from primary to primary lands m2 m-2 yr-1 T +FATES_DISTURBANCE_RATE_P2S - disturbance rate from primary to secondary lands m2 m-2 yr-1 T +FATES_DISTURBANCE_RATE_POTENTIAL - potential (i.e., including unresolved) disturbance rate m2 m-2 yr-1 T +FATES_DISTURBANCE_RATE_S2S - disturbance rate from secondary to secondary lands m2 m-2 yr-1 T +FATES_DISTURBANCE_RATE_TREEFALL - disturbance rate from treefall m2 m-2 yr-1 T +FATES_EFFECT_WSPEED - effective wind speed for fire spread in meters per second m s-1 T +FATES_EXCESS_RESP - respiration of un-allocatable carbon gain kg m-2 s-1 T +FATES_FDI - Fire Danger Index (probability that an ignition will lead to a fire) 1 T +FATES_FIRE_CLOSS - carbon loss to atmosphere from fire in kg carbon per m2 per second kg m-2 s-1 T +FATES_FIRE_INTENSITY - spitfire surface fireline intensity in J per m per second J m-1 s-1 T +FATES_FIRE_INTENSITY_BURNFRAC - product of surface fire intensity and burned area fraction -- divide by FATES_BURNFRAC to get J m-1 s-1 T +FATES_FRACTION - total gridcell fraction which FATES is running over m2 m-2 T +FATES_FROOTC - total biomass in live plant fine roots in kg carbon per m2 kg m-2 T +FATES_FROOTMAINTAR - fine root maintenance autotrophic respiration in kg carbon per m2 per second kg m-2 s-1 T +FATES_FROOT_ALLOC - allocation to fine roots in kg carbon per m2 per second kg m-2 s-1 T +FATES_FUELCONSUMED - total fuel consumed in kg carbon per m2 land area kg m-2 T +FATES_FUEL_AMOUNT - total ground fuel related to FATES_ROS (omits 1000hr fuels) in kg C per m2 land area kg m-2 T +FATES_FUEL_BULKD - fuel bulk density in kg per m3 kg m-3 T +FATES_FUEL_EFF_MOIST - spitfire fuel moisture (volumetric) m3 m-3 T +FATES_FUEL_MEF - fuel moisture of extinction (volumetric) m3 m-3 T +FATES_FUEL_SAV - spitfire fuel surface area to volume ratio m-1 T +FATES_GDD - site-level growing degree days degree_Celsius T +FATES_GPP - gross primary production in kg carbon per m2 per second kg m-2 s-1 T +FATES_GPP_CANOPY - gross primary production of canopy plants in kg carbon per m2 per second kg m-2 s-1 T +FATES_GPP_SECONDARY - gross primary production in kg carbon per m2 per second, secondary patches kg m-2 s-1 T +FATES_GPP_USTORY - gross primary production of understory plants in kg carbon per m2 per second kg m-2 s-1 T +FATES_GROWTH_RESP - growth respiration in kg carbon per m2 per second kg m-2 s-1 T +FATES_GROWTH_RESP_SECONDARY - growth respiration in kg carbon per m2 per second, secondary patches kg m-2 s-1 T +FATES_HARVEST_CARBON_FLUX - harvest carbon flux in kg carbon per m2 per year kg m-2 yr-1 T +FATES_HARVEST_DEBT - Accumulated carbon failed to be harvested kg C T +FATES_HARVEST_DEBT_SEC - Accumulated carbon failed to be harvested from secondary patches kg C T +FATES_HET_RESP - heterotrophic respiration in kg carbon per m2 per second kg m-2 s-1 T +FATES_IGNITIONS - number of successful fire ignitions per m2 land area per second m-2 s-1 T +FATES_LAI - leaf area index per m2 land area m2 m-2 T +FATES_LAI_SECONDARY - leaf area index per m2 land area, secondary patches m2 m-2 T +FATES_LBLAYER_COND - mean leaf boundary layer conductance mol m-2 s-1 T +FATES_LEAFC - total biomass in live plant leaves in kg carbon per m2 kg m-2 T +FATES_LEAFMAINTAR - leaf maintenance autotrophic respiration in kg carbon per m2 per second kg m-2 s-1 T +FATES_LEAF_ALLOC - allocation to leaves in kg carbon per m2 per second kg m-2 s-1 T +FATES_LITTER_IN - litter flux in kg carbon per m2 per second kg m-2 s-1 T +FATES_LITTER_OUT - litter flux out in kg carbon (exudation, fragmentation, seed decay) kg m-2 s-1 T +FATES_LSTEMMAINTAR - live stem maintenance autotrophic respiration in kg carbon per m2 per second kg m-2 s-1 T +FATES_MAINT_RESP - maintenance respiration in kg carbon per m2 land area per second, secondary patches kg m-2 s-1 T +FATES_MAINT_RESP_SECONDARY - maintenance respiration in kg carbon per m2 land area per second kg m-2 s-1 T +FATES_MAINT_RESP_UNREDUCED - diagnostic maintenance respiration if the low-carbon-storage reduction is ignored kg m-2 s-1 F +FATES_MORTALITY_CFLUX_CANOPY - flux of biomass carbon from live to dead pools from mortality of canopy plants in kg carbon pe kg m-2 s-1 T +FATES_MORTALITY_CFLUX_USTORY - flux of biomass carbon from live to dead pools from mortality of understory plants in kg carbo kg m-2 s-1 T +FATES_NCHILLDAYS - site-level number of chill days days T +FATES_NCOHORTS - total number of cohorts per site T +FATES_NCOHORTS_SECONDARY - total number of cohorts per site T +FATES_NCOLDDAYS - site-level number of cold days days T +FATES_NEP - net ecosystem production in kg carbon per m2 per second kg m-2 s-1 T +FATES_NESTEROV_INDEX - nesterov fire danger index T +FATES_NONSTRUCTC - non-structural biomass (sapwood + leaf + fineroot) in kg carbon per m2 kg m-2 T +FATES_NPATCHES - total number of patches per site T +FATES_NPATCHES_SECONDARY - total number of patches per site T +FATES_NPP - net primary production in kg carbon per m2 per second kg m-2 s-1 T +FATES_NPP_SECONDARY - net primary production in kg carbon per m2 per second, secondary patches kg m-2 s-1 T +FATES_PRIMARY_PATCHFUSION_ERR - error in total primary lands associated with patch fusion m2 m-2 yr-1 T +FATES_PROMOTION_CARBONFLUX - promotion-associated biomass carbon flux from understory to canopy in kg carbon per m2 per sec kg m-2 s-1 T +FATES_RAD_ERROR - radiation error in FATES RTM W m-2 T +FATES_REPROC - total biomass in live plant reproductive tissues in kg carbon per m2 kg m-2 T +FATES_ROS - fire rate of spread in meters per second m s-1 T +FATES_SAPWOODC - total biomass in live plant sapwood in kg carbon per m2 kg m-2 T +FATES_SECONDARY_FOREST_FRACTION - secondary forest fraction m2 m-2 T +FATES_SECONDARY_FOREST_VEGC - biomass on secondary lands in kg carbon per m2 land area (mult by FATES_SECONDARY_FOREST_FRACT kg m-2 T +FATES_SEEDLING_POOL - total seedling (ie germinated seeds) mass of all PFTs in kg carbon per m2 land area kg m-2 T +FATES_SEEDS_IN - seed production rate in kg carbon per m2 second kg m-2 s-1 T +FATES_SEEDS_IN_LOCAL - local seed production rate in kg carbon per m2 second kg m-2 s-1 T +FATES_SEED_ALLOC - allocation to seeds in kg carbon per m2 per second kg m-2 s-1 T +FATES_SEED_BANK - total seed mass of all PFTs in kg carbon per m2 land area kg m-2 T +FATES_STEM_ALLOC - allocation to stem in kg carbon per m2 per second kg m-2 s-1 T +FATES_STOMATAL_COND - mean stomatal conductance mol m-2 s-1 T +FATES_STOREC - total biomass in live plant storage in kg carbon per m2 land area kg m-2 T +FATES_STOREC_TF - Storage C fraction of target kg kg-1 T +FATES_STORE_ALLOC - allocation to storage tissues in kg carbon per m2 per second kg m-2 s-1 T +FATES_STRUCTC - structural biomass in kg carbon per m2 land area kg m-2 T +FATES_TGROWTH - fates long-term running mean vegetation temperature by site degree_Celsius F +FATES_TLONGTERM - fates 30-year running mean vegetation temperature by site degree_Celsius F +FATES_TRIMMING - degree to which canopy expansion is limited by leaf economics (0-1) 1 T +FATES_TVEG - fates instantaneous mean vegetation temperature by site degree_Celsius T +FATES_TVEG24 - fates 24-hr running mean vegetation temperature by site degree_Celsius T +FATES_UNGERM_SEED_BANK - ungerminated seed mass of all PFTs in kg carbon per m2 land area kg m-2 T +FATES_USTORY_VEGC - biomass of understory plants in kg carbon per m2 land area kg m-2 T +FATES_VEGC - total biomass in live plants in kg carbon per m2 land area kg m-2 T +FATES_VEGC_ABOVEGROUND - aboveground biomass in kg carbon per m2 land area kg m-2 T +FATES_WOOD_PRODUCT - total wood product from logging in kg carbon per m2 land area kg m-2 T +FCEV - canopy evaporation W/m^2 T +FCH4 - Gridcell surface CH4 flux to atmosphere (+ to atm) kgC/m2/s T +FCH4TOCO2 - Gridcell oxidation of CH4 to CO2 gC/m2/s T +FCH4_DFSAT - CH4 additional flux due to changing fsat, natural vegetated and crop landunits only kgC/m2/s T +FCO2 - CO2 flux to atmosphere (+ to atm) kgCO2/m2/s F +FCOV - fractional impermeable area unitless T +FCTR - canopy transpiration W/m^2 T +FGEV - ground evaporation W/m^2 T +FGR - heat flux into soil/snow including snow melt and lake / snow light transmission W/m^2 T +FGR12 - heat flux between soil layers 1 and 2 W/m^2 T +FGR_ICE - heat flux into soil/snow including snow melt and lake / snow light transmission (ice landunits W/m^2 F +FGR_R - Rural heat flux into soil/snow including snow melt and snow light transmission W/m^2 F +FGR_U - Urban heat flux into soil/snow including snow melt W/m^2 F +FH2OSFC - fraction of ground covered by surface water unitless T +FH2OSFC_NOSNOW - fraction of ground covered by surface water (if no snow present) unitless F +FINUNDATED - fractional inundated area of vegetated columns unitless T +FINUNDATED_LAG - time-lagged inundated fraction of vegetated columns unitless F +FIRA - net infrared (longwave) radiation W/m^2 T +FIRA_ICE - net infrared (longwave) radiation (ice landunits only) W/m^2 F +FIRA_R - Rural net infrared (longwave) radiation W/m^2 T +FIRA_U - Urban net infrared (longwave) radiation W/m^2 F +FIRE - emitted infrared (longwave) radiation W/m^2 T +FIRE_ICE - emitted infrared (longwave) radiation (ice landunits only) W/m^2 F +FIRE_R - Rural emitted infrared (longwave) radiation W/m^2 T +FIRE_U - Urban emitted infrared (longwave) radiation W/m^2 F +FLDS - atmospheric longwave radiation (downscaled to columns in glacier regions) W/m^2 T +FLDS_ICE - atmospheric longwave radiation (downscaled to columns in glacier regions) (ice landunits only) W/m^2 F +FPG - fraction of potential gpp proportion T +FPI - fraction of potential immobilization proportion T +FROST_TABLE - frost table depth (natural vegetated and crop landunits only) m F +FSA - absorbed solar radiation W/m^2 T +FSAT - fractional area with water table at surface unitless T +FSA_ICE - absorbed solar radiation (ice landunits only) W/m^2 F +FSA_R - Rural absorbed solar radiation W/m^2 F +FSA_U - Urban absorbed solar radiation W/m^2 F +FSD24 - direct radiation (last 24hrs) K F +FSD240 - direct radiation (last 240hrs) K F +FSDS - atmospheric incident solar radiation W/m^2 T +FSDSND - direct nir incident solar radiation W/m^2 T +FSDSNDLN - direct nir incident solar radiation at local noon W/m^2 T +FSDSNI - diffuse nir incident solar radiation W/m^2 T +FSDSVD - direct vis incident solar radiation W/m^2 T +FSDSVDLN - direct vis incident solar radiation at local noon W/m^2 T +FSDSVI - diffuse vis incident solar radiation W/m^2 T +FSDSVILN - diffuse vis incident solar radiation at local noon W/m^2 T +FSH - sensible heat not including correction for land use change and rain/snow conversion W/m^2 T +FSH_G - sensible heat from ground W/m^2 T +FSH_ICE - sensible heat not including correction for land use change and rain/snow conversion (ice landu W/m^2 F +FSH_PRECIP_CONVERSION - Sensible heat flux from conversion of rain/snow atm forcing W/m^2 T +FSH_R - Rural sensible heat W/m^2 T +FSH_RUNOFF_ICE_TO_LIQ - sensible heat flux generated from conversion of ice runoff to liquid W/m^2 T +FSH_TO_COUPLER - sensible heat sent to coupler (includes corrections for land use change, rain/snow conversion W/m^2 T +FSH_U - Urban sensible heat W/m^2 F +FSH_V - sensible heat from veg W/m^2 T +FSI24 - indirect radiation (last 24hrs) K F +FSI240 - indirect radiation (last 240hrs) K F +FSM - snow melt heat flux W/m^2 T +FSM_ICE - snow melt heat flux (ice landunits only) W/m^2 F +FSM_R - Rural snow melt heat flux W/m^2 F +FSM_U - Urban snow melt heat flux W/m^2 F +FSNO - fraction of ground covered by snow unitless T +FSNO_EFF - effective fraction of ground covered by snow unitless T +FSNO_ICE - fraction of ground covered by snow (ice landunits only) unitless F +FSR - reflected solar radiation W/m^2 T +FSRND - direct nir reflected solar radiation W/m^2 T +FSRNDLN - direct nir reflected solar radiation at local noon W/m^2 T +FSRNI - diffuse nir reflected solar radiation W/m^2 T +FSRVD - direct vis reflected solar radiation W/m^2 T +FSRVDLN - direct vis reflected solar radiation at local noon W/m^2 T +FSRVI - diffuse vis reflected solar radiation W/m^2 T +FSR_ICE - reflected solar radiation (ice landunits only) W/m^2 F +FSUN - sunlit fraction of canopy proportion F +FSUN24 - fraction sunlit (last 24hrs) K F +FSUN240 - fraction sunlit (last 240hrs) K F +F_DENIT - denitrification flux gN/m^2/s T +F_N2O_DENIT - denitrification N2O flux gN/m^2/s T +F_N2O_NIT - nitrification N2O flux gN/m^2/s T +F_NIT - nitrification flux gN/m^2/s T +GROSS_NMIN - gross rate of N mineralization gN/m^2/s T +GRU_PROD100C_GAIN - gross unrepresented landcover change addition to 100-yr wood product pool gC/m^2/s F +GRU_PROD100N_GAIN - gross unrepresented landcover change addition to 100-yr wood product pool gN/m^2/s F +GRU_PROD10C_GAIN - gross unrepresented landcover change addition to 10-yr wood product pool gC/m^2/s F +GRU_PROD10N_GAIN - gross unrepresented landcover change addition to 10-yr wood product pool gN/m^2/s F +GSSHA - shaded leaf stomatal conductance umol H20/m2/s T +GSSHALN - shaded leaf stomatal conductance at local noon umol H20/m2/s T +GSSUN - sunlit leaf stomatal conductance umol H20/m2/s T +GSSUNLN - sunlit leaf stomatal conductance at local noon umol H20/m2/s T +H2OCAN - intercepted water mm T +H2OSFC - surface water depth mm T +H2OSNO - snow depth (liquid water) mm T +H2OSNO_ICE - snow depth (liquid water, ice landunits only) mm F +H2OSNO_TOP - mass of snow in top snow layer kg/m2 T +HBOT - canopy bottom m F +HEAT_CONTENT1 - initial gridcell total heat content J/m^2 T +HEAT_CONTENT1_VEG - initial gridcell total heat content - natural vegetated and crop landunits only J/m^2 F +HEAT_CONTENT2 - post land cover change total heat content J/m^2 F +HEAT_FROM_AC - sensible heat flux put into canyon due to heat removed from air conditioning W/m^2 T +HIA - 2 m NWS Heat Index C T +HIA_R - Rural 2 m NWS Heat Index C T +HIA_U - Urban 2 m NWS Heat Index C T +HR - total heterotrophic respiration gC/m^2/s T +HTOP - canopy top m T +HUMIDEX - 2 m Humidex C T +HUMIDEX_R - Rural 2 m Humidex C T +HUMIDEX_U - Urban 2 m Humidex C T +ICE_CONTENT1 - initial gridcell total ice content mm T +ICE_CONTENT2 - post land cover change total ice content mm F +ICE_MODEL_FRACTION - Ice sheet model fractional coverage unitless F +INT_SNOW - accumulated swe (natural vegetated and crop landunits only) mm F +INT_SNOW_ICE - accumulated swe (ice landunits only) mm F +IWUELN - local noon intrinsic water use efficiency umolCO2/molH2O T +LAI240 - 240hr average of leaf area index m^2/m^2 F +LAISHA - shaded projected leaf area index m^2/m^2 T +LAISUN - sunlit projected leaf area index m^2/m^2 T +LAKEICEFRAC_SURF - surface lake layer ice mass fraction unitless T +LAKEICETHICK - thickness of lake ice (including physical expansion on freezing) m T +LIQCAN - intercepted liquid water mm T +LIQUID_CONTENT1 - initial gridcell total liq content mm T +LIQUID_CONTENT2 - post landuse change gridcell total liq content mm F +LIQUID_WATER_TEMP1 - initial gridcell weighted average liquid water temperature K F +LITTERC_HR - litter C heterotrophic respiration gC/m^2/s T +LIT_CEL_C - LIT_CEL C gC/m^2 T +LIT_CEL_C_1m - LIT_CEL C to 1 meter gC/m^2 F +LIT_CEL_C_TO_SOM_ACT_C - decomp. of cellulosic litter C to active soil organic C gC/m^2/s F +LIT_CEL_HR - Het. Resp. from cellulosic litter gC/m^2/s F +LIT_CEL_N - LIT_CEL N gN/m^2 T +LIT_CEL_N_1m - LIT_CEL N to 1 meter gN/m^2 F +LIT_CEL_N_TO_SOM_ACT_N - decomp. of cellulosic litter N to active soil organic N gN/m^2 F +LIT_LIG_C - LIT_LIG C gC/m^2 T +LIT_LIG_C_1m - LIT_LIG C to 1 meter gC/m^2 F +LIT_LIG_C_TO_SOM_SLO_C - decomp. of lignin litter C to slow soil organic ma C gC/m^2/s F +LIT_LIG_HR - Het. Resp. from lignin litter gC/m^2/s F +LIT_LIG_N - LIT_LIG N gN/m^2 T +LIT_LIG_N_1m - LIT_LIG N to 1 meter gN/m^2 F +LIT_LIG_N_TO_SOM_SLO_N - decomp. of lignin litter N to slow soil organic ma N gN/m^2 F +LIT_MET_C - LIT_MET C gC/m^2 T +LIT_MET_C_1m - LIT_MET C to 1 meter gC/m^2 F +LIT_MET_C_TO_SOM_ACT_C - decomp. of metabolic litter C to active soil organic C gC/m^2/s F +LIT_MET_HR - Het. Resp. from metabolic litter gC/m^2/s F +LIT_MET_N - LIT_MET N gN/m^2 T +LIT_MET_N_1m - LIT_MET N to 1 meter gN/m^2 F +LIT_MET_N_TO_SOM_ACT_N - decomp. of metabolic litter N to active soil organic N gN/m^2 F +LNC - leaf N concentration gN leaf/m^2 T +LWdown - atmospheric longwave radiation (downscaled to columns in glacier regions) W/m^2 F +LWup - upwelling longwave radiation W/m^2 F +MORTALITY_CROWNAREA_CANOPY - Crown area of canopy trees that died m2/ha/year T +MORTALITY_CROWNAREA_UNDERSTORY - Crown aera of understory trees that died m2/ha/year T +M_LIT_CEL_C_TO_LEACHING - cellulosic litter C leaching loss gC/m^2/s F +M_LIT_CEL_N_TO_LEACHING - cellulosic litter N leaching loss gN/m^2/s F +M_LIT_LIG_C_TO_LEACHING - lignin litter C leaching loss gC/m^2/s F +M_LIT_LIG_N_TO_LEACHING - lignin litter N leaching loss gN/m^2/s F +M_LIT_MET_C_TO_LEACHING - metabolic litter C leaching loss gC/m^2/s F +M_LIT_MET_N_TO_LEACHING - metabolic litter N leaching loss gN/m^2/s F +M_SOM_ACT_C_TO_LEACHING - active soil organic C leaching loss gC/m^2/s F +M_SOM_ACT_N_TO_LEACHING - active soil organic N leaching loss gN/m^2/s F +M_SOM_PAS_C_TO_LEACHING - passive soil organic C leaching loss gC/m^2/s F +M_SOM_PAS_N_TO_LEACHING - passive soil organic N leaching loss gN/m^2/s F +M_SOM_SLO_C_TO_LEACHING - slow soil organic ma C leaching loss gC/m^2/s F +M_SOM_SLO_N_TO_LEACHING - slow soil organic ma N leaching loss gN/m^2/s F +NDEP_TO_SMINN - atmospheric N deposition to soil mineral N gN/m^2/s T +NEM - Gridcell net adjustment to net carbon exchange passed to atm. for methane production gC/m2/s T +NET_NMIN - net rate of N mineralization gN/m^2/s T +NFIX_TO_SMINN - symbiotic/asymbiotic N fixation to soil mineral N gN/m^2/s T +NSUBSTEPS - number of adaptive timesteps in CLM timestep unitless F +OBU - Monin-Obukhov length m F +OCDEP - total OC deposition (dry+wet) from atmosphere kg/m^2/s T +PARVEGLN - absorbed par by vegetation at local noon W/m^2 T +PBOT - atmospheric pressure at surface (downscaled to columns in glacier regions) Pa T +PCH4 - atmospheric partial pressure of CH4 Pa T +PCO2 - atmospheric partial pressure of CO2 Pa T +POTENTIAL_IMMOB - potential N immobilization gN/m^2/s T +POT_F_DENIT - potential denitrification flux gN/m^2/s T +POT_F_NIT - potential nitrification flux gN/m^2/s T +PROD100C - 100-yr wood product C gC/m^2 F +PROD100C_LOSS - loss from 100-yr wood product pool gC/m^2/s F +PROD100N - 100-yr wood product N gN/m^2 F +PROD100N_LOSS - loss from 100-yr wood product pool gN/m^2/s F +PROD10C - 10-yr wood product C gC/m^2 F +PROD10C_LOSS - loss from 10-yr wood product pool gC/m^2/s F +PROD10N - 10-yr wood product N gN/m^2 F +PROD10N_LOSS - loss from 10-yr wood product pool gN/m^2/s F +PSurf - atmospheric pressure at surface (downscaled to columns in glacier regions) Pa F +Q2M - 2m specific humidity kg/kg T +QAF - canopy air humidity kg/kg F +QBOT - atmospheric specific humidity (downscaled to columns in glacier regions) kg/kg T +QDIRECT_THROUGHFALL - direct throughfall of liquid (rain + above-canopy irrigation) mm/s F +QDIRECT_THROUGHFALL_SNOW - direct throughfall of snow mm/s F +QDRAI - sub-surface drainage mm/s T +QDRAI_PERCH - perched wt drainage mm/s T +QDRAI_XS - saturation excess drainage mm/s T +QDRIP - rate of excess canopy liquid falling off canopy mm/s F +QDRIP_SNOW - rate of excess canopy snow falling off canopy mm/s F +QFLOOD - runoff from river flooding mm/s T +QFLX_EVAP_TOT - qflx_evap_soi + qflx_evap_can + qflx_tran_veg kg m-2 s-1 T +QFLX_EVAP_VEG - vegetation evaporation mm H2O/s F +QFLX_ICE_DYNBAL - ice dynamic land cover change conversion runoff flux mm/s T +QFLX_LIQDEW_TO_TOP_LAYER - rate of liquid water deposited on top soil or snow layer (dew) mm H2O/s T +QFLX_LIQEVAP_FROM_TOP_LAYER - rate of liquid water evaporated from top soil or snow layer mm H2O/s T +QFLX_LIQ_DYNBAL - liq dynamic land cover change conversion runoff flux mm/s T +QFLX_LIQ_GRND - liquid (rain+irrigation) on ground after interception mm H2O/s F +QFLX_SNOW_DRAIN - drainage from snow pack mm/s T +QFLX_SNOW_DRAIN_ICE - drainage from snow pack melt (ice landunits only) mm/s T +QFLX_SNOW_GRND - snow on ground after interception mm H2O/s F +QFLX_SOLIDDEW_TO_TOP_LAYER - rate of solid water deposited on top soil or snow layer (frost) mm H2O/s T +QFLX_SOLIDEVAP_FROM_TOP_LAYER - rate of ice evaporated from top soil or snow layer (sublimation) (also includes bare ice subli mm H2O/s T +QFLX_SOLIDEVAP_FROM_TOP_LAYER_ICE - rate of ice evaporated from top soil or snow layer (sublimation) (also includes bare ice subli mm H2O/s F +QH2OSFC - surface water runoff mm/s T +QH2OSFC_TO_ICE - surface water converted to ice mm/s F +QHR - hydraulic redistribution mm/s T +QICE - ice growth/melt mm/s T +QICE_FRZ - ice growth mm/s T +QICE_MELT - ice melt mm/s T +QINFL - infiltration mm/s T +QINTR - interception mm/s T +QIRRIG_DEMAND - irrigation demand mm/s F +QIRRIG_DRIP - water added via drip irrigation mm/s F +QIRRIG_FROM_GW_CONFINED - water added through confined groundwater irrigation mm/s T +QIRRIG_FROM_GW_UNCONFINED - water added through unconfined groundwater irrigation mm/s T +QIRRIG_FROM_SURFACE - water added through surface water irrigation mm/s T +QIRRIG_SPRINKLER - water added via sprinkler irrigation mm/s F +QOVER - total surface runoff (includes QH2OSFC) mm/s T +QOVER_LAG - time-lagged surface runoff for soil columns mm/s F +QPHSNEG - net negative hydraulic redistribution flux mm/s F +QRGWL - surface runoff at glaciers (liquid only), wetlands, lakes; also includes melted ice runoff fro mm/s T +QRUNOFF - total liquid runoff not including correction for land use change mm/s T +QRUNOFF_ICE - total liquid runoff not incl corret for LULCC (ice landunits only) mm/s T +QRUNOFF_ICE_TO_COUPLER - total ice runoff sent to coupler (includes corrections for land use change) mm/s T +QRUNOFF_ICE_TO_LIQ - liquid runoff from converted ice runoff mm/s F +QRUNOFF_R - Rural total runoff mm/s F +QRUNOFF_TO_COUPLER - total liquid runoff sent to coupler (includes corrections for land use change) mm/s T +QRUNOFF_U - Urban total runoff mm/s F +QSNOCPLIQ - excess liquid h2o due to snow capping not including correction for land use change mm H2O/s T +QSNOEVAP - evaporation from snow (only when snl<0, otherwise it is equal to qflx_ev_soil) mm/s T +QSNOFRZ - column-integrated snow freezing rate kg/m2/s T +QSNOFRZ_ICE - column-integrated snow freezing rate (ice landunits only) mm/s T +QSNOMELT - snow melt rate mm/s T +QSNOMELT_ICE - snow melt (ice landunits only) mm/s T +QSNOUNLOAD - canopy snow unloading mm/s T +QSNO_TEMPUNLOAD - canopy snow temp unloading mm/s T +QSNO_WINDUNLOAD - canopy snow wind unloading mm/s T +QSNWCPICE - excess solid h2o due to snow capping not including correction for land use change mm H2O/s T +QSOIL - Ground evaporation (soil/snow evaporation + soil/snow sublimation - dew) mm/s T +QSOIL_ICE - Ground evaporation (ice landunits only) mm/s T +QTOPSOIL - water input to surface mm/s F +QVEGE - canopy evaporation mm/s T +QVEGT - canopy transpiration mm/s T +Qair - atmospheric specific humidity (downscaled to columns in glacier regions) kg/kg F +Qh - sensible heat W/m^2 F +Qle - total evaporation W/m^2 F +Qstor - storage heat flux (includes snowmelt) W/m^2 F +Qtau - momentum flux kg/m/s^2 F +RAH1 - aerodynamical resistance s/m F +RAH2 - aerodynamical resistance s/m F +RAIN - atmospheric rain, after rain/snow repartitioning based on temperature mm/s T +RAIN_FROM_ATM - atmospheric rain received from atmosphere (pre-repartitioning) mm/s T +RAIN_ICE - atmospheric rain, after rain/snow repartitioning based on temperature (ice landunits only) mm/s F +RAM_LAKE - aerodynamic resistance for momentum (lakes only) s/m F +RAW1 - aerodynamical resistance s/m F +RAW2 - aerodynamical resistance s/m F +RB - leaf boundary resistance s/m F +RH - atmospheric relative humidity % F +RH2M - 2m relative humidity % T +RH2M_R - Rural 2m specific humidity % F +RH2M_U - Urban 2m relative humidity % F +RHAF - fractional humidity of canopy air fraction F +RH_LEAF - fractional humidity at leaf surface fraction F +RSCANOPY - canopy resistance s m-1 T +RSSHA - shaded leaf stomatal resistance s/m T +RSSUN - sunlit leaf stomatal resistance s/m T +Rainf - atmospheric rain, after rain/snow repartitioning based on temperature mm/s F +Rnet - net radiation W/m^2 F +SABG - solar rad absorbed by ground W/m^2 T +SABG_PEN - Rural solar rad penetrating top soil or snow layer watt/m^2 T +SABV - solar rad absorbed by veg W/m^2 T +SMINN - soil mineral N gN/m^2 T +SMINN_TO_PLANT - plant uptake of soil mineral N gN/m^2/s T +SMINN_TO_S1N_L1 - mineral N flux for decomp. of LIT_METto SOM_ACT gN/m^2 F +SMINN_TO_S1N_L2 - mineral N flux for decomp. of LIT_CELto SOM_ACT gN/m^2 F +SMINN_TO_S1N_S2 - mineral N flux for decomp. of SOM_SLOto SOM_ACT gN/m^2 F +SMINN_TO_S1N_S3 - mineral N flux for decomp. of SOM_PASto SOM_ACT gN/m^2 F +SMINN_TO_S2N_L3 - mineral N flux for decomp. of LIT_LIGto SOM_SLO gN/m^2 F +SMINN_TO_S2N_S1 - mineral N flux for decomp. of SOM_ACTto SOM_SLO gN/m^2 F +SMINN_TO_S3N_S1 - mineral N flux for decomp. of SOM_ACTto SOM_PAS gN/m^2 F +SMINN_TO_S3N_S2 - mineral N flux for decomp. of SOM_SLOto SOM_PAS gN/m^2 F +SMIN_NH4 - soil mineral NH4 gN/m^2 T +SMIN_NO3 - soil mineral NO3 gN/m^2 T +SMIN_NO3_LEACHED - soil NO3 pool loss to leaching gN/m^2/s T +SMIN_NO3_RUNOFF - soil NO3 pool loss to runoff gN/m^2/s T +SNOBCMCL - mass of BC in snow column kg/m2 T +SNOBCMSL - mass of BC in top snow layer kg/m2 T +SNOCAN - intercepted snow mm T +SNODSTMCL - mass of dust in snow column kg/m2 T +SNODSTMSL - mass of dust in top snow layer kg/m2 T +SNOFSDSND - direct nir incident solar radiation on snow W/m^2 F +SNOFSDSNI - diffuse nir incident solar radiation on snow W/m^2 F +SNOFSDSVD - direct vis incident solar radiation on snow W/m^2 F +SNOFSDSVI - diffuse vis incident solar radiation on snow W/m^2 F +SNOFSRND - direct nir reflected solar radiation from snow W/m^2 T +SNOFSRNI - diffuse nir reflected solar radiation from snow W/m^2 T +SNOFSRVD - direct vis reflected solar radiation from snow W/m^2 T +SNOFSRVI - diffuse vis reflected solar radiation from snow W/m^2 T +SNOINTABS - Fraction of incoming solar absorbed by lower snow layers - T +SNOLIQFL - top snow layer liquid water fraction (land) fraction F +SNOOCMCL - mass of OC in snow column kg/m2 T +SNOOCMSL - mass of OC in top snow layer kg/m2 T +SNORDSL - top snow layer effective grain radius m^-6 F +SNOTTOPL - snow temperature (top layer) K F +SNOTTOPL_ICE - snow temperature (top layer, ice landunits only) K F +SNOTXMASS - snow temperature times layer mass, layer sum; to get mass-weighted temperature, divide by (SNO K kg/m2 T +SNOTXMASS_ICE - snow temperature times layer mass, layer sum (ice landunits only); to get mass-weighted temper K kg/m2 F +SNOW - atmospheric snow, after rain/snow repartitioning based on temperature mm/s T +SNOWDP - gridcell mean snow height m T +SNOWICE - snow ice kg/m2 T +SNOWICE_ICE - snow ice (ice landunits only) kg/m2 F +SNOWLIQ - snow liquid water kg/m2 T +SNOWLIQ_ICE - snow liquid water (ice landunits only) kg/m2 F +SNOW_5D - 5day snow avg m F +SNOW_DEPTH - snow height of snow covered area m T +SNOW_DEPTH_ICE - snow height of snow covered area (ice landunits only) m F +SNOW_FROM_ATM - atmospheric snow received from atmosphere (pre-repartitioning) mm/s T +SNOW_ICE - atmospheric snow, after rain/snow repartitioning based on temperature (ice landunits only) mm/s F +SNOW_PERSISTENCE - Length of time of continuous snow cover (nat. veg. landunits only) seconds T +SNOW_SINKS - snow sinks (liquid water) mm/s T +SNOW_SOURCES - snow sources (liquid water) mm/s T +SNOdTdzL - top snow layer temperature gradient (land) K/m F +SOIL10 - 10-day running mean of 12cm layer soil K F +SOILC_HR - soil C heterotrophic respiration gC/m^2/s T +SOILRESIS - soil resistance to evaporation s/m T +SOILWATER_10CM - soil liquid water + ice in top 10cm of soil (veg landunits only) kg/m2 T +SOMC_FIRE - C loss due to peat burning gC/m^2/s T +SOM_ACT_C - SOM_ACT C gC/m^2 T +SOM_ACT_C_1m - SOM_ACT C to 1 meter gC/m^2 F +SOM_ACT_C_TO_SOM_PAS_C - decomp. of active soil organic C to passive soil organic C gC/m^2/s F +SOM_ACT_C_TO_SOM_SLO_C - decomp. of active soil organic C to slow soil organic ma C gC/m^2/s F +SOM_ACT_HR_S2 - Het. Resp. from active soil organic gC/m^2/s F +SOM_ACT_HR_S3 - Het. Resp. from active soil organic gC/m^2/s F +SOM_ACT_N - SOM_ACT N gN/m^2 T +SOM_ACT_N_1m - SOM_ACT N to 1 meter gN/m^2 F +SOM_ACT_N_TO_SOM_PAS_N - decomp. of active soil organic N to passive soil organic N gN/m^2 F +SOM_ACT_N_TO_SOM_SLO_N - decomp. of active soil organic N to slow soil organic ma N gN/m^2 F +SOM_C_LEACHED - total flux of C from SOM pools due to leaching gC/m^2/s T +SOM_N_LEACHED - total flux of N from SOM pools due to leaching gN/m^2/s F +SOM_PAS_C - SOM_PAS C gC/m^2 T +SOM_PAS_C_1m - SOM_PAS C to 1 meter gC/m^2 F +SOM_PAS_C_TO_SOM_ACT_C - decomp. of passive soil organic C to active soil organic C gC/m^2/s F +SOM_PAS_HR - Het. Resp. from passive soil organic gC/m^2/s F +SOM_PAS_N - SOM_PAS N gN/m^2 T +SOM_PAS_N_1m - SOM_PAS N to 1 meter gN/m^2 F +SOM_PAS_N_TO_SOM_ACT_N - decomp. of passive soil organic N to active soil organic N gN/m^2 F +SOM_SLO_C - SOM_SLO C gC/m^2 T +SOM_SLO_C_1m - SOM_SLO C to 1 meter gC/m^2 F +SOM_SLO_C_TO_SOM_ACT_C - decomp. of slow soil organic ma C to active soil organic C gC/m^2/s F +SOM_SLO_C_TO_SOM_PAS_C - decomp. of slow soil organic ma C to passive soil organic C gC/m^2/s F +SOM_SLO_HR_S1 - Het. Resp. from slow soil organic ma gC/m^2/s F +SOM_SLO_HR_S3 - Het. Resp. from slow soil organic ma gC/m^2/s F +SOM_SLO_N - SOM_SLO N gN/m^2 T +SOM_SLO_N_1m - SOM_SLO N to 1 meter gN/m^2 F +SOM_SLO_N_TO_SOM_ACT_N - decomp. of slow soil organic ma N to active soil organic N gN/m^2 F +SOM_SLO_N_TO_SOM_PAS_N - decomp. of slow soil organic ma N to passive soil organic N gN/m^2 F +SUPPLEMENT_TO_SMINN - supplemental N supply gN/m^2/s T +SWBGT - 2 m Simplified Wetbulb Globe Temp C T +SWBGT_R - Rural 2 m Simplified Wetbulb Globe Temp C T +SWBGT_U - Urban 2 m Simplified Wetbulb Globe Temp C T +SWdown - atmospheric incident solar radiation W/m^2 F +SWup - upwelling shortwave radiation W/m^2 F +SoilAlpha - factor limiting ground evap unitless F +SoilAlpha_U - urban factor limiting ground evap unitless F +T10 - 10-day running mean of 2-m temperature K F +TAF - canopy air temperature K F +TAUX - zonal surface stress kg/m/s^2 T +TAUY - meridional surface stress kg/m/s^2 T +TBOT - atmospheric air temperature (downscaled to columns in glacier regions) K T +TBUILD - internal urban building air temperature K T +TBUILD_MAX - prescribed maximum interior building temperature K F +TFLOOR - floor temperature K F +TG - ground temperature K T +TG_ICE - ground temperature (ice landunits only) K F +TG_R - Rural ground temperature K F +TG_U - Urban ground temperature K F +TH2OSFC - surface water temperature K T +THBOT - atmospheric air potential temperature (downscaled to columns in glacier regions) K T +TKE1 - top lake level eddy thermal conductivity W/(mK) T +TLAI - total projected leaf area index m^2/m^2 T +TOPO_COL - column-level topographic height m F +TOPO_COL_ICE - column-level topographic height (ice landunits only) m F +TOTCOLC - total column carbon, incl veg and cpool but excl product pools gC/m^2 T +TOTCOLCH4 - total belowground CH4 (0 for non-lake special landunits in the absence of dynamic landunits) gC/m2 T +TOTCOLN - total column-level N, excluding product pools gN/m^2 T +TOTECOSYSC - total ecosystem carbon, incl veg but excl cpool and product pools gC/m^2 T +TOTECOSYSN - total ecosystem N, excluding product pools gN/m^2 T +TOTLITC - total litter carbon gC/m^2 T +TOTLITC_1m - total litter carbon to 1 meter depth gC/m^2 T +TOTLITN - total litter N gN/m^2 T +TOTLITN_1m - total litter N to 1 meter gN/m^2 T +TOTSOILICE - vertically summed soil ice (veg landunits only) kg/m2 T +TOTSOILLIQ - vertically summed soil liquid water (veg landunits only) kg/m2 T +TOTSOMC - total soil organic matter carbon gC/m^2 T +TOTSOMC_1m - total soil organic matter carbon to 1 meter depth gC/m^2 T +TOTSOMN - total soil organic matter N gN/m^2 T +TOTSOMN_1m - total soil organic matter N to 1 meter gN/m^2 T +TOT_WOODPRODC - total wood product C gC/m^2 T +TOT_WOODPRODC_LOSS - total loss from wood product pools gC/m^2/s T +TOT_WOODPRODN - total wood product N gN/m^2 T +TOT_WOODPRODN_LOSS - total loss from wood product pools gN/m^2/s T +TRAFFICFLUX - sensible heat flux from urban traffic W/m^2 F +TREFMNAV - daily minimum of average 2-m temperature K T +TREFMNAV_R - Rural daily minimum of average 2-m temperature K F +TREFMNAV_U - Urban daily minimum of average 2-m temperature K F +TREFMXAV - daily maximum of average 2-m temperature K T +TREFMXAV_R - Rural daily maximum of average 2-m temperature K F +TREFMXAV_U - Urban daily maximum of average 2-m temperature K F +TROOF_INNER - roof inside surface temperature K F +TSA - 2m air temperature K T +TSAI - total projected stem area index m^2/m^2 T +TSA_ICE - 2m air temperature (ice landunits only) K F +TSA_R - Rural 2m air temperature K F +TSA_U - Urban 2m air temperature K F +TSHDW_INNER - shadewall inside surface temperature K F +TSKIN - skin temperature K T +TSL - temperature of near-surface soil layer (natural vegetated and crop landunits only) K T +TSOI_10CM - soil temperature in top 10cm of soil K T +TSUNW_INNER - sunwall inside surface temperature K F +TV - vegetation temperature K T +TV24 - vegetation temperature (last 24hrs) K F +TV240 - vegetation temperature (last 240hrs) K F +TWS - total water storage mm T +Tair - atmospheric air temperature (downscaled to columns in glacier regions) K F +Tair_from_atm - atmospheric air temperature received from atmosphere (pre-downscaling) K F +U10 - 10-m wind m/s T +U10_DUST - 10-m wind for dust model m/s T +U10_ICE - 10-m wind (ice landunits only) m/s F +UAF - canopy air speed m/s F +UM - wind speed plus stability effect m/s F +URBAN_AC - urban air conditioning flux W/m^2 T +URBAN_HEAT - urban heating flux W/m^2 T +USTAR - aerodynamical resistance s/m F +UST_LAKE - friction velocity (lakes only) m/s F +VA - atmospheric wind speed plus convective velocity m/s F +VENTILATION - sensible heat flux from building ventilation W/m^2 T +VOLR - river channel total water storage m3 T +VOLRMCH - river channel main channel water storage m3 T +VPD - vpd Pa F +VPD2M - 2m vapor pressure deficit Pa T +VPD_CAN - canopy vapor pressure deficit kPa T +WASTEHEAT - sensible heat flux from heating/cooling sources of urban waste heat W/m^2 T +WBT - 2 m Stull Wet Bulb C T +WBT_R - Rural 2 m Stull Wet Bulb C T +WBT_U - Urban 2 m Stull Wet Bulb C T +WIND - atmospheric wind velocity magnitude m/s T +WTGQ - surface tracer conductance m/s T +Wind - atmospheric wind velocity magnitude m/s F +Z0HG - roughness length over ground, sensible heat (vegetated landunits only) m F +Z0MG - roughness length over ground, momentum (vegetated landunits only) m F +Z0MV_DENSE - roughness length over vegetation, momentum, for dense canopy m F +Z0M_TO_COUPLER - roughness length, momentum: gridcell average sent to coupler m F +Z0QG - roughness length over ground, latent heat (vegetated landunits only) m F +ZBOT - atmospheric reference height m T +ZETA - dimensionless stability parameter unitless F +ZII - convective boundary height m F +ZWT - water table depth (natural vegetated and crop landunits only) m T +ZWT_CH4_UNSAT - depth of water table for methane production used in non-inundated area m T +ZWT_PERCH - perched water table depth (natural vegetated and crop landunits only) m T +num_iter - number of iterations unitless F +QICE_FORC elevclas qice forcing sent to GLC mm/s F +TOPO_FORC elevclas topograephic height sent to GLC m F +TSRF_FORC elevclas surface temperature sent to GLC K F +FATES_BURNFRAC_AP fates_levage spitfire fraction area burnt (per second) by patch age s-1 T +FATES_CANOPYAREA_AP fates_levage canopy area by age bin per m2 land area m2 m-2 T +FATES_FIRE_INTENSITY_BURNFRAC_AP fates_levage product of fire intensity and burned fraction, resolved by patch age (so divide by FATES_BURNF J m-1 s-1 T +FATES_FUEL_AMOUNT_AP fates_levage spitfire ground fuel (kg carbon per m2) related to FATES_ROS (omits 1000hr fuels) within each kg m-2 T +FATES_GPP_AP fates_levage gross primary productivity by age bin in kg carbon per m2 per second kg m-2 s-1 F +FATES_LAI_AP fates_levage leaf area index by age bin per m2 land area m2 m-2 T +FATES_LBLAYER_COND_AP fates_levage mean leaf boundary layer conductance - by patch age mol m-2 s-1 F +FATES_NCL_AP fates_levage number of canopy levels by age bin F +FATES_NPATCH_AP fates_levage number of patches by age bin F +FATES_NPP_AP fates_levage net primary productivity by age bin in kg carbon per m2 per second kg m-2 s-1 F +FATES_PATCHAREA_AP fates_levage patch area by age bin per m2 land area m2 m-2 T +FATES_SECONDAREA_ANTHRODIST_AP fates_levage secondary forest patch area age distribution since anthropgenic disturbance m2 m-2 F +FATES_SECONDAREA_DIST_AP fates_levage secondary forest patch area age distribution since any kind of disturbance m2 m-2 F +FATES_STOMATAL_COND_AP fates_levage mean stomatal conductance - by patch age mol m-2 s-1 F +FATES_VEGC_AP fates_levage total biomass within a given patch age bin in kg carbon per m2 land area kg m-2 F +FATES_ZSTAR_AP fates_levage product of zstar and patch area by age bin (divide by FATES_PATCHAREA_AP to get mean zstar) m F +FATES_FUEL_AMOUNT_APFC fates_levagefuel spitfire fuel quantity in each age x fuel class in kg carbon per m2 land area kg m-2 F +FATES_NPP_APPF fates_levagepft NPP per PFT in each age bin in kg carbon per m2 per second kg m-2 s-1 F +FATES_SCORCH_HEIGHT_APPF fates_levagepft SPITFIRE flame Scorch Height (calculated per PFT in each patch age bin) m F +FATES_VEGC_APPF fates_levagepft biomass per PFT in each age bin in kg carbon per m2 kg m-2 F +FATES_MORTALITY_AGESCEN_AC fates_levcacls age senescence mortality by cohort age in number of plants per m2 per year m-2 yr-1 T +FATES_NPLANT_AC fates_levcacls number of plants per m2 by cohort age class m-2 T +FATES_CROWNAREA_CL fates_levcan total crown area in each canopy layer m2 m-2 T +FATES_FABD_SHA_TOPLF_CL fates_levcan shade fraction of direct light absorbed by the top leaf layer of each canopy layer 1 F +FATES_FABD_SUN_TOPLF_CL fates_levcan sun fraction of direct light absorbed by the top leaf layer of each canopy layer 1 F +FATES_FABI_SHA_TOPLF_CL fates_levcan shade fraction of indirect light absorbed by the top leaf layer of each canopy layer 1 F +FATES_FABI_SUN_TOPLF_CL fates_levcan sun fraction of indirect light absorbed by the top leaf layer of each canopy layer 1 F +FATES_LAISHA_TOP_CL fates_levcan LAI in the shade by the top leaf layer of each canopy layer m2 m-2 F +FATES_LAISUN_TOP_CL fates_levcan LAI in the sun by the top leaf layer of each canopy layer m2 m-2 F +FATES_PARSHA_Z_CL fates_levcan PAR absorbed in the shade by top leaf layer in each canopy layer W m-2 F +FATES_PARSUN_Z_CL fates_levcan PAR absorbed in the sun by top leaf layer in each canopy layer W m-2 F +FATES_MORTALITY_AGESCEN_ACPF fates_levcapf age senescence mortality by pft/cohort age in number of plants per m2 per year m-2 yr-1 F +FATES_NPLANT_ACPF fates_levcapf stem number density by pft and age class m-2 F +FATES_CROWNAREA_CLLL fates_levcnlf total crown area that is occupied by leaves in each canopy and leaf layer m2 m-2 F +FATES_FABD_SHA_CLLL fates_levcnlf shade fraction of direct light absorbed by each canopy and leaf layer 1 F +FATES_FABD_SUN_CLLL fates_levcnlf sun fraction of direct light absorbed by each canopy and leaf layer 1 F +FATES_FABI_SHA_CLLL fates_levcnlf shade fraction of indirect light absorbed by each canopy and leaf layer 1 F +FATES_FABI_SUN_CLLL fates_levcnlf sun fraction of indirect light absorbed by each canopy and leaf layer 1 F +FATES_LAISHA_Z_CLLL fates_levcnlf LAI in the shade by each canopy and leaf layer m2 m-2 F +FATES_LAISUN_Z_CLLL fates_levcnlf LAI in the sun by each canopy and leaf layer m2 m-2 F +FATES_NET_C_UPTAKE_CLLL fates_levcnlf net carbon uptake in kg carbon per m2 per second by each canopy and leaf layer per unit ground kg m-2 s-1 F +FATES_PARPROF_DIF_CLLL fates_levcnlf radiative profile of diffuse PAR through each canopy and leaf layer (averaged across PFTs) W m-2 F +FATES_PARPROF_DIR_CLLL fates_levcnlf radiative profile of direct PAR through each canopy and leaf layer (averaged across PFTs) W m-2 F +FATES_PARSHA_Z_CLLL fates_levcnlf PAR absorbed in the shade by each canopy and leaf layer W m-2 F +FATES_PARSUN_Z_CLLL fates_levcnlf PAR absorbed in the sun by each canopy and leaf layer W m-2 F +FATES_FABD_SHA_CLLLPF fates_levcnlfpf shade fraction of direct light absorbed by each canopy, leaf, and PFT 1 F +FATES_FABD_SUN_CLLLPF fates_levcnlfpf sun fraction of direct light absorbed by each canopy, leaf, and PFT 1 F +FATES_FABI_SHA_CLLLPF fates_levcnlfpf shade fraction of indirect light absorbed by each canopy, leaf, and PFT 1 F +FATES_FABI_SUN_CLLLPF fates_levcnlfpf sun fraction of indirect light absorbed by each canopy, leaf, and PFT 1 F +FATES_LAISHA_Z_CLLLPF fates_levcnlfpf LAI in the shade by each canopy, leaf, and PFT m2 m-2 F +FATES_LAISUN_Z_CLLLPF fates_levcnlfpf LAI in the sun by each canopy, leaf, and PFT m2 m-2 F +FATES_PARPROF_DIF_CLLLPF fates_levcnlfpf radiative profile of diffuse PAR through each canopy, leaf, and PFT W m-2 F +FATES_PARPROF_DIR_CLLLPF fates_levcnlfpf radiative profile of direct PAR through each canopy, leaf, and PFT W m-2 F +FATES_PARSHA_Z_CLLLPF fates_levcnlfpf PAR absorbed in the shade by each canopy, leaf, and PFT W m-2 F +FATES_PARSUN_Z_CLLLPF fates_levcnlfpf PAR absorbed in the sun by each canopy, leaf, and PFT W m-2 F +FATES_CWD_ABOVEGROUND_DC fates_levcwdsc debris class-level aboveground coarse woody debris stocks in kg carbon per m2 kg m-2 F +FATES_CWD_ABOVEGROUND_IN_DC fates_levcwdsc debris class-level aboveground coarse woody debris input in kg carbon per m2 per second kg m-2 s-1 F +FATES_CWD_ABOVEGROUND_OUT_DC fates_levcwdsc debris class-level aboveground coarse woody debris output in kg carbon per m2 per second kg m-2 s-1 F +FATES_CWD_BELOWGROUND_DC fates_levcwdsc debris class-level belowground coarse woody debris stocks in kg carbon per m2 kg m-2 F +FATES_CWD_BELOWGROUND_IN_DC fates_levcwdsc debris class-level belowground coarse woody debris input in kg carbon per m2 per second kg m-2 s-1 F +FATES_CWD_BELOWGROUND_OUT_DC fates_levcwdsc debris class-level belowground coarse woody debris output in kg carbon per m2 per second kg m-2 s-1 F +FATES_LITTER_CWD_ELDC fates_levelcwd total mass of litter in coarse woody debris by element and coarse woody debris size kg m-2 T +FATES_ERROR_EL fates_levelem total mass-balance error in kg per second by element kg s-1 T +FATES_FIRE_FLUX_EL fates_levelem loss to atmosphere from fire by element in kg element per m2 per s kg m-2 s-1 T +FATES_LITTER_AG_CWD_EL fates_levelem mass of aboveground litter in coarse woody debris (trunks/branches/twigs) by element kg m-2 T +FATES_LITTER_AG_FINE_EL fates_levelem mass of aboveground litter in fines (leaves, nonviable seed) by element kg m-2 T +FATES_LITTER_BG_CWD_EL fates_levelem mass of belowground litter in coarse woody debris (coarse roots) by element kg m-2 T +FATES_LITTER_BG_FINE_EL fates_levelem mass of belowground litter in fines (fineroots) by element kg m-2 T +FATES_LITTER_IN_EL fates_levelem litter flux in in kg element per m2 per second kg m-2 s-1 T +FATES_LITTER_OUT_EL fates_levelem litter flux out (exudation, fragmentation and seed decay) in kg element kg m-2 s-1 T +FATES_SEEDS_IN_EXTERN_EL fates_levelem external seed influx rate in kg element per m2 per second kg m-2 s-1 T +FATES_SEEDS_IN_LOCAL_EL fates_levelem within-site, element-level seed production rate in kg element per m2 per second kg m-2 s-1 T +FATES_SEED_BANK_EL fates_levelem element-level total seed mass of all PFTs in kg element per m2 kg m-2 T +FATES_SEED_DECAY_EL fates_levelem seed mass decay (germinated and un-germinated) in kg element per m2 per second kg m-2 s-1 T +FATES_SEED_GERM_EL fates_levelem element-level total germinated seed mass of all PFTs in kg element per m2 kg m-2 T +FATES_FUEL_AMOUNT_FC fates_levfuel spitfire fuel-class level fuel amount in kg carbon per m2 land area kg m-2 T +FATES_FUEL_BURNT_BURNFRAC_FC fates_levfuel product of fraction (0-1) of fuel burnt and burnt fraction (divide by FATES_BURNFRAC to get bu 1 T +FATES_FUEL_MOISTURE_FC fates_levfuel spitfire fuel class-level fuel moisture (volumetric) m3 m-3 T +FATES_CANOPYAREA_HT fates_levheight canopy area height distribution m2 m-2 T +FATES_LEAFAREA_HT fates_levheight leaf area height distribution m2 m-2 T +FATES_CANOPYCROWNAREA_PF fates_levpft total PFT-level canopy-layer crown area per m2 land area m2 m-2 T +FATES_CROWNAREA_PF fates_levpft total PFT-level crown area per m2 land area m2 m-2 T +FATES_DAYSINCE_DROUGHTLEAFOFF_PF fates_levpft PFT-level days elapsed since drought leaf drop days T +FATES_DAYSINCE_DROUGHTLEAFON_PF fates_levpft PFT-level days elapsed since drought leaf flush days T +FATES_DROUGHT_STATUS_PF fates_levpft PFT-level drought status, <2 too dry for leaves, >=2 not too dry T +FATES_ELONG_FACTOR_PF fates_levpft PFT-level mean elongation factor (partial flushing/abscission) 1 T +FATES_GPP_PF fates_levpft total PFT-level GPP in kg carbon per m2 land area per second kg m-2 s-1 T +FATES_GPP_SE_PF fates_levpft total PFT-level GPP in kg carbon per m2 land area per second, secondary patches kg m-2 s-1 T +FATES_LEAFC_PF fates_levpft total PFT-level leaf biomass in kg carbon per m2 land area kg m-2 T +FATES_MEANLIQVOL_DROUGHTPHEN_PF fates_levpft PFT-level mean liquid water volume for drought phenolgy m3 m-3 T +FATES_MEANSMP_DROUGHTPHEN_PF fates_levpft PFT-level mean soil matric potential for drought phenology Pa T +FATES_MORTALITY_CFLUX_PF fates_levpft PFT-level flux of biomass carbon from live to dead pool from mortality kg m-2 s-1 T +FATES_MORTALITY_CSTARV_CFLUX_PF fates_levpft PFT-level flux of biomass carbon from live to dead pool from carbon starvation mortality kg m-2 s-1 T +FATES_MORTALITY_FIRE_CFLUX_PF fates_levpft PFT-level flux of biomass carbon from live to dead pool from fire mortality kg m-2 s-1 T +FATES_MORTALITY_HYDRO_CFLUX_PF fates_levpft PFT-level flux of biomass carbon from live to dead pool from hydraulic failure mortality kg m-2 s-1 T +FATES_MORTALITY_PF fates_levpft PFT-level mortality rate in number of individuals per m2 land area per year m-2 yr-1 T +FATES_NPLANT_PF fates_levpft total PFT-level number of individuals per m2 land area m-2 T +FATES_NPLANT_SEC_PF fates_levpft total PFT-level number of individuals per m2 land area, secondary patches m-2 T +FATES_NPP_PF fates_levpft total PFT-level NPP in kg carbon per m2 land area per second kg m-2 s-1 T +FATES_NPP_SE_PF fates_levpft total PFT-level NPP in kg carbon per m2 land area per second, secondary patches kg m-2 yr-1 T +FATES_RECRUITMENT_PF fates_levpft PFT-level recruitment rate in number of individuals per m2 land area per year m-2 yr-1 T +FATES_STOREC_PF fates_levpft total PFT-level stored biomass in kg carbon per m2 land area kg m-2 T +FATES_VEGC_PF fates_levpft total PFT-level biomass in kg of carbon per land area kg m-2 T +FATES_VEGC_SE_PF fates_levpft total PFT-level biomass in kg of carbon per land area, secondary patches kg m-2 T +FATES_DDBH_CANOPY_SZAP fates_levscag growth rate of canopy plants in meters DBH per m2 per year in canopy in each size x age class m m-2 yr-1 F +FATES_DDBH_USTORY_SZAP fates_levscag growth rate of understory plants in meters DBH per m2 per year in each size x age class m m-2 yr-1 F +FATES_MORTALITY_CANOPY_SZAP fates_levscag mortality rate of canopy plants in number of plants per m2 per year in each size x age class m-2 yr-1 F +FATES_MORTALITY_USTORY_SZAP fates_levscag mortality rate of understory plants in number of plants per m2 per year in each size x age cla m-2 yr-1 F +FATES_NPLANT_CANOPY_SZAP fates_levscag number of plants per m2 in canopy in each size x age class m-2 F +FATES_NPLANT_SZAP fates_levscag number of plants per m2 in each size x age class m-2 F +FATES_NPLANT_USTORY_SZAP fates_levscag number of plants per m2 in understory in each size x age class m-2 F +FATES_NPLANT_SZAPPF fates_levscagpf number of plants per m2 in each size x age x pft class m-2 F +FATES_BASALAREA_SZ fates_levscls basal area by size class m2 m-2 T +FATES_CROOTMAINTAR_CANOPY_SZ fates_levscls live coarse root maintenance autotrophic respiration for canopy plants in kg carbon per m2 per kg m-2 s-1 F +FATES_CROOTMAINTAR_USTORY_SZ fates_levscls live coarse root maintenance autotrophic respiration for understory plants in kg carbon per m2 kg m-2 s-1 F +FATES_CROWNAREA_CANOPY_SZ fates_levscls total crown area of canopy plants by size class m2 m-2 F +FATES_CROWNAREA_USTORY_SZ fates_levscls total crown area of understory plants by size class m2 m-2 F +FATES_DDBH_CANOPY_SZ fates_levscls diameter growth increment by size of canopy plants m m-2 yr-1 T +FATES_DDBH_USTORY_SZ fates_levscls diameter growth increment by size of understory plants m m-2 yr-1 T +FATES_DEMOTION_RATE_SZ fates_levscls demotion rate from canopy to understory by size class in number of plants per m2 per year m-2 yr-1 F +FATES_FROOTCTURN_CANOPY_SZ fates_levscls fine root turnover (non-mortal) for canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_FROOTCTURN_USTORY_SZ fates_levscls fine root turnover (non-mortal) for understory plants by size class in kg carbon per m2 per se kg m-2 s-1 F +FATES_FROOTMAINTAR_CANOPY_SZ fates_levscls live coarse root maintenance autotrophic respiration for canopy plants in kg carbon per m2 per kg m-2 s-1 F +FATES_FROOTMAINTAR_USTORY_SZ fates_levscls fine root maintenance autotrophic respiration for understory plants in kg carbon per m2 per se kg m-2 s-1 F +FATES_FROOT_ALLOC_CANOPY_SZ fates_levscls allocation to fine root C for canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_FROOT_ALLOC_USTORY_SZ fates_levscls allocation to fine roots for understory plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_GROWAR_CANOPY_SZ fates_levscls growth autotrophic respiration of canopy plants in kg carbon per m2 per second by size kg m-2 s-1 F +FATES_GROWAR_USTORY_SZ fates_levscls growth autotrophic respiration of understory plants in kg carbon per m2 per second by size kg m-2 s-1 F +FATES_LAI_CANOPY_SZ fates_levscls leaf area index (LAI) of canopy plants by size class m2 m-2 T +FATES_LAI_USTORY_SZ fates_levscls leaf area index (LAI) of understory plants by size class m2 m-2 T +FATES_LEAFCTURN_CANOPY_SZ fates_levscls leaf turnover (non-mortal) for canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_LEAFCTURN_USTORY_SZ fates_levscls leaf turnover (non-mortal) for understory plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_LEAF_ALLOC_CANOPY_SZ fates_levscls allocation to leaves for canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_LEAF_ALLOC_USTORY_SZ fates_levscls allocation to leaves for understory plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_LSTEMMAINTAR_CANOPY_SZ fates_levscls live stem maintenance autotrophic respiration for canopy plants in kg carbon per m2 per second kg m-2 s-1 F +FATES_LSTEMMAINTAR_USTORY_SZ fates_levscls live stem maintenance autotrophic respiration for understory plants in kg carbon per m2 per se kg m-2 s-1 F +FATES_M3_MORTALITY_CANOPY_SZ fates_levscls C starvation mortality of canopy plants by size N/ha/yr F +FATES_M3_MORTALITY_USTORY_SZ fates_levscls C starvation mortality of understory plants by size N/ha/yr F +FATES_MAINTAR_CANOPY_SZ fates_levscls maintenance autotrophic respiration of canopy plants in kg carbon per m2 per second by size kg m-2 s-1 F +FATES_MAINTAR_USTORY_SZ fates_levscls maintenance autotrophic respiration of understory plants in kg carbon per m2 per second by siz kg m-2 s-1 F +FATES_MORTALITY_AGESCEN_SE_SZ fates_levscls age senescence mortality by size in number of plants per m2 per year, secondary patches m-2 yr-1 T +FATES_MORTALITY_AGESCEN_SZ fates_levscls age senescence mortality by size in number of plants per m2 per year m-2 yr-1 T +FATES_MORTALITY_BACKGROUND_SE_SZ fates_levscls background mortality by size in number of plants per m2 per year, secondary patches m-2 yr-1 T +FATES_MORTALITY_BACKGROUND_SZ fates_levscls background mortality by size in number of plants per m2 per year m-2 yr-1 T +FATES_MORTALITY_CANOPY_SE_SZ fates_levscls total mortality of canopy trees by size class in number of plants per m2, secondary patches m-2 yr-1 T +FATES_MORTALITY_CANOPY_SZ fates_levscls total mortality of canopy trees by size class in number of plants per m2 m-2 yr-1 T +FATES_MORTALITY_CSTARV_SE_SZ fates_levscls carbon starvation mortality by size in number of plants per m2 per year, secondary patches m-2 yr-1 T +FATES_MORTALITY_CSTARV_SZ fates_levscls carbon starvation mortality by size in number of plants per m2 per year m-2 yr-1 T +FATES_MORTALITY_FIRE_SZ fates_levscls fire mortality by size in number of plants per m2 per year m-2 yr-1 T +FATES_MORTALITY_FREEZING_SE_SZ fates_levscls freezing mortality by size in number of plants per m2 per event, secondary patches m-2 event-1 T +FATES_MORTALITY_FREEZING_SZ fates_levscls freezing mortality by size in number of plants per m2 per year m-2 yr-1 T +FATES_MORTALITY_HYDRAULIC_SE_SZ fates_levscls hydraulic mortality by size in number of plants per m2 per year, secondary patches m-2 yr-1 T +FATES_MORTALITY_HYDRAULIC_SZ fates_levscls hydraulic mortality by size in number of plants per m2 per year m-2 yr-1 T +FATES_MORTALITY_IMPACT_SZ fates_levscls impact mortality by size in number of plants per m2 per year m-2 yr-1 T +FATES_MORTALITY_LOGGING_SE_SZ fates_levscls logging mortality by size in number of plants per m2 per event, secondary patches m-2 yr-1 T +FATES_MORTALITY_LOGGING_SZ fates_levscls logging mortality by size in number of plants per m2 per year m-2 yr-1 T +FATES_MORTALITY_SENESCENCE_SE_SZ fates_levscls senescence mortality by size in number of plants per m2 per event, secondary patches m-2 yr-1 T +FATES_MORTALITY_SENESCENCE_SZ fates_levscls senescence mortality by size in number of plants per m2 per year m-2 yr-1 T +FATES_MORTALITY_TERMINATION_SZ fates_levscls termination mortality by size in number of plants per m2 per year m-2 yr-1 T +FATES_MORTALITY_USTORY_SZ fates_levscls total mortality of understory trees by size class in individuals per m2 per year m-2 yr-1 T +FATES_NPLANT_CANOPY_SZ fates_levscls number of canopy plants per m2 by size class m-2 T +FATES_NPLANT_SZ fates_levscls number of plants per m2 by size class m-2 T +FATES_NPLANT_USTORY_SZ fates_levscls number of understory plants per m2 by size class m-2 T +FATES_NPP_CANOPY_SZ fates_levscls NPP of canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_NPP_USTORY_SZ fates_levscls NPP of understory plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_PROMOTION_RATE_SZ fates_levscls promotion rate from understory to canopy by size class m-2 yr-1 F +FATES_RDARK_CANOPY_SZ fates_levscls dark respiration for canopy plants in kg carbon per m2 per second by size kg m-2 s-1 F +FATES_RDARK_USTORY_SZ fates_levscls dark respiration for understory plants in kg carbon per m2 per second by size kg m-2 s-1 F +FATES_SAI_CANOPY_SZ fates_levscls stem area index (SAI) of canopy plants by size class m2 m-2 F +FATES_SAI_USTORY_SZ fates_levscls stem area index (SAI) of understory plants by size class m2 m-2 F +FATES_SAPWOODCTURN_CANOPY_SZ fates_levscls sapwood turnover (non-mortal) for canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_SAPWOODCTURN_USTORY_SZ fates_levscls sapwood C turnover (non-mortal) for understory plants by size class in kg carbon per m2 per se kg m-2 s-1 F +FATES_SAPWOOD_ALLOC_CANOPY_SZ fates_levscls allocation to sapwood C for canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_SAPWOOD_ALLOC_USTORY_SZ fates_levscls allocation to sapwood C for understory plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_SEED_ALLOC_CANOPY_SZ fates_levscls allocation to reproductive C for canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_SEED_ALLOC_USTORY_SZ fates_levscls allocation to reproductive C for understory plants by size class in kg carbon per m2 per secon kg m-2 s-1 F +FATES_SEED_PROD_CANOPY_SZ fates_levscls seed production of canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_SEED_PROD_USTORY_SZ fates_levscls seed production of understory plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_STORECTURN_CANOPY_SZ fates_levscls storage turnover (non-mortal) for canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_STORECTURN_USTORY_SZ fates_levscls storage C turnover (non-mortal) for understory plants by size class in kg carbon per m2 per se kg m-2 s-1 F +FATES_STORE_ALLOC_CANOPY_SZ fates_levscls allocation to storage C for canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_STORE_ALLOC_USTORY_SZ fates_levscls allocation to storage C for understory plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_STRUCTCTURN_CANOPY_SZ fates_levscls structural C turnover (non-mortal) for canopy plants by size class in kg carbon per m2 per sec kg m-2 s-1 F +FATES_STRUCTCTURN_USTORY_SZ fates_levscls structural C turnover (non-mortal) for understory plants by size class in kg carbon per m2 per kg m-2 s-1 F +FATES_STRUCT_ALLOC_CANOPY_SZ fates_levscls allocation to structural C for canopy plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_STRUCT_ALLOC_USTORY_SZ fates_levscls allocation to structural C for understory plants by size class in kg carbon per m2 per second kg m-2 s-1 F +FATES_TRIMMING_CANOPY_SZ fates_levscls trimming term of canopy plants weighted by plant density, by size class m-2 F +FATES_TRIMMING_USTORY_SZ fates_levscls trimming term of understory plants weighted by plant density, by size class m-2 F +FATES_VEGC_ABOVEGROUND_SZ fates_levscls aboveground biomass by size class in kg carbon per m2 kg m-2 T +FATES_VEGC_SZ fates_levscls total biomass by size class in kg carbon per m2 kg m-2 F +FATES_YESTCANLEV_CANOPY_SZ fates_levscls yesterdays canopy level for canopy plants by size class in number of plants per m2 m-2 F +FATES_YESTCANLEV_USTORY_SZ fates_levscls yesterdays canopy level for understory plants by size class in number of plants per m2 m-2 F +FATES_ABOVEGROUND_MORT_SZPF fates_levscpf Aboveground flux of carbon from AGB to necromass due to mortality kg m-2 s-1 F +FATES_ABOVEGROUND_PROD_SZPF fates_levscpf Aboveground carbon productivity kg m-2 s-1 F +FATES_AGSAPMAINTAR_SZPF fates_levscpf above-ground sapwood maintenance autotrophic respiration in kg carbon per m2 per second by pft kg m-2 s-1 F +FATES_AGSAPWOOD_ALLOC_SZPF fates_levscpf allocation to above-ground sapwood by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_AGSTRUCT_ALLOC_SZPF fates_levscpf allocation to above-ground structural (deadwood) by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_AUTORESP_CANOPY_SZPF fates_levscpf autotrophic respiration of canopy plants by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_AUTORESP_SZPF fates_levscpf total autotrophic respiration in kg carbon per m2 per second by pft/size kg m-2 s-1 F +FATES_AUTORESP_USTORY_SZPF fates_levscpf autotrophic respiration of understory plants by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_BASALAREA_SZPF fates_levscpf basal area by pft/size m2 m-2 F +FATES_BGSAPMAINTAR_SZPF fates_levscpf below-ground sapwood maintenance autotrophic respiration in kg carbon per m2 per second by pft kg m-2 s-1 F +FATES_BGSAPWOOD_ALLOC_SZPF fates_levscpf allocation to below-ground sapwood by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_BGSTRUCT_ALLOC_SZPF fates_levscpf allocation to below-ground structural (deadwood) by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_C13DISC_SZPF fates_levscpf C13 discrimination by pft/size per mil F +FATES_DDBH_CANOPY_SZPF fates_levscpf diameter growth increment by pft/size m m-2 yr-1 F +FATES_DDBH_SZPF fates_levscpf diameter growth increment by pft/size m m-2 yr-1 F +FATES_DDBH_USTORY_SZPF fates_levscpf diameter growth increment by pft/size m m-2 yr-1 F +FATES_FROOTC_SZPF fates_levscpf fine-root carbon mass by size-class x pft in kg carbon per m2 kg m-2 F +FATES_FROOTMAINTAR_SZPF fates_levscpf fine root maintenance autotrophic respiration in kg carbon per m2 per second by pft/size kg m-2 s-1 F +FATES_FROOT_ALLOC_SZPF fates_levscpf allocation to fine roots by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_GPP_CANOPY_SZPF fates_levscpf gross primary production of canopy plants by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_GPP_SZPF fates_levscpf gross primary production by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_GPP_USTORY_SZPF fates_levscpf gross primary production of understory plants by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_GROWAR_SZPF fates_levscpf growth autotrophic respiration in kg carbon per m2 per second by pft/size kg m-2 s-1 F +FATES_GROWTHFLUX_FUSION_SZPF fates_levscpf flux of individuals into a given size class bin via fusion m-2 yr-1 F +FATES_GROWTHFLUX_SZPF fates_levscpf flux of individuals into a given size class bin via growth and recruitment m-2 yr-1 F +FATES_LAI_CANOPY_SZPF fates_levscpf Leaf area index (LAI) of canopy plants by pft/size m2 m-2 F +FATES_LAI_USTORY_SZPF fates_levscpf Leaf area index (LAI) of understory plants by pft/size m2 m-2 F +FATES_LEAFC_CANOPY_SZPF fates_levscpf biomass in leaves of canopy plants by pft/size in kg carbon per m2 kg m-2 F +FATES_LEAFC_SZPF fates_levscpf leaf carbon mass by size-class x pft in kg carbon per m2 kg m-2 F +FATES_LEAFC_USTORY_SZPF fates_levscpf biomass in leaves of understory plants by pft/size in kg carbon per m2 kg m-2 F +FATES_LEAF_ALLOC_SZPF fates_levscpf allocation to leaves by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_M3_MORTALITY_CANOPY_SZPF fates_levscpf C starvation mortality of canopy plants by pft/size N/ha/yr F +FATES_M3_MORTALITY_USTORY_SZPF fates_levscpf C starvation mortality of understory plants by pft/size N/ha/yr F +FATES_MAINTAR_SZPF fates_levscpf maintenance autotrophic respiration in kg carbon per m2 per second by pft/size kg m-2 s-1 F +FATES_MORTALITY_AGESCEN_SZPF fates_levscpf age senescence mortality by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_BACKGROUND_SZPF fates_levscpf background mortality by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_CAMBIALBURN_SZPF fates_levscpf fire mortality from cambial burn by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_CANOPY_SZPF fates_levscpf total mortality of canopy plants by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_CROWNSCORCH_SZPF fates_levscpf fire mortality from crown scorch by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_CSTARV_SZPF fates_levscpf carbon starvation mortality by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_FIRE_SZPF fates_levscpf fire mortality by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_FREEZING_SZPF fates_levscpf freezing mortality by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_HYDRAULIC_SZPF fates_levscpf hydraulic mortality by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_IMPACT_SZPF fates_levscpf impact mortality by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_LOGGING_SZPF fates_levscpf logging mortality by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_SENESCENCE_SZPF fates_levscpf senescence mortality by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_TERMINATION_SZPF fates_levscpf termination mortality by pft/size in number pf plants per m2 per year m-2 yr-1 F +FATES_MORTALITY_USTORY_SZPF fates_levscpf total mortality of understory plants by pft/size in number of plants per m2 per year m-2 yr-1 F +FATES_NPLANT_CANOPY_SZPF fates_levscpf number of canopy plants by size/pft per m2 m-2 F +FATES_NPLANT_SZPF fates_levscpf stem number density by pft/size m-2 F +FATES_NPLANT_USTORY_SZPF fates_levscpf density of understory plants by pft/size in number of plants per m2 m-2 F +FATES_NPP_SZPF fates_levscpf total net primary production by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_RDARK_SZPF fates_levscpf dark portion of maintenance autotrophic respiration in kg carbon per m2 per second by pft/size kg m-2 s-1 F +FATES_REPROC_SZPF fates_levscpf reproductive carbon mass (on plant) by size-class x pft in kg carbon per m2 kg m-2 F +FATES_SAPWOODC_SZPF fates_levscpf sapwood carbon mass by size-class x pft in kg carbon per m2 kg m-2 F +FATES_SEED_ALLOC_SZPF fates_levscpf allocation to seeds by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_STOREC_CANOPY_SZPF fates_levscpf biomass in storage pools of canopy plants by pft/size in kg carbon per m2 kg m-2 F +FATES_STOREC_SZPF fates_levscpf storage carbon mass by size-class x pft in kg carbon per m2 kg m-2 F +FATES_STOREC_TF_CANOPY_SZPF fates_levscpf Storage C fraction of target by size x pft, in the canopy kg kg-1 F +FATES_STOREC_TF_USTORY_SZPF fates_levscpf Storage C fraction of target by size x pft, in the understory kg kg-1 F +FATES_STOREC_USTORY_SZPF fates_levscpf biomass in storage pools of understory plants by pft/size in kg carbon per m2 kg m-2 F +FATES_STORE_ALLOC_SZPF fates_levscpf allocation to storage C by pft/size in kg carbon per m2 per second kg m-2 s-1 F +FATES_VEGC_ABOVEGROUND_SZPF fates_levscpf aboveground biomass by pft/size in kg carbon per m2 kg m-2 F +FATES_VEGC_SZPF fates_levscpf total vegetation biomass in live plants by size-class x pft in kg carbon per m2 kg m-2 F +ACTUAL_IMMOB_NH4 levdcmp immobilization of NH4 gN/m^3/s F +ACTUAL_IMMOB_NO3 levdcmp immobilization of NO3 gN/m^3/s F +ACTUAL_IMMOB_vr levdcmp actual N immobilization gN/m^3/s F +FMAX_DENIT_CARBONSUBSTRATE levdcmp FMAX_DENIT_CARBONSUBSTRATE gN/m^3/s F +FMAX_DENIT_NITRATE levdcmp FMAX_DENIT_NITRATE gN/m^3/s F +FPI_vr levdcmp fraction of potential immobilization proportion F +F_DENIT_BASE levdcmp F_DENIT_BASE gN/m^3/s F +F_DENIT_vr levdcmp denitrification flux gN/m^3/s F +F_NIT_vr levdcmp nitrification flux gN/m^3/s F +GROSS_NMIN_vr levdcmp gross rate of N mineralization gN/m^3/s F +K_LIT_CEL levdcmp cellulosic litter potential loss coefficient 1/s F +K_LIT_LIG levdcmp lignin litter potential loss coefficient 1/s F +K_LIT_MET levdcmp metabolic litter potential loss coefficient 1/s F +K_NITR levdcmp K_NITR 1/s F +K_NITR_H2O levdcmp K_NITR_H2O unitless F +K_NITR_PH levdcmp K_NITR_PH unitless F +K_NITR_T levdcmp K_NITR_T unitless F +K_SOM_ACT levdcmp active soil organic potential loss coefficient 1/s F +K_SOM_PAS levdcmp passive soil organic potential loss coefficient 1/s F +K_SOM_SLO levdcmp slow soil organic ma potential loss coefficient 1/s F +L1_PATHFRAC_S1_vr levdcmp PATHFRAC from metabolic litter to active soil organic fraction F +L1_RESP_FRAC_S1_vr levdcmp respired from metabolic litter to active soil organic fraction F +L2_PATHFRAC_S1_vr levdcmp PATHFRAC from cellulosic litter to active soil organic fraction F +L2_RESP_FRAC_S1_vr levdcmp respired from cellulosic litter to active soil organic fraction F +L3_PATHFRAC_S2_vr levdcmp PATHFRAC from lignin litter to slow soil organic ma fraction F +L3_RESP_FRAC_S2_vr levdcmp respired from lignin litter to slow soil organic ma fraction F +LIT_CEL_C_TNDNCY_VERT_TR levdcmp cellulosic litter C tendency due to vertical transport gC/m^3/s F +LIT_CEL_C_TO_SOM_ACT_C_v levdcmp decomp. of cellulosic litter C to active soil organic C gC/m^3/s F +LIT_CEL_HR_vr levdcmp Het. Resp. from cellulosic litter gC/m^3/s F +LIT_CEL_N_TNDNCY_VERT_TR levdcmp cellulosic litter N tendency due to vertical transport gN/m^3/s F +LIT_CEL_N_TO_SOM_ACT_N_v levdcmp decomp. of cellulosic litter N to active soil organic N gN/m^3 F +LIT_CEL_N_vr levdcmp LIT_CEL N (vertically resolved) gN/m^3 T +LIT_LIG_C_TNDNCY_VERT_TR levdcmp lignin litter C tendency due to vertical transport gC/m^3/s F +LIT_LIG_C_TO_SOM_SLO_C_v levdcmp decomp. of lignin litter C to slow soil organic ma C gC/m^3/s F +LIT_LIG_HR_vr levdcmp Het. Resp. from lignin litter gC/m^3/s F +LIT_LIG_N_TNDNCY_VERT_TR levdcmp lignin litter N tendency due to vertical transport gN/m^3/s F +LIT_LIG_N_TO_SOM_SLO_N_v levdcmp decomp. of lignin litter N to slow soil organic ma N gN/m^3 F +LIT_LIG_N_vr levdcmp LIT_LIG N (vertically resolved) gN/m^3 T +LIT_MET_C_TNDNCY_VERT_TR levdcmp metabolic litter C tendency due to vertical transport gC/m^3/s F +LIT_MET_C_TO_SOM_ACT_C_v levdcmp decomp. of metabolic litter C to active soil organic C gC/m^3/s F +LIT_MET_HR_vr levdcmp Het. Resp. from metabolic litter gC/m^3/s F +LIT_MET_N_TNDNCY_VERT_TR levdcmp metabolic litter N tendency due to vertical transport gN/m^3/s F +LIT_MET_N_TO_SOM_ACT_N_v levdcmp decomp. of metabolic litter N to active soil organic N gN/m^3 F +LIT_MET_N_vr levdcmp LIT_MET N (vertically resolved) gN/m^3 T +NDEP_PROF levdcmp profile for atmospheric N deposition 1/m F +NET_NMIN_vr levdcmp net rate of N mineralization gN/m^3/s F +NFIXATION_PROF levdcmp profile for biological N fixation 1/m F +POTENTIAL_IMMOB_vr levdcmp potential N immobilization gN/m^3/s F +POT_F_DENIT_vr levdcmp potential denitrification flux gN/m^3/s F +POT_F_NIT_vr levdcmp potential nitrification flux gN/m^3/s F +S1_PATHFRAC_S2_vr levdcmp PATHFRAC from active soil organic to slow soil organic ma fraction F +S1_PATHFRAC_S3_vr levdcmp PATHFRAC from active soil organic to passive soil organic fraction F +S1_RESP_FRAC_S2_vr levdcmp respired from active soil organic to slow soil organic ma fraction F +S1_RESP_FRAC_S3_vr levdcmp respired from active soil organic to passive soil organic fraction F +S2_PATHFRAC_S1_vr levdcmp PATHFRAC from slow soil organic ma to active soil organic fraction F +S2_PATHFRAC_S3_vr levdcmp PATHFRAC from slow soil organic ma to passive soil organic fraction F +S2_RESP_FRAC_S1_vr levdcmp respired from slow soil organic ma to active soil organic fraction F +S2_RESP_FRAC_S3_vr levdcmp respired from slow soil organic ma to passive soil organic fraction F +S3_PATHFRAC_S1_vr levdcmp PATHFRAC from passive soil organic to active soil organic fraction F +S3_RESP_FRAC_S1_vr levdcmp respired from passive soil organic to active soil organic fraction F +SMINN_TO_PLANT_vr levdcmp plant uptake of soil mineral N gN/m^3/s F +SMINN_TO_S1N_L1_vr levdcmp mineral N flux for decomp. of LIT_METto SOM_ACT gN/m^3 F +SMINN_TO_S1N_L2_vr levdcmp mineral N flux for decomp. of LIT_CELto SOM_ACT gN/m^3 F +SMINN_TO_S1N_S2_vr levdcmp mineral N flux for decomp. of SOM_SLOto SOM_ACT gN/m^3 F +SMINN_TO_S1N_S3_vr levdcmp mineral N flux for decomp. of SOM_PASto SOM_ACT gN/m^3 F +SMINN_TO_S2N_L3_vr levdcmp mineral N flux for decomp. of LIT_LIGto SOM_SLO gN/m^3 F +SMINN_TO_S2N_S1_vr levdcmp mineral N flux for decomp. of SOM_ACTto SOM_SLO gN/m^3 F +SMINN_TO_S3N_S1_vr levdcmp mineral N flux for decomp. of SOM_ACTto SOM_PAS gN/m^3 F +SMINN_TO_S3N_S2_vr levdcmp mineral N flux for decomp. of SOM_SLOto SOM_PAS gN/m^3 F +SMIN_NH4_TO_PLANT levdcmp plant uptake of NH4 gN/m^3/s F +SMIN_NO3_LEACHED_vr levdcmp soil NO3 pool loss to leaching gN/m^3/s F +SMIN_NO3_MASSDENS levdcmp SMIN_NO3_MASSDENS ugN/cm^3 soil F +SMIN_NO3_RUNOFF_vr levdcmp soil NO3 pool loss to runoff gN/m^3/s F +SMIN_NO3_TO_PLANT levdcmp plant uptake of NO3 gN/m^3/s F +SOILN_vr levdcmp SOIL N (vertically resolved) gN/m^3 T +SOM_ACT_C_TNDNCY_VERT_TR levdcmp active soil organic C tendency due to vertical transport gC/m^3/s F +SOM_ACT_C_TO_SOM_PAS_C_v levdcmp decomp. of active soil organic C to passive soil organic C gC/m^3/s F +SOM_ACT_C_TO_SOM_SLO_C_v levdcmp decomp. of active soil organic C to slow soil organic ma C gC/m^3/s F +SOM_ACT_HR_S2_vr levdcmp Het. Resp. from active soil organic gC/m^3/s F +SOM_ACT_HR_S3_vr levdcmp Het. Resp. from active soil organic gC/m^3/s F +SOM_ACT_N_TNDNCY_VERT_TR levdcmp active soil organic N tendency due to vertical transport gN/m^3/s F +SOM_ACT_N_TO_SOM_PAS_N_v levdcmp decomp. of active soil organic N to passive soil organic N gN/m^3 F +SOM_ACT_N_TO_SOM_SLO_N_v levdcmp decomp. of active soil organic N to slow soil organic ma N gN/m^3 F +SOM_ACT_N_vr levdcmp SOM_ACT N (vertically resolved) gN/m^3 T +SOM_ADV_COEF levdcmp advection term for vertical SOM translocation m/s F +SOM_DIFFUS_COEF levdcmp diffusion coefficient for vertical SOM translocation m^2/s F +SOM_PAS_C_TNDNCY_VERT_TR levdcmp passive soil organic C tendency due to vertical transport gC/m^3/s F +SOM_PAS_C_TO_SOM_ACT_C_v levdcmp decomp. of passive soil organic C to active soil organic C gC/m^3/s F +SOM_PAS_HR_vr levdcmp Het. Resp. from passive soil organic gC/m^3/s F +SOM_PAS_N_TNDNCY_VERT_TR levdcmp passive soil organic N tendency due to vertical transport gN/m^3/s F +SOM_PAS_N_TO_SOM_ACT_N_v levdcmp decomp. of passive soil organic N to active soil organic N gN/m^3 F +SOM_PAS_N_vr levdcmp SOM_PAS N (vertically resolved) gN/m^3 T +SOM_SLO_C_TNDNCY_VERT_TR levdcmp slow soil organic ma C tendency due to vertical transport gC/m^3/s F +SOM_SLO_C_TO_SOM_ACT_C_v levdcmp decomp. of slow soil organic ma C to active soil organic C gC/m^3/s F +SOM_SLO_C_TO_SOM_PAS_C_v levdcmp decomp. of slow soil organic ma C to passive soil organic C gC/m^3/s F +SOM_SLO_HR_S1_vr levdcmp Het. Resp. from slow soil organic ma gC/m^3/s F +SOM_SLO_HR_S3_vr levdcmp Het. Resp. from slow soil organic ma gC/m^3/s F +SOM_SLO_N_TNDNCY_VERT_TR levdcmp slow soil organic ma N tendency due to vertical transport gN/m^3/s F +SOM_SLO_N_TO_SOM_ACT_N_v levdcmp decomp. of slow soil organic ma N to active soil organic N gN/m^3 F +SOM_SLO_N_TO_SOM_PAS_N_v levdcmp decomp. of slow soil organic ma N to passive soil organic N gN/m^3 F +SOM_SLO_N_vr levdcmp SOM_SLO N (vertically resolved) gN/m^3 T +SUPPLEMENT_TO_SMINN_vr levdcmp supplemental N supply gN/m^3/s F +WFPS levdcmp WFPS percent F +anaerobic_frac levdcmp anaerobic_frac m3/m3 F +diffus levdcmp diffusivity m^2/s F +fr_WFPS levdcmp fr_WFPS fraction F +n2_n2o_ratio_denit levdcmp n2_n2o_ratio_denit gN/gN F +r_psi levdcmp r_psi m F +ratio_k1 levdcmp ratio_k1 none F +ratio_no3_co2 levdcmp ratio_no3_co2 ratio F +soil_bulkdensity levdcmp soil_bulkdensity kg/m3 F +soil_co2_prod levdcmp soil_co2_prod ug C / g soil / day F +CONC_CH4_SAT levgrnd CH4 soil Concentration for inundated / lake area mol/m3 F +CONC_CH4_UNSAT levgrnd CH4 soil Concentration for non-inundated area mol/m3 F +FGR_SOIL_R levgrnd Rural downward heat flux at interface below each soil layer watt/m^2 F +HK levgrnd hydraulic conductivity (natural vegetated and crop landunits only) mm/s F +O2_DECOMP_DEPTH_UNSAT levgrnd O2 consumption from HR and AR for non-inundated area mol/m3/s F +SMP levgrnd soil matric potential (natural vegetated and crop landunits only) mm T +SOILPSI levgrnd soil water potential in each soil layer MPa F +TSOI levgrnd soil temperature (natural vegetated and crop landunits only) K T +TSOI_ICE levgrnd soil temperature (ice landunits only) K T +LAKEICEFRAC levlak lake layer ice mass fraction unitless F +TLAKE levlak lake temperature K T +SNO_ABS levsno Absorbed solar radiation in each snow layer W/m^2 F +SNO_ABS_ICE levsno Absorbed solar radiation in each snow layer (ice landunits only) W/m^2 F +SNO_BW levsno Partial density of water in the snow pack (ice + liquid) kg/m3 F +SNO_BW_ICE levsno Partial density of water in the snow pack (ice + liquid, ice landunits only) kg/m3 F +SNO_EXISTENCE levsno Fraction of averaging period for which each snow layer existed unitless F +SNO_FRZ levsno snow freezing rate in each snow layer kg/m2/s F +SNO_FRZ_ICE levsno snow freezing rate in each snow layer (ice landunits only) mm/s F +SNO_GS levsno Mean snow grain size Microns F +SNO_GS_ICE levsno Mean snow grain size (ice landunits only) Microns F +SNO_ICE levsno Snow ice content kg/m2 F +SNO_LIQH2O levsno Snow liquid water content kg/m2 F +SNO_MELT levsno snow melt rate in each snow layer mm/s F +SNO_MELT_ICE levsno snow melt rate in each snow layer (ice landunits only) mm/s F +SNO_T levsno Snow temperatures K F +SNO_TK levsno Thermal conductivity W/m-K F +SNO_TK_ICE levsno Thermal conductivity (ice landunits only) W/m-K F +SNO_T_ICE levsno Snow temperatures (ice landunits only) K F +SNO_Z levsno Snow layer thicknesses m F +SNO_Z_ICE levsno Snow layer thicknesses (ice landunits only) m F +CONC_O2_SAT levsoi O2 soil Concentration for inundated / lake area mol/m3 T +CONC_O2_UNSAT levsoi O2 soil Concentration for non-inundated area mol/m3 T +FATES_FRAGMENTATION_SCALER_SL levsoi factor (0-1) by which litter/cwd fragmentation proceeds relative to max rate by soil layer T +FATES_FROOTC_SL levsoi Total carbon in live plant fine-roots over depth kg m-3 T +H2OSOI levsoi volumetric soil water (natural vegetated and crop landunits only) mm3/mm3 T +HR_vr levsoi total vertically resolved heterotrophic respiration gC/m^3/s T +KROOT levsoi root conductance each soil layer 1/s F +KSOIL levsoi soil conductance in each soil layer 1/s F +LIT_CEL_C_vr levsoi LIT_CEL C (vertically resolved) gC/m^3 T +LIT_LIG_C_vr levsoi LIT_LIG C (vertically resolved) gC/m^3 T +LIT_MET_C_vr levsoi LIT_MET C (vertically resolved) gC/m^3 T +O_SCALAR levsoi fraction by which decomposition is reduced due to anoxia unitless T +QROOTSINK levsoi water flux from soil to root in each soil-layer mm/s F +SMINN_vr levsoi soil mineral N gN/m^3 T +SMIN_NH4_vr levsoi soil mineral NH4 (vert. res.) gN/m^3 T +SMIN_NO3_vr levsoi soil mineral NO3 (vert. res.) gN/m^3 T +SOILC_vr levsoi SOIL C (vertically resolved) gC/m^3 T +SOILICE levsoi soil ice (natural vegetated and crop landunits only) kg/m2 T +SOILLIQ levsoi soil liquid water (natural vegetated and crop landunits only) kg/m2 T +SOM_ACT_C_vr levsoi SOM_ACT C (vertically resolved) gC/m^3 T +SOM_PAS_C_vr levsoi SOM_PAS C (vertically resolved) gC/m^3 T +SOM_SLO_C_vr levsoi SOM_SLO C (vertically resolved) gC/m^3 T +T_SCALAR levsoi temperature inhibition of decomposition unitless T +W_SCALAR levsoi Moisture (dryness) inhibition of decomposition unitless T +ALBD numrad surface albedo (direct) proportion F +ALBGRD numrad ground albedo (direct) proportion F +ALBGRI numrad ground albedo (indirect) proportion F +ALBI numrad surface albedo (indirect) proportion F +=================================== ================ ============================================================================================== ================================================================= ======= diff --git a/doc/source/users_guide/setting-up-and-running-a-case/history_fields_nofates.rst b/doc/source/users_guide/setting-up-and-running-a-case/history_fields_nofates.rst new file mode 100644 index 0000000000..4e96f5fb91 --- /dev/null +++ b/doc/source/users_guide/setting-up-and-running-a-case/history_fields_nofates.rst @@ -0,0 +1,1288 @@ +============================= +CTSM History Fields (nofates) +============================= + +CAUTION: Not all variables are relevant / present for all CTSM cases. +Key flags used in this CTSM case: +use_cn = T +use_crop = T +use_fates = F + +=================================== ================ ============================================================================================== ================================================================= ======= +CTSM History Fields +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Variable Name Level Dim. Long Description Units Active? +=================================== ================ ============================================================================================== ================================================================= ======= +A10TMIN - 10-day running mean of min 2-m temperature K F +A5TMIN - 5-day running mean of min 2-m temperature K F +ACTUAL_IMMOB - actual N immobilization gN/m^2/s T +AGLB - Aboveground leaf biomass kg/m^2 F +AGNPP - aboveground NPP gC/m^2/s T +AGSB - Aboveground stem biomass kg/m^2 F +ALPHA - alpha coefficient for VOC calc non F +ALT - current active layer thickness m T +ALTMAX - maximum annual active layer thickness m T +ALTMAX_LASTYEAR - maximum prior year active layer thickness m F +ANNAVG_T2M - annual average 2m air temperature K F +ANNMAX_RETRANSN - annual max of retranslocated N pool gN/m^2 F +ANNSUM_COUNTER - seconds since last annual accumulator turnover s F +ANNSUM_NPP - annual sum of NPP gC/m^2/yr F +ANNSUM_POTENTIAL_GPP - annual sum of potential GPP gN/m^2/yr F +AR - autotrophic respiration (MR + GR) gC/m^2/s T +ATM_O3 - atmospheric ozone partial pressure mol/mol F +ATM_TOPO - atmospheric surface height m T +AVAILC - C flux available for allocation gC/m^2/s F +AVAIL_RETRANSN - N flux available from retranslocation pool gN/m^2/s F +AnnET - Annual ET mm/s F +BAF_CROP - fractional area burned for crop s-1 T +BAF_PEATF - fractional area burned in peatland s-1 T +BCDEP - total BC deposition (dry+wet) from atmosphere kg/m^2/s T +BETA - coefficient of convective velocity none F +BGLFR - background litterfall rate 1/s F +BGNPP - belowground NPP gC/m^2/s T +BGTR - background transfer growth rate 1/s F +BTRANMN - daily minimum of transpiration beta factor unitless T +CANNAVG_T2M - annual average of 2m air temperature K F +CANNSUM_NPP - annual sum of column-level NPP gC/m^2/s F +CGRND - deriv. of soil energy flux wrt to soil temp W/m^2/K F +CGRNDL - deriv. of soil latent heat flux wrt soil temp W/m^2/K F +CGRNDS - deriv. of soil sensible heat flux wrt soil temp W/m^2/K F +CH4PROD - Gridcell total production of CH4 gC/m2/s T +CH4_EBUL_TOTAL_SAT - ebullition surface CH4 flux; (+ to atm) mol/m2/s F +CH4_EBUL_TOTAL_UNSAT - ebullition surface CH4 flux; (+ to atm) mol/m2/s F +CH4_SURF_AERE_SAT - aerenchyma surface CH4 flux for inundated area; (+ to atm) mol/m2/s T +CH4_SURF_AERE_UNSAT - aerenchyma surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T +CH4_SURF_DIFF_SAT - diffusive surface CH4 flux for inundated / lake area; (+ to atm) mol/m2/s T +CH4_SURF_DIFF_UNSAT - diffusive surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T +CH4_SURF_EBUL_SAT - ebullition surface CH4 flux for inundated / lake area; (+ to atm) mol/m2/s T +CH4_SURF_EBUL_UNSAT - ebullition surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T +COL_CTRUNC - column-level sink for C truncation gC/m^2 F +COL_FIRE_CLOSS - total column-level fire C loss for non-peat fires outside land-type converted region gC/m^2/s T +COL_FIRE_NLOSS - total column-level fire N loss gN/m^2/s T +COL_NTRUNC - column-level sink for N truncation gN/m^2 F +COST_NACTIVE - Cost of active uptake gN/gC T +COST_NFIX - Cost of fixation gN/gC T +COST_NRETRANS - Cost of retranslocation gN/gC T +COSZEN - cosine of solar zenith angle none F +CPHASE - crop phenology phase 0-not planted, 1-planted, 2-leaf emerge, 3-grain fill, 4-harvest T +CPOOL - temporary photosynthate C pool gC/m^2 T +CPOOL_DEADCROOT_GR - dead coarse root growth respiration gC/m^2/s F +CPOOL_DEADCROOT_STORAGE_GR - dead coarse root growth respiration to storage gC/m^2/s F +CPOOL_DEADSTEM_GR - dead stem growth respiration gC/m^2/s F +CPOOL_DEADSTEM_STORAGE_GR - dead stem growth respiration to storage gC/m^2/s F +CPOOL_FROOT_GR - fine root growth respiration gC/m^2/s F +CPOOL_FROOT_STORAGE_GR - fine root growth respiration to storage gC/m^2/s F +CPOOL_LEAF_GR - leaf growth respiration gC/m^2/s F +CPOOL_LEAF_STORAGE_GR - leaf growth respiration to storage gC/m^2/s F +CPOOL_LIVECROOT_GR - live coarse root growth respiration gC/m^2/s F +CPOOL_LIVECROOT_STORAGE_GR - live coarse root growth respiration to storage gC/m^2/s F +CPOOL_LIVESTEM_GR - live stem growth respiration gC/m^2/s F +CPOOL_LIVESTEM_STORAGE_GR - live stem growth respiration to storage gC/m^2/s F +CPOOL_TO_DEADCROOTC - allocation to dead coarse root C gC/m^2/s F +CPOOL_TO_DEADCROOTC_STORAGE - allocation to dead coarse root C storage gC/m^2/s F +CPOOL_TO_DEADSTEMC - allocation to dead stem C gC/m^2/s F +CPOOL_TO_DEADSTEMC_STORAGE - allocation to dead stem C storage gC/m^2/s F +CPOOL_TO_FROOTC - allocation to fine root C gC/m^2/s F +CPOOL_TO_FROOTC_STORAGE - allocation to fine root C storage gC/m^2/s F +CPOOL_TO_GRESP_STORAGE - allocation to growth respiration storage gC/m^2/s F +CPOOL_TO_LEAFC - allocation to leaf C gC/m^2/s F +CPOOL_TO_LEAFC_STORAGE - allocation to leaf C storage gC/m^2/s F +CPOOL_TO_LIVECROOTC - allocation to live coarse root C gC/m^2/s F +CPOOL_TO_LIVECROOTC_STORAGE - allocation to live coarse root C storage gC/m^2/s F +CPOOL_TO_LIVESTEMC - allocation to live stem C gC/m^2/s F +CPOOL_TO_LIVESTEMC_STORAGE - allocation to live stem C storage gC/m^2/s F +CROPPROD1C - 1-yr crop product (grain+biofuel) C gC/m^2 T +CROPPROD1C_LOSS - loss from 1-yr crop product pool gC/m^2/s T +CROPPROD1N - 1-yr crop product (grain+biofuel) N gN/m^2 T +CROPPROD1N_LOSS - loss from 1-yr crop product pool gN/m^2/s T +CROPSEEDC_DEFICIT - C used for crop seed that needs to be repaid gC/m^2 T +CROPSEEDN_DEFICIT - N used for crop seed that needs to be repaid gN/m^2 F +CROP_SEEDC_TO_LEAF - crop seed source to leaf gC/m^2/s F +CROP_SEEDN_TO_LEAF - crop seed source to leaf gN/m^2/s F +CURRENT_GR - growth resp for new growth displayed in this timestep gC/m^2/s F +CWDC_HR - cwd C heterotrophic respiration gC/m^2/s T +CWDC_LOSS - coarse woody debris C loss gC/m^2/s T +CWD_C - CWD C gC/m^2 T +CWD_C_1m - CWD C to 1 meter gC/m^2 F +CWD_C_TO_LIT_CEL_C - decomp. of coarse woody debris C to cellulosic litter C gC/m^2/s F +CWD_C_TO_LIT_LIG_C - decomp. of coarse woody debris C to lignin litter C gC/m^2/s F +CWD_HR_L2 - Het. Resp. from coarse woody debris gC/m^2/s F +CWD_HR_L3 - Het. Resp. from coarse woody debris gC/m^2/s F +CWD_N - CWD N gN/m^2 T +CWD_N_1m - CWD N to 1 meter gN/m^2 F +CWD_N_TO_LIT_CEL_N - decomp. of coarse woody debris N to cellulosic litter N gN/m^2 F +CWD_N_TO_LIT_LIG_N - decomp. of coarse woody debris N to lignin litter N gN/m^2 F +C_ALLOMETRY - C allocation index none F +DAYL - daylength s F +DAYS_ACTIVE - number of days since last dormancy days F +DEADCROOTC - dead coarse root C gC/m^2 T +DEADCROOTC_STORAGE - dead coarse root C storage gC/m^2 F +DEADCROOTC_STORAGE_TO_XFER - dead coarse root C shift storage to transfer gC/m^2/s F +DEADCROOTC_XFER - dead coarse root C transfer gC/m^2 F +DEADCROOTC_XFER_TO_DEADCROOTC - dead coarse root C growth from storage gC/m^2/s F +DEADCROOTN - dead coarse root N gN/m^2 T +DEADCROOTN_STORAGE - dead coarse root N storage gN/m^2 F +DEADCROOTN_STORAGE_TO_XFER - dead coarse root N shift storage to transfer gN/m^2/s F +DEADCROOTN_XFER - dead coarse root N transfer gN/m^2 F +DEADCROOTN_XFER_TO_DEADCROOTN - dead coarse root N growth from storage gN/m^2/s F +DEADSTEMC - dead stem C gC/m^2 T +DEADSTEMC_STORAGE - dead stem C storage gC/m^2 F +DEADSTEMC_STORAGE_TO_XFER - dead stem C shift storage to transfer gC/m^2/s F +DEADSTEMC_XFER - dead stem C transfer gC/m^2 F +DEADSTEMC_XFER_TO_DEADSTEMC - dead stem C growth from storage gC/m^2/s F +DEADSTEMN - dead stem N gN/m^2 T +DEADSTEMN_STORAGE - dead stem N storage gN/m^2 F +DEADSTEMN_STORAGE_TO_XFER - dead stem N shift storage to transfer gN/m^2/s F +DEADSTEMN_XFER - dead stem N transfer gN/m^2 F +DEADSTEMN_XFER_TO_DEADSTEMN - dead stem N growth from storage gN/m^2/s F +DENIT - total rate of denitrification gN/m^2/s T +DGNETDT - derivative of net ground heat flux wrt soil temp W/m^2/K F +DISPLA - displacement height (vegetated landunits only) m F +DISPVEGC - displayed veg carbon, excluding storage and cpool gC/m^2 T +DISPVEGN - displayed vegetation nitrogen gN/m^2 T +DLRAD - downward longwave radiation below the canopy W/m^2 F +DORMANT_FLAG - dormancy flag none F +DOWNREG - fractional reduction in GPP due to N limitation proportion F +DPVLTRB1 - turbulent deposition velocity 1 m/s F +DPVLTRB2 - turbulent deposition velocity 2 m/s F +DPVLTRB3 - turbulent deposition velocity 3 m/s F +DPVLTRB4 - turbulent deposition velocity 4 m/s F +DSL - dry surface layer thickness mm T +DSTDEP - total dust deposition (dry+wet) from atmosphere kg/m^2/s T +DSTFLXT - total surface dust emission kg/m2/s T +DT_VEG - change in t_veg, last iteration K F +DWT_CONV_CFLUX - conversion C flux (immediate loss to atm) (0 at all times except first timestep of year) gC/m^2/s T +DWT_CONV_CFLUX_DRIBBLED - conversion C flux (immediate loss to atm), dribbled throughout the year gC/m^2/s T +DWT_CONV_CFLUX_PATCH - patch-level conversion C flux (immediate loss to atm) (0 at all times except first timestep of gC/m^2/s F +DWT_CONV_NFLUX - conversion N flux (immediate loss to atm) (0 at all times except first timestep of year) gN/m^2/s T +DWT_CONV_NFLUX_PATCH - patch-level conversion N flux (immediate loss to atm) (0 at all times except first timestep of gN/m^2/s F +DWT_CROPPROD1C_GAIN - landcover change-driven addition to 1-year crop product pool gC/m^2/s T +DWT_CROPPROD1N_GAIN - landcover change-driven addition to 1-year crop product pool gN/m^2/s T +DWT_PROD100C_GAIN - landcover change-driven addition to 100-yr wood product pool gC/m^2/s F +DWT_PROD100N_GAIN - landcover change-driven addition to 100-yr wood product pool gN/m^2/s F +DWT_PROD10C_GAIN - landcover change-driven addition to 10-yr wood product pool gC/m^2/s F +DWT_PROD10N_GAIN - landcover change-driven addition to 10-yr wood product pool gN/m^2/s F +DWT_SEEDC_TO_DEADSTEM - seed source to patch-level deadstem gC/m^2/s F +DWT_SEEDC_TO_DEADSTEM_PATCH - patch-level seed source to patch-level deadstem (per-area-gridcell; only makes sense with dov2 gC/m^2/s F +DWT_SEEDC_TO_LEAF - seed source to patch-level leaf gC/m^2/s F +DWT_SEEDC_TO_LEAF_PATCH - patch-level seed source to patch-level leaf (per-area-gridcell; only makes sense with dov2xy=. gC/m^2/s F +DWT_SEEDN_TO_DEADSTEM - seed source to patch-level deadstem gN/m^2/s T +DWT_SEEDN_TO_DEADSTEM_PATCH - patch-level seed source to patch-level deadstem (per-area-gridcell; only makes sense with dov2 gN/m^2/s F +DWT_SEEDN_TO_LEAF - seed source to patch-level leaf gN/m^2/s T +DWT_SEEDN_TO_LEAF_PATCH - patch-level seed source to patch-level leaf (per-area-gridcell; only makes sense with dov2xy=. gN/m^2/s F +DWT_SLASH_CFLUX - slash C flux (to litter diagnostic only) (0 at all times except first timestep of year) gC/m^2/s T +DWT_SLASH_CFLUX_PATCH - patch-level slash C flux (to litter diagnostic only) (0 at all times except first timestep of gC/m^2/s F +DWT_WOODPRODC_GAIN - landcover change-driven addition to wood product pools gC/m^2/s T +DWT_WOODPRODN_GAIN - landcover change-driven addition to wood product pools gN/m^2/s T +DWT_WOOD_PRODUCTC_GAIN_PATCH - patch-level landcover change-driven addition to wood product pools(0 at all times except first gC/m^2/s F +DYN_COL_ADJUSTMENTS_CH4 - Adjustments in ch4 due to dynamic column areas; only makes sense at the column level: should n gC/m^2 F +DYN_COL_SOIL_ADJUSTMENTS_C - Adjustments in soil carbon due to dynamic column areas; only makes sense at the column level: gC/m^2 F +DYN_COL_SOIL_ADJUSTMENTS_N - Adjustments in soil nitrogen due to dynamic column areas; only makes sense at the column level gN/m^2 F +DYN_COL_SOIL_ADJUSTMENTS_NH4 - Adjustments in soil NH4 due to dynamic column areas; only makes sense at the column level: sho gN/m^2 F +DYN_COL_SOIL_ADJUSTMENTS_NO3 - Adjustments in soil NO3 due to dynamic column areas; only makes sense at the column level: sho gN/m^2 F +EFLXBUILD - building heat flux from change in interior building air temperature W/m^2 T +EFLX_DYNBAL - dynamic land cover change conversion energy flux W/m^2 T +EFLX_GNET - net heat flux into ground W/m^2 F +EFLX_GRND_LAKE - net heat flux into lake/snow surface, excluding light transmission W/m^2 T +EFLX_LH_TOT - total latent heat flux [+ to atm] W/m^2 T +EFLX_LH_TOT_ICE - total latent heat flux [+ to atm] (ice landunits only) W/m^2 F +EFLX_LH_TOT_R - Rural total evaporation W/m^2 T +EFLX_LH_TOT_U - Urban total evaporation W/m^2 F +EFLX_SOIL_GRND - soil heat flux [+ into soil] W/m^2 F +ELAI - exposed one-sided leaf area index m^2/m^2 T +EMG - ground emissivity proportion F +EMV - vegetation emissivity proportion F +EOPT - Eopt coefficient for VOC calc non F +ER - total ecosystem respiration, autotrophic + heterotrophic gC/m^2/s T +ERRH2O - total water conservation error mm T +ERRH2OSNO - imbalance in snow depth (liquid water) mm T +ERRSEB - surface energy conservation error W/m^2 T +ERRSOI - soil/lake energy conservation error W/m^2 T +ERRSOL - solar radiation conservation error W/m^2 T +ESAI - exposed one-sided stem area index m^2/m^2 T +EXCESSC_MR - excess C maintenance respiration gC/m^2/s F +EXCESS_CFLUX - C flux not allocated due to downregulation gC/m^2/s F +FAREA_BURNED - timestep fractional area burned s-1 T +FCANSNO - fraction of canopy that is wet proportion F +FCEV - canopy evaporation W/m^2 T +FCH4 - Gridcell surface CH4 flux to atmosphere (+ to atm) kgC/m2/s T +FCH4TOCO2 - Gridcell oxidation of CH4 to CO2 gC/m2/s T +FCH4_DFSAT - CH4 additional flux due to changing fsat, natural vegetated and crop landunits only kgC/m2/s T +FCO2 - CO2 flux to atmosphere (+ to atm) kgCO2/m2/s F +FCOV - fractional impermeable area unitless T +FCTR - canopy transpiration W/m^2 T +FDRY - fraction of foliage that is green and dry proportion F +FERTNITRO - Nitrogen fertilizer for each crop gN/m2/yr F +FERT_COUNTER - time left to fertilize seconds F +FERT_TO_SMINN - fertilizer to soil mineral N gN/m^2/s F +FFIX_TO_SMINN - free living N fixation to soil mineral N gN/m^2/s T +FGEV - ground evaporation W/m^2 T +FGR - heat flux into soil/snow including snow melt and lake / snow light transmission W/m^2 T +FGR12 - heat flux between soil layers 1 and 2 W/m^2 T +FGR_ICE - heat flux into soil/snow including snow melt and lake / snow light transmission (ice landunits W/m^2 F +FGR_R - Rural heat flux into soil/snow including snow melt and snow light transmission W/m^2 F +FGR_U - Urban heat flux into soil/snow including snow melt W/m^2 F +FH2OSFC - fraction of ground covered by surface water unitless T +FH2OSFC_NOSNOW - fraction of ground covered by surface water (if no snow present) unitless F +FINUNDATED - fractional inundated area of vegetated columns unitless T +FINUNDATED_LAG - time-lagged inundated fraction of vegetated columns unitless F +FIRA - net infrared (longwave) radiation W/m^2 T +FIRA_ICE - net infrared (longwave) radiation (ice landunits only) W/m^2 F +FIRA_R - Rural net infrared (longwave) radiation W/m^2 T +FIRA_U - Urban net infrared (longwave) radiation W/m^2 F +FIRE - emitted infrared (longwave) radiation W/m^2 T +FIRE_ICE - emitted infrared (longwave) radiation (ice landunits only) W/m^2 F +FIRE_R - Rural emitted infrared (longwave) radiation W/m^2 T +FIRE_U - Urban emitted infrared (longwave) radiation W/m^2 F +FLDS - atmospheric longwave radiation (downscaled to columns in glacier regions) W/m^2 T +FLDS_ICE - atmospheric longwave radiation (downscaled to columns in glacier regions) (ice landunits only) W/m^2 F +FPI - fraction of potential immobilization proportion T +FPSN - photosynthesis umol m-2 s-1 T +FPSN24 - 24 hour accumulative patch photosynthesis starting from mid-night umol CO2/m^2 ground/day F +FPSN_WC - Rubisco-limited photosynthesis umol m-2 s-1 F +FPSN_WJ - RuBP-limited photosynthesis umol m-2 s-1 F +FPSN_WP - Product-limited photosynthesis umol m-2 s-1 F +FREE_RETRANSN_TO_NPOOL - deployment of retranslocated N gN/m^2/s T +FROOTC - fine root C gC/m^2 T +FROOTC_ALLOC - fine root C allocation gC/m^2/s T +FROOTC_LOSS - fine root C loss gC/m^2/s T +FROOTC_STORAGE - fine root C storage gC/m^2 F +FROOTC_STORAGE_TO_XFER - fine root C shift storage to transfer gC/m^2/s F +FROOTC_TO_LITTER - fine root C litterfall gC/m^2/s F +FROOTC_XFER - fine root C transfer gC/m^2 F +FROOTC_XFER_TO_FROOTC - fine root C growth from storage gC/m^2/s F +FROOTN - fine root N gN/m^2 T +FROOTN_STORAGE - fine root N storage gN/m^2 F +FROOTN_STORAGE_TO_XFER - fine root N shift storage to transfer gN/m^2/s F +FROOTN_TO_LITTER - fine root N litterfall gN/m^2/s F +FROOTN_XFER - fine root N transfer gN/m^2 F +FROOTN_XFER_TO_FROOTN - fine root N growth from storage gN/m^2/s F +FROOT_MR - fine root maintenance respiration gC/m^2/s F +FROST_TABLE - frost table depth (natural vegetated and crop landunits only) m F +FSA - absorbed solar radiation W/m^2 T +FSAT - fractional area with water table at surface unitless T +FSA_ICE - absorbed solar radiation (ice landunits only) W/m^2 F +FSA_R - Rural absorbed solar radiation W/m^2 F +FSA_U - Urban absorbed solar radiation W/m^2 F +FSD24 - direct radiation (last 24hrs) K F +FSD240 - direct radiation (last 240hrs) K F +FSDS - atmospheric incident solar radiation W/m^2 T +FSDSND - direct nir incident solar radiation W/m^2 T +FSDSNDLN - direct nir incident solar radiation at local noon W/m^2 T +FSDSNI - diffuse nir incident solar radiation W/m^2 T +FSDSVD - direct vis incident solar radiation W/m^2 T +FSDSVDLN - direct vis incident solar radiation at local noon W/m^2 T +FSDSVI - diffuse vis incident solar radiation W/m^2 T +FSDSVILN - diffuse vis incident solar radiation at local noon W/m^2 T +FSH - sensible heat not including correction for land use change and rain/snow conversion W/m^2 T +FSH_G - sensible heat from ground W/m^2 T +FSH_ICE - sensible heat not including correction for land use change and rain/snow conversion (ice landu W/m^2 F +FSH_PRECIP_CONVERSION - Sensible heat flux from conversion of rain/snow atm forcing W/m^2 T +FSH_R - Rural sensible heat W/m^2 T +FSH_RUNOFF_ICE_TO_LIQ - sensible heat flux generated from conversion of ice runoff to liquid W/m^2 T +FSH_TO_COUPLER - sensible heat sent to coupler (includes corrections for land use change, rain/snow conversion W/m^2 T +FSH_U - Urban sensible heat W/m^2 F +FSH_V - sensible heat from veg W/m^2 T +FSI24 - indirect radiation (last 24hrs) K F +FSI240 - indirect radiation (last 240hrs) K F +FSM - snow melt heat flux W/m^2 T +FSM_ICE - snow melt heat flux (ice landunits only) W/m^2 F +FSM_R - Rural snow melt heat flux W/m^2 F +FSM_U - Urban snow melt heat flux W/m^2 F +FSNO - fraction of ground covered by snow unitless T +FSNO_EFF - effective fraction of ground covered by snow unitless T +FSNO_ICE - fraction of ground covered by snow (ice landunits only) unitless F +FSR - reflected solar radiation W/m^2 T +FSRND - direct nir reflected solar radiation W/m^2 T +FSRNDLN - direct nir reflected solar radiation at local noon W/m^2 T +FSRNI - diffuse nir reflected solar radiation W/m^2 T +FSRVD - direct vis reflected solar radiation W/m^2 T +FSRVDLN - direct vis reflected solar radiation at local noon W/m^2 T +FSRVI - diffuse vis reflected solar radiation W/m^2 T +FSR_ICE - reflected solar radiation (ice landunits only) W/m^2 F +FSUN - sunlit fraction of canopy proportion F +FSUN24 - fraction sunlit (last 24hrs) K F +FSUN240 - fraction sunlit (last 240hrs) K F +FUELC - fuel load gC/m^2 T +FV - friction velocity m/s T +FWET - fraction of canopy that is wet proportion F +F_DENIT - denitrification flux gN/m^2/s T +F_N2O_DENIT - denitrification N2O flux gN/m^2/s T +F_N2O_NIT - nitrification N2O flux gN/m^2/s T +F_NIT - nitrification flux gN/m^2/s T +GAMMA - total gamma for VOC calc non F +GAMMAA - gamma A for VOC calc non F +GAMMAC - gamma C for VOC calc non F +GAMMAL - gamma L for VOC calc non F +GAMMAP - gamma P for VOC calc non F +GAMMAS - gamma S for VOC calc non F +GAMMAT - gamma T for VOC calc non F +GDD0 - Growing degree days base 0C from planting ddays F +GDD020 - Twenty year average of growing degree days base 0C from planting ddays F +GDD10 - Growing degree days base 10C from planting ddays F +GDD1020 - Twenty year average of growing degree days base 10C from planting ddays F +GDD8 - Growing degree days base 8C from planting ddays F +GDD820 - Twenty year average of growing degree days base 8C from planting ddays F +GDDACCUM - Accumulated growing degree days past planting date for crop ddays F +GDDHARV - Growing degree days (gdd) needed to harvest ddays F +GDDTSOI - Growing degree-days from planting (top two soil layers) ddays F +GPP - gross primary production gC/m^2/s T +GR - total growth respiration gC/m^2/s T +GRAINC - grain C (does not equal yield) gC/m^2 T +GRAINC_TO_FOOD - grain C to food gC/m^2/s T +GRAINC_TO_FOOD_ANN - grain C to food harvested per calendar year; should only be output annually gC/m^2 F +GRAINC_TO_SEED - grain C to seed gC/m^2/s T +GRAINN - grain N gN/m^2 T +GRESP_STORAGE - growth respiration storage gC/m^2 F +GRESP_STORAGE_TO_XFER - growth respiration shift storage to transfer gC/m^2/s F +GRESP_XFER - growth respiration transfer gC/m^2 F +GROSS_NMIN - gross rate of N mineralization gN/m^2/s T +GRU_PROD100C_GAIN - gross unrepresented landcover change addition to 100-yr wood product pool gC/m^2/s F +GRU_PROD100N_GAIN - gross unrepresented landcover change addition to 100-yr wood product pool gN/m^2/s F +GRU_PROD10C_GAIN - gross unrepresented landcover change addition to 10-yr wood product pool gC/m^2/s F +GRU_PROD10N_GAIN - gross unrepresented landcover change addition to 10-yr wood product pool gN/m^2/s F +GSSHA - shaded leaf stomatal conductance umol H20/m2/s T +GSSHALN - shaded leaf stomatal conductance at local noon umol H20/m2/s T +GSSUN - sunlit leaf stomatal conductance umol H20/m2/s T +GSSUNLN - sunlit leaf stomatal conductance at local noon umol H20/m2/s T +H2OCAN - intercepted water mm T +H2OSFC - surface water depth mm T +H2OSNO - snow depth (liquid water) mm T +H2OSNO_ICE - snow depth (liquid water, ice landunits only) mm F +H2OSNO_TOP - mass of snow in top snow layer kg/m2 T +HBOT - canopy bottom m F +HEAT_CONTENT1 - initial gridcell total heat content J/m^2 T +HEAT_CONTENT1_VEG - initial gridcell total heat content - natural vegetated and crop landunits only J/m^2 F +HEAT_CONTENT2 - post land cover change total heat content J/m^2 F +HEAT_FROM_AC - sensible heat flux put into canyon due to heat removed from air conditioning W/m^2 T +HIA - 2 m NWS Heat Index C T +HIA_R - Rural 2 m NWS Heat Index C T +HIA_U - Urban 2 m NWS Heat Index C T +HR - total heterotrophic respiration gC/m^2/s T +HTOP - canopy top m T +HUI - Crop patch heat unit index ddays F +HUMIDEX - 2 m Humidex C T +HUMIDEX_R - Rural 2 m Humidex C T +HUMIDEX_U - Urban 2 m Humidex C T +ICE_CONTENT1 - initial gridcell total ice content mm T +ICE_CONTENT2 - post land cover change total ice content mm F +ICE_MODEL_FRACTION - Ice sheet model fractional coverage unitless F +INIT_GPP - GPP flux before downregulation gC/m^2/s F +INT_SNOW - accumulated swe (natural vegetated and crop landunits only) mm F +INT_SNOW_ICE - accumulated swe (ice landunits only) mm F +IWUELN - local noon intrinsic water use efficiency umolCO2/molH2O T +JMX25T - canopy profile of jmax umol/m2/s T +Jmx25Z - maximum rate of electron transport at 25 Celcius for canopy layers umol electrons/m2/s T +LAI240 - 240hr average of leaf area index m^2/m^2 F +LAISHA - shaded projected leaf area index m^2/m^2 T +LAISUN - sunlit projected leaf area index m^2/m^2 T +LAKEICEFRAC_SURF - surface lake layer ice mass fraction unitless T +LAKEICETHICK - thickness of lake ice (including physical expansion on freezing) m T +LAND_USE_FLUX - total C emitted from land cover conversion (smoothed over the year) and wood and grain product gC/m^2/s T +LATBASET - latitude vary base temperature for hui degree C F +LEAFC - leaf C gC/m^2 T +LEAFCN - Leaf CN ratio used for flexible CN gC/gN T +LEAFCN_OFFSET - Leaf C:N used by FUN unitless F +LEAFCN_STORAGE - Storage Leaf CN ratio used for flexible CN gC/gN F +LEAFC_ALLOC - leaf C allocation gC/m^2/s T +LEAFC_CHANGE - C change in leaf gC/m^2/s T +LEAFC_LOSS - leaf C loss gC/m^2/s T +LEAFC_STORAGE - leaf C storage gC/m^2 F +LEAFC_STORAGE_TO_XFER - leaf C shift storage to transfer gC/m^2/s F +LEAFC_STORAGE_XFER_ACC - Accumulated leaf C transfer gC/m^2 F +LEAFC_TO_BIOFUELC - leaf C to biofuel C gC/m^2/s T +LEAFC_TO_LITTER - leaf C litterfall gC/m^2/s F +LEAFC_TO_LITTER_FUN - leaf C litterfall used by FUN gC/m^2/s T +LEAFC_XFER - leaf C transfer gC/m^2 F +LEAFC_XFER_TO_LEAFC - leaf C growth from storage gC/m^2/s F +LEAFN - leaf N gN/m^2 T +LEAFN_STORAGE - leaf N storage gN/m^2 F +LEAFN_STORAGE_TO_XFER - leaf N shift storage to transfer gN/m^2/s F +LEAFN_STORAGE_XFER_ACC - Accmulated leaf N transfer gN/m^2 F +LEAFN_TO_LITTER - leaf N litterfall gN/m^2/s T +LEAFN_TO_RETRANSN - leaf N to retranslocated N pool gN/m^2/s F +LEAFN_XFER - leaf N transfer gN/m^2 F +LEAFN_XFER_TO_LEAFN - leaf N growth from storage gN/m^2/s F +LEAF_MR - leaf maintenance respiration gC/m^2/s T +LFC2 - conversion area fraction of BET and BDT that burned per sec T +LGSF - long growing season factor proportion F +LIQCAN - intercepted liquid water mm T +LIQUID_CONTENT1 - initial gridcell total liq content mm T +LIQUID_CONTENT2 - post landuse change gridcell total liq content mm F +LIQUID_WATER_TEMP1 - initial gridcell weighted average liquid water temperature K F +LITFALL - litterfall (leaves and fine roots) gC/m^2/s T +LITFIRE - litter fire losses gC/m^2/s F +LITTERC_HR - litter C heterotrophic respiration gC/m^2/s T +LITTERC_LOSS - litter C loss gC/m^2/s T +LIT_CEL_C - LIT_CEL C gC/m^2 T +LIT_CEL_C_1m - LIT_CEL C to 1 meter gC/m^2 F +LIT_CEL_C_TO_SOM_ACT_C - decomp. of cellulosic litter C to active soil organic C gC/m^2/s F +LIT_CEL_HR - Het. Resp. from cellulosic litter gC/m^2/s F +LIT_CEL_N - LIT_CEL N gN/m^2 T +LIT_CEL_N_1m - LIT_CEL N to 1 meter gN/m^2 F +LIT_CEL_N_TO_SOM_ACT_N - decomp. of cellulosic litter N to active soil organic N gN/m^2 F +LIT_LIG_C - LIT_LIG C gC/m^2 T +LIT_LIG_C_1m - LIT_LIG C to 1 meter gC/m^2 F +LIT_LIG_C_TO_SOM_SLO_C - decomp. of lignin litter C to slow soil organic ma C gC/m^2/s F +LIT_LIG_HR - Het. Resp. from lignin litter gC/m^2/s F +LIT_LIG_N - LIT_LIG N gN/m^2 T +LIT_LIG_N_1m - LIT_LIG N to 1 meter gN/m^2 F +LIT_LIG_N_TO_SOM_SLO_N - decomp. of lignin litter N to slow soil organic ma N gN/m^2 F +LIT_MET_C - LIT_MET C gC/m^2 T +LIT_MET_C_1m - LIT_MET C to 1 meter gC/m^2 F +LIT_MET_C_TO_SOM_ACT_C - decomp. of metabolic litter C to active soil organic C gC/m^2/s F +LIT_MET_HR - Het. Resp. from metabolic litter gC/m^2/s F +LIT_MET_N - LIT_MET N gN/m^2 T +LIT_MET_N_1m - LIT_MET N to 1 meter gN/m^2 F +LIT_MET_N_TO_SOM_ACT_N - decomp. of metabolic litter N to active soil organic N gN/m^2 F +LIVECROOTC - live coarse root C gC/m^2 T +LIVECROOTC_STORAGE - live coarse root C storage gC/m^2 F +LIVECROOTC_STORAGE_TO_XFER - live coarse root C shift storage to transfer gC/m^2/s F +LIVECROOTC_TO_DEADCROOTC - live coarse root C turnover gC/m^2/s F +LIVECROOTC_XFER - live coarse root C transfer gC/m^2 F +LIVECROOTC_XFER_TO_LIVECROOTC - live coarse root C growth from storage gC/m^2/s F +LIVECROOTN - live coarse root N gN/m^2 T +LIVECROOTN_STORAGE - live coarse root N storage gN/m^2 F +LIVECROOTN_STORAGE_TO_XFER - live coarse root N shift storage to transfer gN/m^2/s F +LIVECROOTN_TO_DEADCROOTN - live coarse root N turnover gN/m^2/s F +LIVECROOTN_TO_RETRANSN - live coarse root N to retranslocated N pool gN/m^2/s F +LIVECROOTN_XFER - live coarse root N transfer gN/m^2 F +LIVECROOTN_XFER_TO_LIVECROOTN - live coarse root N growth from storage gN/m^2/s F +LIVECROOT_MR - live coarse root maintenance respiration gC/m^2/s F +LIVESTEMC - live stem C gC/m^2 T +LIVESTEMC_STORAGE - live stem C storage gC/m^2 F +LIVESTEMC_STORAGE_TO_XFER - live stem C shift storage to transfer gC/m^2/s F +LIVESTEMC_TO_BIOFUELC - livestem C to biofuel C gC/m^2/s T +LIVESTEMC_TO_DEADSTEMC - live stem C turnover gC/m^2/s F +LIVESTEMC_XFER - live stem C transfer gC/m^2 F +LIVESTEMC_XFER_TO_LIVESTEMC - live stem C growth from storage gC/m^2/s F +LIVESTEMN - live stem N gN/m^2 T +LIVESTEMN_STORAGE - live stem N storage gN/m^2 F +LIVESTEMN_STORAGE_TO_XFER - live stem N shift storage to transfer gN/m^2/s F +LIVESTEMN_TO_DEADSTEMN - live stem N turnover gN/m^2/s F +LIVESTEMN_TO_RETRANSN - live stem N to retranslocated N pool gN/m^2/s F +LIVESTEMN_XFER - live stem N transfer gN/m^2 F +LIVESTEMN_XFER_TO_LIVESTEMN - live stem N growth from storage gN/m^2/s F +LIVESTEM_MR - live stem maintenance respiration gC/m^2/s F +LNC - leaf N concentration gN leaf/m^2 T +LWdown - atmospheric longwave radiation (downscaled to columns in glacier regions) W/m^2 F +LWup - upwelling longwave radiation W/m^2 F +MEG_acetaldehyde - MEGAN flux kg/m2/sec T +MEG_acetic_acid - MEGAN flux kg/m2/sec T +MEG_acetone - MEGAN flux kg/m2/sec T +MEG_carene_3 - MEGAN flux kg/m2/sec T +MEG_ethanol - MEGAN flux kg/m2/sec T +MEG_formaldehyde - MEGAN flux kg/m2/sec T +MEG_isoprene - MEGAN flux kg/m2/sec T +MEG_methanol - MEGAN flux kg/m2/sec T +MEG_pinene_a - MEGAN flux kg/m2/sec T +MEG_thujene_a - MEGAN flux kg/m2/sec T +MR - maintenance respiration gC/m^2/s T +M_CWD_C_TO_FIRE - coarse woody debris C fire loss gC/m^2/s F +M_CWD_N_TO_FIRE - coarse woody debris N fire loss gN/m^2 F +M_DEADCROOTC_STORAGE_TO_LITTER - dead coarse root C storage mortality gC/m^2/s F +M_DEADCROOTC_STORAGE_TO_LITTER_FIRE - dead coarse root C storage fire mortality to litter gC/m^2/s F +M_DEADCROOTC_TO_LITTER - dead coarse root C mortality gC/m^2/s F +M_DEADCROOTC_XFER_TO_LITTER - dead coarse root C transfer mortality gC/m^2/s F +M_DEADCROOTN_STORAGE_TO_FIRE - dead coarse root N storage fire loss gN/m^2/s F +M_DEADCROOTN_STORAGE_TO_LITTER - dead coarse root N storage mortality gN/m^2/s F +M_DEADCROOTN_TO_FIRE - dead coarse root N fire loss gN/m^2/s F +M_DEADCROOTN_TO_LITTER - dead coarse root N mortality gN/m^2/s F +M_DEADCROOTN_TO_LITTER_FIRE - dead coarse root N fire mortality to litter gN/m^2/s F +M_DEADCROOTN_XFER_TO_FIRE - dead coarse root N transfer fire loss gN/m^2/s F +M_DEADCROOTN_XFER_TO_LITTER - dead coarse root N transfer mortality gN/m^2/s F +M_DEADROOTC_STORAGE_TO_FIRE - dead root C storage fire loss gC/m^2/s F +M_DEADROOTC_STORAGE_TO_LITTER_FIRE - dead root C storage fire mortality to litter gC/m^2/s F +M_DEADROOTC_TO_FIRE - dead root C fire loss gC/m^2/s F +M_DEADROOTC_TO_LITTER_FIRE - dead root C fire mortality to litter gC/m^2/s F +M_DEADROOTC_XFER_TO_FIRE - dead root C transfer fire loss gC/m^2/s F +M_DEADROOTC_XFER_TO_LITTER_FIRE - dead root C transfer fire mortality to litter gC/m^2/s F +M_DEADSTEMC_STORAGE_TO_FIRE - dead stem C storage fire loss gC/m^2/s F +M_DEADSTEMC_STORAGE_TO_LITTER - dead stem C storage mortality gC/m^2/s F +M_DEADSTEMC_STORAGE_TO_LITTER_FIRE - dead stem C storage fire mortality to litter gC/m^2/s F +M_DEADSTEMC_TO_FIRE - dead stem C fire loss gC/m^2/s F +M_DEADSTEMC_TO_LITTER - dead stem C mortality gC/m^2/s F +M_DEADSTEMC_TO_LITTER_FIRE - dead stem C fire mortality to litter gC/m^2/s F +M_DEADSTEMC_XFER_TO_FIRE - dead stem C transfer fire loss gC/m^2/s F +M_DEADSTEMC_XFER_TO_LITTER - dead stem C transfer mortality gC/m^2/s F +M_DEADSTEMC_XFER_TO_LITTER_FIRE - dead stem C transfer fire mortality to litter gC/m^2/s F +M_DEADSTEMN_STORAGE_TO_FIRE - dead stem N storage fire loss gN/m^2/s F +M_DEADSTEMN_STORAGE_TO_LITTER - dead stem N storage mortality gN/m^2/s F +M_DEADSTEMN_TO_FIRE - dead stem N fire loss gN/m^2/s F +M_DEADSTEMN_TO_LITTER - dead stem N mortality gN/m^2/s F +M_DEADSTEMN_TO_LITTER_FIRE - dead stem N fire mortality to litter gN/m^2/s F +M_DEADSTEMN_XFER_TO_FIRE - dead stem N transfer fire loss gN/m^2/s F +M_DEADSTEMN_XFER_TO_LITTER - dead stem N transfer mortality gN/m^2/s F +M_FROOTC_STORAGE_TO_FIRE - fine root C storage fire loss gC/m^2/s F +M_FROOTC_STORAGE_TO_LITTER - fine root C storage mortality gC/m^2/s F +M_FROOTC_STORAGE_TO_LITTER_FIRE - fine root C storage fire mortality to litter gC/m^2/s F +M_FROOTC_TO_FIRE - fine root C fire loss gC/m^2/s F +M_FROOTC_TO_LITTER - fine root C mortality gC/m^2/s F +M_FROOTC_TO_LITTER_FIRE - fine root C fire mortality to litter gC/m^2/s F +M_FROOTC_XFER_TO_FIRE - fine root C transfer fire loss gC/m^2/s F +M_FROOTC_XFER_TO_LITTER - fine root C transfer mortality gC/m^2/s F +M_FROOTC_XFER_TO_LITTER_FIRE - fine root C transfer fire mortality to litter gC/m^2/s F +M_FROOTN_STORAGE_TO_FIRE - fine root N storage fire loss gN/m^2/s F +M_FROOTN_STORAGE_TO_LITTER - fine root N storage mortality gN/m^2/s F +M_FROOTN_TO_FIRE - fine root N fire loss gN/m^2/s F +M_FROOTN_TO_LITTER - fine root N mortality gN/m^2/s F +M_FROOTN_XFER_TO_FIRE - fine root N transfer fire loss gN/m^2/s F +M_FROOTN_XFER_TO_LITTER - fine root N transfer mortality gN/m^2/s F +M_GRESP_STORAGE_TO_FIRE - growth respiration storage fire loss gC/m^2/s F +M_GRESP_STORAGE_TO_LITTER - growth respiration storage mortality gC/m^2/s F +M_GRESP_STORAGE_TO_LITTER_FIRE - growth respiration storage fire mortality to litter gC/m^2/s F +M_GRESP_XFER_TO_FIRE - growth respiration transfer fire loss gC/m^2/s F +M_GRESP_XFER_TO_LITTER - growth respiration transfer mortality gC/m^2/s F +M_GRESP_XFER_TO_LITTER_FIRE - growth respiration transfer fire mortality to litter gC/m^2/s F +M_LEAFC_STORAGE_TO_FIRE - leaf C storage fire loss gC/m^2/s F +M_LEAFC_STORAGE_TO_LITTER - leaf C storage mortality gC/m^2/s F +M_LEAFC_STORAGE_TO_LITTER_FIRE - leaf C fire mortality to litter gC/m^2/s F +M_LEAFC_TO_FIRE - leaf C fire loss gC/m^2/s F +M_LEAFC_TO_LITTER - leaf C mortality gC/m^2/s F +M_LEAFC_TO_LITTER_FIRE - leaf C fire mortality to litter gC/m^2/s F +M_LEAFC_XFER_TO_FIRE - leaf C transfer fire loss gC/m^2/s F +M_LEAFC_XFER_TO_LITTER - leaf C transfer mortality gC/m^2/s F +M_LEAFC_XFER_TO_LITTER_FIRE - leaf C transfer fire mortality to litter gC/m^2/s F +M_LEAFN_STORAGE_TO_FIRE - leaf N storage fire loss gN/m^2/s F +M_LEAFN_STORAGE_TO_LITTER - leaf N storage mortality gN/m^2/s F +M_LEAFN_TO_FIRE - leaf N fire loss gN/m^2/s F +M_LEAFN_TO_LITTER - leaf N mortality gN/m^2/s F +M_LEAFN_XFER_TO_FIRE - leaf N transfer fire loss gN/m^2/s F +M_LEAFN_XFER_TO_LITTER - leaf N transfer mortality gN/m^2/s F +M_LIT_CEL_C_TO_FIRE - cellulosic litter C fire loss gC/m^2/s F +M_LIT_CEL_C_TO_LEACHING - cellulosic litter C leaching loss gC/m^2/s F +M_LIT_CEL_N_TO_FIRE - cellulosic litter N fire loss gN/m^2 F +M_LIT_CEL_N_TO_LEACHING - cellulosic litter N leaching loss gN/m^2/s F +M_LIT_LIG_C_TO_FIRE - lignin litter C fire loss gC/m^2/s F +M_LIT_LIG_C_TO_LEACHING - lignin litter C leaching loss gC/m^2/s F +M_LIT_LIG_N_TO_FIRE - lignin litter N fire loss gN/m^2 F +M_LIT_LIG_N_TO_LEACHING - lignin litter N leaching loss gN/m^2/s F +M_LIT_MET_C_TO_FIRE - metabolic litter C fire loss gC/m^2/s F +M_LIT_MET_C_TO_LEACHING - metabolic litter C leaching loss gC/m^2/s F +M_LIT_MET_N_TO_FIRE - metabolic litter N fire loss gN/m^2 F +M_LIT_MET_N_TO_LEACHING - metabolic litter N leaching loss gN/m^2/s F +M_LIVECROOTC_STORAGE_TO_LITTER - live coarse root C storage mortality gC/m^2/s F +M_LIVECROOTC_STORAGE_TO_LITTER_FIRE - live coarse root C fire mortality to litter gC/m^2/s F +M_LIVECROOTC_TO_LITTER - live coarse root C mortality gC/m^2/s F +M_LIVECROOTC_XFER_TO_LITTER - live coarse root C transfer mortality gC/m^2/s F +M_LIVECROOTN_STORAGE_TO_FIRE - live coarse root N storage fire loss gN/m^2/s F +M_LIVECROOTN_STORAGE_TO_LITTER - live coarse root N storage mortality gN/m^2/s F +M_LIVECROOTN_TO_FIRE - live coarse root N fire loss gN/m^2/s F +M_LIVECROOTN_TO_LITTER - live coarse root N mortality gN/m^2/s F +M_LIVECROOTN_XFER_TO_FIRE - live coarse root N transfer fire loss gN/m^2/s F +M_LIVECROOTN_XFER_TO_LITTER - live coarse root N transfer mortality gN/m^2/s F +M_LIVEROOTC_STORAGE_TO_FIRE - live root C storage fire loss gC/m^2/s F +M_LIVEROOTC_STORAGE_TO_LITTER_FIRE - live root C storage fire mortality to litter gC/m^2/s F +M_LIVEROOTC_TO_DEADROOTC_FIRE - live root C fire mortality to dead root C gC/m^2/s F +M_LIVEROOTC_TO_FIRE - live root C fire loss gC/m^2/s F +M_LIVEROOTC_TO_LITTER_FIRE - live root C fire mortality to litter gC/m^2/s F +M_LIVEROOTC_XFER_TO_FIRE - live root C transfer fire loss gC/m^2/s F +M_LIVEROOTC_XFER_TO_LITTER_FIRE - live root C transfer fire mortality to litter gC/m^2/s F +M_LIVESTEMC_STORAGE_TO_FIRE - live stem C storage fire loss gC/m^2/s F +M_LIVESTEMC_STORAGE_TO_LITTER - live stem C storage mortality gC/m^2/s F +M_LIVESTEMC_STORAGE_TO_LITTER_FIRE - live stem C storage fire mortality to litter gC/m^2/s F +M_LIVESTEMC_TO_DEADSTEMC_FIRE - live stem C fire mortality to dead stem C gC/m^2/s F +M_LIVESTEMC_TO_FIRE - live stem C fire loss gC/m^2/s F +M_LIVESTEMC_TO_LITTER - live stem C mortality gC/m^2/s F +M_LIVESTEMC_TO_LITTER_FIRE - live stem C fire mortality to litter gC/m^2/s F +M_LIVESTEMC_XFER_TO_FIRE - live stem C transfer fire loss gC/m^2/s F +M_LIVESTEMC_XFER_TO_LITTER - live stem C transfer mortality gC/m^2/s F +M_LIVESTEMC_XFER_TO_LITTER_FIRE - live stem C transfer fire mortality to litter gC/m^2/s F +M_LIVESTEMN_STORAGE_TO_FIRE - live stem N storage fire loss gN/m^2/s F +M_LIVESTEMN_STORAGE_TO_LITTER - live stem N storage mortality gN/m^2/s F +M_LIVESTEMN_TO_FIRE - live stem N fire loss gN/m^2/s F +M_LIVESTEMN_TO_LITTER - live stem N mortality gN/m^2/s F +M_LIVESTEMN_XFER_TO_FIRE - live stem N transfer fire loss gN/m^2/s F +M_LIVESTEMN_XFER_TO_LITTER - live stem N transfer mortality gN/m^2/s F +M_RETRANSN_TO_FIRE - retranslocated N pool fire loss gN/m^2/s F +M_RETRANSN_TO_LITTER - retranslocated N pool mortality gN/m^2/s F +M_SOM_ACT_C_TO_LEACHING - active soil organic C leaching loss gC/m^2/s F +M_SOM_ACT_N_TO_LEACHING - active soil organic N leaching loss gN/m^2/s F +M_SOM_PAS_C_TO_LEACHING - passive soil organic C leaching loss gC/m^2/s F +M_SOM_PAS_N_TO_LEACHING - passive soil organic N leaching loss gN/m^2/s F +M_SOM_SLO_C_TO_LEACHING - slow soil organic ma C leaching loss gC/m^2/s F +M_SOM_SLO_N_TO_LEACHING - slow soil organic ma N leaching loss gN/m^2/s F +NACTIVE - Mycorrhizal N uptake flux gN/m^2/s T +NACTIVE_NH4 - Mycorrhizal N uptake flux gN/m^2/s T +NACTIVE_NO3 - Mycorrhizal N uptake flux gN/m^2/s T +NAM - AM-associated N uptake flux gN/m^2/s T +NAM_NH4 - AM-associated N uptake flux gN/m^2/s T +NAM_NO3 - AM-associated N uptake flux gN/m^2/s T +NBP - net biome production, includes fire, landuse, harvest and hrv_xsmrpool flux (latter smoothed o gC/m^2/s T +NDEPLOY - total N deployed in new growth gN/m^2/s T +NDEP_TO_SMINN - atmospheric N deposition to soil mineral N gN/m^2/s T +NECM - ECM-associated N uptake flux gN/m^2/s T +NECM_NH4 - ECM-associated N uptake flux gN/m^2/s T +NECM_NO3 - ECM-associated N uptake flux gN/m^2/s T +NEE - net ecosystem exchange of carbon, includes fire and hrv_xsmrpool (latter smoothed over the yea gC/m^2/s T +NEM - Gridcell net adjustment to net carbon exchange passed to atm. for methane production gC/m2/s T +NEP - net ecosystem production, excludes fire, landuse, and harvest flux, positive for sink gC/m^2/s T +NET_NMIN - net rate of N mineralization gN/m^2/s T +NFERTILIZATION - fertilizer added gN/m^2/s T +NFIRE - fire counts valid only in Reg.C counts/km2/sec T +NFIX - Symbiotic BNF uptake flux gN/m^2/s T +NFIX_TO_SMINN - symbiotic/asymbiotic N fixation to soil mineral N gN/m^2/s F +NNONMYC - Non-mycorrhizal N uptake flux gN/m^2/s T +NNONMYC_NH4 - Non-mycorrhizal N uptake flux gN/m^2/s T +NNONMYC_NO3 - Non-mycorrhizal N uptake flux gN/m^2/s T +NPASSIVE - Passive N uptake flux gN/m^2/s T +NPOOL - temporary plant N pool gN/m^2 T +NPOOL_TO_DEADCROOTN - allocation to dead coarse root N gN/m^2/s F +NPOOL_TO_DEADCROOTN_STORAGE - allocation to dead coarse root N storage gN/m^2/s F +NPOOL_TO_DEADSTEMN - allocation to dead stem N gN/m^2/s F +NPOOL_TO_DEADSTEMN_STORAGE - allocation to dead stem N storage gN/m^2/s F +NPOOL_TO_FROOTN - allocation to fine root N gN/m^2/s F +NPOOL_TO_FROOTN_STORAGE - allocation to fine root N storage gN/m^2/s F +NPOOL_TO_LEAFN - allocation to leaf N gN/m^2/s F +NPOOL_TO_LEAFN_STORAGE - allocation to leaf N storage gN/m^2/s F +NPOOL_TO_LIVECROOTN - allocation to live coarse root N gN/m^2/s F +NPOOL_TO_LIVECROOTN_STORAGE - allocation to live coarse root N storage gN/m^2/s F +NPOOL_TO_LIVESTEMN - allocation to live stem N gN/m^2/s F +NPOOL_TO_LIVESTEMN_STORAGE - allocation to live stem N storage gN/m^2/s F +NPP - net primary production gC/m^2/s T +NPP_BURNEDOFF - C that cannot be used for N uptake gC/m^2/s F +NPP_GROWTH - Total C used for growth in FUN gC/m^2/s T +NPP_NACTIVE - Mycorrhizal N uptake used C gC/m^2/s T +NPP_NACTIVE_NH4 - Mycorrhizal N uptake use C gC/m^2/s T +NPP_NACTIVE_NO3 - Mycorrhizal N uptake used C gC/m^2/s T +NPP_NAM - AM-associated N uptake used C gC/m^2/s T +NPP_NAM_NH4 - AM-associated N uptake use C gC/m^2/s T +NPP_NAM_NO3 - AM-associated N uptake use C gC/m^2/s T +NPP_NECM - ECM-associated N uptake used C gC/m^2/s T +NPP_NECM_NH4 - ECM-associated N uptake use C gC/m^2/s T +NPP_NECM_NO3 - ECM-associated N uptake used C gC/m^2/s T +NPP_NFIX - Symbiotic BNF uptake used C gC/m^2/s T +NPP_NNONMYC - Non-mycorrhizal N uptake used C gC/m^2/s T +NPP_NNONMYC_NH4 - Non-mycorrhizal N uptake use C gC/m^2/s T +NPP_NNONMYC_NO3 - Non-mycorrhizal N uptake use C gC/m^2/s T +NPP_NRETRANS - Retranslocated N uptake flux gC/m^2/s T +NPP_NUPTAKE - Total C used by N uptake in FUN gC/m^2/s T +NRETRANS - Retranslocated N uptake flux gN/m^2/s T +NRETRANS_REG - Retranslocated N uptake flux gN/m^2/s T +NRETRANS_SEASON - Retranslocated N uptake flux gN/m^2/s T +NRETRANS_STRESS - Retranslocated N uptake flux gN/m^2/s T +NSUBSTEPS - number of adaptive timesteps in CLM timestep unitless F +NUPTAKE - Total N uptake of FUN gN/m^2/s T +NUPTAKE_NPP_FRACTION - frac of NPP used in N uptake - T +N_ALLOMETRY - N allocation index none F +OBU - Monin-Obukhov length m F +OCDEP - total OC deposition (dry+wet) from atmosphere kg/m^2/s T +OFFSET_COUNTER - offset days counter days F +OFFSET_FDD - offset freezing degree days counter C degree-days F +OFFSET_FLAG - offset flag none F +OFFSET_SWI - offset soil water index none F +ONSET_COUNTER - onset days counter days F +ONSET_FDD - onset freezing degree days counter C degree-days F +ONSET_FLAG - onset flag none F +ONSET_GDD - onset growing degree days C degree-days F +ONSET_GDDFLAG - onset flag for growing degree day sum none F +ONSET_SWI - onset soil water index none F +PAR240DZ - 10-day running mean of daytime patch absorbed PAR for leaves for top canopy layer W/m^2 F +PAR240XZ - 10-day running mean of maximum patch absorbed PAR for leaves for top canopy layer W/m^2 F +PAR240_shade - shade PAR (240 hrs) umol/m2/s F +PAR240_sun - sunlit PAR (240 hrs) umol/m2/s F +PAR24_shade - shade PAR (24 hrs) umol/m2/s F +PAR24_sun - sunlit PAR (24 hrs) umol/m2/s F +PARVEGLN - absorbed par by vegetation at local noon W/m^2 T +PAR_shade - shade PAR umol/m2/s F +PAR_sun - sunlit PAR umol/m2/s F +PBOT - atmospheric pressure at surface (downscaled to columns in glacier regions) Pa T +PBOT_240 - 10 day running mean of air pressure Pa F +PCH4 - atmospheric partial pressure of CH4 Pa T +PCO2 - atmospheric partial pressure of CO2 Pa T +PCO2_240 - 10 day running mean of CO2 pressure Pa F +PFT_CTRUNC - patch-level sink for C truncation gC/m^2 F +PFT_FIRE_CLOSS - total patch-level fire C loss for non-peat fires outside land-type converted region gC/m^2/s T +PFT_FIRE_NLOSS - total patch-level fire N loss gN/m^2/s T +PFT_NTRUNC - patch-level sink for N truncation gN/m^2 F +PLANTCN - Plant C:N used by FUN unitless F +PLANT_CALLOC - total allocated C flux gC/m^2/s F +PLANT_NALLOC - total allocated N flux gN/m^2/s F +PLANT_NDEMAND - N flux required to support initial GPP gN/m^2/s T +PNLCZ - Proportion of nitrogen allocated for light capture unitless F +PO2_240 - 10 day running mean of O2 pressure Pa F +POTENTIAL_IMMOB - potential N immobilization gN/m^2/s T +POT_F_DENIT - potential denitrification flux gN/m^2/s T +POT_F_NIT - potential nitrification flux gN/m^2/s T +PREC10 - 10-day running mean of PREC MM H2O/S F +PREC60 - 60-day running mean of PREC MM H2O/S F +PREV_DAYL - daylength from previous timestep s F +PREV_FROOTC_TO_LITTER - previous timestep froot C litterfall flux gC/m^2/s F +PREV_LEAFC_TO_LITTER - previous timestep leaf C litterfall flux gC/m^2/s F +PROD100C - 100-yr wood product C gC/m^2 F +PROD100C_LOSS - loss from 100-yr wood product pool gC/m^2/s F +PROD100N - 100-yr wood product N gN/m^2 F +PROD100N_LOSS - loss from 100-yr wood product pool gN/m^2/s F +PROD10C - 10-yr wood product C gC/m^2 F +PROD10C_LOSS - loss from 10-yr wood product pool gC/m^2/s F +PROD10N - 10-yr wood product N gN/m^2 F +PROD10N_LOSS - loss from 10-yr wood product pool gN/m^2/s F +PSNSHA - shaded leaf photosynthesis umolCO2/m^2/s T +PSNSHADE_TO_CPOOL - C fixation from shaded canopy gC/m^2/s T +PSNSUN - sunlit leaf photosynthesis umolCO2/m^2/s T +PSNSUN_TO_CPOOL - C fixation from sunlit canopy gC/m^2/s T +PSurf - atmospheric pressure at surface (downscaled to columns in glacier regions) Pa F +Q2M - 2m specific humidity kg/kg T +QAF - canopy air humidity kg/kg F +QBOT - atmospheric specific humidity (downscaled to columns in glacier regions) kg/kg T +QDIRECT_THROUGHFALL - direct throughfall of liquid (rain + above-canopy irrigation) mm/s F +QDIRECT_THROUGHFALL_SNOW - direct throughfall of snow mm/s F +QDRAI - sub-surface drainage mm/s T +QDRAI_PERCH - perched wt drainage mm/s T +QDRAI_XS - saturation excess drainage mm/s T +QDRIP - rate of excess canopy liquid falling off canopy mm/s F +QDRIP_SNOW - rate of excess canopy snow falling off canopy mm/s F +QFLOOD - runoff from river flooding mm/s T +QFLX_EVAP_TOT - qflx_evap_soi + qflx_evap_can + qflx_tran_veg kg m-2 s-1 T +QFLX_EVAP_VEG - vegetation evaporation mm H2O/s F +QFLX_ICE_DYNBAL - ice dynamic land cover change conversion runoff flux mm/s T +QFLX_LIQDEW_TO_TOP_LAYER - rate of liquid water deposited on top soil or snow layer (dew) mm H2O/s T +QFLX_LIQEVAP_FROM_TOP_LAYER - rate of liquid water evaporated from top soil or snow layer mm H2O/s T +QFLX_LIQ_DYNBAL - liq dynamic land cover change conversion runoff flux mm/s T +QFLX_LIQ_GRND - liquid (rain+irrigation) on ground after interception mm H2O/s F +QFLX_SNOW_DRAIN - drainage from snow pack mm/s T +QFLX_SNOW_DRAIN_ICE - drainage from snow pack melt (ice landunits only) mm/s T +QFLX_SNOW_GRND - snow on ground after interception mm H2O/s F +QFLX_SOLIDDEW_TO_TOP_LAYER - rate of solid water deposited on top soil or snow layer (frost) mm H2O/s T +QFLX_SOLIDEVAP_FROM_TOP_LAYER - rate of ice evaporated from top soil or snow layer (sublimation) (also includes bare ice subli mm H2O/s T +QFLX_SOLIDEVAP_FROM_TOP_LAYER_ICE - rate of ice evaporated from top soil or snow layer (sublimation) (also includes bare ice subli mm H2O/s F +QH2OSFC - surface water runoff mm/s T +QH2OSFC_TO_ICE - surface water converted to ice mm/s F +QHR - hydraulic redistribution mm/s T +QICE - ice growth/melt mm/s T +QICE_FRZ - ice growth mm/s T +QICE_MELT - ice melt mm/s T +QINFL - infiltration mm/s T +QINTR - interception mm/s T +QIRRIG_DEMAND - irrigation demand mm/s F +QIRRIG_DRIP - water added via drip irrigation mm/s F +QIRRIG_FROM_GW_CONFINED - water added through confined groundwater irrigation mm/s T +QIRRIG_FROM_GW_UNCONFINED - water added through unconfined groundwater irrigation mm/s T +QIRRIG_FROM_SURFACE - water added through surface water irrigation mm/s T +QIRRIG_SPRINKLER - water added via sprinkler irrigation mm/s F +QOVER - total surface runoff (includes QH2OSFC) mm/s T +QOVER_LAG - time-lagged surface runoff for soil columns mm/s F +QPHSNEG - net negative hydraulic redistribution flux mm/s F +QRGWL - surface runoff at glaciers (liquid only), wetlands, lakes; also includes melted ice runoff fro mm/s T +QRUNOFF - total liquid runoff not including correction for land use change mm/s T +QRUNOFF_ICE - total liquid runoff not incl corret for LULCC (ice landunits only) mm/s T +QRUNOFF_ICE_TO_COUPLER - total ice runoff sent to coupler (includes corrections for land use change) mm/s T +QRUNOFF_ICE_TO_LIQ - liquid runoff from converted ice runoff mm/s F +QRUNOFF_R - Rural total runoff mm/s F +QRUNOFF_TO_COUPLER - total liquid runoff sent to coupler (includes corrections for land use change) mm/s T +QRUNOFF_U - Urban total runoff mm/s F +QSNOCPLIQ - excess liquid h2o due to snow capping not including correction for land use change mm H2O/s T +QSNOEVAP - evaporation from snow (only when snl<0, otherwise it is equal to qflx_ev_soil) mm/s T +QSNOFRZ - column-integrated snow freezing rate kg/m2/s T +QSNOFRZ_ICE - column-integrated snow freezing rate (ice landunits only) mm/s T +QSNOMELT - snow melt rate mm/s T +QSNOMELT_ICE - snow melt (ice landunits only) mm/s T +QSNOUNLOAD - canopy snow unloading mm/s T +QSNO_TEMPUNLOAD - canopy snow temp unloading mm/s T +QSNO_WINDUNLOAD - canopy snow wind unloading mm/s T +QSNWCPICE - excess solid h2o due to snow capping not including correction for land use change mm H2O/s T +QSOIL - Ground evaporation (soil/snow evaporation + soil/snow sublimation - dew) mm/s T +QSOIL_ICE - Ground evaporation (ice landunits only) mm/s T +QTOPSOIL - water input to surface mm/s F +QVEGE - canopy evaporation mm/s T +QVEGT - canopy transpiration mm/s T +Qair - atmospheric specific humidity (downscaled to columns in glacier regions) kg/kg F +Qh - sensible heat W/m^2 F +Qle - total evaporation W/m^2 F +Qstor - storage heat flux (includes snowmelt) W/m^2 F +Qtau - momentum flux kg/m/s^2 F +RAH1 - aerodynamical resistance s/m F +RAH2 - aerodynamical resistance s/m F +RAIN - atmospheric rain, after rain/snow repartitioning based on temperature mm/s T +RAIN_FROM_ATM - atmospheric rain received from atmosphere (pre-repartitioning) mm/s T +RAIN_ICE - atmospheric rain, after rain/snow repartitioning based on temperature (ice landunits only) mm/s F +RAM1 - aerodynamical resistance s/m F +RAM_LAKE - aerodynamic resistance for momentum (lakes only) s/m F +RAW1 - aerodynamical resistance s/m F +RAW2 - aerodynamical resistance s/m F +RB - leaf boundary resistance s/m F +RB10 - 10 day running mean boundary layer resistance s/m F +RETRANSN - plant pool of retranslocated N gN/m^2 T +RETRANSN_TO_NPOOL - deployment of retranslocated N gN/m^2/s T +RH - atmospheric relative humidity % F +RH2M - 2m relative humidity % T +RH2M_R - Rural 2m specific humidity % F +RH2M_U - Urban 2m relative humidity % F +RH30 - 30-day running mean of relative humidity % F +RHAF - fractional humidity of canopy air fraction F +RHAF10 - 10 day running mean of fractional humidity of canopy air fraction F +RH_LEAF - fractional humidity at leaf surface fraction F +RR - root respiration (fine root MR + total root GR) gC/m^2/s T +RSSHA - shaded leaf stomatal resistance s/m T +RSSUN - sunlit leaf stomatal resistance s/m T +Rainf - atmospheric rain, after rain/snow repartitioning based on temperature mm/s F +Rnet - net radiation W/m^2 F +SABG - solar rad absorbed by ground W/m^2 T +SABG_PEN - Rural solar rad penetrating top soil or snow layer watt/m^2 T +SABV - solar rad absorbed by veg W/m^2 T +SEEDC - pool for seeding new PFTs via dynamic landcover gC/m^2 T +SEEDN - pool for seeding new PFTs via dynamic landcover gN/m^2 T +SLASH_HARVESTC - slash harvest carbon (to litter) gC/m^2/s T +SMINN - soil mineral N gN/m^2 T +SMINN_TO_NPOOL - deployment of soil mineral N uptake gN/m^2/s T +SMINN_TO_PLANT - plant uptake of soil mineral N gN/m^2/s T +SMINN_TO_PLANT_FUN - Total soil N uptake of FUN gN/m^2/s T +SMINN_TO_S1N_L1 - mineral N flux for decomp. of LIT_METto SOM_ACT gN/m^2 F +SMINN_TO_S1N_L2 - mineral N flux for decomp. of LIT_CELto SOM_ACT gN/m^2 F +SMINN_TO_S1N_S2 - mineral N flux for decomp. of SOM_SLOto SOM_ACT gN/m^2 F +SMINN_TO_S1N_S3 - mineral N flux for decomp. of SOM_PASto SOM_ACT gN/m^2 F +SMINN_TO_S2N_L3 - mineral N flux for decomp. of LIT_LIGto SOM_SLO gN/m^2 F +SMINN_TO_S2N_S1 - mineral N flux for decomp. of SOM_ACTto SOM_SLO gN/m^2 F +SMINN_TO_S3N_S1 - mineral N flux for decomp. of SOM_ACTto SOM_PAS gN/m^2 F +SMINN_TO_S3N_S2 - mineral N flux for decomp. of SOM_SLOto SOM_PAS gN/m^2 F +SMIN_NH4 - soil mineral NH4 gN/m^2 T +SMIN_NO3 - soil mineral NO3 gN/m^2 T +SMIN_NO3_LEACHED - soil NO3 pool loss to leaching gN/m^2/s T +SMIN_NO3_RUNOFF - soil NO3 pool loss to runoff gN/m^2/s T +SNOBCMCL - mass of BC in snow column kg/m2 T +SNOBCMSL - mass of BC in top snow layer kg/m2 T +SNOCAN - intercepted snow mm T +SNODSTMCL - mass of dust in snow column kg/m2 T +SNODSTMSL - mass of dust in top snow layer kg/m2 T +SNOFSDSND - direct nir incident solar radiation on snow W/m^2 F +SNOFSDSNI - diffuse nir incident solar radiation on snow W/m^2 F +SNOFSDSVD - direct vis incident solar radiation on snow W/m^2 F +SNOFSDSVI - diffuse vis incident solar radiation on snow W/m^2 F +SNOFSRND - direct nir reflected solar radiation from snow W/m^2 T +SNOFSRNI - diffuse nir reflected solar radiation from snow W/m^2 T +SNOFSRVD - direct vis reflected solar radiation from snow W/m^2 T +SNOFSRVI - diffuse vis reflected solar radiation from snow W/m^2 T +SNOINTABS - Fraction of incoming solar absorbed by lower snow layers - T +SNOLIQFL - top snow layer liquid water fraction (land) fraction F +SNOOCMCL - mass of OC in snow column kg/m2 T +SNOOCMSL - mass of OC in top snow layer kg/m2 T +SNORDSL - top snow layer effective grain radius m^-6 F +SNOTTOPL - snow temperature (top layer) K F +SNOTTOPL_ICE - snow temperature (top layer, ice landunits only) K F +SNOTXMASS - snow temperature times layer mass, layer sum; to get mass-weighted temperature, divide by (SNO K kg/m2 T +SNOTXMASS_ICE - snow temperature times layer mass, layer sum (ice landunits only); to get mass-weighted temper K kg/m2 F +SNOW - atmospheric snow, after rain/snow repartitioning based on temperature mm/s T +SNOWDP - gridcell mean snow height m T +SNOWICE - snow ice kg/m2 T +SNOWICE_ICE - snow ice (ice landunits only) kg/m2 F +SNOWLIQ - snow liquid water kg/m2 T +SNOWLIQ_ICE - snow liquid water (ice landunits only) kg/m2 F +SNOW_5D - 5day snow avg m F +SNOW_DEPTH - snow height of snow covered area m T +SNOW_DEPTH_ICE - snow height of snow covered area (ice landunits only) m F +SNOW_FROM_ATM - atmospheric snow received from atmosphere (pre-repartitioning) mm/s T +SNOW_ICE - atmospheric snow, after rain/snow repartitioning based on temperature (ice landunits only) mm/s F +SNOW_PERSISTENCE - Length of time of continuous snow cover (nat. veg. landunits only) seconds T +SNOW_SINKS - snow sinks (liquid water) mm/s T +SNOW_SOURCES - snow sources (liquid water) mm/s T +SNOdTdzL - top snow layer temperature gradient (land) K/m F +SOIL10 - 10-day running mean of 12cm layer soil K F +SOILC_CHANGE - C change in soil gC/m^2/s T +SOILC_HR - soil C heterotrophic respiration gC/m^2/s T +SOILRESIS - soil resistance to evaporation s/m T +SOILWATER_10CM - soil liquid water + ice in top 10cm of soil (veg landunits only) kg/m2 T +SOMC_FIRE - C loss due to peat burning gC/m^2/s T +SOMFIRE - soil organic matter fire losses gC/m^2/s F +SOM_ACT_C - SOM_ACT C gC/m^2 T +SOM_ACT_C_1m - SOM_ACT C to 1 meter gC/m^2 F +SOM_ACT_C_TO_SOM_PAS_C - decomp. of active soil organic C to passive soil organic C gC/m^2/s F +SOM_ACT_C_TO_SOM_SLO_C - decomp. of active soil organic C to slow soil organic ma C gC/m^2/s F +SOM_ACT_HR_S2 - Het. Resp. from active soil organic gC/m^2/s F +SOM_ACT_HR_S3 - Het. Resp. from active soil organic gC/m^2/s F +SOM_ACT_N - SOM_ACT N gN/m^2 T +SOM_ACT_N_1m - SOM_ACT N to 1 meter gN/m^2 F +SOM_ACT_N_TO_SOM_PAS_N - decomp. of active soil organic N to passive soil organic N gN/m^2 F +SOM_ACT_N_TO_SOM_SLO_N - decomp. of active soil organic N to slow soil organic ma N gN/m^2 F +SOM_C_LEACHED - total flux of C from SOM pools due to leaching gC/m^2/s T +SOM_N_LEACHED - total flux of N from SOM pools due to leaching gN/m^2/s F +SOM_PAS_C - SOM_PAS C gC/m^2 T +SOM_PAS_C_1m - SOM_PAS C to 1 meter gC/m^2 F +SOM_PAS_C_TO_SOM_ACT_C - decomp. of passive soil organic C to active soil organic C gC/m^2/s F +SOM_PAS_HR - Het. Resp. from passive soil organic gC/m^2/s F +SOM_PAS_N - SOM_PAS N gN/m^2 T +SOM_PAS_N_1m - SOM_PAS N to 1 meter gN/m^2 F +SOM_PAS_N_TO_SOM_ACT_N - decomp. of passive soil organic N to active soil organic N gN/m^2 F +SOM_SLO_C - SOM_SLO C gC/m^2 T +SOM_SLO_C_1m - SOM_SLO C to 1 meter gC/m^2 F +SOM_SLO_C_TO_SOM_ACT_C - decomp. of slow soil organic ma C to active soil organic C gC/m^2/s F +SOM_SLO_C_TO_SOM_PAS_C - decomp. of slow soil organic ma C to passive soil organic C gC/m^2/s F +SOM_SLO_HR_S1 - Het. Resp. from slow soil organic ma gC/m^2/s F +SOM_SLO_HR_S3 - Het. Resp. from slow soil organic ma gC/m^2/s F +SOM_SLO_N - SOM_SLO N gN/m^2 T +SOM_SLO_N_1m - SOM_SLO N to 1 meter gN/m^2 F +SOM_SLO_N_TO_SOM_ACT_N - decomp. of slow soil organic ma N to active soil organic N gN/m^2 F +SOM_SLO_N_TO_SOM_PAS_N - decomp. of slow soil organic ma N to passive soil organic N gN/m^2 F +SR - total soil respiration (HR + root resp) gC/m^2/s T +STORAGE_CDEMAND - C use from the C storage pool gC/m^2 F +STORAGE_GR - growth resp for growth sent to storage for later display gC/m^2/s F +STORAGE_NDEMAND - N demand during the offset period gN/m^2 F +STORVEGC - stored vegetation carbon, excluding cpool gC/m^2 T +STORVEGN - stored vegetation nitrogen gN/m^2 T +SUPPLEMENT_TO_SMINN - supplemental N supply gN/m^2/s T +SWBGT - 2 m Simplified Wetbulb Globe Temp C T +SWBGT_R - Rural 2 m Simplified Wetbulb Globe Temp C T +SWBGT_U - Urban 2 m Simplified Wetbulb Globe Temp C T +SWdown - atmospheric incident solar radiation W/m^2 F +SWup - upwelling shortwave radiation W/m^2 F +SoilAlpha - factor limiting ground evap unitless F +SoilAlpha_U - urban factor limiting ground evap unitless F +T10 - 10-day running mean of 2-m temperature K F +TAF - canopy air temperature K F +TAUX - zonal surface stress kg/m/s^2 T +TAUY - meridional surface stress kg/m/s^2 T +TBOT - atmospheric air temperature (downscaled to columns in glacier regions) K T +TBUILD - internal urban building air temperature K T +TBUILD_MAX - prescribed maximum interior building temperature K F +TEMPAVG_T2M - temporary average 2m air temperature K F +TEMPMAX_RETRANSN - temporary annual max of retranslocated N pool gN/m^2 F +TEMPSUM_POTENTIAL_GPP - temporary annual sum of potential GPP gC/m^2/yr F +TFLOOR - floor temperature K F +TG - ground temperature K T +TG_ICE - ground temperature (ice landunits only) K F +TG_R - Rural ground temperature K F +TG_U - Urban ground temperature K F +TH2OSFC - surface water temperature K T +THBOT - atmospheric air potential temperature (downscaled to columns in glacier regions) K T +TKE1 - top lake level eddy thermal conductivity W/(mK) T +TLAI - total projected leaf area index m^2/m^2 T +TOPO_COL - column-level topographic height m F +TOPO_COL_ICE - column-level topographic height (ice landunits only) m F +TOPT - topt coefficient for VOC calc non F +TOTCOLC - total column carbon, incl veg and cpool but excl product pools gC/m^2 T +TOTCOLCH4 - total belowground CH4 (0 for non-lake special landunits in the absence of dynamic landunits) gC/m2 T +TOTCOLN - total column-level N, excluding product pools gN/m^2 T +TOTECOSYSC - total ecosystem carbon, incl veg but excl cpool and product pools gC/m^2 T +TOTECOSYSN - total ecosystem N, excluding product pools gN/m^2 T +TOTFIRE - total ecosystem fire losses gC/m^2/s F +TOTLITC - total litter carbon gC/m^2 T +TOTLITC_1m - total litter carbon to 1 meter depth gC/m^2 T +TOTLITN - total litter N gN/m^2 T +TOTLITN_1m - total litter N to 1 meter gN/m^2 T +TOTPFTC - total patch-level carbon, including cpool gC/m^2 T +TOTPFTN - total patch-level nitrogen gN/m^2 T +TOTSOILICE - vertically summed soil ice (veg landunits only) kg/m2 T +TOTSOILLIQ - vertically summed soil liquid water (veg landunits only) kg/m2 T +TOTSOMC - total soil organic matter carbon gC/m^2 T +TOTSOMC_1m - total soil organic matter carbon to 1 meter depth gC/m^2 T +TOTSOMN - total soil organic matter N gN/m^2 T +TOTSOMN_1m - total soil organic matter N to 1 meter gN/m^2 T +TOTVEGC - total vegetation carbon, excluding cpool gC/m^2 T +TOTVEGN - total vegetation nitrogen gN/m^2 T +TOT_WOODPRODC - total wood product C gC/m^2 T +TOT_WOODPRODC_LOSS - total loss from wood product pools gC/m^2/s T +TOT_WOODPRODN - total wood product N gN/m^2 T +TOT_WOODPRODN_LOSS - total loss from wood product pools gN/m^2/s T +TPU25T - canopy profile of tpu umol/m2/s T +TRAFFICFLUX - sensible heat flux from urban traffic W/m^2 F +TRANSFER_DEADCROOT_GR - dead coarse root growth respiration from storage gC/m^2/s F +TRANSFER_DEADSTEM_GR - dead stem growth respiration from storage gC/m^2/s F +TRANSFER_FROOT_GR - fine root growth respiration from storage gC/m^2/s F +TRANSFER_GR - growth resp for transfer growth displayed in this timestep gC/m^2/s F +TRANSFER_LEAF_GR - leaf growth respiration from storage gC/m^2/s F +TRANSFER_LIVECROOT_GR - live coarse root growth respiration from storage gC/m^2/s F +TRANSFER_LIVESTEM_GR - live stem growth respiration from storage gC/m^2/s F +TREFMNAV - daily minimum of average 2-m temperature K T +TREFMNAV_R - Rural daily minimum of average 2-m temperature K F +TREFMNAV_U - Urban daily minimum of average 2-m temperature K F +TREFMXAV - daily maximum of average 2-m temperature K T +TREFMXAV_R - Rural daily maximum of average 2-m temperature K F +TREFMXAV_U - Urban daily maximum of average 2-m temperature K F +TROOF_INNER - roof inside surface temperature K F +TSA - 2m air temperature K T +TSAI - total projected stem area index m^2/m^2 T +TSA_ICE - 2m air temperature (ice landunits only) K F +TSA_R - Rural 2m air temperature K F +TSA_U - Urban 2m air temperature K F +TSHDW_INNER - shadewall inside surface temperature K F +TSKIN - skin temperature K T +TSL - temperature of near-surface soil layer (natural vegetated and crop landunits only) K T +TSOI_10CM - soil temperature in top 10cm of soil K T +TSUNW_INNER - sunwall inside surface temperature K F +TV - vegetation temperature K T +TV24 - vegetation temperature (last 24hrs) K F +TV240 - vegetation temperature (last 240hrs) K F +TVEGD10 - 10 day running mean of patch daytime vegetation temperature Kelvin F +TVEGN10 - 10 day running mean of patch night-time vegetation temperature Kelvin F +TWS - total water storage mm T +Tair - atmospheric air temperature (downscaled to columns in glacier regions) K F +Tair_from_atm - atmospheric air temperature received from atmosphere (pre-downscaling) K F +U10 - 10-m wind m/s T +U10_DUST - 10-m wind for dust model m/s T +U10_ICE - 10-m wind (ice landunits only) m/s F +UAF - canopy air speed m/s F +ULRAD - upward longwave radiation above the canopy W/m^2 F +UM - wind speed plus stability effect m/s F +URBAN_AC - urban air conditioning flux W/m^2 T +URBAN_HEAT - urban heating flux W/m^2 T +USTAR - aerodynamical resistance s/m F +UST_LAKE - friction velocity (lakes only) m/s F +VA - atmospheric wind speed plus convective velocity m/s F +VCMX25T - canopy profile of vcmax25 umol/m2/s T +VENTILATION - sensible heat flux from building ventilation W/m^2 T +VOCFLXT - total VOC flux into atmosphere moles/m2/sec F +VOLR - river channel total water storage m3 T +VOLRMCH - river channel main channel water storage m3 T +VPD - vpd Pa F +VPD2M - 2m vapor pressure deficit Pa T +VPD_CAN - canopy vapor pressure deficit kPa T +Vcmx25Z - canopy profile of vcmax25 predicted by LUNA model umol/m2/s T +WASTEHEAT - sensible heat flux from heating/cooling sources of urban waste heat W/m^2 T +WBT - 2 m Stull Wet Bulb C T +WBT_R - Rural 2 m Stull Wet Bulb C T +WBT_U - Urban 2 m Stull Wet Bulb C T +WF - soil water as frac. of whc for top 0.05 m proportion F +WIND - atmospheric wind velocity magnitude m/s T +WOODC - wood C gC/m^2 T +WOODC_ALLOC - wood C eallocation gC/m^2/s T +WOODC_LOSS - wood C loss gC/m^2/s T +WOOD_HARVESTC - wood harvest carbon (to product pools) gC/m^2/s T +WOOD_HARVESTN - wood harvest N (to product pools) gN/m^2/s T +WTGQ - surface tracer conductance m/s T +Wind - atmospheric wind velocity magnitude m/s F +XSMRPOOL - temporary photosynthate C pool gC/m^2 T +XSMRPOOL_LOSS - temporary photosynthate C pool loss gC/m^2 F +XSMRPOOL_RECOVER - C flux assigned to recovery of negative xsmrpool gC/m^2/s T +Z0HG - roughness length over ground, sensible heat (vegetated landunits only) m F +Z0HV - roughness length over vegetation, sensible heat m F +Z0MG - roughness length over ground, momentum (vegetated landunits only) m F +Z0MV - roughness length over vegetation, momentum m F +Z0MV_DENSE - roughness length over vegetation, momentum, for dense canopy m F +Z0M_TO_COUPLER - roughness length, momentum: gridcell average sent to coupler m F +Z0QG - roughness length over ground, latent heat (vegetated landunits only) m F +Z0QV - roughness length over vegetation, latent heat m F +ZBOT - atmospheric reference height m T +ZETA - dimensionless stability parameter unitless F +ZII - convective boundary height m F +ZWT - water table depth (natural vegetated and crop landunits only) m T +ZWT_CH4_UNSAT - depth of water table for methane production used in non-inundated area m T +ZWT_PERCH - perched water table depth (natural vegetated and crop landunits only) m T +currentPatch - currentPatch coefficient for VOC calc non F +num_iter - number of iterations unitless F +QICE_FORC elevclas qice forcing sent to GLC mm/s F +TOPO_FORC elevclas topograephic height sent to GLC m F +TSRF_FORC elevclas surface temperature sent to GLC K F +ACTUAL_IMMOB_NH4 levdcmp immobilization of NH4 gN/m^3/s F +ACTUAL_IMMOB_NO3 levdcmp immobilization of NO3 gN/m^3/s F +ACTUAL_IMMOB_vr levdcmp actual N immobilization gN/m^3/s F +CROOT_PROF levdcmp profile for litter C and N inputs from coarse roots 1/m F +CWD_C_TO_LIT_CEL_C_vr levdcmp decomp. of coarse woody debris C to cellulosic litter C gC/m^3/s F +CWD_C_TO_LIT_LIG_C_vr levdcmp decomp. of coarse woody debris C to lignin litter C gC/m^3/s F +CWD_HR_L2_vr levdcmp Het. Resp. from coarse woody debris gC/m^3/s F +CWD_HR_L3_vr levdcmp Het. Resp. from coarse woody debris gC/m^3/s F +CWD_N_TO_LIT_CEL_N_vr levdcmp decomp. of coarse woody debris N to cellulosic litter N gN/m^3 F +CWD_N_TO_LIT_LIG_N_vr levdcmp decomp. of coarse woody debris N to lignin litter N gN/m^3 F +CWD_N_vr levdcmp CWD N (vertically resolved) gN/m^3 T +CWD_PATHFRAC_L2_vr levdcmp PATHFRAC from coarse woody debris to cellulosic litter fraction F +CWD_PATHFRAC_L3_vr levdcmp PATHFRAC from coarse woody debris to lignin litter fraction F +CWD_RESP_FRAC_L2_vr levdcmp respired from coarse woody debris to cellulosic litter fraction F +CWD_RESP_FRAC_L3_vr levdcmp respired from coarse woody debris to lignin litter fraction F +DWT_DEADCROOTC_TO_CWDC levdcmp dead coarse root to CWD due to landcover change gC/m^2/s F +DWT_DEADCROOTN_TO_CWDN levdcmp dead coarse root to CWD due to landcover change gN/m^2/s F +DWT_FROOTC_TO_LIT_CEL_C levdcmp fine root to cellulosic litter due to landcover change gC/m^2/s F +DWT_FROOTC_TO_LIT_LIG_C levdcmp fine root to lignin litter due to landcover change gC/m^2/s F +DWT_FROOTC_TO_LIT_MET_C levdcmp fine root to metabolic litter due to landcover change gC/m^2/s F +DWT_FROOTN_TO_LIT_CEL_N levdcmp fine root N to cellulosic litter due to landcover change gN/m^2/s F +DWT_FROOTN_TO_LIT_LIG_N levdcmp fine root N to lignin litter due to landcover change gN/m^2/s F +DWT_FROOTN_TO_LIT_MET_N levdcmp fine root N to metabolic litter due to landcover change gN/m^2/s F +DWT_LIVECROOTC_TO_CWDC levdcmp live coarse root to CWD due to landcover change gC/m^2/s F +DWT_LIVECROOTN_TO_CWDN levdcmp live coarse root to CWD due to landcover change gN/m^2/s F +FMAX_DENIT_CARBONSUBSTRATE levdcmp FMAX_DENIT_CARBONSUBSTRATE gN/m^3/s F +FMAX_DENIT_NITRATE levdcmp FMAX_DENIT_NITRATE gN/m^3/s F +FPI_vr levdcmp fraction of potential immobilization proportion F +FROOT_PROF levdcmp profile for litter C and N inputs from fine roots 1/m F +F_DENIT_BASE levdcmp F_DENIT_BASE gN/m^3/s F +F_DENIT_vr levdcmp denitrification flux gN/m^3/s F +F_NIT_vr levdcmp nitrification flux gN/m^3/s F +GROSS_NMIN_vr levdcmp gross rate of N mineralization gN/m^3/s F +K_CWD levdcmp coarse woody debris potential loss coefficient 1/s F +K_LIT_CEL levdcmp cellulosic litter potential loss coefficient 1/s F +K_LIT_LIG levdcmp lignin litter potential loss coefficient 1/s F +K_LIT_MET levdcmp metabolic litter potential loss coefficient 1/s F +K_NITR levdcmp K_NITR 1/s F +K_NITR_H2O levdcmp K_NITR_H2O unitless F +K_NITR_PH levdcmp K_NITR_PH unitless F +K_NITR_T levdcmp K_NITR_T unitless F +K_SOM_ACT levdcmp active soil organic potential loss coefficient 1/s F +K_SOM_PAS levdcmp passive soil organic potential loss coefficient 1/s F +K_SOM_SLO levdcmp slow soil organic ma potential loss coefficient 1/s F +L1_PATHFRAC_S1_vr levdcmp PATHFRAC from metabolic litter to active soil organic fraction F +L1_RESP_FRAC_S1_vr levdcmp respired from metabolic litter to active soil organic fraction F +L2_PATHFRAC_S1_vr levdcmp PATHFRAC from cellulosic litter to active soil organic fraction F +L2_RESP_FRAC_S1_vr levdcmp respired from cellulosic litter to active soil organic fraction F +L3_PATHFRAC_S2_vr levdcmp PATHFRAC from lignin litter to slow soil organic ma fraction F +L3_RESP_FRAC_S2_vr levdcmp respired from lignin litter to slow soil organic ma fraction F +LEAF_PROF levdcmp profile for litter C and N inputs from leaves 1/m F +LIT_CEL_C_TNDNCY_VERT_TR levdcmp cellulosic litter C tendency due to vertical transport gC/m^3/s F +LIT_CEL_C_TO_SOM_ACT_C_v levdcmp decomp. of cellulosic litter C to active soil organic C gC/m^3/s F +LIT_CEL_HR_vr levdcmp Het. Resp. from cellulosic litter gC/m^3/s F +LIT_CEL_N_TNDNCY_VERT_TR levdcmp cellulosic litter N tendency due to vertical transport gN/m^3/s F +LIT_CEL_N_TO_SOM_ACT_N_v levdcmp decomp. of cellulosic litter N to active soil organic N gN/m^3 F +LIT_CEL_N_vr levdcmp LIT_CEL N (vertically resolved) gN/m^3 T +LIT_LIG_C_TNDNCY_VERT_TR levdcmp lignin litter C tendency due to vertical transport gC/m^3/s F +LIT_LIG_C_TO_SOM_SLO_C_v levdcmp decomp. of lignin litter C to slow soil organic ma C gC/m^3/s F +LIT_LIG_HR_vr levdcmp Het. Resp. from lignin litter gC/m^3/s F +LIT_LIG_N_TNDNCY_VERT_TR levdcmp lignin litter N tendency due to vertical transport gN/m^3/s F +LIT_LIG_N_TO_SOM_SLO_N_v levdcmp decomp. of lignin litter N to slow soil organic ma N gN/m^3 F +LIT_LIG_N_vr levdcmp LIT_LIG N (vertically resolved) gN/m^3 T +LIT_MET_C_TNDNCY_VERT_TR levdcmp metabolic litter C tendency due to vertical transport gC/m^3/s F +LIT_MET_C_TO_SOM_ACT_C_v levdcmp decomp. of metabolic litter C to active soil organic C gC/m^3/s F +LIT_MET_HR_vr levdcmp Het. Resp. from metabolic litter gC/m^3/s F +LIT_MET_N_TNDNCY_VERT_TR levdcmp metabolic litter N tendency due to vertical transport gN/m^3/s F +LIT_MET_N_TO_SOM_ACT_N_v levdcmp decomp. of metabolic litter N to active soil organic N gN/m^3 F +LIT_MET_N_vr levdcmp LIT_MET N (vertically resolved) gN/m^3 T +M_CWD_C_TO_FIRE_vr levdcmp coarse woody debris C fire loss gC/m^3/s F +M_CWD_N_TO_FIRE_vr levdcmp coarse woody debris N fire loss gN/m^3 F +M_LIT_CEL_C_TO_FIRE_vr levdcmp cellulosic litter C fire loss gC/m^3/s F +M_LIT_CEL_N_TO_FIRE_vr levdcmp cellulosic litter N fire loss gN/m^3 F +M_LIT_LIG_C_TO_FIRE_vr levdcmp lignin litter C fire loss gC/m^3/s F +M_LIT_LIG_N_TO_FIRE_vr levdcmp lignin litter N fire loss gN/m^3 F +M_LIT_MET_C_TO_FIRE_vr levdcmp metabolic litter C fire loss gC/m^3/s F +M_LIT_MET_N_TO_FIRE_vr levdcmp metabolic litter N fire loss gN/m^3 F +NDEP_PROF levdcmp profile for atmospheric N deposition 1/m F +NET_NMIN_vr levdcmp net rate of N mineralization gN/m^3/s F +NFIXATION_PROF levdcmp profile for biological N fixation 1/m F +POTENTIAL_IMMOB_vr levdcmp potential N immobilization gN/m^3/s F +POT_F_DENIT_vr levdcmp potential denitrification flux gN/m^3/s F +POT_F_NIT_vr levdcmp potential nitrification flux gN/m^3/s F +S1_PATHFRAC_S2_vr levdcmp PATHFRAC from active soil organic to slow soil organic ma fraction F +S1_PATHFRAC_S3_vr levdcmp PATHFRAC from active soil organic to passive soil organic fraction F +S1_RESP_FRAC_S2_vr levdcmp respired from active soil organic to slow soil organic ma fraction F +S1_RESP_FRAC_S3_vr levdcmp respired from active soil organic to passive soil organic fraction F +S2_PATHFRAC_S1_vr levdcmp PATHFRAC from slow soil organic ma to active soil organic fraction F +S2_PATHFRAC_S3_vr levdcmp PATHFRAC from slow soil organic ma to passive soil organic fraction F +S2_RESP_FRAC_S1_vr levdcmp respired from slow soil organic ma to active soil organic fraction F +S2_RESP_FRAC_S3_vr levdcmp respired from slow soil organic ma to passive soil organic fraction F +S3_PATHFRAC_S1_vr levdcmp PATHFRAC from passive soil organic to active soil organic fraction F +S3_RESP_FRAC_S1_vr levdcmp respired from passive soil organic to active soil organic fraction F +SMINN_TO_PLANT_vr levdcmp plant uptake of soil mineral N gN/m^3/s F +SMINN_TO_S1N_L1_vr levdcmp mineral N flux for decomp. of LIT_METto SOM_ACT gN/m^3 F +SMINN_TO_S1N_L2_vr levdcmp mineral N flux for decomp. of LIT_CELto SOM_ACT gN/m^3 F +SMINN_TO_S1N_S2_vr levdcmp mineral N flux for decomp. of SOM_SLOto SOM_ACT gN/m^3 F +SMINN_TO_S1N_S3_vr levdcmp mineral N flux for decomp. of SOM_PASto SOM_ACT gN/m^3 F +SMINN_TO_S2N_L3_vr levdcmp mineral N flux for decomp. of LIT_LIGto SOM_SLO gN/m^3 F +SMINN_TO_S2N_S1_vr levdcmp mineral N flux for decomp. of SOM_ACTto SOM_SLO gN/m^3 F +SMINN_TO_S3N_S1_vr levdcmp mineral N flux for decomp. of SOM_ACTto SOM_PAS gN/m^3 F +SMINN_TO_S3N_S2_vr levdcmp mineral N flux for decomp. of SOM_SLOto SOM_PAS gN/m^3 F +SMIN_NH4_TO_PLANT levdcmp plant uptake of NH4 gN/m^3/s F +SMIN_NO3_LEACHED_vr levdcmp soil NO3 pool loss to leaching gN/m^3/s F +SMIN_NO3_MASSDENS levdcmp SMIN_NO3_MASSDENS ugN/cm^3 soil F +SMIN_NO3_RUNOFF_vr levdcmp soil NO3 pool loss to runoff gN/m^3/s F +SMIN_NO3_TO_PLANT levdcmp plant uptake of NO3 gN/m^3/s F +SOILN_vr levdcmp SOIL N (vertically resolved) gN/m^3 T +SOM_ACT_C_TNDNCY_VERT_TR levdcmp active soil organic C tendency due to vertical transport gC/m^3/s F +SOM_ACT_C_TO_SOM_PAS_C_v levdcmp decomp. of active soil organic C to passive soil organic C gC/m^3/s F +SOM_ACT_C_TO_SOM_SLO_C_v levdcmp decomp. of active soil organic C to slow soil organic ma C gC/m^3/s F +SOM_ACT_HR_S2_vr levdcmp Het. Resp. from active soil organic gC/m^3/s F +SOM_ACT_HR_S3_vr levdcmp Het. Resp. from active soil organic gC/m^3/s F +SOM_ACT_N_TNDNCY_VERT_TR levdcmp active soil organic N tendency due to vertical transport gN/m^3/s F +SOM_ACT_N_TO_SOM_PAS_N_v levdcmp decomp. of active soil organic N to passive soil organic N gN/m^3 F +SOM_ACT_N_TO_SOM_SLO_N_v levdcmp decomp. of active soil organic N to slow soil organic ma N gN/m^3 F +SOM_ACT_N_vr levdcmp SOM_ACT N (vertically resolved) gN/m^3 T +SOM_ADV_COEF levdcmp advection term for vertical SOM translocation m/s F +SOM_DIFFUS_COEF levdcmp diffusion coefficient for vertical SOM translocation m^2/s F +SOM_PAS_C_TNDNCY_VERT_TR levdcmp passive soil organic C tendency due to vertical transport gC/m^3/s F +SOM_PAS_C_TO_SOM_ACT_C_v levdcmp decomp. of passive soil organic C to active soil organic C gC/m^3/s F +SOM_PAS_HR_vr levdcmp Het. Resp. from passive soil organic gC/m^3/s F +SOM_PAS_N_TNDNCY_VERT_TR levdcmp passive soil organic N tendency due to vertical transport gN/m^3/s F +SOM_PAS_N_TO_SOM_ACT_N_v levdcmp decomp. of passive soil organic N to active soil organic N gN/m^3 F +SOM_PAS_N_vr levdcmp SOM_PAS N (vertically resolved) gN/m^3 T +SOM_SLO_C_TNDNCY_VERT_TR levdcmp slow soil organic ma C tendency due to vertical transport gC/m^3/s F +SOM_SLO_C_TO_SOM_ACT_C_v levdcmp decomp. of slow soil organic ma C to active soil organic C gC/m^3/s F +SOM_SLO_C_TO_SOM_PAS_C_v levdcmp decomp. of slow soil organic ma C to passive soil organic C gC/m^3/s F +SOM_SLO_HR_S1_vr levdcmp Het. Resp. from slow soil organic ma gC/m^3/s F +SOM_SLO_HR_S3_vr levdcmp Het. Resp. from slow soil organic ma gC/m^3/s F +SOM_SLO_N_TNDNCY_VERT_TR levdcmp slow soil organic ma N tendency due to vertical transport gN/m^3/s F +SOM_SLO_N_TO_SOM_ACT_N_v levdcmp decomp. of slow soil organic ma N to active soil organic N gN/m^3 F +SOM_SLO_N_TO_SOM_PAS_N_v levdcmp decomp. of slow soil organic ma N to passive soil organic N gN/m^3 F +SOM_SLO_N_vr levdcmp SOM_SLO N (vertically resolved) gN/m^3 T +STEM_PROF levdcmp profile for litter C and N inputs from stems 1/m F +SUPPLEMENT_TO_SMINN_vr levdcmp supplemental N supply gN/m^3/s F +WFPS levdcmp WFPS percent F +anaerobic_frac levdcmp anaerobic_frac m3/m3 F +diffus levdcmp diffusivity m^2/s F +fr_WFPS levdcmp fr_WFPS fraction F +n2_n2o_ratio_denit levdcmp n2_n2o_ratio_denit gN/gN F +r_psi levdcmp r_psi m F +ratio_k1 levdcmp ratio_k1 none F +ratio_no3_co2 levdcmp ratio_no3_co2 ratio F +soil_bulkdensity levdcmp soil_bulkdensity kg/m3 F +soil_co2_prod levdcmp soil_co2_prod ug C / g soil / day F +CONC_CH4_SAT levgrnd CH4 soil Concentration for inundated / lake area mol/m3 F +CONC_CH4_UNSAT levgrnd CH4 soil Concentration for non-inundated area mol/m3 F +EFF_POROSITY levgrnd effective porosity = porosity - vol_ice proportion F +FGR_SOIL_R levgrnd Rural downward heat flux at interface below each soil layer watt/m^2 F +FRAC_ICEOLD levgrnd fraction of ice relative to the tot water proportion F +HK levgrnd hydraulic conductivity (natural vegetated and crop landunits only) mm/s F +O2_DECOMP_DEPTH_UNSAT levgrnd O2 consumption from HR and AR for non-inundated area mol/m3/s F +ROOTR levgrnd effective fraction of roots in each soil layer (SMS method) proportion F +RRESIS levgrnd root resistance in each soil layer proportion F +SMP levgrnd soil matric potential (natural vegetated and crop landunits only) mm T +SOILPSI levgrnd soil water potential in each soil layer MPa F +TSOI levgrnd soil temperature (natural vegetated and crop landunits only) K T +TSOI_ICE levgrnd soil temperature (ice landunits only) K T +bsw levgrnd clap and hornberger B unitless F +watfc levgrnd water field capacity m^3/m^3 F +watsat levgrnd water saturated m^3/m^3 F +LAKEICEFRAC levlak lake layer ice mass fraction unitless F +TLAKE levlak lake temperature K T +SNO_ABS levsno Absorbed solar radiation in each snow layer W/m^2 F +SNO_ABS_ICE levsno Absorbed solar radiation in each snow layer (ice landunits only) W/m^2 F +SNO_BW levsno Partial density of water in the snow pack (ice + liquid) kg/m3 F +SNO_BW_ICE levsno Partial density of water in the snow pack (ice + liquid, ice landunits only) kg/m3 F +SNO_EXISTENCE levsno Fraction of averaging period for which each snow layer existed unitless F +SNO_FRZ levsno snow freezing rate in each snow layer kg/m2/s F +SNO_FRZ_ICE levsno snow freezing rate in each snow layer (ice landunits only) mm/s F +SNO_GS levsno Mean snow grain size Microns F +SNO_GS_ICE levsno Mean snow grain size (ice landunits only) Microns F +SNO_ICE levsno Snow ice content kg/m2 F +SNO_LIQH2O levsno Snow liquid water content kg/m2 F +SNO_MELT levsno snow melt rate in each snow layer mm/s F +SNO_MELT_ICE levsno snow melt rate in each snow layer (ice landunits only) mm/s F +SNO_T levsno Snow temperatures K F +SNO_TK levsno Thermal conductivity W/m-K F +SNO_TK_ICE levsno Thermal conductivity (ice landunits only) W/m-K F +SNO_T_ICE levsno Snow temperatures (ice landunits only) K F +SNO_Z levsno Snow layer thicknesses m F +SNO_Z_ICE levsno Snow layer thicknesses (ice landunits only) m F +CONC_O2_SAT levsoi O2 soil Concentration for inundated / lake area mol/m3 T +CONC_O2_UNSAT levsoi O2 soil Concentration for non-inundated area mol/m3 T +CWD_C_vr levsoi CWD C (vertically resolved) gC/m^3 T +H2OSOI levsoi volumetric soil water (natural vegetated and crop landunits only) mm3/mm3 T +HR_vr levsoi total vertically resolved heterotrophic respiration gC/m^3/s T +KROOT levsoi root conductance each soil layer 1/s F +KSOIL levsoi soil conductance in each soil layer 1/s F +LIT_CEL_C_vr levsoi LIT_CEL C (vertically resolved) gC/m^3 T +LIT_LIG_C_vr levsoi LIT_LIG C (vertically resolved) gC/m^3 T +LIT_MET_C_vr levsoi LIT_MET C (vertically resolved) gC/m^3 T +O_SCALAR levsoi fraction by which decomposition is reduced due to anoxia unitless T +QROOTSINK levsoi water flux from soil to root in each soil-layer mm/s F +SMINN_vr levsoi soil mineral N gN/m^3 T +SMIN_NH4_vr levsoi soil mineral NH4 (vert. res.) gN/m^3 T +SMIN_NO3_vr levsoi soil mineral NO3 (vert. res.) gN/m^3 T +SOILC_vr levsoi SOIL C (vertically resolved) gC/m^3 T +SOILICE levsoi soil ice (natural vegetated and crop landunits only) kg/m2 T +SOILLIQ levsoi soil liquid water (natural vegetated and crop landunits only) kg/m2 T +SOM_ACT_C_vr levsoi SOM_ACT C (vertically resolved) gC/m^3 T +SOM_PAS_C_vr levsoi SOM_PAS C (vertically resolved) gC/m^3 T +SOM_SLO_C_vr levsoi SOM_SLO C (vertically resolved) gC/m^3 T +T_SCALAR levsoi temperature inhibition of decomposition unitless T +W_SCALAR levsoi Moisture (dryness) inhibition of decomposition unitless T +GDDACCUM_PERHARV mxharvests At-harvest accumulated growing degree days past planting date for crop; should only be output ddays F +GDDHARV_PERHARV mxharvests Growing degree days (gdd) needed to harvest; should only be output annually ddays F +GRAINC_TO_FOOD_PERHARV mxharvests grain C to food per harvest; should only be output annually gC/m^2 F +HARVEST_REASON_PERHARV mxharvests Reason for each crop harvest; should only be output annually 1 = mature; 2 = max season length; 3 = incorrect Dec. 31 sowing; F +HDATES mxharvests actual crop harvest dates; should only be output annually day of year F +HUI_PERHARV mxharvests At-harvest accumulated heat unit index for crop; should only be output annually ddays F +SDATES_PERHARV mxharvests actual sowing dates for crops harvested this year; should only be output annually day of year F +SOWING_REASON_PERHARV mxharvests Reason for sowing of each crop harvested this year; should only be output annually unitless F +SYEARS_PERHARV mxharvests actual sowing years for crops harvested this year; should only be output annually year F +SDATES mxsowings actual crop sowing dates; should only be output annually day of year F +SOWING_REASON mxsowings Reason for each crop sowing; should only be output annually unitless F +ALBD numrad surface albedo (direct) proportion F +ALBGRD numrad ground albedo (direct) proportion F +ALBGRI numrad ground albedo (indirect) proportion F +ALBI numrad surface albedo (indirect) proportion F +VEGWP nvegwcs vegetation water matric potential for sun/sha canopy,xyl,root segments mm T +VEGWPLN nvegwcs vegetation water matric potential for sun/sha canopy,xyl,root at local noon mm T +VEGWPPD nvegwcs predawn vegetation water matric potential for sun/sha canopy,xyl,root mm T +=================================== ================ ============================================================================================== ================================================================= ======= diff --git a/doc/source/users_guide/setting-up-and-running-a-case/index.rst b/doc/source/users_guide/setting-up-and-running-a-case/index.rst index f882df277b..b11587ee21 100644 --- a/doc/source/users_guide/setting-up-and-running-a-case/index.rst +++ b/doc/source/users_guide/setting-up-and-running-a-case/index.rst @@ -18,6 +18,6 @@ Setting Up and Running a Case customizing-the-clm-configuration.rst customizing-the-clm-namelist.rst customizing-the-datm-namelist.rst - master_list_nofates - master_list_fates + history_fields_nofates + history_fields_fates diff --git a/doc/source/users_guide/setting-up-and-running-a-case/master_list_fates.rst b/doc/source/users_guide/setting-up-and-running-a-case/master_list_fates.rst deleted file mode 100644 index 57edbfd3ca..0000000000 --- a/doc/source/users_guide/setting-up-and-running-a-case/master_list_fates.rst +++ /dev/null @@ -1,955 +0,0 @@ -============================= -CTSM History Fields (fates) -============================= - -CAUTION: Not all variables are relevant / present for all CTSM cases. -Key flags used in this CTSM case: -use_cn = F -use_crop = F -use_fates = T - -==== =================================== ============================================================================================== ================================================================= ======= -CTSM History Fields ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - # Variable Name Long Description Units Active? -==== =================================== ============================================================================================== ================================================================= ======= - 1 A5TMIN 5-day running mean of min 2-m temperature K F - 2 ACTUAL_IMMOB actual N immobilization gN/m^2/s T - 3 ACT_SOMC ACT_SOM C gC/m^2 T - 4 ACT_SOMC_1m ACT_SOM C to 1 meter gC/m^2 F - 5 ACT_SOMC_TNDNCY_VERT_TRA active soil organic C tendency due to vertical transport gC/m^3/s F - 6 ACT_SOMC_TO_PAS_SOMC decomp. of active soil organic C to passive soil organic C gC/m^2/s F - 7 ACT_SOMC_TO_PAS_SOMC_vr decomp. of active soil organic C to passive soil organic C gC/m^3/s F - 8 ACT_SOMC_TO_SLO_SOMC decomp. of active soil organic C to slow soil organic ma C gC/m^2/s F - 9 ACT_SOMC_TO_SLO_SOMC_vr decomp. of active soil organic C to slow soil organic ma C gC/m^3/s F - 10 ACT_SOMC_vr ACT_SOM C (vertically resolved) gC/m^3 T - 11 ACT_SOMN ACT_SOM N gN/m^2 T - 12 ACT_SOMN_1m ACT_SOM N to 1 meter gN/m^2 F - 13 ACT_SOMN_TNDNCY_VERT_TRA active soil organic N tendency due to vertical transport gN/m^3/s F - 14 ACT_SOMN_TO_PAS_SOMN decomp. of active soil organic N to passive soil organic N gN/m^2 F - 15 ACT_SOMN_TO_PAS_SOMN_vr decomp. of active soil organic N to passive soil organic N gN/m^3 F - 16 ACT_SOMN_TO_SLO_SOMN decomp. of active soil organic N to slow soil organic ma N gN/m^2 F - 17 ACT_SOMN_TO_SLO_SOMN_vr decomp. of active soil organic N to slow soil organic ma N gN/m^3 F - 18 ACT_SOMN_vr ACT_SOM N (vertically resolved) gN/m^3 T - 19 ACT_SOM_HR_S2 Het. Resp. from active soil organic gC/m^2/s F - 20 ACT_SOM_HR_S2_vr Het. Resp. from active soil organic gC/m^3/s F - 21 ACT_SOM_HR_S3 Het. Resp. from active soil organic gC/m^2/s F - 22 ACT_SOM_HR_S3_vr Het. Resp. from active soil organic gC/m^3/s F - 23 AGB Aboveground biomass gC m-2 T - 24 AGB_SCLS Aboveground biomass by size class kgC/m2 T - 25 AGB_SCPF Aboveground biomass by pft/size kgC/m2 F - 26 AGLB Aboveground leaf biomass kg/m^2 F - 27 AGSB Aboveground stem biomass kg/m^2 F - 28 ALBD surface albedo (direct) proportion F - 29 ALBGRD ground albedo (direct) proportion F - 30 ALBGRI ground albedo (indirect) proportion F - 31 ALBI surface albedo (indirect) proportion F - 32 ALT current active layer thickness m F - 33 ALTMAX maximum annual active layer thickness m F - 34 ALTMAX_LASTYEAR maximum prior year active layer thickness m F - 35 AR autotrophic respiration gC/m^2/s T - 36 AREA_BURNT_BY_PATCH_AGE spitfire area burnt by patch age (divide by patch_area_by_age to get burnt fraction by age) m2/m2/day T - 37 AREA_PLANT area occupied by all plants m2/m2 T - 38 AREA_TREES area occupied by woody plants m2/m2 T - 39 AR_AGSAPM_SCPF above-ground sapwood maintenance autotrophic respiration per m2 per year by pft/size kgC/m2/yr F - 40 AR_CANOPY autotrophic respiration of canopy plants gC/m^2/s T - 41 AR_CANOPY_SCPF autotrophic respiration of canopy plants by pft/size kgC/m2/yr F - 42 AR_CROOTM_SCPF below-ground sapwood maintenance autotrophic respiration per m2 per year by pft/size kgC/m2/yr F - 43 AR_DARKM_SCPF dark portion of maintenance autotrophic respiration per m2 per year by pft/size kgC/m2/yr F - 44 AR_FROOTM_SCPF fine root maintenance autotrophic respiration per m2 per year by pft/size kgC/m2/yr F - 45 AR_GROW_SCPF growth autotrophic respiration per m2 per year by pft/size kgC/m2/yr F - 46 AR_MAINT_SCPF maintenance autotrophic respiration per m2 per year by pft/size kgC/m2/yr F - 47 AR_SCPF total autotrophic respiration per m2 per year by pft/size kgC/m2/yr F - 48 AR_UNDERSTORY autotrophic respiration of understory plants gC/m^2/s T - 49 AR_UNDERSTORY_SCPF autotrophic respiration of understory plants by pft/size kgC/m2/yr F - 50 ATM_TOPO atmospheric surface height m T - 51 AnnET Annual ET mm/s F - 52 BA_SCLS basal area by size class m2/ha T - 53 BA_SCPF basal area by pft/size m2/ha F - 54 BCDEP total BC deposition (dry+wet) from atmosphere kg/m^2/s T - 55 BDEAD_MD_CANOPY_SCLS BDEAD_MD for canopy plants by size class kg C / ha / yr F - 56 BDEAD_MD_UNDERSTORY_SCLS BDEAD_MD for understory plants by size class kg C / ha / yr F - 57 BIOMASS_AGEPFT biomass per PFT in each age bin kg C / m2 F - 58 BIOMASS_BY_AGE Total Biomass within a given patch age bin kgC/m2 F - 59 BIOMASS_CANOPY Biomass of canopy plants gC m-2 T - 60 BIOMASS_SCLS Total biomass by size class kgC/m2 F - 61 BIOMASS_UNDERSTORY Biomass of understory plants gC m-2 T - 62 BLEAF_CANOPY_SCPF biomass carbon in leaf of canopy plants by pft/size kgC/ha F - 63 BLEAF_UNDERSTORY_SCPF biomass carbon in leaf of understory plants by pft/size kgC/ha F - 64 BSTORE_MD_CANOPY_SCLS BSTORE_MD for canopy plants by size class kg C / ha / yr F - 65 BSTORE_MD_UNDERSTORY_SCLS BSTORE_MD for understory plants by size class kg C / ha / yr F - 66 BSTOR_CANOPY_SCPF biomass carbon in storage pools of canopy plants by pft/size kgC/ha F - 67 BSTOR_UNDERSTORY_SCPF biomass carbon in storage pools of understory plants by pft/size kgC/ha F - 68 BSW_MD_CANOPY_SCLS BSW_MD for canopy plants by size class kg C / ha / yr F - 69 BSW_MD_UNDERSTORY_SCLS BSW_MD for understory plants by size class kg C / ha / yr F - 70 BTRAN transpiration beta factor unitless T - 71 BTRANMN daily minimum of transpiration beta factor unitless T - 72 BURNT_LITTER_FRAC_AREA_PRODUCT product of fraction of fuel burnt and burned area (divide by FIRE_AREA to get burned-area-weig fraction T - 73 C13disc_SCPF C13 discrimination by pft/size per mil F - 74 CAMBIALFIREMORT_SCPF cambial fire mortality by pft/size N/ha/yr F - 75 CANOPY_AREA_BY_AGE canopy area by age bin m2/m2 T - 76 CANOPY_HEIGHT_DIST canopy height distribution m2/m2 T - 77 CANOPY_SPREAD Scaling factor between tree basal area and canopy area 0-1 T - 78 CARBON_BALANCE_CANOPY_SCLS CARBON_BALANCE for canopy plants by size class kg C / ha / yr F - 79 CARBON_BALANCE_UNDERSTORY_SCLS CARBON_BALANCE for understory plants by size class kg C / ha / yr F - 80 CBALANCE_ERROR_FATES total carbon error, FATES mgC/day T - 81 CEFFLUX carbon efflux, root to soil kgC/ha/day T - 82 CEFFLUX_SCPF carbon efflux, root to soil, by size-class x pft kg/ha/day F - 83 CEL_LITC CEL_LIT C gC/m^2 T - 84 CEL_LITC_1m CEL_LIT C to 1 meter gC/m^2 F - 85 CEL_LITC_TNDNCY_VERT_TRA cellulosic litter C tendency due to vertical transport gC/m^3/s F - 86 CEL_LITC_TO_ACT_SOMC decomp. of cellulosic litter C to active soil organic C gC/m^2/s F - 87 CEL_LITC_TO_ACT_SOMC_vr decomp. of cellulosic litter C to active soil organic C gC/m^3/s F - 88 CEL_LITC_vr CEL_LIT C (vertically resolved) gC/m^3 T - 89 CEL_LITN CEL_LIT N gN/m^2 T - 90 CEL_LITN_1m CEL_LIT N to 1 meter gN/m^2 F - 91 CEL_LITN_TNDNCY_VERT_TRA cellulosic litter N tendency due to vertical transport gN/m^3/s F - 92 CEL_LITN_TO_ACT_SOMN decomp. of cellulosic litter N to active soil organic N gN/m^2 F - 93 CEL_LITN_TO_ACT_SOMN_vr decomp. of cellulosic litter N to active soil organic N gN/m^3 F - 94 CEL_LITN_vr CEL_LIT N (vertically resolved) gN/m^3 T - 95 CEL_LIT_HR Het. Resp. from cellulosic litter gC/m^2/s F - 96 CEL_LIT_HR_vr Het. Resp. from cellulosic litter gC/m^3/s F - 97 CH4PROD Gridcell total production of CH4 gC/m2/s T - 98 CH4_EBUL_TOTAL_SAT ebullition surface CH4 flux; (+ to atm) mol/m2/s F - 99 CH4_EBUL_TOTAL_UNSAT ebullition surface CH4 flux; (+ to atm) mol/m2/s F - 100 CH4_SURF_AERE_SAT aerenchyma surface CH4 flux for inundated area; (+ to atm) mol/m2/s T - 101 CH4_SURF_AERE_UNSAT aerenchyma surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T - 102 CH4_SURF_DIFF_SAT diffusive surface CH4 flux for inundated / lake area; (+ to atm) mol/m2/s T - 103 CH4_SURF_DIFF_UNSAT diffusive surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T - 104 CH4_SURF_EBUL_SAT ebullition surface CH4 flux for inundated / lake area; (+ to atm) mol/m2/s T - 105 CH4_SURF_EBUL_UNSAT ebullition surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T - 106 COL_CTRUNC column-level sink for C truncation gC/m^2 F - 107 COL_NTRUNC column-level sink for N truncation gN/m^2 F - 108 CONC_CH4_SAT CH4 soil Concentration for inundated / lake area mol/m3 F - 109 CONC_CH4_UNSAT CH4 soil Concentration for non-inundated area mol/m3 F - 110 CONC_O2_SAT O2 soil Concentration for inundated / lake area mol/m3 T - 111 CONC_O2_UNSAT O2 soil Concentration for non-inundated area mol/m3 T - 112 COSZEN cosine of solar zenith angle none F - 113 CROWNAREA_CAN total crown area in each canopy layer m2/m2 T - 114 CROWNAREA_CNLF total crown area that is occupied by leaves in each canopy and leaf layer m2/m2 F - 115 CROWNFIREMORT_SCPF crown fire mortality by pft/size N/ha/yr F - 116 CROWN_AREA_CANOPY_SCLS total crown area of canopy plants by size class m2/ha F - 117 CROWN_AREA_UNDERSTORY_SCLS total crown area of understory plants by size class m2/ha F - 118 CWDC_HR cwd C heterotrophic respiration gC/m^2/s F - 119 CWD_AG_CWDSC size-resolved AG CWD stocks gC/m^2 F - 120 CWD_AG_IN_CWDSC size-resolved AG CWD input gC/m^2/y F - 121 CWD_AG_OUT_CWDSC size-resolved AG CWD output gC/m^2/y F - 122 CWD_BG_CWDSC size-resolved BG CWD stocks gC/m^2 F - 123 CWD_BG_IN_CWDSC size-resolved BG CWD input gC/m^2/y F - 124 CWD_BG_OUT_CWDSC size-resolved BG CWD output gC/m^2/y F - 125 C_LBLAYER mean leaf boundary layer conductance umol m-2 s-1 T - 126 C_LBLAYER_BY_AGE mean leaf boundary layer conductance - by patch age umol m-2 s-1 F - 127 C_STOMATA mean stomatal conductance umol m-2 s-1 T - 128 C_STOMATA_BY_AGE mean stomatal conductance - by patch age umol m-2 s-1 F - 129 DDBH_CANOPY_SCAG growth rate of canopy plantsnumber of plants per hectare in canopy in each size x age class cm/yr/ha F - 130 DDBH_CANOPY_SCLS diameter growth increment by pft/size cm/yr/ha T - 131 DDBH_CANOPY_SCPF diameter growth increment by pft/size cm/yr/ha F - 132 DDBH_SCPF diameter growth increment by pft/size cm/yr/ha F - 133 DDBH_UNDERSTORY_SCAG growth rate of understory plants in each size x age class cm/yr/ha F - 134 DDBH_UNDERSTORY_SCLS diameter growth increment by pft/size cm/yr/ha T - 135 DDBH_UNDERSTORY_SCPF diameter growth increment by pft/size cm/yr/ha F - 136 DEMOTION_CARBONFLUX demotion-associated biomass carbon flux from canopy to understory gC/m2/s T - 137 DEMOTION_RATE_SCLS demotion rate from canopy to understory by size class indiv/ha/yr F - 138 DENIT total rate of denitrification gN/m^2/s T - 139 DGNETDT derivative of net ground heat flux wrt soil temp W/m^2/K F - 140 DISPLA displacement height m F - 141 DISTURBANCE_RATE_FIRE Disturbance rate from fire m2 m-2 d-1 T - 142 DISTURBANCE_RATE_LOGGING Disturbance rate from logging m2 m-2 d-1 T - 143 DISTURBANCE_RATE_P2P Disturbance rate from primary to primary lands m2 m-2 d-1 T - 144 DISTURBANCE_RATE_P2S Disturbance rate from primary to secondary lands m2 m-2 d-1 T - 145 DISTURBANCE_RATE_POTENTIAL Potential (i.e., including unresolved) disturbance rate m2 m-2 d-1 T - 146 DISTURBANCE_RATE_S2S Disturbance rate from secondary to secondary lands m2 m-2 d-1 T - 147 DISTURBANCE_RATE_TREEFALL Disturbance rate from treefall m2 m-2 d-1 T - 148 DPVLTRB1 turbulent deposition velocity 1 m/s F - 149 DPVLTRB2 turbulent deposition velocity 2 m/s F - 150 DPVLTRB3 turbulent deposition velocity 3 m/s F - 151 DPVLTRB4 turbulent deposition velocity 4 m/s F - 152 DSL dry surface layer thickness mm T - 153 DSTDEP total dust deposition (dry+wet) from atmosphere kg/m^2/s T - 154 DSTFLXT total surface dust emission kg/m2/s T - 155 DYN_COL_ADJUSTMENTS_CH4 Adjustments in ch4 due to dynamic column areas; only makes sense at the column level: should n gC/m^2 F - 156 DYN_COL_SOIL_ADJUSTMENTS_C Adjustments in soil carbon due to dynamic column areas; only makes sense at the column level: gC/m^2 F - 157 DYN_COL_SOIL_ADJUSTMENTS_N Adjustments in soil nitrogen due to dynamic column areas; only makes sense at the column level gN/m^2 F - 158 ED_NCOHORTS Total number of ED cohorts per site none T - 159 ED_NPATCHES Total number of ED patches per site none T - 160 ED_balive Live biomass gC m-2 T - 161 ED_bdead Dead (structural) biomass (live trees, not CWD) gC m-2 T - 162 ED_bfineroot Fine root biomass gC m-2 T - 163 ED_biomass Total biomass gC m-2 T - 164 ED_bleaf Leaf biomass gC m-2 T - 165 ED_bsapwood Sapwood biomass gC m-2 T - 166 ED_bstore Storage biomass gC m-2 T - 167 EFFECT_WSPEED effective windspeed for fire spread none T - 168 EFLXBUILD building heat flux from change in interior building air temperature W/m^2 T - 169 EFLX_DYNBAL dynamic land cover change conversion energy flux W/m^2 T - 170 EFLX_GNET net heat flux into ground W/m^2 F - 171 EFLX_GRND_LAKE net heat flux into lake/snow surface, excluding light transmission W/m^2 T - 172 EFLX_LH_TOT total latent heat flux [+ to atm] W/m^2 T - 173 EFLX_LH_TOT_ICE total latent heat flux [+ to atm] (ice landunits only) W/m^2 F - 174 EFLX_LH_TOT_R Rural total evaporation W/m^2 T - 175 EFLX_LH_TOT_U Urban total evaporation W/m^2 F - 176 EFLX_SOIL_GRND soil heat flux [+ into soil] W/m^2 F - 177 ELAI exposed one-sided leaf area index m^2/m^2 T - 178 ERRH2O total water conservation error mm T - 179 ERRH2OSNO imbalance in snow depth (liquid water) mm T - 180 ERROR_FATES total error, FATES mass-balance mg/day T - 181 ERRSEB surface energy conservation error W/m^2 T - 182 ERRSOI soil/lake energy conservation error W/m^2 T - 183 ERRSOL solar radiation conservation error W/m^2 T - 184 ESAI exposed one-sided stem area index m^2/m^2 T - 185 FABD_SHA_CNLF shade fraction of direct light absorbed by each canopy and leaf layer fraction F - 186 FABD_SHA_CNLFPFT shade fraction of direct light absorbed by each canopy, leaf, and PFT fraction F - 187 FABD_SHA_TOPLF_BYCANLAYER shade fraction of direct light absorbed by the top leaf layer of each canopy layer fraction F - 188 FABD_SUN_CNLF sun fraction of direct light absorbed by each canopy and leaf layer fraction F - 189 FABD_SUN_CNLFPFT sun fraction of direct light absorbed by each canopy, leaf, and PFT fraction F - 190 FABD_SUN_TOPLF_BYCANLAYER sun fraction of direct light absorbed by the top leaf layer of each canopy layer fraction F - 191 FABI_SHA_CNLF shade fraction of indirect light absorbed by each canopy and leaf layer fraction F - 192 FABI_SHA_CNLFPFT shade fraction of indirect light absorbed by each canopy, leaf, and PFT fraction F - 193 FABI_SHA_TOPLF_BYCANLAYER shade fraction of indirect light absorbed by the top leaf layer of each canopy layer fraction F - 194 FABI_SUN_CNLF sun fraction of indirect light absorbed by each canopy and leaf layer fraction F - 195 FABI_SUN_CNLFPFT sun fraction of indirect light absorbed by each canopy, leaf, and PFT fraction F - 196 FABI_SUN_TOPLF_BYCANLAYER sun fraction of indirect light absorbed by the top leaf layer of each canopy layer fraction F - 197 FATES_HR heterotrophic respiration gC/m^2/s T - 198 FATES_c_to_litr_cel_c litter celluluse carbon flux from FATES to BGC gC/m^3/s T - 199 FATES_c_to_litr_lab_c litter labile carbon flux from FATES to BGC gC/m^3/s T - 200 FATES_c_to_litr_lig_c litter lignin carbon flux from FATES to BGC gC/m^3/s T - 201 FCEV canopy evaporation W/m^2 T - 202 FCH4 Gridcell surface CH4 flux to atmosphere (+ to atm) kgC/m2/s T - 203 FCH4TOCO2 Gridcell oxidation of CH4 to CO2 gC/m2/s T - 204 FCH4_DFSAT CH4 additional flux due to changing fsat, natural vegetated and crop landunits only kgC/m2/s T - 205 FCO2 CO2 flux to atmosphere (+ to atm) kgCO2/m2/s F - 206 FCOV fractional impermeable area unitless T - 207 FCTR canopy transpiration W/m^2 T - 208 FGEV ground evaporation W/m^2 T - 209 FGR heat flux into soil/snow including snow melt and lake / snow light transmission W/m^2 T - 210 FGR12 heat flux between soil layers 1 and 2 W/m^2 T - 211 FGR_ICE heat flux into soil/snow including snow melt and lake / snow light transmission (ice landunits W/m^2 F - 212 FGR_R Rural heat flux into soil/snow including snow melt and snow light transmission W/m^2 F - 213 FGR_SOIL_R Rural downward heat flux at interface below each soil layer watt/m^2 F - 214 FGR_U Urban heat flux into soil/snow including snow melt W/m^2 F - 215 FH2OSFC fraction of ground covered by surface water unitless T - 216 FH2OSFC_NOSNOW fraction of ground covered by surface water (if no snow present) unitless F - 217 FINUNDATED fractional inundated area of vegetated columns unitless T - 218 FINUNDATED_LAG time-lagged inundated fraction of vegetated columns unitless F - 219 FIRA net infrared (longwave) radiation W/m^2 T - 220 FIRA_ICE net infrared (longwave) radiation (ice landunits only) W/m^2 F - 221 FIRA_R Rural net infrared (longwave) radiation W/m^2 T - 222 FIRA_U Urban net infrared (longwave) radiation W/m^2 F - 223 FIRE emitted infrared (longwave) radiation W/m^2 T - 224 FIRE_AREA spitfire fire area burn fraction fraction/day T - 225 FIRE_FDI probability that an ignition will lead to a fire none T - 226 FIRE_FLUX ED-spitfire loss to atmosphere of elements g/m^2/s T - 227 FIRE_FUEL_BULKD spitfire fuel bulk density kg biomass/m3 T - 228 FIRE_FUEL_EFF_MOIST spitfire fuel moisture m T - 229 FIRE_FUEL_MEF spitfire fuel moisture m T - 230 FIRE_FUEL_SAV spitfire fuel surface/volume per m T - 231 FIRE_ICE emitted infrared (longwave) radiation (ice landunits only) W/m^2 F - 232 FIRE_IGNITIONS number of successful ignitions number/km2/day T - 233 FIRE_INTENSITY spitfire fire intensity: kJ/m/s kJ/m/s T - 234 FIRE_INTENSITY_AREA_PRODUCT spitfire product of fire intensity and burned area (divide by FIRE_AREA to get area-weighted m kJ/m/s T - 235 FIRE_INTENSITY_BY_PATCH_AGE product of fire intensity and burned area, resolved by patch age (so divide by AREA_BURNT_BY_P kJ/m/2 T - 236 FIRE_NESTEROV_INDEX nesterov_fire_danger index none T - 237 FIRE_R Rural emitted infrared (longwave) radiation W/m^2 T - 238 FIRE_ROS fire rate of spread m/min m/min T - 239 FIRE_ROS_AREA_PRODUCT product of fire rate of spread (m/min) and burned area (fraction)--divide by FIRE_AREA to get m/min T - 240 FIRE_TFC_ROS total fuel consumed kgC/m2 T - 241 FIRE_TFC_ROS_AREA_PRODUCT product of total fuel consumed and burned area--divide by FIRE_AREA to get burned-area-weighte kgC/m2 T - 242 FIRE_U Urban emitted infrared (longwave) radiation W/m^2 F - 243 FLDS atmospheric longwave radiation (downscaled to columns in glacier regions) W/m^2 T - 244 FLDS_ICE atmospheric longwave radiation (downscaled to columns in glacier regions) (ice landunits only) W/m^2 F - 245 FNRTC Total carbon in live plant fine-roots kgC ha-1 T - 246 FNRTC_SCPF fine-root carbon mass by size-class x pft kgC/ha F - 247 FRAGMENTATION_SCALER_SL factor by which litter/cwd fragmentation proceeds relative to max rate by soil layer unitless (0-1) T - 248 FROOT_MR fine root maintenance respiration) kg C / m2 / yr T - 249 FROOT_MR_CANOPY_SCLS FROOT_MR for canopy plants by size class kg C / ha / yr F - 250 FROOT_MR_UNDERSTORY_SCLS FROOT_MR for understory plants by size class kg C / ha / yr F - 251 FROST_TABLE frost table depth (natural vegetated and crop landunits only) m F - 252 FSA absorbed solar radiation W/m^2 T - 253 FSAT fractional area with water table at surface unitless T - 254 FSA_ICE absorbed solar radiation (ice landunits only) W/m^2 F - 255 FSA_R Rural absorbed solar radiation W/m^2 F - 256 FSA_U Urban absorbed solar radiation W/m^2 F - 257 FSD24 direct radiation (last 24hrs) K F - 258 FSD240 direct radiation (last 240hrs) K F - 259 FSDS atmospheric incident solar radiation W/m^2 T - 260 FSDSND direct nir incident solar radiation W/m^2 T - 261 FSDSNDLN direct nir incident solar radiation at local noon W/m^2 T - 262 FSDSNI diffuse nir incident solar radiation W/m^2 T - 263 FSDSVD direct vis incident solar radiation W/m^2 T - 264 FSDSVDLN direct vis incident solar radiation at local noon W/m^2 T - 265 FSDSVI diffuse vis incident solar radiation W/m^2 T - 266 FSDSVILN diffuse vis incident solar radiation at local noon W/m^2 T - 267 FSH sensible heat not including correction for land use change and rain/snow conversion W/m^2 T - 268 FSH_G sensible heat from ground W/m^2 T - 269 FSH_ICE sensible heat not including correction for land use change and rain/snow conversion (ice landu W/m^2 F - 270 FSH_PRECIP_CONVERSION Sensible heat flux from conversion of rain/snow atm forcing W/m^2 T - 271 FSH_R Rural sensible heat W/m^2 T - 272 FSH_RUNOFF_ICE_TO_LIQ sensible heat flux generated from conversion of ice runoff to liquid W/m^2 T - 273 FSH_TO_COUPLER sensible heat sent to coupler (includes corrections for land use change, rain/snow conversion W/m^2 T - 274 FSH_U Urban sensible heat W/m^2 F - 275 FSH_V sensible heat from veg W/m^2 T - 276 FSI24 indirect radiation (last 24hrs) K F - 277 FSI240 indirect radiation (last 240hrs) K F - 278 FSM snow melt heat flux W/m^2 T - 279 FSM_ICE snow melt heat flux (ice landunits only) W/m^2 F - 280 FSM_R Rural snow melt heat flux W/m^2 F - 281 FSM_U Urban snow melt heat flux W/m^2 F - 282 FSNO fraction of ground covered by snow unitless T - 283 FSNO_EFF effective fraction of ground covered by snow unitless T - 284 FSNO_ICE fraction of ground covered by snow (ice landunits only) unitless F - 285 FSR reflected solar radiation W/m^2 T - 286 FSRND direct nir reflected solar radiation W/m^2 T - 287 FSRNDLN direct nir reflected solar radiation at local noon W/m^2 T - 288 FSRNI diffuse nir reflected solar radiation W/m^2 T - 289 FSRVD direct vis reflected solar radiation W/m^2 T - 290 FSRVDLN direct vis reflected solar radiation at local noon W/m^2 T - 291 FSRVI diffuse vis reflected solar radiation W/m^2 T - 292 FSR_ICE reflected solar radiation (ice landunits only) W/m^2 F - 293 FSUN sunlit fraction of canopy proportion F - 294 FSUN24 fraction sunlit (last 24hrs) K F - 295 FSUN240 fraction sunlit (last 240hrs) K F - 296 FUEL_AMOUNT_AGEFUEL spitfire fuel quantity in each age x fuel class kg C / m2 T - 297 FUEL_AMOUNT_BY_NFSC spitfire size-resolved fuel quantity kg C / m2 T - 298 FUEL_MOISTURE_NFSC spitfire size-resolved fuel moisture - T - 299 Fire_Closs ED/SPitfire Carbon loss to atmosphere gC/m^2/s T - 300 GPP gross primary production gC/m^2/s T - 301 GPP_BY_AGE gross primary productivity by age bin gC/m^2/s F - 302 GPP_CANOPY gross primary production of canopy plants gC/m^2/s T - 303 GPP_CANOPY_SCPF gross primary production of canopy plants by pft/size kgC/m2/yr F - 304 GPP_SCPF gross primary production by pft/size kgC/m2/yr F - 305 GPP_UNDERSTORY gross primary production of understory plants gC/m^2/s T - 306 GPP_UNDERSTORY_SCPF gross primary production of understory plants by pft/size kgC/m2/yr F - 307 GROSS_NMIN gross rate of N mineralization gN/m^2/s T - 308 GROWTHFLUX_FUSION_SCPF flux of individuals into a given size class bin via fusion n/yr/ha F - 309 GROWTHFLUX_SCPF flux of individuals into a given size class bin via growth and recruitment n/yr/ha F - 310 GROWTH_RESP growth respiration gC/m^2/s T - 311 GSSHA shaded leaf stomatal conductance umol H20/m2/s T - 312 GSSHALN shaded leaf stomatal conductance at local noon umol H20/m2/s T - 313 GSSUN sunlit leaf stomatal conductance umol H20/m2/s T - 314 GSSUNLN sunlit leaf stomatal conductance at local noon umol H20/m2/s T - 315 H2OCAN intercepted water mm T - 316 H2OSFC surface water depth mm T - 317 H2OSNO snow depth (liquid water) mm T - 318 H2OSNO_ICE snow depth (liquid water, ice landunits only) mm F - 319 H2OSNO_TOP mass of snow in top snow layer kg/m2 T - 320 H2OSOI volumetric soil water (natural vegetated and crop landunits only) mm3/mm3 T - 321 HARVEST_CARBON_FLUX Harvest carbon flux kg C m-2 d-1 T - 322 HBOT canopy bottom m F - 323 HEAT_CONTENT1 initial gridcell total heat content J/m^2 T - 324 HEAT_CONTENT1_VEG initial gridcell total heat content - natural vegetated and crop landunits only J/m^2 F - 325 HEAT_CONTENT2 post land cover change total heat content J/m^2 F - 326 HEAT_FROM_AC sensible heat flux put into canyon due to heat removed from air conditioning W/m^2 T - 327 HIA 2 m NWS Heat Index C T - 328 HIA_R Rural 2 m NWS Heat Index C T - 329 HIA_U Urban 2 m NWS Heat Index C T - 330 HK hydraulic conductivity (natural vegetated and crop landunits only) mm/s F - 331 HR total heterotrophic respiration gC/m^2/s T - 332 HR_vr total vertically resolved heterotrophic respiration gC/m^3/s T - 333 HTOP canopy top m T - 334 HUMIDEX 2 m Humidex C T - 335 HUMIDEX_R Rural 2 m Humidex C T - 336 HUMIDEX_U Urban 2 m Humidex C T - 337 ICE_CONTENT1 initial gridcell total ice content mm T - 338 ICE_CONTENT2 post land cover change total ice content mm F - 339 ICE_MODEL_FRACTION Ice sheet model fractional coverage unitless F - 340 INT_SNOW accumulated swe (natural vegetated and crop landunits only) mm F - 341 INT_SNOW_ICE accumulated swe (ice landunits only) mm F - 342 IWUELN local noon intrinsic water use efficiency umolCO2/molH2O T - 343 KROOT root conductance each soil layer 1/s F - 344 KSOIL soil conductance in each soil layer 1/s F - 345 K_ACT_SOM active soil organic potential loss coefficient 1/s F - 346 K_CEL_LIT cellulosic litter potential loss coefficient 1/s F - 347 K_LIG_LIT lignin litter potential loss coefficient 1/s F - 348 K_MET_LIT metabolic litter potential loss coefficient 1/s F - 349 K_PAS_SOM passive soil organic potential loss coefficient 1/s F - 350 K_SLO_SOM slow soil organic ma potential loss coefficient 1/s F - 351 LAI240 240hr average of leaf area index m^2/m^2 F - 352 LAISHA shaded projected leaf area index m^2/m^2 T - 353 LAISHA_TOP_CAN LAI in the shade by the top leaf layer of each canopy layer m2/m2 F - 354 LAISHA_Z_CNLF LAI in the shade by each canopy and leaf layer m2/m2 F - 355 LAISHA_Z_CNLFPFT LAI in the shade by each canopy, leaf, and PFT m2/m2 F - 356 LAISUN sunlit projected leaf area index m^2/m^2 T - 357 LAISUN_TOP_CAN LAI in the sun by the top leaf layer of each canopy layer m2/m2 F - 358 LAISUN_Z_CNLF LAI in the sun by each canopy and leaf layer m2/m2 F - 359 LAISUN_Z_CNLFPFT LAI in the sun by each canopy, leaf, and PFT m2/m2 F - 360 LAI_BY_AGE leaf area index by age bin m2/m2 T - 361 LAI_CANOPY_SCLS Leaf are index (LAI) by size class m2/m2 T - 362 LAI_UNDERSTORY_SCLS number of understory plants by size class indiv/ha T - 363 LAKEICEFRAC lake layer ice mass fraction unitless F - 364 LAKEICEFRAC_SURF surface lake layer ice mass fraction unitless T - 365 LAKEICETHICK thickness of lake ice (including physical expansion on freezing) m T - 366 LEAFC Total carbon in live plant leaves kgC ha-1 T - 367 LEAFC_SCPF leaf carbon mass by size-class x pft kgC/ha F - 368 LEAF_HEIGHT_DIST leaf height distribution m2/m2 T - 369 LEAF_MD_CANOPY_SCLS LEAF_MD for canopy plants by size class kg C / ha / yr F - 370 LEAF_MD_UNDERSTORY_SCLS LEAF_MD for understory plants by size class kg C / ha / yr F - 371 LEAF_MR RDARK (leaf maintenance respiration) kg C / m2 / yr T - 372 LIG_LITC LIG_LIT C gC/m^2 T - 373 LIG_LITC_1m LIG_LIT C to 1 meter gC/m^2 F - 374 LIG_LITC_TNDNCY_VERT_TRA lignin litter C tendency due to vertical transport gC/m^3/s F - 375 LIG_LITC_TO_SLO_SOMC decomp. of lignin litter C to slow soil organic ma C gC/m^2/s F - 376 LIG_LITC_TO_SLO_SOMC_vr decomp. of lignin litter C to slow soil organic ma C gC/m^3/s F - 377 LIG_LITC_vr LIG_LIT C (vertically resolved) gC/m^3 T - 378 LIG_LITN LIG_LIT N gN/m^2 T - 379 LIG_LITN_1m LIG_LIT N to 1 meter gN/m^2 F - 380 LIG_LITN_TNDNCY_VERT_TRA lignin litter N tendency due to vertical transport gN/m^3/s F - 381 LIG_LITN_TO_SLO_SOMN decomp. of lignin litter N to slow soil organic ma N gN/m^2 F - 382 LIG_LITN_TO_SLO_SOMN_vr decomp. of lignin litter N to slow soil organic ma N gN/m^3 F - 383 LIG_LITN_vr LIG_LIT N (vertically resolved) gN/m^3 T - 384 LIG_LIT_HR Het. Resp. from lignin litter gC/m^2/s F - 385 LIG_LIT_HR_vr Het. Resp. from lignin litter gC/m^3/s F - 386 LIQCAN intercepted liquid water mm T - 387 LIQUID_CONTENT1 initial gridcell total liq content mm T - 388 LIQUID_CONTENT2 post landuse change gridcell total liq content mm F - 389 LIQUID_WATER_TEMP1 initial gridcell weighted average liquid water temperature K F - 390 LITTERC_HR litter C heterotrophic respiration gC/m^2/s T - 391 LITTER_CWD total mass of litter in CWD kg ha-1 T - 392 LITTER_CWD_AG_ELEM mass of above ground litter in CWD (trunks/branches/twigs) kg ha-1 T - 393 LITTER_CWD_BG_ELEM mass of below ground litter in CWD (coarse roots) kg ha-1 T - 394 LITTER_FINES_AG_ELEM mass of above ground litter in fines (leaves,nonviable seed) kg ha-1 T - 395 LITTER_FINES_BG_ELEM mass of below ground litter in fines (fineroots) kg ha-1 T - 396 LITTER_IN FATES litter flux in gC m-2 s-1 T - 397 LITTER_IN_ELEM FATES litter flux in kg ha-1 d-1 T - 398 LITTER_OUT FATES litter flux out gC m-2 s-1 T - 399 LITTER_OUT_ELEM FATES litter flux out (fragmentation only) kg ha-1 d-1 T - 400 LIVECROOT_MR live coarse root maintenance respiration) kg C / m2 / yr T - 401 LIVECROOT_MR_CANOPY_SCLS LIVECROOT_MR for canopy plants by size class kg C / ha / yr F - 402 LIVECROOT_MR_UNDERSTORY_SCLS LIVECROOT_MR for understory plants by size class kg C / ha / yr F - 403 LIVESTEM_MR live stem maintenance respiration) kg C / m2 / yr T - 404 LIVESTEM_MR_CANOPY_SCLS LIVESTEM_MR for canopy plants by size class kg C / ha / yr F - 405 LIVESTEM_MR_UNDERSTORY_SCLS LIVESTEM_MR for understory plants by size class kg C / ha / yr F - 406 LNC leaf N concentration gN leaf/m^2 T - 407 LWdown atmospheric longwave radiation (downscaled to columns in glacier regions) W/m^2 F - 408 LWup upwelling longwave radiation W/m^2 F - 409 M10_CACLS age senescence mortality by cohort age N/ha/yr T - 410 M10_CAPF age senescence mortality by pft/cohort age N/ha/yr F - 411 M10_SCLS age senescence mortality by size N/ha/yr T - 412 M10_SCPF age senescence mortality by pft/size N/ha/yr F - 413 M1_SCLS background mortality by size N/ha/yr T - 414 M1_SCPF background mortality by pft/size N/ha/yr F - 415 M2_SCLS hydraulic mortality by size N/ha/yr T - 416 M2_SCPF hydraulic mortality by pft/size N/ha/yr F - 417 M3_SCLS carbon starvation mortality by size N/ha/yr T - 418 M3_SCPF carbon starvation mortality by pft/size N/ha/yr F - 419 M4_SCLS impact mortality by size N/ha/yr T - 420 M4_SCPF impact mortality by pft/size N/ha/yr F - 421 M5_SCLS fire mortality by size N/ha/yr T - 422 M5_SCPF fire mortality by pft/size N/ha/yr F - 423 M6_SCLS termination mortality by size N/ha/yr T - 424 M6_SCPF termination mortality by pft/size N/ha/yr F - 425 M7_SCLS logging mortality by size N/ha/event T - 426 M7_SCPF logging mortality by pft/size N/ha/event F - 427 M8_SCLS freezing mortality by size N/ha/event T - 428 M8_SCPF freezing mortality by pft/size N/ha/yr F - 429 M9_SCLS senescence mortality by size N/ha/yr T - 430 M9_SCPF senescence mortality by pft/size N/ha/yr F - 431 MAINT_RESP maintenance respiration gC/m^2/s T - 432 MET_LITC MET_LIT C gC/m^2 T - 433 MET_LITC_1m MET_LIT C to 1 meter gC/m^2 F - 434 MET_LITC_TNDNCY_VERT_TRA metabolic litter C tendency due to vertical transport gC/m^3/s F - 435 MET_LITC_TO_ACT_SOMC decomp. of metabolic litter C to active soil organic C gC/m^2/s F - 436 MET_LITC_TO_ACT_SOMC_vr decomp. of metabolic litter C to active soil organic C gC/m^3/s F - 437 MET_LITC_vr MET_LIT C (vertically resolved) gC/m^3 T - 438 MET_LITN MET_LIT N gN/m^2 T - 439 MET_LITN_1m MET_LIT N to 1 meter gN/m^2 F - 440 MET_LITN_TNDNCY_VERT_TRA metabolic litter N tendency due to vertical transport gN/m^3/s F - 441 MET_LITN_TO_ACT_SOMN decomp. of metabolic litter N to active soil organic N gN/m^2 F - 442 MET_LITN_TO_ACT_SOMN_vr decomp. of metabolic litter N to active soil organic N gN/m^3 F - 443 MET_LITN_vr MET_LIT N (vertically resolved) gN/m^3 T - 444 MET_LIT_HR Het. Resp. from metabolic litter gC/m^2/s F - 445 MET_LIT_HR_vr Het. Resp. from metabolic litter gC/m^3/s F - 446 MORTALITY Rate of total mortality by PFT indiv/ha/yr T - 447 MORTALITY_CANOPY_SCAG mortality rate of canopy plants in each size x age class plants/ha/yr F - 448 MORTALITY_CANOPY_SCLS total mortality of canopy trees by size class indiv/ha/yr T - 449 MORTALITY_CANOPY_SCPF total mortality of canopy plants by pft/size N/ha/yr F - 450 MORTALITY_CARBONFLUX_CANOPY flux of biomass carbon from live to dead pools from mortality of canopy plants gC/m2/s T - 451 MORTALITY_CARBONFLUX_UNDERSTORY flux of biomass carbon from live to dead pools from mortality of understory plants gC/m2/s T - 452 MORTALITY_UNDERSTORY_SCAG mortality rate of understory plantsin each size x age class plants/ha/yr F - 453 MORTALITY_UNDERSTORY_SCLS total mortality of understory trees by size class indiv/ha/yr T - 454 MORTALITY_UNDERSTORY_SCPF total mortality of understory plants by pft/size N/ha/yr F - 455 M_ACT_SOMC_TO_LEACHING active soil organic C leaching loss gC/m^2/s F - 456 M_ACT_SOMN_TO_LEACHING active soil organic N leaching loss gN/m^2/s F - 457 M_CEL_LITC_TO_LEACHING cellulosic litter C leaching loss gC/m^2/s F - 458 M_CEL_LITN_TO_LEACHING cellulosic litter N leaching loss gN/m^2/s F - 459 M_LIG_LITC_TO_LEACHING lignin litter C leaching loss gC/m^2/s F - 460 M_LIG_LITN_TO_LEACHING lignin litter N leaching loss gN/m^2/s F - 461 M_MET_LITC_TO_LEACHING metabolic litter C leaching loss gC/m^2/s F - 462 M_MET_LITN_TO_LEACHING metabolic litter N leaching loss gN/m^2/s F - 463 M_PAS_SOMC_TO_LEACHING passive soil organic C leaching loss gC/m^2/s F - 464 M_PAS_SOMN_TO_LEACHING passive soil organic N leaching loss gN/m^2/s F - 465 M_SLO_SOMC_TO_LEACHING slow soil organic ma C leaching loss gC/m^2/s F - 466 M_SLO_SOMN_TO_LEACHING slow soil organic ma N leaching loss gN/m^2/s F - 467 NCL_BY_AGE number of canopy levels by age bin -- F - 468 NDEP_TO_SMINN atmospheric N deposition to soil mineral N gN/m^2/s T - 469 NEM Gridcell net adjustment to net carbon exchange passed to atm. for methane production gC/m2/s T - 470 NEP net ecosystem production gC/m^2/s T - 471 NET_C_UPTAKE_CNLF net carbon uptake by each canopy and leaf layer per unit ground area (i.e. divide by CROWNAREA gC/m2/s F - 472 NET_NMIN net rate of N mineralization gN/m^2/s T - 473 NFIX_TO_SMINN symbiotic/asymbiotic N fixation to soil mineral N gN/m^2/s T - 474 NPATCH_BY_AGE number of patches by age bin -- F - 475 NPLANT_CACLS number of plants by coage class indiv/ha T - 476 NPLANT_CANOPY_SCAG number of plants per hectare in canopy in each size x age class plants/ha F - 477 NPLANT_CANOPY_SCLS number of canopy plants by size class indiv/ha T - 478 NPLANT_CANOPY_SCPF stem number of canopy plants density by pft/size N/ha F - 479 NPLANT_CAPF stem number density by pft/coage N/ha F - 480 NPLANT_SCAG number of plants per hectare in each size x age class plants/ha T - 481 NPLANT_SCAGPFT number of plants per hectare in each size x age x pft class plants/ha F - 482 NPLANT_SCLS number of plants by size class indiv/ha T - 483 NPLANT_SCPF stem number density by pft/size N/ha F - 484 NPLANT_UNDERSTORY_SCAG number of plants per hectare in understory in each size x age class plants/ha F - 485 NPLANT_UNDERSTORY_SCLS number of understory plants by size class indiv/ha T - 486 NPLANT_UNDERSTORY_SCPF stem number of understory plants density by pft/size N/ha F - 487 NPP net primary production gC/m^2/s T - 488 NPP_AGDW_SCPF NPP flux into above-ground deadwood by pft/size kgC/m2/yr F - 489 NPP_AGEPFT NPP per PFT in each age bin kgC/m2/yr F - 490 NPP_AGSW_SCPF NPP flux into above-ground sapwood by pft/size kgC/m2/yr F - 491 NPP_BDEAD_CANOPY_SCLS NPP_BDEAD for canopy plants by size class kg C / ha / yr F - 492 NPP_BDEAD_UNDERSTORY_SCLS NPP_BDEAD for understory plants by size class kg C / ha / yr F - 493 NPP_BGDW_SCPF NPP flux into below-ground deadwood by pft/size kgC/m2/yr F - 494 NPP_BGSW_SCPF NPP flux into below-ground sapwood by pft/size kgC/m2/yr F - 495 NPP_BSEED_CANOPY_SCLS NPP_BSEED for canopy plants by size class kg C / ha / yr F - 496 NPP_BSEED_UNDERSTORY_SCLS NPP_BSEED for understory plants by size class kg C / ha / yr F - 497 NPP_BSW_CANOPY_SCLS NPP_BSW for canopy plants by size class kg C / ha / yr F - 498 NPP_BSW_UNDERSTORY_SCLS NPP_BSW for understory plants by size class kg C / ha / yr F - 499 NPP_BY_AGE net primary productivity by age bin gC/m^2/s F - 500 NPP_CROOT NPP flux into coarse roots kgC/m2/yr T - 501 NPP_FNRT_SCPF NPP flux into fine roots by pft/size kgC/m2/yr F - 502 NPP_FROOT NPP flux into fine roots kgC/m2/yr T - 503 NPP_FROOT_CANOPY_SCLS NPP_FROOT for canopy plants by size class kg C / ha / yr F - 504 NPP_FROOT_UNDERSTORY_SCLS NPP_FROOT for understory plants by size class kg C / ha / yr F - 505 NPP_LEAF NPP flux into leaves kgC/m2/yr T - 506 NPP_LEAF_CANOPY_SCLS NPP_LEAF for canopy plants by size class kg C / ha / yr F - 507 NPP_LEAF_SCPF NPP flux into leaves by pft/size kgC/m2/yr F - 508 NPP_LEAF_UNDERSTORY_SCLS NPP_LEAF for understory plants by size class kg C / ha / yr F - 509 NPP_SCPF total net primary production by pft/size kgC/m2/yr F - 510 NPP_SEED NPP flux into seeds kgC/m2/yr T - 511 NPP_SEED_SCPF NPP flux into seeds by pft/size kgC/m2/yr F - 512 NPP_STEM NPP flux into stem kgC/m2/yr T - 513 NPP_STOR NPP flux into storage tissues kgC/m2/yr T - 514 NPP_STORE_CANOPY_SCLS NPP_STORE for canopy plants by size class kg C / ha / yr F - 515 NPP_STORE_UNDERSTORY_SCLS NPP_STORE for understory plants by size class kg C / ha / yr F - 516 NPP_STOR_SCPF NPP flux into storage by pft/size kgC/m2/yr F - 517 NSUBSTEPS number of adaptive timesteps in CLM timestep unitless F - 518 O2_DECOMP_DEPTH_UNSAT O2 consumption from HR and AR for non-inundated area mol/m3/s F - 519 OBU Monin-Obukhov length m F - 520 OCDEP total OC deposition (dry+wet) from atmosphere kg/m^2/s T - 521 O_SCALAR fraction by which decomposition is reduced due to anoxia unitless T - 522 PARPROF_DIF_CNLF Radiative profile of diffuse PAR through each canopy and leaf layer (averaged across PFTs) W/m2 F - 523 PARPROF_DIF_CNLFPFT Radiative profile of diffuse PAR through each canopy, leaf, and PFT W/m2 F - 524 PARPROF_DIR_CNLF Radiative profile of direct PAR through each canopy and leaf layer (averaged across PFTs) W/m2 F - 525 PARPROF_DIR_CNLFPFT Radiative profile of direct PAR through each canopy, leaf, and PFT W/m2 F - 526 PARSHA_Z_CAN PAR absorbed in the shade by top leaf layer in each canopy layer W/m2 F - 527 PARSHA_Z_CNLF PAR absorbed in the shade by each canopy and leaf layer W/m2 F - 528 PARSHA_Z_CNLFPFT PAR absorbed in the shade by each canopy, leaf, and PFT W/m2 F - 529 PARSUN_Z_CAN PAR absorbed in the sun by top leaf layer in each canopy layer W/m2 F - 530 PARSUN_Z_CNLF PAR absorbed in the sun by each canopy and leaf layer W/m2 F - 531 PARSUN_Z_CNLFPFT PAR absorbed in the sun by each canopy, leaf, and PFT W/m2 F - 532 PARVEGLN absorbed par by vegetation at local noon W/m^2 T - 533 PAS_SOMC PAS_SOM C gC/m^2 T - 534 PAS_SOMC_1m PAS_SOM C to 1 meter gC/m^2 F - 535 PAS_SOMC_TNDNCY_VERT_TRA passive soil organic C tendency due to vertical transport gC/m^3/s F - 536 PAS_SOMC_TO_ACT_SOMC decomp. of passive soil organic C to active soil organic C gC/m^2/s F - 537 PAS_SOMC_TO_ACT_SOMC_vr decomp. of passive soil organic C to active soil organic C gC/m^3/s F - 538 PAS_SOMC_vr PAS_SOM C (vertically resolved) gC/m^3 T - 539 PAS_SOMN PAS_SOM N gN/m^2 T - 540 PAS_SOMN_1m PAS_SOM N to 1 meter gN/m^2 F - 541 PAS_SOMN_TNDNCY_VERT_TRA passive soil organic N tendency due to vertical transport gN/m^3/s F - 542 PAS_SOMN_TO_ACT_SOMN decomp. of passive soil organic N to active soil organic N gN/m^2 F - 543 PAS_SOMN_TO_ACT_SOMN_vr decomp. of passive soil organic N to active soil organic N gN/m^3 F - 544 PAS_SOMN_vr PAS_SOM N (vertically resolved) gN/m^3 T - 545 PAS_SOM_HR Het. Resp. from passive soil organic gC/m^2/s F - 546 PAS_SOM_HR_vr Het. Resp. from passive soil organic gC/m^3/s F - 547 PATCH_AREA_BY_AGE patch area by age bin m2/m2 T - 548 PBOT atmospheric pressure at surface (downscaled to columns in glacier regions) Pa T - 549 PCH4 atmospheric partial pressure of CH4 Pa T - 550 PCO2 atmospheric partial pressure of CO2 Pa T - 551 PFTbiomass total PFT level biomass gC/m2 T - 552 PFTcanopycrownarea total PFT-level canopy-layer crown area m2/m2 F - 553 PFTcrownarea total PFT level crown area m2/m2 F - 554 PFTgpp total PFT-level GPP kg C m-2 y-1 T - 555 PFTleafbiomass total PFT level leaf biomass gC/m2 T - 556 PFTnindivs total PFT level number of individuals indiv / m2 T - 557 PFTnpp total PFT-level NPP kg C m-2 y-1 T - 558 PFTstorebiomass total PFT level stored biomass gC/m2 T - 559 POTENTIAL_IMMOB potential N immobilization gN/m^2/s T - 560 PRIMARYLAND_PATCHFUSION_ERROR Error in total primary lands associated with patch fusion m2 m-2 d-1 T - 561 PROMOTION_CARBONFLUX promotion-associated biomass carbon flux from understory to canopy gC/m2/s T - 562 PROMOTION_RATE_SCLS promotion rate from understory to canopy by size class indiv/ha/yr F - 563 PSurf atmospheric pressure at surface (downscaled to columns in glacier regions) Pa F - 564 Q2M 2m specific humidity kg/kg T - 565 QAF canopy air humidity kg/kg F - 566 QBOT atmospheric specific humidity (downscaled to columns in glacier regions) kg/kg T - 567 QDIRECT_THROUGHFALL direct throughfall of liquid (rain + above-canopy irrigation) mm/s F - 568 QDIRECT_THROUGHFALL_SNOW direct throughfall of snow mm/s F - 569 QDRAI sub-surface drainage mm/s T - 570 QDRAI_PERCH perched wt drainage mm/s T - 571 QDRAI_XS saturation excess drainage mm/s T - 572 QDRIP rate of excess canopy liquid falling off canopy mm/s F - 573 QDRIP_SNOW rate of excess canopy snow falling off canopy mm/s F - 574 QFLOOD runoff from river flooding mm/s T - 575 QFLX_EVAP_TOT qflx_evap_soi + qflx_evap_can + qflx_tran_veg kg m-2 s-1 T - 576 QFLX_EVAP_VEG vegetation evaporation mm H2O/s F - 577 QFLX_ICE_DYNBAL ice dynamic land cover change conversion runoff flux mm/s T - 578 QFLX_LIQDEW_TO_TOP_LAYER rate of liquid water deposited on top soil or snow layer (dew) mm H2O/s T - 579 QFLX_LIQEVAP_FROM_TOP_LAYER rate of liquid water evaporated from top soil or snow layer mm H2O/s T - 580 QFLX_LIQ_DYNBAL liq dynamic land cover change conversion runoff flux mm/s T - 581 QFLX_LIQ_GRND liquid (rain+irrigation) on ground after interception mm H2O/s F - 582 QFLX_SNOW_DRAIN drainage from snow pack mm/s T - 583 QFLX_SNOW_DRAIN_ICE drainage from snow pack melt (ice landunits only) mm/s T - 584 QFLX_SNOW_GRND snow on ground after interception mm H2O/s F - 585 QFLX_SOLIDDEW_TO_TOP_LAYER rate of solid water deposited on top soil or snow layer (frost) mm H2O/s T - 586 QFLX_SOLIDEVAP_FROM_TOP_LAYER rate of ice evaporated from top soil or snow layer (sublimation) (also includes bare ice subli mm H2O/s T - 587 QFLX_SOLIDEVAP_FROM_TOP_LAYER_ICE rate of ice evaporated from top soil or snow layer (sublimation) (also includes bare ice subli mm H2O/s F - 588 QH2OSFC surface water runoff mm/s T - 589 QH2OSFC_TO_ICE surface water converted to ice mm/s F - 590 QHR hydraulic redistribution mm/s T - 591 QICE ice growth/melt mm/s T - 592 QICE_FORC qice forcing sent to GLC mm/s F - 593 QICE_FRZ ice growth mm/s T - 594 QICE_MELT ice melt mm/s T - 595 QINFL infiltration mm/s T - 596 QINTR interception mm/s T - 597 QIRRIG_DEMAND irrigation demand mm/s F - 598 QIRRIG_DRIP water added via drip irrigation mm/s F - 599 QIRRIG_FROM_GW_CONFINED water added through confined groundwater irrigation mm/s T - 600 QIRRIG_FROM_GW_UNCONFINED water added through unconfined groundwater irrigation mm/s T - 601 QIRRIG_FROM_SURFACE water added through surface water irrigation mm/s T - 602 QIRRIG_SPRINKLER water added via sprinkler irrigation mm/s F - 603 QOVER total surface runoff (includes QH2OSFC) mm/s T - 604 QOVER_LAG time-lagged surface runoff for soil columns mm/s F - 605 QPHSNEG net negative hydraulic redistribution flux mm/s F - 606 QRGWL surface runoff at glaciers (liquid only), wetlands, lakes; also includes melted ice runoff fro mm/s T - 607 QROOTSINK water flux from soil to root in each soil-layer mm/s F - 608 QRUNOFF total liquid runoff not including correction for land use change mm/s T - 609 QRUNOFF_ICE total liquid runoff not incl corret for LULCC (ice landunits only) mm/s T - 610 QRUNOFF_ICE_TO_COUPLER total ice runoff sent to coupler (includes corrections for land use change) mm/s T - 611 QRUNOFF_ICE_TO_LIQ liquid runoff from converted ice runoff mm/s F - 612 QRUNOFF_R Rural total runoff mm/s F - 613 QRUNOFF_TO_COUPLER total liquid runoff sent to coupler (includes corrections for land use change) mm/s T - 614 QRUNOFF_U Urban total runoff mm/s F - 615 QSNOCPLIQ excess liquid h2o due to snow capping not including correction for land use change mm H2O/s T - 616 QSNOEVAP evaporation from snow (only when snl<0, otherwise it is equal to qflx_ev_soil) mm/s T - 617 QSNOFRZ column-integrated snow freezing rate kg/m2/s T - 618 QSNOFRZ_ICE column-integrated snow freezing rate (ice landunits only) mm/s T - 619 QSNOMELT snow melt rate mm/s T - 620 QSNOMELT_ICE snow melt (ice landunits only) mm/s T - 621 QSNOUNLOAD canopy snow unloading mm/s T - 622 QSNO_TEMPUNLOAD canopy snow temp unloading mm/s T - 623 QSNO_WINDUNLOAD canopy snow wind unloading mm/s T - 624 QSNWCPICE excess solid h2o due to snow capping not including correction for land use change mm H2O/s T - 625 QSOIL Ground evaporation (soil/snow evaporation + soil/snow sublimation - dew) mm/s T - 626 QSOIL_ICE Ground evaporation (ice landunits only) mm/s T - 627 QTOPSOIL water input to surface mm/s F - 628 QVEGE canopy evaporation mm/s T - 629 QVEGT canopy transpiration mm/s T - 630 Qair atmospheric specific humidity (downscaled to columns in glacier regions) kg/kg F - 631 Qh sensible heat W/m^2 F - 632 Qle total evaporation W/m^2 F - 633 Qstor storage heat flux (includes snowmelt) W/m^2 F - 634 Qtau momentum flux kg/m/s^2 F - 635 RAH1 aerodynamical resistance s/m F - 636 RAH2 aerodynamical resistance s/m F - 637 RAIN atmospheric rain, after rain/snow repartitioning based on temperature mm/s T - 638 RAIN_FROM_ATM atmospheric rain received from atmosphere (pre-repartitioning) mm/s T - 639 RAIN_ICE atmospheric rain, after rain/snow repartitioning based on temperature (ice landunits only) mm/s F - 640 RAM_LAKE aerodynamic resistance for momentum (lakes only) s/m F - 641 RAW1 aerodynamical resistance s/m F - 642 RAW2 aerodynamical resistance s/m F - 643 RB leaf boundary resistance s/m F - 644 RDARK_CANOPY_SCLS RDARK for canopy plants by size class kg C / ha / yr F - 645 RDARK_UNDERSTORY_SCLS RDARK for understory plants by size class kg C / ha / yr F - 646 RECRUITMENT Rate of recruitment by PFT indiv/ha/yr T - 647 REPROC Total carbon in live plant reproductive tissues kgC ha-1 T - 648 REPROC_SCPF reproductive carbon mass (on plant) by size-class x pft kgC/ha F - 649 RESP_G_CANOPY_SCLS RESP_G for canopy plants by size class kg C / ha / yr F - 650 RESP_G_UNDERSTORY_SCLS RESP_G for understory plants by size class kg C / ha / yr F - 651 RESP_M_CANOPY_SCLS RESP_M for canopy plants by size class kg C / ha / yr F - 652 RESP_M_UNDERSTORY_SCLS RESP_M for understory plants by size class kg C / ha / yr F - 653 RH atmospheric relative humidity % F - 654 RH2M 2m relative humidity % T - 655 RH2M_R Rural 2m specific humidity % F - 656 RH2M_U Urban 2m relative humidity % F - 657 RHAF fractional humidity of canopy air fraction F - 658 RH_LEAF fractional humidity at leaf surface fraction F - 659 ROOT_MD_CANOPY_SCLS ROOT_MD for canopy plants by size class kg C / ha / yr F - 660 ROOT_MD_UNDERSTORY_SCLS ROOT_MD for understory plants by size class kg C / ha / yr F - 661 RSCANOPY canopy resistance s m-1 T - 662 RSSHA shaded leaf stomatal resistance s/m T - 663 RSSUN sunlit leaf stomatal resistance s/m T - 664 Rainf atmospheric rain, after rain/snow repartitioning based on temperature mm/s F - 665 Rnet net radiation W/m^2 F - 666 SABG solar rad absorbed by ground W/m^2 T - 667 SABG_PEN Rural solar rad penetrating top soil or snow layer watt/m^2 T - 668 SABV solar rad absorbed by veg W/m^2 T - 669 SAI_CANOPY_SCLS stem area index(SAI) by size class m2/m2 F - 670 SAI_UNDERSTORY_SCLS number of understory plants by size class indiv/ha F - 671 SAPWC Total carbon in live plant sapwood kgC ha-1 T - 672 SAPWC_SCPF sapwood carbon mass by size-class x pft kgC/ha F - 673 SCORCH_HEIGHT SPITFIRE Flame Scorch Height (calculated per PFT in each patch age bin) m T - 674 SECONDARY_AREA_AGE_ANTHRO_DIST Secondary forest patch area age distribution since anthropgenic disturbance m2/m2 F - 675 SECONDARY_AREA_PATCH_AGE_DIST Secondary forest patch area age distribution since any kind of disturbance m2/m2 F - 676 SECONDARY_FOREST_BIOMASS Biomass on secondary lands (per total site area, mult by SECONDARY_FOREST_FRACTION to get per kgC/m2 F - 677 SECONDARY_FOREST_FRACTION Secondary forest fraction m2/m2 F - 678 SEEDS_IN Seed Production Rate gC m-2 s-1 T - 679 SEEDS_IN_EXTERN_ELEM External Seed Influx Rate kg ha-1 d-1 T - 680 SEEDS_IN_LOCAL_ELEM Within Site Seed Production Rate kg ha-1 d-1 T - 681 SEED_BANK Total Seed Mass of all PFTs gC m-2 T - 682 SEED_BANK_ELEM Total Seed Mass of all PFTs kg ha-1 T - 683 SEED_DECAY_ELEM Seed mass decay (germinated and un-germinated) kg ha-1 d-1 T - 684 SEED_GERM_ELEM Seed mass converted into new cohorts kg ha-1 d-1 T - 685 SEED_PROD_CANOPY_SCLS SEED_PROD for canopy plants by size class kg C / ha / yr F - 686 SEED_PROD_UNDERSTORY_SCLS SEED_PROD for understory plants by size class kg C / ha / yr F - 687 SITE_COLD_STATUS Site level cold status, 0=not cold-dec, 1=too cold for leaves, 2=not-too cold 0,1,2 T - 688 SITE_DAYSINCE_COLDLEAFOFF site level days elapsed since cold leaf drop days T - 689 SITE_DAYSINCE_COLDLEAFON site level days elapsed since cold leaf flush days T - 690 SITE_DAYSINCE_DROUGHTLEAFOFF site level days elapsed since drought leaf drop days T - 691 SITE_DAYSINCE_DROUGHTLEAFON site level days elapsed since drought leaf flush days T - 692 SITE_DROUGHT_STATUS Site level drought status, <2 too dry for leaves, >=2 not-too dry 0,1,2,3 T - 693 SITE_GDD site level growing degree days degC T - 694 SITE_MEANLIQVOL_DROUGHTPHEN site level mean liquid water volume for drought phen m3/m3 T - 695 SITE_NCHILLDAYS site level number of chill days days T - 696 SITE_NCOLDDAYS site level number of cold days days T - 697 SLO_SOMC SLO_SOM C gC/m^2 T - 698 SLO_SOMC_1m SLO_SOM C to 1 meter gC/m^2 F - 699 SLO_SOMC_TNDNCY_VERT_TRA slow soil organic ma C tendency due to vertical transport gC/m^3/s F - 700 SLO_SOMC_TO_ACT_SOMC decomp. of slow soil organic ma C to active soil organic C gC/m^2/s F - 701 SLO_SOMC_TO_ACT_SOMC_vr decomp. of slow soil organic ma C to active soil organic C gC/m^3/s F - 702 SLO_SOMC_TO_PAS_SOMC decomp. of slow soil organic ma C to passive soil organic C gC/m^2/s F - 703 SLO_SOMC_TO_PAS_SOMC_vr decomp. of slow soil organic ma C to passive soil organic C gC/m^3/s F - 704 SLO_SOMC_vr SLO_SOM C (vertically resolved) gC/m^3 T - 705 SLO_SOMN SLO_SOM N gN/m^2 T - 706 SLO_SOMN_1m SLO_SOM N to 1 meter gN/m^2 F - 707 SLO_SOMN_TNDNCY_VERT_TRA slow soil organic ma N tendency due to vertical transport gN/m^3/s F - 708 SLO_SOMN_TO_ACT_SOMN decomp. of slow soil organic ma N to active soil organic N gN/m^2 F - 709 SLO_SOMN_TO_ACT_SOMN_vr decomp. of slow soil organic ma N to active soil organic N gN/m^3 F - 710 SLO_SOMN_TO_PAS_SOMN decomp. of slow soil organic ma N to passive soil organic N gN/m^2 F - 711 SLO_SOMN_TO_PAS_SOMN_vr decomp. of slow soil organic ma N to passive soil organic N gN/m^3 F - 712 SLO_SOMN_vr SLO_SOM N (vertically resolved) gN/m^3 T - 713 SLO_SOM_HR_S1 Het. Resp. from slow soil organic ma gC/m^2/s F - 714 SLO_SOM_HR_S1_vr Het. Resp. from slow soil organic ma gC/m^3/s F - 715 SLO_SOM_HR_S3 Het. Resp. from slow soil organic ma gC/m^2/s F - 716 SLO_SOM_HR_S3_vr Het. Resp. from slow soil organic ma gC/m^3/s F - 717 SMINN soil mineral N gN/m^2 T - 718 SMINN_LEACHED soil mineral N pool loss to leaching gN/m^2/s T - 719 SMINN_LEACHED_vr soil mineral N pool loss to leaching gN/m^3/s F - 720 SMINN_TO_DENIT_EXCESS denitrification from excess mineral N pool gN/m^2/s F - 721 SMINN_TO_DENIT_EXCESS_vr denitrification from excess mineral N pool gN/m^3/s F - 722 SMINN_TO_DENIT_L1S1 denitrification for decomp. of metabolic litterto ACT_SOM gN/m^2 F - 723 SMINN_TO_DENIT_L1S1_vr denitrification for decomp. of metabolic litterto ACT_SOM gN/m^3 F - 724 SMINN_TO_DENIT_L2S1 denitrification for decomp. of cellulosic litterto ACT_SOM gN/m^2 F - 725 SMINN_TO_DENIT_L2S1_vr denitrification for decomp. of cellulosic litterto ACT_SOM gN/m^3 F - 726 SMINN_TO_DENIT_L3S2 denitrification for decomp. of lignin litterto SLO_SOM gN/m^2 F - 727 SMINN_TO_DENIT_L3S2_vr denitrification for decomp. of lignin litterto SLO_SOM gN/m^3 F - 728 SMINN_TO_DENIT_S1S2 denitrification for decomp. of active soil organicto SLO_SOM gN/m^2 F - 729 SMINN_TO_DENIT_S1S2_vr denitrification for decomp. of active soil organicto SLO_SOM gN/m^3 F - 730 SMINN_TO_DENIT_S1S3 denitrification for decomp. of active soil organicto PAS_SOM gN/m^2 F - 731 SMINN_TO_DENIT_S1S3_vr denitrification for decomp. of active soil organicto PAS_SOM gN/m^3 F - 732 SMINN_TO_DENIT_S2S1 denitrification for decomp. of slow soil organic mato ACT_SOM gN/m^2 F - 733 SMINN_TO_DENIT_S2S1_vr denitrification for decomp. of slow soil organic mato ACT_SOM gN/m^3 F - 734 SMINN_TO_DENIT_S2S3 denitrification for decomp. of slow soil organic mato PAS_SOM gN/m^2 F - 735 SMINN_TO_DENIT_S2S3_vr denitrification for decomp. of slow soil organic mato PAS_SOM gN/m^3 F - 736 SMINN_TO_DENIT_S3S1 denitrification for decomp. of passive soil organicto ACT_SOM gN/m^2 F - 737 SMINN_TO_DENIT_S3S1_vr denitrification for decomp. of passive soil organicto ACT_SOM gN/m^3 F - 738 SMINN_TO_PLANT plant uptake of soil mineral N gN/m^2/s T - 739 SMINN_TO_S1N_L1 mineral N flux for decomp. of MET_LITto ACT_SOM gN/m^2 F - 740 SMINN_TO_S1N_L1_vr mineral N flux for decomp. of MET_LITto ACT_SOM gN/m^3 F - 741 SMINN_TO_S1N_L2 mineral N flux for decomp. of CEL_LITto ACT_SOM gN/m^2 F - 742 SMINN_TO_S1N_L2_vr mineral N flux for decomp. of CEL_LITto ACT_SOM gN/m^3 F - 743 SMINN_TO_S1N_S2 mineral N flux for decomp. of SLO_SOMto ACT_SOM gN/m^2 F - 744 SMINN_TO_S1N_S2_vr mineral N flux for decomp. of SLO_SOMto ACT_SOM gN/m^3 F - 745 SMINN_TO_S1N_S3 mineral N flux for decomp. of PAS_SOMto ACT_SOM gN/m^2 F - 746 SMINN_TO_S1N_S3_vr mineral N flux for decomp. of PAS_SOMto ACT_SOM gN/m^3 F - 747 SMINN_TO_S2N_L3 mineral N flux for decomp. of LIG_LITto SLO_SOM gN/m^2 F - 748 SMINN_TO_S2N_L3_vr mineral N flux for decomp. of LIG_LITto SLO_SOM gN/m^3 F - 749 SMINN_TO_S2N_S1 mineral N flux for decomp. of ACT_SOMto SLO_SOM gN/m^2 F - 750 SMINN_TO_S2N_S1_vr mineral N flux for decomp. of ACT_SOMto SLO_SOM gN/m^3 F - 751 SMINN_TO_S3N_S1 mineral N flux for decomp. of ACT_SOMto PAS_SOM gN/m^2 F - 752 SMINN_TO_S3N_S1_vr mineral N flux for decomp. of ACT_SOMto PAS_SOM gN/m^3 F - 753 SMINN_TO_S3N_S2 mineral N flux for decomp. of SLO_SOMto PAS_SOM gN/m^2 F - 754 SMINN_TO_S3N_S2_vr mineral N flux for decomp. of SLO_SOMto PAS_SOM gN/m^3 F - 755 SMINN_vr soil mineral N gN/m^3 T - 756 SMP soil matric potential (natural vegetated and crop landunits only) mm T - 757 SNOBCMCL mass of BC in snow column kg/m2 T - 758 SNOBCMSL mass of BC in top snow layer kg/m2 T - 759 SNOCAN intercepted snow mm T - 760 SNODSTMCL mass of dust in snow column kg/m2 T - 761 SNODSTMSL mass of dust in top snow layer kg/m2 T - 762 SNOFSDSND direct nir incident solar radiation on snow W/m^2 F - 763 SNOFSDSNI diffuse nir incident solar radiation on snow W/m^2 F - 764 SNOFSDSVD direct vis incident solar radiation on snow W/m^2 F - 765 SNOFSDSVI diffuse vis incident solar radiation on snow W/m^2 F - 766 SNOFSRND direct nir reflected solar radiation from snow W/m^2 T - 767 SNOFSRNI diffuse nir reflected solar radiation from snow W/m^2 T - 768 SNOFSRVD direct vis reflected solar radiation from snow W/m^2 T - 769 SNOFSRVI diffuse vis reflected solar radiation from snow W/m^2 T - 770 SNOINTABS Fraction of incoming solar absorbed by lower snow layers - T - 771 SNOLIQFL top snow layer liquid water fraction (land) fraction F - 772 SNOOCMCL mass of OC in snow column kg/m2 T - 773 SNOOCMSL mass of OC in top snow layer kg/m2 T - 774 SNORDSL top snow layer effective grain radius m^-6 F - 775 SNOTTOPL snow temperature (top layer) K F - 776 SNOTTOPL_ICE snow temperature (top layer, ice landunits only) K F - 777 SNOTXMASS snow temperature times layer mass, layer sum; to get mass-weighted temperature, divide by (SNO K kg/m2 T - 778 SNOTXMASS_ICE snow temperature times layer mass, layer sum (ice landunits only); to get mass-weighted temper K kg/m2 F - 779 SNOW atmospheric snow, after rain/snow repartitioning based on temperature mm/s T - 780 SNOWDP gridcell mean snow height m T - 781 SNOWICE snow ice kg/m2 T - 782 SNOWICE_ICE snow ice (ice landunits only) kg/m2 F - 783 SNOWLIQ snow liquid water kg/m2 T - 784 SNOWLIQ_ICE snow liquid water (ice landunits only) kg/m2 F - 785 SNOW_5D 5day snow avg m F - 786 SNOW_DEPTH snow height of snow covered area m T - 787 SNOW_DEPTH_ICE snow height of snow covered area (ice landunits only) m F - 788 SNOW_FROM_ATM atmospheric snow received from atmosphere (pre-repartitioning) mm/s T - 789 SNOW_ICE atmospheric snow, after rain/snow repartitioning based on temperature (ice landunits only) mm/s F - 790 SNOW_PERSISTENCE Length of time of continuous snow cover (nat. veg. landunits only) seconds T - 791 SNOW_SINKS snow sinks (liquid water) mm/s T - 792 SNOW_SOURCES snow sources (liquid water) mm/s T - 793 SNO_ABS Absorbed solar radiation in each snow layer W/m^2 F - 794 SNO_ABS_ICE Absorbed solar radiation in each snow layer (ice landunits only) W/m^2 F - 795 SNO_BW Partial density of water in the snow pack (ice + liquid) kg/m3 F - 796 SNO_BW_ICE Partial density of water in the snow pack (ice + liquid, ice landunits only) kg/m3 F - 797 SNO_EXISTENCE Fraction of averaging period for which each snow layer existed unitless F - 798 SNO_FRZ snow freezing rate in each snow layer kg/m2/s F - 799 SNO_FRZ_ICE snow freezing rate in each snow layer (ice landunits only) mm/s F - 800 SNO_GS Mean snow grain size Microns F - 801 SNO_GS_ICE Mean snow grain size (ice landunits only) Microns F - 802 SNO_ICE Snow ice content kg/m2 F - 803 SNO_LIQH2O Snow liquid water content kg/m2 F - 804 SNO_MELT snow melt rate in each snow layer mm/s F - 805 SNO_MELT_ICE snow melt rate in each snow layer (ice landunits only) mm/s F - 806 SNO_T Snow temperatures K F - 807 SNO_TK Thermal conductivity W/m-K F - 808 SNO_TK_ICE Thermal conductivity (ice landunits only) W/m-K F - 809 SNO_T_ICE Snow temperatures (ice landunits only) K F - 810 SNO_Z Snow layer thicknesses m F - 811 SNO_Z_ICE Snow layer thicknesses (ice landunits only) m F - 812 SNOdTdzL top snow layer temperature gradient (land) K/m F - 813 SOIL10 10-day running mean of 12cm layer soil K F - 814 SOILC_HR soil C heterotrophic respiration gC/m^2/s T - 815 SOILC_vr SOIL C (vertically resolved) gC/m^3 T - 816 SOILICE soil ice (natural vegetated and crop landunits only) kg/m2 T - 817 SOILLIQ soil liquid water (natural vegetated and crop landunits only) kg/m2 T - 818 SOILN_vr SOIL N (vertically resolved) gN/m^3 T - 819 SOILPSI soil water potential in each soil layer MPa F - 820 SOILRESIS soil resistance to evaporation s/m T - 821 SOILWATER_10CM soil liquid water + ice in top 10cm of soil (veg landunits only) kg/m2 T - 822 SOMC_FIRE C loss due to peat burning gC/m^2/s T - 823 SOM_C_LEACHED total flux of C from SOM pools due to leaching gC/m^2/s T - 824 SOM_N_LEACHED total flux of N from SOM pools due to leaching gN/m^2/s F - 825 STOREC Total carbon in live plant storage kgC ha-1 T - 826 STOREC_SCPF storage carbon mass by size-class x pft kgC/ha F - 827 SUM_FUEL total ground fuel related to ros (omits 1000hr fuels) gC m-2 T - 828 SUM_FUEL_BY_PATCH_AGE spitfire ground fuel related to ros (omits 1000hr fuels) within each patch age bin (divide by gC / m2 of site area T - 829 SUPPLEMENT_TO_SMINN supplemental N supply gN/m^2/s T - 830 SWBGT 2 m Simplified Wetbulb Globe Temp C T - 831 SWBGT_R Rural 2 m Simplified Wetbulb Globe Temp C T - 832 SWBGT_U Urban 2 m Simplified Wetbulb Globe Temp C T - 833 SWdown atmospheric incident solar radiation W/m^2 F - 834 SWup upwelling shortwave radiation W/m^2 F - 835 SoilAlpha factor limiting ground evap unitless F - 836 SoilAlpha_U urban factor limiting ground evap unitless F - 837 T10 10-day running mean of 2-m temperature K F - 838 TAF canopy air temperature K F - 839 TAUX zonal surface stress kg/m/s^2 T - 840 TAUY meridional surface stress kg/m/s^2 T - 841 TBOT atmospheric air temperature (downscaled to columns in glacier regions) K T - 842 TBUILD internal urban building air temperature K T - 843 TBUILD_MAX prescribed maximum interior building temperature K F - 844 TFLOOR floor temperature K F - 845 TG ground temperature K T - 846 TG_ICE ground temperature (ice landunits only) K F - 847 TG_R Rural ground temperature K F - 848 TG_U Urban ground temperature K F - 849 TH2OSFC surface water temperature K T - 850 THBOT atmospheric air potential temperature (downscaled to columns in glacier regions) K T - 851 TKE1 top lake level eddy thermal conductivity W/(mK) T - 852 TLAI total projected leaf area index m^2/m^2 T - 853 TLAKE lake temperature K T - 854 TOPO_COL column-level topographic height m F - 855 TOPO_COL_ICE column-level topographic height (ice landunits only) m F - 856 TOPO_FORC topograephic height sent to GLC m F - 857 TOTCOLCH4 total belowground CH4 (0 for non-lake special landunits in the absence of dynamic landunits) gC/m2 T - 858 TOTLITC total litter carbon gC/m^2 T - 859 TOTLITC_1m total litter carbon to 1 meter depth gC/m^2 T - 860 TOTLITN total litter N gN/m^2 T - 861 TOTLITN_1m total litter N to 1 meter gN/m^2 T - 862 TOTSOILICE vertically summed soil cie (veg landunits only) kg/m2 T - 863 TOTSOILLIQ vertically summed soil liquid water (veg landunits only) kg/m2 T - 864 TOTSOMC total soil organic matter carbon gC/m^2 T - 865 TOTSOMC_1m total soil organic matter carbon to 1 meter depth gC/m^2 T - 866 TOTSOMN total soil organic matter N gN/m^2 T - 867 TOTSOMN_1m total soil organic matter N to 1 meter gN/m^2 T - 868 TOTVEGC Total carbon in live plants kgC ha-1 T - 869 TOTVEGC_SCPF total vegetation carbon mass in live plants by size-class x pft kgC/ha F - 870 TRAFFICFLUX sensible heat flux from urban traffic W/m^2 F - 871 TREFMNAV daily minimum of average 2-m temperature K T - 872 TREFMNAV_R Rural daily minimum of average 2-m temperature K F - 873 TREFMNAV_U Urban daily minimum of average 2-m temperature K F - 874 TREFMXAV daily maximum of average 2-m temperature K T - 875 TREFMXAV_R Rural daily maximum of average 2-m temperature K F - 876 TREFMXAV_U Urban daily maximum of average 2-m temperature K F - 877 TRIMMING Degree to which canopy expansion is limited by leaf economics none T - 878 TRIMMING_CANOPY_SCLS trimming term of canopy plants by size class indiv/ha F - 879 TRIMMING_UNDERSTORY_SCLS trimming term of understory plants by size class indiv/ha F - 880 TROOF_INNER roof inside surface temperature K F - 881 TSA 2m air temperature K T - 882 TSAI total projected stem area index m^2/m^2 T - 883 TSA_ICE 2m air temperature (ice landunits only) K F - 884 TSA_R Rural 2m air temperature K F - 885 TSA_U Urban 2m air temperature K F - 886 TSHDW_INNER shadewall inside surface temperature K F - 887 TSKIN skin temperature K T - 888 TSL temperature of near-surface soil layer (natural vegetated and crop landunits only) K T - 889 TSOI soil temperature (natural vegetated and crop landunits only) K T - 890 TSOI_10CM soil temperature in top 10cm of soil K T - 891 TSOI_ICE soil temperature (ice landunits only) K T - 892 TSRF_FORC surface temperature sent to GLC K F - 893 TSUNW_INNER sunwall inside surface temperature K F - 894 TV vegetation temperature K T - 895 TV24 vegetation temperature (last 24hrs) K F - 896 TV240 vegetation temperature (last 240hrs) K F - 897 TWS total water storage mm T - 898 T_SCALAR temperature inhibition of decomposition unitless T - 899 Tair atmospheric air temperature (downscaled to columns in glacier regions) K F - 900 Tair_from_atm atmospheric air temperature received from atmosphere (pre-downscaling) K F - 901 U10 10-m wind m/s T - 902 U10_DUST 10-m wind for dust model m/s T - 903 U10_ICE 10-m wind (ice landunits only) m/s F - 904 UAF canopy air speed m/s F - 905 UM wind speed plus stability effect m/s F - 906 URBAN_AC urban air conditioning flux W/m^2 T - 907 URBAN_HEAT urban heating flux W/m^2 T - 908 USTAR aerodynamical resistance s/m F - 909 UST_LAKE friction velocity (lakes only) m/s F - 910 VA atmospheric wind speed plus convective velocity m/s F - 911 VOLR river channel total water storage m3 T - 912 VOLRMCH river channel main channel water storage m3 T - 913 VPD vpd Pa F - 914 VPD2M 2m vapor pressure deficit Pa T - 915 VPD_CAN canopy vapor pressure deficit kPa T - 916 WASTEHEAT sensible heat flux from heating/cooling sources of urban waste heat W/m^2 T - 917 WBT 2 m Stull Wet Bulb C T - 918 WBT_R Rural 2 m Stull Wet Bulb C T - 919 WBT_U Urban 2 m Stull Wet Bulb C T - 920 WIND atmospheric wind velocity magnitude m/s T - 921 WOOD_PRODUCT Total wood product from logging gC/m2 F - 922 WTGQ surface tracer conductance m/s T - 923 W_SCALAR Moisture (dryness) inhibition of decomposition unitless T - 924 Wind atmospheric wind velocity magnitude m/s F - 925 YESTERDAYCANLEV_CANOPY_SCLS Yesterdays canopy level for canopy plants by size class indiv/ha F - 926 YESTERDAYCANLEV_UNDERSTORY_SCLS Yesterdays canopy level for understory plants by size class indiv/ha F - 927 Z0HG roughness length over ground, sensible heat m F - 928 Z0M momentum roughness length m F - 929 Z0MG roughness length over ground, momentum m F - 930 Z0M_TO_COUPLER roughness length, momentum: gridcell average sent to coupler m F - 931 Z0QG roughness length over ground, latent heat m F - 932 ZBOT atmospheric reference height m T - 933 ZETA dimensionless stability parameter unitless F - 934 ZII convective boundary height m F - 935 ZSTAR_BY_AGE product of zstar and patch area by age bin (divide by PATCH_AREA_BY_AGE to get mean zstar) m F - 936 ZWT water table depth (natural vegetated and crop landunits only) m T - 937 ZWT_CH4_UNSAT depth of water table for methane production used in non-inundated area m T - 938 ZWT_PERCH perched water table depth (natural vegetated and crop landunits only) m T - 939 num_iter number of iterations unitless F -==== =================================== ============================================================================================== ================================================================= ======= diff --git a/doc/source/users_guide/setting-up-and-running-a-case/master_list_nofates.rst b/doc/source/users_guide/setting-up-and-running-a-case/master_list_nofates.rst deleted file mode 100644 index 776acc9833..0000000000 --- a/doc/source/users_guide/setting-up-and-running-a-case/master_list_nofates.rst +++ /dev/null @@ -1,1303 +0,0 @@ -============================= -CTSM History Fields (nofates) -============================= - -CAUTION: Not all variables are relevant / present for all CTSM cases. -Key flags used in this CTSM case: -use_cn = T -use_crop = T -use_fates = F - -==== =================================== ============================================================================================== ================================================================= ======= -CTSM History Fields ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - # Variable Name Long Description Units Active? -==== =================================== ============================================================================================== ================================================================= ======= - 1 A10TMIN 10-day running mean of min 2-m temperature K F - 2 A5TMIN 5-day running mean of min 2-m temperature K F - 3 ACTUAL_IMMOB actual N immobilization gN/m^2/s T - 4 ACTUAL_IMMOB_NH4 immobilization of NH4 gN/m^3/s F - 5 ACTUAL_IMMOB_NO3 immobilization of NO3 gN/m^3/s F - 6 ACTUAL_IMMOB_vr actual N immobilization gN/m^3/s F - 7 ACT_SOMC ACT_SOM C gC/m^2 T - 8 ACT_SOMC_1m ACT_SOM C to 1 meter gC/m^2 F - 9 ACT_SOMC_TNDNCY_VERT_TRA active soil organic C tendency due to vertical transport gC/m^3/s F - 10 ACT_SOMC_TO_PAS_SOMC decomp. of active soil organic C to passive soil organic C gC/m^2/s F - 11 ACT_SOMC_TO_PAS_SOMC_vr decomp. of active soil organic C to passive soil organic C gC/m^3/s F - 12 ACT_SOMC_TO_SLO_SOMC decomp. of active soil organic C to slow soil organic ma C gC/m^2/s F - 13 ACT_SOMC_TO_SLO_SOMC_vr decomp. of active soil organic C to slow soil organic ma C gC/m^3/s F - 14 ACT_SOMC_vr ACT_SOM C (vertically resolved) gC/m^3 T - 15 ACT_SOMN ACT_SOM N gN/m^2 T - 16 ACT_SOMN_1m ACT_SOM N to 1 meter gN/m^2 F - 17 ACT_SOMN_TNDNCY_VERT_TRA active soil organic N tendency due to vertical transport gN/m^3/s F - 18 ACT_SOMN_TO_PAS_SOMN decomp. of active soil organic N to passive soil organic N gN/m^2 F - 19 ACT_SOMN_TO_PAS_SOMN_vr decomp. of active soil organic N to passive soil organic N gN/m^3 F - 20 ACT_SOMN_TO_SLO_SOMN decomp. of active soil organic N to slow soil organic ma N gN/m^2 F - 21 ACT_SOMN_TO_SLO_SOMN_vr decomp. of active soil organic N to slow soil organic ma N gN/m^3 F - 22 ACT_SOMN_vr ACT_SOM N (vertically resolved) gN/m^3 T - 23 ACT_SOM_HR_S2 Het. Resp. from active soil organic gC/m^2/s F - 24 ACT_SOM_HR_S2_vr Het. Resp. from active soil organic gC/m^3/s F - 25 ACT_SOM_HR_S3 Het. Resp. from active soil organic gC/m^2/s F - 26 ACT_SOM_HR_S3_vr Het. Resp. from active soil organic gC/m^3/s F - 27 AGLB Aboveground leaf biomass kg/m^2 F - 28 AGNPP aboveground NPP gC/m^2/s T - 29 AGSB Aboveground stem biomass kg/m^2 F - 30 ALBD surface albedo (direct) proportion T - 31 ALBDSF diagnostic snow-free surface albedo (direct) proportion T - 32 ALBGRD ground albedo (direct) proportion F - 33 ALBGRI ground albedo (indirect) proportion F - 34 ALBI surface albedo (indirect) proportion T - 35 ALBISF diagnostic snow-free surface albedo (indirect) proportion T - 36 ALPHA alpha coefficient for VOC calc non F - 37 ALT current active layer thickness m T - 38 ALTMAX maximum annual active layer thickness m T - 39 ALTMAX_LASTYEAR maximum prior year active layer thickness m F - 40 ANNAVG_T2M annual average 2m air temperature K F - 41 ANNMAX_RETRANSN annual max of retranslocated N pool gN/m^2 F - 42 ANNSUM_COUNTER seconds since last annual accumulator turnover s F - 43 ANNSUM_NPP annual sum of NPP gC/m^2/yr F - 44 ANNSUM_POTENTIAL_GPP annual sum of potential GPP gN/m^2/yr F - 45 APPAR_TEMP 2 m apparent temperature C T - 46 APPAR_TEMP_R Rural 2 m apparent temperature C T - 47 APPAR_TEMP_U Urban 2 m apparent temperature C T - 48 AR autotrophic respiration (MR + GR) gC/m^2/s T - 49 ATM_TOPO atmospheric surface height m T - 50 AVAILC C flux available for allocation gC/m^2/s F - 51 AVAIL_RETRANSN N flux available from retranslocation pool gN/m^2/s F - 52 AnnET Annual ET mm/s F - 53 BAF_CROP fractional area burned for crop s-1 T - 54 BAF_PEATF fractional area burned in peatland s-1 T - 55 BCDEP total BC deposition (dry+wet) from atmosphere kg/m^2/s T - 56 BETA coefficient of convective velocity none F - 57 BGLFR background litterfall rate 1/s F - 58 BGNPP belowground NPP gC/m^2/s T - 59 BGTR background transfer growth rate 1/s F - 60 BTRANMN daily minimum of transpiration beta factor unitless T - 61 CANNAVG_T2M annual average of 2m air temperature K F - 62 CANNSUM_NPP annual sum of column-level NPP gC/m^2/s F - 63 CEL_LITC CEL_LIT C gC/m^2 T - 64 CEL_LITC_1m CEL_LIT C to 1 meter gC/m^2 F - 65 CEL_LITC_TNDNCY_VERT_TRA cellulosic litter C tendency due to vertical transport gC/m^3/s F - 66 CEL_LITC_TO_ACT_SOMC decomp. of cellulosic litter C to active soil organic C gC/m^2/s F - 67 CEL_LITC_TO_ACT_SOMC_vr decomp. of cellulosic litter C to active soil organic C gC/m^3/s F - 68 CEL_LITC_vr CEL_LIT C (vertically resolved) gC/m^3 T - 69 CEL_LITN CEL_LIT N gN/m^2 T - 70 CEL_LITN_1m CEL_LIT N to 1 meter gN/m^2 F - 71 CEL_LITN_TNDNCY_VERT_TRA cellulosic litter N tendency due to vertical transport gN/m^3/s F - 72 CEL_LITN_TO_ACT_SOMN decomp. of cellulosic litter N to active soil organic N gN/m^2 F - 73 CEL_LITN_TO_ACT_SOMN_vr decomp. of cellulosic litter N to active soil organic N gN/m^3 F - 74 CEL_LITN_vr CEL_LIT N (vertically resolved) gN/m^3 T - 75 CEL_LIT_HR Het. Resp. from cellulosic litter gC/m^2/s F - 76 CEL_LIT_HR_vr Het. Resp. from cellulosic litter gC/m^3/s F - 77 CGRND deriv. of soil energy flux wrt to soil temp W/m^2/K F - 78 CGRNDL deriv. of soil latent heat flux wrt soil temp W/m^2/K F - 79 CGRNDS deriv. of soil sensible heat flux wrt soil temp W/m^2/K F - 80 CH4PROD Gridcell total production of CH4 gC/m2/s T - 81 CH4_EBUL_TOTAL_SAT ebullition surface CH4 flux; (+ to atm) mol/m2/s F - 82 CH4_EBUL_TOTAL_UNSAT ebullition surface CH4 flux; (+ to atm) mol/m2/s F - 83 CH4_SURF_AERE_SAT aerenchyma surface CH4 flux for inundated area; (+ to atm) mol/m2/s T - 84 CH4_SURF_AERE_UNSAT aerenchyma surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T - 85 CH4_SURF_DIFF_SAT diffusive surface CH4 flux for inundated / lake area; (+ to atm) mol/m2/s T - 86 CH4_SURF_DIFF_UNSAT diffusive surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T - 87 CH4_SURF_EBUL_SAT ebullition surface CH4 flux for inundated / lake area; (+ to atm) mol/m2/s T - 88 CH4_SURF_EBUL_UNSAT ebullition surface CH4 flux for non-inundated area; (+ to atm) mol/m2/s T - 89 COL_CTRUNC column-level sink for C truncation gC/m^2 F - 90 COL_FIRE_CLOSS total column-level fire C loss for non-peat fires outside land-type converted region gC/m^2/s T - 91 COL_FIRE_NLOSS total column-level fire N loss gN/m^2/s T - 92 COL_NTRUNC column-level sink for N truncation gN/m^2 F - 93 CONC_CH4_SAT CH4 soil Concentration for inundated / lake area mol/m3 F - 94 CONC_CH4_UNSAT CH4 soil Concentration for non-inundated area mol/m3 F - 95 CONC_O2_SAT O2 soil Concentration for inundated / lake area mol/m3 T - 96 CONC_O2_UNSAT O2 soil Concentration for non-inundated area mol/m3 T - 97 COST_NACTIVE Cost of active uptake gN/gC T - 98 COST_NFIX Cost of fixation gN/gC T - 99 COST_NRETRANS Cost of retranslocation gN/gC T - 100 COSZEN cosine of solar zenith angle none F - 101 CPHASE crop phenology phase 0-not planted, 1-planted, 2-leaf emerge, 3-grain fill, 4-harvest T - 102 CPOOL temporary photosynthate C pool gC/m^2 T - 103 CPOOL_DEADCROOT_GR dead coarse root growth respiration gC/m^2/s F - 104 CPOOL_DEADCROOT_STORAGE_GR dead coarse root growth respiration to storage gC/m^2/s F - 105 CPOOL_DEADSTEM_GR dead stem growth respiration gC/m^2/s F - 106 CPOOL_DEADSTEM_STORAGE_GR dead stem growth respiration to storage gC/m^2/s F - 107 CPOOL_FROOT_GR fine root growth respiration gC/m^2/s F - 108 CPOOL_FROOT_STORAGE_GR fine root growth respiration to storage gC/m^2/s F - 109 CPOOL_LEAF_GR leaf growth respiration gC/m^2/s F - 110 CPOOL_LEAF_STORAGE_GR leaf growth respiration to storage gC/m^2/s F - 111 CPOOL_LIVECROOT_GR live coarse root growth respiration gC/m^2/s F - 112 CPOOL_LIVECROOT_STORAGE_GR live coarse root growth respiration to storage gC/m^2/s F - 113 CPOOL_LIVESTEM_GR live stem growth respiration gC/m^2/s F - 114 CPOOL_LIVESTEM_STORAGE_GR live stem growth respiration to storage gC/m^2/s F - 115 CPOOL_TO_DEADCROOTC allocation to dead coarse root C gC/m^2/s F - 116 CPOOL_TO_DEADCROOTC_STORAGE allocation to dead coarse root C storage gC/m^2/s F - 117 CPOOL_TO_DEADSTEMC allocation to dead stem C gC/m^2/s F - 118 CPOOL_TO_DEADSTEMC_STORAGE allocation to dead stem C storage gC/m^2/s F - 119 CPOOL_TO_FROOTC allocation to fine root C gC/m^2/s F - 120 CPOOL_TO_FROOTC_STORAGE allocation to fine root C storage gC/m^2/s F - 121 CPOOL_TO_GRESP_STORAGE allocation to growth respiration storage gC/m^2/s F - 122 CPOOL_TO_LEAFC allocation to leaf C gC/m^2/s F - 123 CPOOL_TO_LEAFC_STORAGE allocation to leaf C storage gC/m^2/s F - 124 CPOOL_TO_LIVECROOTC allocation to live coarse root C gC/m^2/s F - 125 CPOOL_TO_LIVECROOTC_STORAGE allocation to live coarse root C storage gC/m^2/s F - 126 CPOOL_TO_LIVESTEMC allocation to live stem C gC/m^2/s F - 127 CPOOL_TO_LIVESTEMC_STORAGE allocation to live stem C storage gC/m^2/s F - 128 CROOT_PROF profile for litter C and N inputs from coarse roots 1/m F - 129 CROPPROD1C 1-yr crop product (grain+biofuel) C gC/m^2 T - 130 CROPPROD1C_LOSS loss from 1-yr crop product pool gC/m^2/s T - 131 CROPPROD1N 1-yr crop product (grain+biofuel) N gN/m^2 T - 132 CROPPROD1N_LOSS loss from 1-yr crop product pool gN/m^2/s T - 133 CROPSEEDC_DEFICIT C used for crop seed that needs to be repaid gC/m^2 T - 134 CROPSEEDN_DEFICIT N used for crop seed that needs to be repaid gN/m^2 F - 135 CROP_SEEDC_TO_LEAF crop seed source to leaf gC/m^2/s F - 136 CROP_SEEDN_TO_LEAF crop seed source to leaf gN/m^2/s F - 137 CURRENT_GR growth resp for new growth displayed in this timestep gC/m^2/s F - 138 CWDC CWD C gC/m^2 T - 139 CWDC_1m CWD C to 1 meter gC/m^2 F - 140 CWDC_HR cwd C heterotrophic respiration gC/m^2/s F - 141 CWDC_LOSS coarse woody debris C loss gC/m^2/s T - 142 CWDC_TO_CEL_LITC decomp. of coarse woody debris C to cellulosic litter C gC/m^2/s F - 143 CWDC_TO_CEL_LITC_vr decomp. of coarse woody debris C to cellulosic litter C gC/m^3/s F - 144 CWDC_TO_LIG_LITC decomp. of coarse woody debris C to lignin litter C gC/m^2/s F - 145 CWDC_TO_LIG_LITC_vr decomp. of coarse woody debris C to lignin litter C gC/m^3/s F - 146 CWDC_vr CWD C (vertically resolved) gC/m^3 T - 147 CWDN CWD N gN/m^2 T - 148 CWDN_1m CWD N to 1 meter gN/m^2 F - 149 CWDN_TO_CEL_LITN decomp. of coarse woody debris N to cellulosic litter N gN/m^2 F - 150 CWDN_TO_CEL_LITN_vr decomp. of coarse woody debris N to cellulosic litter N gN/m^3 F - 151 CWDN_TO_LIG_LITN decomp. of coarse woody debris N to lignin litter N gN/m^2 F - 152 CWDN_TO_LIG_LITN_vr decomp. of coarse woody debris N to lignin litter N gN/m^3 F - 153 CWDN_vr CWD N (vertically resolved) gN/m^3 T - 154 CWD_HR_L2 Het. Resp. from coarse woody debris gC/m^2/s F - 155 CWD_HR_L2_vr Het. Resp. from coarse woody debris gC/m^3/s F - 156 CWD_HR_L3 Het. Resp. from coarse woody debris gC/m^2/s F - 157 CWD_HR_L3_vr Het. Resp. from coarse woody debris gC/m^3/s F - 158 C_ALLOMETRY C allocation index none F - 159 DAYL daylength s F - 160 DAYS_ACTIVE number of days since last dormancy days F - 161 DEADCROOTC dead coarse root C gC/m^2 T - 162 DEADCROOTC_STORAGE dead coarse root C storage gC/m^2 F - 163 DEADCROOTC_STORAGE_TO_XFER dead coarse root C shift storage to transfer gC/m^2/s F - 164 DEADCROOTC_XFER dead coarse root C transfer gC/m^2 F - 165 DEADCROOTC_XFER_TO_DEADCROOTC dead coarse root C growth from storage gC/m^2/s F - 166 DEADCROOTN dead coarse root N gN/m^2 T - 167 DEADCROOTN_STORAGE dead coarse root N storage gN/m^2 F - 168 DEADCROOTN_STORAGE_TO_XFER dead coarse root N shift storage to transfer gN/m^2/s F - 169 DEADCROOTN_XFER dead coarse root N transfer gN/m^2 F - 170 DEADCROOTN_XFER_TO_DEADCROOTN dead coarse root N growth from storage gN/m^2/s F - 171 DEADSTEMC dead stem C gC/m^2 T - 172 DEADSTEMC_STORAGE dead stem C storage gC/m^2 F - 173 DEADSTEMC_STORAGE_TO_XFER dead stem C shift storage to transfer gC/m^2/s F - 174 DEADSTEMC_XFER dead stem C transfer gC/m^2 F - 175 DEADSTEMC_XFER_TO_DEADSTEMC dead stem C growth from storage gC/m^2/s F - 176 DEADSTEMN dead stem N gN/m^2 T - 177 DEADSTEMN_STORAGE dead stem N storage gN/m^2 F - 178 DEADSTEMN_STORAGE_TO_XFER dead stem N shift storage to transfer gN/m^2/s F - 179 DEADSTEMN_XFER dead stem N transfer gN/m^2 F - 180 DEADSTEMN_XFER_TO_DEADSTEMN dead stem N growth from storage gN/m^2/s F - 181 DENIT total rate of denitrification gN/m^2/s T - 182 DGNETDT derivative of net ground heat flux wrt soil temp W/m^2/K F - 183 DISCOI 2 m Discomfort Index C T - 184 DISCOIS 2 m Stull Discomfort Index C T - 185 DISCOIS_R Rural 2 m Stull Discomfort Index C T - 186 DISCOIS_U Urban 2 m Stull Discomfort Index C T - 187 DISCOI_R Rural 2 m Discomfort Index C T - 188 DISCOI_U Urban 2 m Discomfort Index C T - 189 DISPLA displacement height m F - 190 DISPVEGC displayed veg carbon, excluding storage and cpool gC/m^2 T - 191 DISPVEGN displayed vegetation nitrogen gN/m^2 T - 192 DLRAD downward longwave radiation below the canopy W/m^2 F - 193 DORMANT_FLAG dormancy flag none F - 194 DOWNREG fractional reduction in GPP due to N limitation proportion F - 195 DPVLTRB1 turbulent deposition velocity 1 m/s F - 196 DPVLTRB2 turbulent deposition velocity 2 m/s F - 197 DPVLTRB3 turbulent deposition velocity 3 m/s F - 198 DPVLTRB4 turbulent deposition velocity 4 m/s F - 199 DSL dry surface layer thickness mm T - 200 DSTDEP total dust deposition (dry+wet) from atmosphere kg/m^2/s T - 201 DSTFLXT total surface dust emission kg/m2/s T - 202 DT_VEG change in t_veg, last iteration K F - 203 DWT_CONV_CFLUX conversion C flux (immediate loss to atm) (0 at all times except first timestep of year) gC/m^2/s T - 204 DWT_CONV_CFLUX_DRIBBLED conversion C flux (immediate loss to atm), dribbled throughout the year gC/m^2/s T - 205 DWT_CONV_CFLUX_PATCH patch-level conversion C flux (immediate loss to atm) (0 at all times except first timestep of gC/m^2/s F - 206 DWT_CONV_NFLUX conversion N flux (immediate loss to atm) (0 at all times except first timestep of year) gN/m^2/s T - 207 DWT_CONV_NFLUX_PATCH patch-level conversion N flux (immediate loss to atm) (0 at all times except first timestep of gN/m^2/s F - 208 DWT_CROPPROD1C_GAIN landcover change-driven addition to 1-year crop product pool gC/m^2/s T - 209 DWT_CROPPROD1N_GAIN landcover change-driven addition to 1-year crop product pool gN/m^2/s T - 210 DWT_DEADCROOTC_TO_CWDC dead coarse root to CWD due to landcover change gC/m^2/s F - 211 DWT_DEADCROOTN_TO_CWDN dead coarse root to CWD due to landcover change gN/m^2/s F - 212 DWT_FROOTC_TO_CEL_LIT_C fine root to cellulosic litter due to landcover change gC/m^2/s F - 213 DWT_FROOTC_TO_LIG_LIT_C fine root to lignin litter due to landcover change gC/m^2/s F - 214 DWT_FROOTC_TO_MET_LIT_C fine root to metabolic litter due to landcover change gC/m^2/s F - 215 DWT_FROOTN_TO_CEL_LIT_N fine root N to cellulosic litter due to landcover change gN/m^2/s F - 216 DWT_FROOTN_TO_LIG_LIT_N fine root N to lignin litter due to landcover change gN/m^2/s F - 217 DWT_FROOTN_TO_MET_LIT_N fine root N to metabolic litter due to landcover change gN/m^2/s F - 218 DWT_LIVECROOTC_TO_CWDC live coarse root to CWD due to landcover change gC/m^2/s F - 219 DWT_LIVECROOTN_TO_CWDN live coarse root to CWD due to landcover change gN/m^2/s F - 220 DWT_PROD100C_GAIN landcover change-driven addition to 100-yr wood product pool gC/m^2/s F - 221 DWT_PROD100N_GAIN landcover change-driven addition to 100-yr wood product pool gN/m^2/s F - 222 DWT_PROD10C_GAIN landcover change-driven addition to 10-yr wood product pool gC/m^2/s F - 223 DWT_PROD10N_GAIN landcover change-driven addition to 10-yr wood product pool gN/m^2/s F - 224 DWT_SEEDC_TO_DEADSTEM seed source to patch-level deadstem gC/m^2/s F - 225 DWT_SEEDC_TO_DEADSTEM_PATCH patch-level seed source to patch-level deadstem (per-area-gridcell; only makes sense with dov2 gC/m^2/s F - 226 DWT_SEEDC_TO_LEAF seed source to patch-level leaf gC/m^2/s F - 227 DWT_SEEDC_TO_LEAF_PATCH patch-level seed source to patch-level leaf (per-area-gridcell; only makes sense with dov2xy=. gC/m^2/s F - 228 DWT_SEEDN_TO_DEADSTEM seed source to patch-level deadstem gN/m^2/s T - 229 DWT_SEEDN_TO_DEADSTEM_PATCH patch-level seed source to patch-level deadstem (per-area-gridcell; only makes sense with dov2 gN/m^2/s F - 230 DWT_SEEDN_TO_LEAF seed source to patch-level leaf gN/m^2/s T - 231 DWT_SEEDN_TO_LEAF_PATCH patch-level seed source to patch-level leaf (per-area-gridcell; only makes sense with dov2xy=. gN/m^2/s F - 232 DWT_SLASH_CFLUX slash C flux (to litter diagnostic only) (0 at all times except first timestep of year) gC/m^2/s T - 233 DWT_SLASH_CFLUX_PATCH patch-level slash C flux (to litter diagnostic only) (0 at all times except first timestep of gC/m^2/s F - 234 DWT_WOODPRODC_GAIN landcover change-driven addition to wood product pools gC/m^2/s T - 235 DWT_WOODPRODN_GAIN landcover change-driven addition to wood product pools gN/m^2/s T - 236 DWT_WOOD_PRODUCTC_GAIN_PATCH patch-level landcover change-driven addition to wood product pools(0 at all times except first gC/m^2/s F - 237 DYN_COL_ADJUSTMENTS_CH4 Adjustments in ch4 due to dynamic column areas; only makes sense at the column level: should n gC/m^2 F - 238 DYN_COL_SOIL_ADJUSTMENTS_C Adjustments in soil carbon due to dynamic column areas; only makes sense at the column level: gC/m^2 F - 239 DYN_COL_SOIL_ADJUSTMENTS_N Adjustments in soil nitrogen due to dynamic column areas; only makes sense at the column level gN/m^2 F - 240 DYN_COL_SOIL_ADJUSTMENTS_NH4 Adjustments in soil NH4 due to dynamic column areas; only makes sense at the column level: sho gN/m^2 F - 241 DYN_COL_SOIL_ADJUSTMENTS_NO3 Adjustments in soil NO3 due to dynamic column areas; only makes sense at the column level: sho gN/m^2 F - 242 EFF_POROSITY effective porosity = porosity - vol_ice proportion F - 243 EFLXBUILD building heat flux from change in interior building air temperature W/m^2 T - 244 EFLX_DYNBAL dynamic land cover change conversion energy flux W/m^2 T - 245 EFLX_GNET net heat flux into ground W/m^2 F - 246 EFLX_GRND_LAKE net heat flux into lake/snow surface, excluding light transmission W/m^2 T - 247 EFLX_LH_TOT total latent heat flux [+ to atm] W/m^2 T - 248 EFLX_LH_TOT_ICE total latent heat flux [+ to atm] (ice landunits only) W/m^2 F - 249 EFLX_LH_TOT_R Rural total evaporation W/m^2 T - 250 EFLX_LH_TOT_U Urban total evaporation W/m^2 F - 251 EFLX_SOIL_GRND soil heat flux [+ into soil] W/m^2 F - 252 ELAI exposed one-sided leaf area index m^2/m^2 T - 253 EMG ground emissivity proportion F - 254 EMV vegetation emissivity proportion F - 255 EOPT Eopt coefficient for VOC calc non F - 256 EPT 2 m Equiv Pot Temp K T - 257 EPT_R Rural 2 m Equiv Pot Temp K T - 258 EPT_U Urban 2 m Equiv Pot Temp K T - 259 ER total ecosystem respiration, autotrophic + heterotrophic gC/m^2/s T - 260 ERRH2O total water conservation error mm T - 261 ERRH2OSNO imbalance in snow depth (liquid water) mm T - 262 ERRSEB surface energy conservation error W/m^2 T - 263 ERRSOI soil/lake energy conservation error W/m^2 T - 264 ERRSOL solar radiation conservation error W/m^2 T - 265 ESAI exposed one-sided stem area index m^2/m^2 T - 266 EXCESSC_MR excess C maintenance respiration gC/m^2/s F - 267 EXCESS_CFLUX C flux not allocated due to downregulation gC/m^2/s F - 268 FAREA_BURNED timestep fractional area burned s-1 T - 269 FCANSNO fraction of canopy that is wet proportion F - 270 FCEV canopy evaporation W/m^2 T - 271 FCH4 Gridcell surface CH4 flux to atmosphere (+ to atm) kgC/m2/s T - 272 FCH4TOCO2 Gridcell oxidation of CH4 to CO2 gC/m2/s T - 273 FCH4_DFSAT CH4 additional flux due to changing fsat, natural vegetated and crop landunits only kgC/m2/s T - 274 FCO2 CO2 flux to atmosphere (+ to atm) kgCO2/m2/s F - 275 FCOV fractional impermeable area unitless T - 276 FCTR canopy transpiration W/m^2 T - 277 FDRY fraction of foliage that is green and dry proportion F - 278 FERTNITRO Nitrogen fertilizer for each crop gN/m2/yr F - 279 FERT_COUNTER time left to fertilize seconds F - 280 FERT_TO_SMINN fertilizer to soil mineral N gN/m^2/s F - 281 FFIX_TO_SMINN free living N fixation to soil mineral N gN/m^2/s T - 282 FGEV ground evaporation W/m^2 T - 283 FGR heat flux into soil/snow including snow melt and lake / snow light transmission W/m^2 T - 284 FGR12 heat flux between soil layers 1 and 2 W/m^2 T - 285 FGR_ICE heat flux into soil/snow including snow melt and lake / snow light transmission (ice landunits W/m^2 F - 286 FGR_R Rural heat flux into soil/snow including snow melt and snow light transmission W/m^2 F - 287 FGR_SOIL_R Rural downward heat flux at interface below each soil layer watt/m^2 F - 288 FGR_U Urban heat flux into soil/snow including snow melt W/m^2 F - 289 FH2OSFC fraction of ground covered by surface water unitless T - 290 FH2OSFC_NOSNOW fraction of ground covered by surface water (if no snow present) unitless F - 291 FINUNDATED fractional inundated area of vegetated columns unitless T - 292 FINUNDATED_LAG time-lagged inundated fraction of vegetated columns unitless F - 293 FIRA net infrared (longwave) radiation W/m^2 T - 294 FIRA_ICE net infrared (longwave) radiation (ice landunits only) W/m^2 F - 295 FIRA_R Rural net infrared (longwave) radiation W/m^2 T - 296 FIRA_U Urban net infrared (longwave) radiation W/m^2 F - 297 FIRE emitted infrared (longwave) radiation W/m^2 T - 298 FIRE_ICE emitted infrared (longwave) radiation (ice landunits only) W/m^2 F - 299 FIRE_R Rural emitted infrared (longwave) radiation W/m^2 T - 300 FIRE_U Urban emitted infrared (longwave) radiation W/m^2 F - 301 FLDS atmospheric longwave radiation (downscaled to columns in glacier regions) W/m^2 T - 302 FLDS_ICE atmospheric longwave radiation (downscaled to columns in glacier regions) (ice landunits only) W/m^2 F - 303 FMAX_DENIT_CARBONSUBSTRATE FMAX_DENIT_CARBONSUBSTRATE gN/m^3/s F - 304 FMAX_DENIT_NITRATE FMAX_DENIT_NITRATE gN/m^3/s F - 305 FPI fraction of potential immobilization proportion T - 306 FPI_vr fraction of potential immobilization proportion F - 307 FPSN photosynthesis umol m-2 s-1 T - 308 FPSN24 24 hour accumulative patch photosynthesis starting from mid-night umol CO2/m^2 ground/day F - 309 FPSN_WC Rubisco-limited photosynthesis umol m-2 s-1 F - 310 FPSN_WJ RuBP-limited photosynthesis umol m-2 s-1 F - 311 FPSN_WP Product-limited photosynthesis umol m-2 s-1 F - 312 FRAC_ICEOLD fraction of ice relative to the tot water proportion F - 313 FREE_RETRANSN_TO_NPOOL deployment of retranslocated N gN/m^2/s T - 314 FROOTC fine root C gC/m^2 T - 315 FROOTC_ALLOC fine root C allocation gC/m^2/s T - 316 FROOTC_LOSS fine root C loss gC/m^2/s T - 317 FROOTC_STORAGE fine root C storage gC/m^2 F - 318 FROOTC_STORAGE_TO_XFER fine root C shift storage to transfer gC/m^2/s F - 319 FROOTC_TO_LITTER fine root C litterfall gC/m^2/s F - 320 FROOTC_XFER fine root C transfer gC/m^2 F - 321 FROOTC_XFER_TO_FROOTC fine root C growth from storage gC/m^2/s F - 322 FROOTN fine root N gN/m^2 T - 323 FROOTN_STORAGE fine root N storage gN/m^2 F - 324 FROOTN_STORAGE_TO_XFER fine root N shift storage to transfer gN/m^2/s F - 325 FROOTN_TO_LITTER fine root N litterfall gN/m^2/s F - 326 FROOTN_XFER fine root N transfer gN/m^2 F - 327 FROOTN_XFER_TO_FROOTN fine root N growth from storage gN/m^2/s F - 328 FROOT_MR fine root maintenance respiration gC/m^2/s F - 329 FROOT_PROF profile for litter C and N inputs from fine roots 1/m F - 330 FROST_TABLE frost table depth (natural vegetated and crop landunits only) m F - 331 FSA absorbed solar radiation W/m^2 T - 332 FSAT fractional area with water table at surface unitless T - 333 FSA_ICE absorbed solar radiation (ice landunits only) W/m^2 F - 334 FSA_R Rural absorbed solar radiation W/m^2 F - 335 FSA_U Urban absorbed solar radiation W/m^2 F - 336 FSD24 direct radiation (last 24hrs) K F - 337 FSD240 direct radiation (last 240hrs) K F - 338 FSDS atmospheric incident solar radiation W/m^2 T - 339 FSDSND direct nir incident solar radiation W/m^2 T - 340 FSDSNDLN direct nir incident solar radiation at local noon W/m^2 T - 341 FSDSNI diffuse nir incident solar radiation W/m^2 T - 342 FSDSVD direct vis incident solar radiation W/m^2 T - 343 FSDSVDLN direct vis incident solar radiation at local noon W/m^2 T - 344 FSDSVI diffuse vis incident solar radiation W/m^2 T - 345 FSDSVILN diffuse vis incident solar radiation at local noon W/m^2 T - 346 FSH sensible heat not including correction for land use change and rain/snow conversion W/m^2 T - 347 FSH_G sensible heat from ground W/m^2 T - 348 FSH_ICE sensible heat not including correction for land use change and rain/snow conversion (ice landu W/m^2 F - 349 FSH_PRECIP_CONVERSION Sensible heat flux from conversion of rain/snow atm forcing W/m^2 T - 350 FSH_R Rural sensible heat W/m^2 T - 351 FSH_RUNOFF_ICE_TO_LIQ sensible heat flux generated from conversion of ice runoff to liquid W/m^2 T - 352 FSH_TO_COUPLER sensible heat sent to coupler (includes corrections for land use change, rain/snow conversion W/m^2 T - 353 FSH_U Urban sensible heat W/m^2 F - 354 FSH_V sensible heat from veg W/m^2 T - 355 FSI24 indirect radiation (last 24hrs) K F - 356 FSI240 indirect radiation (last 240hrs) K F - 357 FSM snow melt heat flux W/m^2 T - 358 FSM_ICE snow melt heat flux (ice landunits only) W/m^2 F - 359 FSM_R Rural snow melt heat flux W/m^2 F - 360 FSM_U Urban snow melt heat flux W/m^2 F - 361 FSNO fraction of ground covered by snow unitless T - 362 FSNO_EFF effective fraction of ground covered by snow unitless T - 363 FSNO_ICE fraction of ground covered by snow (ice landunits only) unitless F - 364 FSR reflected solar radiation W/m^2 T - 365 FSRND direct nir reflected solar radiation W/m^2 T - 366 FSRNDLN direct nir reflected solar radiation at local noon W/m^2 T - 367 FSRNI diffuse nir reflected solar radiation W/m^2 T - 368 FSRSF reflected solar radiation W/m^2 T - 369 FSRSFND direct nir reflected solar radiation W/m^2 T - 370 FSRSFNDLN direct nir reflected solar radiation at local noon W/m^2 T - 371 FSRSFNI diffuse nir reflected solar radiation W/m^2 T - 372 FSRSFVD direct vis reflected solar radiation W/m^2 T - 373 FSRSFVDLN direct vis reflected solar radiation at local noon W/m^2 T - 374 FSRSFVI diffuse vis reflected solar radiation W/m^2 T - 375 FSRVD direct vis reflected solar radiation W/m^2 T - 376 FSRVDLN direct vis reflected solar radiation at local noon W/m^2 T - 377 FSRVI diffuse vis reflected solar radiation W/m^2 T - 378 FSR_ICE reflected solar radiation (ice landunits only) W/m^2 F - 379 FSUN sunlit fraction of canopy proportion F - 380 FSUN24 fraction sunlit (last 24hrs) K F - 381 FSUN240 fraction sunlit (last 240hrs) K F - 382 FUELC fuel load gC/m^2 T - 383 FV friction velocity m/s T - 384 FWET fraction of canopy that is wet proportion F - 385 F_DENIT denitrification flux gN/m^2/s T - 386 F_DENIT_BASE F_DENIT_BASE gN/m^3/s F - 387 F_DENIT_vr denitrification flux gN/m^3/s F - 388 F_N2O_DENIT denitrification N2O flux gN/m^2/s T - 389 F_N2O_NIT nitrification N2O flux gN/m^2/s T - 390 F_NIT nitrification flux gN/m^2/s T - 391 F_NIT_vr nitrification flux gN/m^3/s F - 392 FireComp_BC fire emissions flux of BC kg/m2/sec F - 393 FireComp_OC fire emissions flux of OC kg/m2/sec F - 394 FireComp_SO2 fire emissions flux of SO2 kg/m2/sec F - 395 FireEmis_TOT Total fire emissions flux gC/m2/sec F - 396 FireEmis_ZTOP Top of vertical fire emissions distribution m F - 397 FireMech_SO2 fire emissions flux of SO2 kg/m2/sec F - 398 FireMech_bc_a1 fire emissions flux of bc_a1 kg/m2/sec F - 399 FireMech_pom_a1 fire emissions flux of pom_a1 kg/m2/sec F - 400 GAMMA total gamma for VOC calc non F - 401 GAMMAA gamma A for VOC calc non F - 402 GAMMAC gamma C for VOC calc non F - 403 GAMMAL gamma L for VOC calc non F - 404 GAMMAP gamma P for VOC calc non F - 405 GAMMAS gamma S for VOC calc non F - 406 GAMMAT gamma T for VOC calc non F - 407 GDD0 Growing degree days base 0C from planting ddays F - 408 GDD020 Twenty year average of growing degree days base 0C from planting ddays F - 409 GDD10 Growing degree days base 10C from planting ddays F - 410 GDD1020 Twenty year average of growing degree days base 10C from planting ddays F - 411 GDD8 Growing degree days base 8C from planting ddays F - 412 GDD820 Twenty year average of growing degree days base 8C from planting ddays F - 413 GDDHARV Growing degree days (gdd) needed to harvest ddays F - 414 GDDPLANT Accumulated growing degree days past planting date for crop ddays F - 415 GDDTSOI Growing degree-days from planting (top two soil layers) ddays F - 416 GPP gross primary production gC/m^2/s T - 417 GR total growth respiration gC/m^2/s T - 418 GRAINC grain C (does not equal yield) gC/m^2 T - 419 GRAINC_TO_FOOD grain C to food gC/m^2/s T - 420 GRAINC_TO_SEED grain C to seed gC/m^2/s T - 421 GRAINN grain N gN/m^2 T - 422 GRESP_STORAGE growth respiration storage gC/m^2 F - 423 GRESP_STORAGE_TO_XFER growth respiration shift storage to transfer gC/m^2/s F - 424 GRESP_XFER growth respiration transfer gC/m^2 F - 425 GROSS_NMIN gross rate of N mineralization gN/m^2/s T - 426 GROSS_NMIN_vr gross rate of N mineralization gN/m^3/s F - 427 GSSHA shaded leaf stomatal conductance umol H20/m2/s T - 428 GSSHALN shaded leaf stomatal conductance at local noon umol H20/m2/s T - 429 GSSUN sunlit leaf stomatal conductance umol H20/m2/s T - 430 GSSUNLN sunlit leaf stomatal conductance at local noon umol H20/m2/s T - 431 H2OCAN intercepted water mm T - 432 H2OSFC surface water depth mm T - 433 H2OSNO snow depth (liquid water) mm T - 434 H2OSNO_ICE snow depth (liquid water, ice landunits only) mm F - 435 H2OSNO_TOP mass of snow in top snow layer kg/m2 T - 436 H2OSOI volumetric soil water (natural vegetated and crop landunits only) mm3/mm3 T - 437 HBOT canopy bottom m F - 438 HEAT_CONTENT1 initial gridcell total heat content J/m^2 T - 439 HEAT_CONTENT1_VEG initial gridcell total heat content - natural vegetated and crop landunits only J/m^2 F - 440 HEAT_CONTENT2 post land cover change total heat content J/m^2 F - 441 HEAT_FROM_AC sensible heat flux put into canyon due to heat removed from air conditioning W/m^2 T - 442 HIA 2 m NWS Heat Index C T - 443 HIA_R Rural 2 m NWS Heat Index C T - 444 HIA_U Urban 2 m NWS Heat Index C T - 445 HK hydraulic conductivity (natural vegetated and crop landunits only) mm/s F - 446 HR total heterotrophic respiration gC/m^2/s T - 447 HR_vr total vertically resolved heterotrophic respiration gC/m^3/s T - 448 HTOP canopy top m T - 449 HUMIDEX 2 m Humidex C T - 450 HUMIDEX_R Rural 2 m Humidex C T - 451 HUMIDEX_U Urban 2 m Humidex C T - 452 ICE_CONTENT1 initial gridcell total ice content mm T - 453 ICE_CONTENT2 post land cover change total ice content mm F - 454 ICE_MODEL_FRACTION Ice sheet model fractional coverage unitless F - 455 INIT_GPP GPP flux before downregulation gC/m^2/s F - 456 INT_SNOW accumulated swe (natural vegetated and crop landunits only) mm F - 457 INT_SNOW_ICE accumulated swe (ice landunits only) mm F - 458 IWUELN local noon intrinsic water use efficiency umolCO2/molH2O T - 459 JMX25T canopy profile of jmax umol/m2/s T - 460 Jmx25Z maximum rate of electron transport at 25 Celcius for canopy layers umol electrons/m2/s T - 461 KROOT root conductance each soil layer 1/s F - 462 KSOIL soil conductance in each soil layer 1/s F - 463 K_ACT_SOM active soil organic potential loss coefficient 1/s F - 464 K_CEL_LIT cellulosic litter potential loss coefficient 1/s F - 465 K_CWD coarse woody debris potential loss coefficient 1/s F - 466 K_LIG_LIT lignin litter potential loss coefficient 1/s F - 467 K_MET_LIT metabolic litter potential loss coefficient 1/s F - 468 K_NITR K_NITR 1/s F - 469 K_NITR_H2O K_NITR_H2O unitless F - 470 K_NITR_PH K_NITR_PH unitless F - 471 K_NITR_T K_NITR_T unitless F - 472 K_PAS_SOM passive soil organic potential loss coefficient 1/s F - 473 K_SLO_SOM slow soil organic ma potential loss coefficient 1/s F - 474 LAI240 240hr average of leaf area index m^2/m^2 F - 475 LAISHA shaded projected leaf area index m^2/m^2 T - 476 LAISUN sunlit projected leaf area index m^2/m^2 T - 477 LAKEICEFRAC lake layer ice mass fraction unitless F - 478 LAKEICEFRAC_SURF surface lake layer ice mass fraction unitless T - 479 LAKEICETHICK thickness of lake ice (including physical expansion on freezing) m T - 480 LAND_USE_FLUX total C emitted from land cover conversion (smoothed over the year) and wood and grain product gC/m^2/s T - 481 LATBASET latitude vary base temperature for gddplant degree C F - 482 LEAFC leaf C gC/m^2 T - 483 LEAFCN Leaf CN ratio used for flexible CN gC/gN T - 484 LEAFCN_OFFSET Leaf C:N used by FUN unitless F - 485 LEAFCN_STORAGE Storage Leaf CN ratio used for flexible CN gC/gN F - 486 LEAFC_ALLOC leaf C allocation gC/m^2/s T - 487 LEAFC_CHANGE C change in leaf gC/m^2/s T - 488 LEAFC_LOSS leaf C loss gC/m^2/s T - 489 LEAFC_STORAGE leaf C storage gC/m^2 F - 490 LEAFC_STORAGE_TO_XFER leaf C shift storage to transfer gC/m^2/s F - 491 LEAFC_STORAGE_XFER_ACC Accumulated leaf C transfer gC/m^2 F - 492 LEAFC_TO_BIOFUELC leaf C to biofuel C gC/m^2/s T - 493 LEAFC_TO_LITTER leaf C litterfall gC/m^2/s F - 494 LEAFC_TO_LITTER_FUN leaf C litterfall used by FUN gC/m^2/s T - 495 LEAFC_XFER leaf C transfer gC/m^2 F - 496 LEAFC_XFER_TO_LEAFC leaf C growth from storage gC/m^2/s F - 497 LEAFN leaf N gN/m^2 T - 498 LEAFN_STORAGE leaf N storage gN/m^2 F - 499 LEAFN_STORAGE_TO_XFER leaf N shift storage to transfer gN/m^2/s F - 500 LEAFN_STORAGE_XFER_ACC Accmulated leaf N transfer gN/m^2 F - 501 LEAFN_TO_LITTER leaf N litterfall gN/m^2/s T - 502 LEAFN_TO_RETRANSN leaf N to retranslocated N pool gN/m^2/s F - 503 LEAFN_XFER leaf N transfer gN/m^2 F - 504 LEAFN_XFER_TO_LEAFN leaf N growth from storage gN/m^2/s F - 505 LEAF_MR leaf maintenance respiration gC/m^2/s T - 506 LEAF_PROF profile for litter C and N inputs from leaves 1/m F - 507 LFC2 conversion area fraction of BET and BDT that burned per sec T - 508 LGSF long growing season factor proportion F - 509 LIG_LITC LIG_LIT C gC/m^2 T - 510 LIG_LITC_1m LIG_LIT C to 1 meter gC/m^2 F - 511 LIG_LITC_TNDNCY_VERT_TRA lignin litter C tendency due to vertical transport gC/m^3/s F - 512 LIG_LITC_TO_SLO_SOMC decomp. of lignin litter C to slow soil organic ma C gC/m^2/s F - 513 LIG_LITC_TO_SLO_SOMC_vr decomp. of lignin litter C to slow soil organic ma C gC/m^3/s F - 514 LIG_LITC_vr LIG_LIT C (vertically resolved) gC/m^3 T - 515 LIG_LITN LIG_LIT N gN/m^2 T - 516 LIG_LITN_1m LIG_LIT N to 1 meter gN/m^2 F - 517 LIG_LITN_TNDNCY_VERT_TRA lignin litter N tendency due to vertical transport gN/m^3/s F - 518 LIG_LITN_TO_SLO_SOMN decomp. of lignin litter N to slow soil organic ma N gN/m^2 F - 519 LIG_LITN_TO_SLO_SOMN_vr decomp. of lignin litter N to slow soil organic ma N gN/m^3 F - 520 LIG_LITN_vr LIG_LIT N (vertically resolved) gN/m^3 T - 521 LIG_LIT_HR Het. Resp. from lignin litter gC/m^2/s F - 522 LIG_LIT_HR_vr Het. Resp. from lignin litter gC/m^3/s F - 523 LIQCAN intercepted liquid water mm T - 524 LIQUID_CONTENT1 initial gridcell total liq content mm T - 525 LIQUID_CONTENT2 post landuse change gridcell total liq content mm F - 526 LIQUID_WATER_TEMP1 initial gridcell weighted average liquid water temperature K F - 527 LITFALL litterfall (leaves and fine roots) gC/m^2/s T - 528 LITFIRE litter fire losses gC/m^2/s F - 529 LITTERC_HR litter C heterotrophic respiration gC/m^2/s T - 530 LITTERC_LOSS litter C loss gC/m^2/s T - 531 LIVECROOTC live coarse root C gC/m^2 T - 532 LIVECROOTC_STORAGE live coarse root C storage gC/m^2 F - 533 LIVECROOTC_STORAGE_TO_XFER live coarse root C shift storage to transfer gC/m^2/s F - 534 LIVECROOTC_TO_DEADCROOTC live coarse root C turnover gC/m^2/s F - 535 LIVECROOTC_XFER live coarse root C transfer gC/m^2 F - 536 LIVECROOTC_XFER_TO_LIVECROOTC live coarse root C growth from storage gC/m^2/s F - 537 LIVECROOTN live coarse root N gN/m^2 T - 538 LIVECROOTN_STORAGE live coarse root N storage gN/m^2 F - 539 LIVECROOTN_STORAGE_TO_XFER live coarse root N shift storage to transfer gN/m^2/s F - 540 LIVECROOTN_TO_DEADCROOTN live coarse root N turnover gN/m^2/s F - 541 LIVECROOTN_TO_RETRANSN live coarse root N to retranslocated N pool gN/m^2/s F - 542 LIVECROOTN_XFER live coarse root N transfer gN/m^2 F - 543 LIVECROOTN_XFER_TO_LIVECROOTN live coarse root N growth from storage gN/m^2/s F - 544 LIVECROOT_MR live coarse root maintenance respiration gC/m^2/s F - 545 LIVESTEMC live stem C gC/m^2 T - 546 LIVESTEMC_STORAGE live stem C storage gC/m^2 F - 547 LIVESTEMC_STORAGE_TO_XFER live stem C shift storage to transfer gC/m^2/s F - 548 LIVESTEMC_TO_BIOFUELC livestem C to biofuel C gC/m^2/s T - 549 LIVESTEMC_TO_DEADSTEMC live stem C turnover gC/m^2/s F - 550 LIVESTEMC_XFER live stem C transfer gC/m^2 F - 551 LIVESTEMC_XFER_TO_LIVESTEMC live stem C growth from storage gC/m^2/s F - 552 LIVESTEMN live stem N gN/m^2 T - 553 LIVESTEMN_STORAGE live stem N storage gN/m^2 F - 554 LIVESTEMN_STORAGE_TO_XFER live stem N shift storage to transfer gN/m^2/s F - 555 LIVESTEMN_TO_DEADSTEMN live stem N turnover gN/m^2/s F - 556 LIVESTEMN_TO_RETRANSN live stem N to retranslocated N pool gN/m^2/s F - 557 LIVESTEMN_XFER live stem N transfer gN/m^2 F - 558 LIVESTEMN_XFER_TO_LIVESTEMN live stem N growth from storage gN/m^2/s F - 559 LIVESTEM_MR live stem maintenance respiration gC/m^2/s F - 560 LNC leaf N concentration gN leaf/m^2 T - 561 LWdown atmospheric longwave radiation (downscaled to columns in glacier regions) W/m^2 F - 562 LWup upwelling longwave radiation W/m^2 F - 563 MEG_acetaldehyde MEGAN flux kg/m2/sec T - 564 MEG_acetic_acid MEGAN flux kg/m2/sec T - 565 MEG_acetone MEGAN flux kg/m2/sec T - 566 MEG_carene_3 MEGAN flux kg/m2/sec T - 567 MEG_ethanol MEGAN flux kg/m2/sec T - 568 MEG_formaldehyde MEGAN flux kg/m2/sec T - 569 MEG_isoprene MEGAN flux kg/m2/sec T - 570 MEG_methanol MEGAN flux kg/m2/sec T - 571 MEG_pinene_a MEGAN flux kg/m2/sec T - 572 MEG_thujene_a MEGAN flux kg/m2/sec T - 573 MET_LITC MET_LIT C gC/m^2 T - 574 MET_LITC_1m MET_LIT C to 1 meter gC/m^2 F - 575 MET_LITC_TNDNCY_VERT_TRA metabolic litter C tendency due to vertical transport gC/m^3/s F - 576 MET_LITC_TO_ACT_SOMC decomp. of metabolic litter C to active soil organic C gC/m^2/s F - 577 MET_LITC_TO_ACT_SOMC_vr decomp. of metabolic litter C to active soil organic C gC/m^3/s F - 578 MET_LITC_vr MET_LIT C (vertically resolved) gC/m^3 T - 579 MET_LITN MET_LIT N gN/m^2 T - 580 MET_LITN_1m MET_LIT N to 1 meter gN/m^2 F - 581 MET_LITN_TNDNCY_VERT_TRA metabolic litter N tendency due to vertical transport gN/m^3/s F - 582 MET_LITN_TO_ACT_SOMN decomp. of metabolic litter N to active soil organic N gN/m^2 F - 583 MET_LITN_TO_ACT_SOMN_vr decomp. of metabolic litter N to active soil organic N gN/m^3 F - 584 MET_LITN_vr MET_LIT N (vertically resolved) gN/m^3 T - 585 MET_LIT_HR Het. Resp. from metabolic litter gC/m^2/s F - 586 MET_LIT_HR_vr Het. Resp. from metabolic litter gC/m^3/s F - 587 MR maintenance respiration gC/m^2/s T - 588 M_ACT_SOMC_TO_LEACHING active soil organic C leaching loss gC/m^2/s F - 589 M_ACT_SOMN_TO_LEACHING active soil organic N leaching loss gN/m^2/s F - 590 M_CEL_LITC_TO_FIRE cellulosic litter C fire loss gC/m^2/s F - 591 M_CEL_LITC_TO_FIRE_vr cellulosic litter C fire loss gC/m^3/s F - 592 M_CEL_LITC_TO_LEACHING cellulosic litter C leaching loss gC/m^2/s F - 593 M_CEL_LITN_TO_FIRE cellulosic litter N fire loss gN/m^2 F - 594 M_CEL_LITN_TO_FIRE_vr cellulosic litter N fire loss gN/m^3 F - 595 M_CEL_LITN_TO_LEACHING cellulosic litter N leaching loss gN/m^2/s F - 596 M_CWDC_TO_FIRE coarse woody debris C fire loss gC/m^2/s F - 597 M_CWDC_TO_FIRE_vr coarse woody debris C fire loss gC/m^3/s F - 598 M_CWDN_TO_FIRE coarse woody debris N fire loss gN/m^2 F - 599 M_CWDN_TO_FIRE_vr coarse woody debris N fire loss gN/m^3 F - 600 M_DEADCROOTC_STORAGE_TO_LITTER dead coarse root C storage mortality gC/m^2/s F - 601 M_DEADCROOTC_STORAGE_TO_LITTER_FIRE dead coarse root C storage fire mortality to litter gC/m^2/s F - 602 M_DEADCROOTC_TO_LITTER dead coarse root C mortality gC/m^2/s F - 603 M_DEADCROOTC_XFER_TO_LITTER dead coarse root C transfer mortality gC/m^2/s F - 604 M_DEADCROOTN_STORAGE_TO_FIRE dead coarse root N storage fire loss gN/m^2/s F - 605 M_DEADCROOTN_STORAGE_TO_LITTER dead coarse root N storage mortality gN/m^2/s F - 606 M_DEADCROOTN_TO_FIRE dead coarse root N fire loss gN/m^2/s F - 607 M_DEADCROOTN_TO_LITTER dead coarse root N mortality gN/m^2/s F - 608 M_DEADCROOTN_TO_LITTER_FIRE dead coarse root N fire mortality to litter gN/m^2/s F - 609 M_DEADCROOTN_XFER_TO_FIRE dead coarse root N transfer fire loss gN/m^2/s F - 610 M_DEADCROOTN_XFER_TO_LITTER dead coarse root N transfer mortality gN/m^2/s F - 611 M_DEADROOTC_STORAGE_TO_FIRE dead root C storage fire loss gC/m^2/s F - 612 M_DEADROOTC_STORAGE_TO_LITTER_FIRE dead root C storage fire mortality to litter gC/m^2/s F - 613 M_DEADROOTC_TO_FIRE dead root C fire loss gC/m^2/s F - 614 M_DEADROOTC_TO_LITTER_FIRE dead root C fire mortality to litter gC/m^2/s F - 615 M_DEADROOTC_XFER_TO_FIRE dead root C transfer fire loss gC/m^2/s F - 616 M_DEADROOTC_XFER_TO_LITTER_FIRE dead root C transfer fire mortality to litter gC/m^2/s F - 617 M_DEADSTEMC_STORAGE_TO_FIRE dead stem C storage fire loss gC/m^2/s F - 618 M_DEADSTEMC_STORAGE_TO_LITTER dead stem C storage mortality gC/m^2/s F - 619 M_DEADSTEMC_STORAGE_TO_LITTER_FIRE dead stem C storage fire mortality to litter gC/m^2/s F - 620 M_DEADSTEMC_TO_FIRE dead stem C fire loss gC/m^2/s F - 621 M_DEADSTEMC_TO_LITTER dead stem C mortality gC/m^2/s F - 622 M_DEADSTEMC_TO_LITTER_FIRE dead stem C fire mortality to litter gC/m^2/s F - 623 M_DEADSTEMC_XFER_TO_FIRE dead stem C transfer fire loss gC/m^2/s F - 624 M_DEADSTEMC_XFER_TO_LITTER dead stem C transfer mortality gC/m^2/s F - 625 M_DEADSTEMC_XFER_TO_LITTER_FIRE dead stem C transfer fire mortality to litter gC/m^2/s F - 626 M_DEADSTEMN_STORAGE_TO_FIRE dead stem N storage fire loss gN/m^2/s F - 627 M_DEADSTEMN_STORAGE_TO_LITTER dead stem N storage mortality gN/m^2/s F - 628 M_DEADSTEMN_TO_FIRE dead stem N fire loss gN/m^2/s F - 629 M_DEADSTEMN_TO_LITTER dead stem N mortality gN/m^2/s F - 630 M_DEADSTEMN_TO_LITTER_FIRE dead stem N fire mortality to litter gN/m^2/s F - 631 M_DEADSTEMN_XFER_TO_FIRE dead stem N transfer fire loss gN/m^2/s F - 632 M_DEADSTEMN_XFER_TO_LITTER dead stem N transfer mortality gN/m^2/s F - 633 M_FROOTC_STORAGE_TO_FIRE fine root C storage fire loss gC/m^2/s F - 634 M_FROOTC_STORAGE_TO_LITTER fine root C storage mortality gC/m^2/s F - 635 M_FROOTC_STORAGE_TO_LITTER_FIRE fine root C storage fire mortality to litter gC/m^2/s F - 636 M_FROOTC_TO_FIRE fine root C fire loss gC/m^2/s F - 637 M_FROOTC_TO_LITTER fine root C mortality gC/m^2/s F - 638 M_FROOTC_TO_LITTER_FIRE fine root C fire mortality to litter gC/m^2/s F - 639 M_FROOTC_XFER_TO_FIRE fine root C transfer fire loss gC/m^2/s F - 640 M_FROOTC_XFER_TO_LITTER fine root C transfer mortality gC/m^2/s F - 641 M_FROOTC_XFER_TO_LITTER_FIRE fine root C transfer fire mortality to litter gC/m^2/s F - 642 M_FROOTN_STORAGE_TO_FIRE fine root N storage fire loss gN/m^2/s F - 643 M_FROOTN_STORAGE_TO_LITTER fine root N storage mortality gN/m^2/s F - 644 M_FROOTN_TO_FIRE fine root N fire loss gN/m^2/s F - 645 M_FROOTN_TO_LITTER fine root N mortality gN/m^2/s F - 646 M_FROOTN_XFER_TO_FIRE fine root N transfer fire loss gN/m^2/s F - 647 M_FROOTN_XFER_TO_LITTER fine root N transfer mortality gN/m^2/s F - 648 M_GRESP_STORAGE_TO_FIRE growth respiration storage fire loss gC/m^2/s F - 649 M_GRESP_STORAGE_TO_LITTER growth respiration storage mortality gC/m^2/s F - 650 M_GRESP_STORAGE_TO_LITTER_FIRE growth respiration storage fire mortality to litter gC/m^2/s F - 651 M_GRESP_XFER_TO_FIRE growth respiration transfer fire loss gC/m^2/s F - 652 M_GRESP_XFER_TO_LITTER growth respiration transfer mortality gC/m^2/s F - 653 M_GRESP_XFER_TO_LITTER_FIRE growth respiration transfer fire mortality to litter gC/m^2/s F - 654 M_LEAFC_STORAGE_TO_FIRE leaf C storage fire loss gC/m^2/s F - 655 M_LEAFC_STORAGE_TO_LITTER leaf C storage mortality gC/m^2/s F - 656 M_LEAFC_STORAGE_TO_LITTER_FIRE leaf C fire mortality to litter gC/m^2/s F - 657 M_LEAFC_TO_FIRE leaf C fire loss gC/m^2/s F - 658 M_LEAFC_TO_LITTER leaf C mortality gC/m^2/s F - 659 M_LEAFC_TO_LITTER_FIRE leaf C fire mortality to litter gC/m^2/s F - 660 M_LEAFC_XFER_TO_FIRE leaf C transfer fire loss gC/m^2/s F - 661 M_LEAFC_XFER_TO_LITTER leaf C transfer mortality gC/m^2/s F - 662 M_LEAFC_XFER_TO_LITTER_FIRE leaf C transfer fire mortality to litter gC/m^2/s F - 663 M_LEAFN_STORAGE_TO_FIRE leaf N storage fire loss gN/m^2/s F - 664 M_LEAFN_STORAGE_TO_LITTER leaf N storage mortality gN/m^2/s F - 665 M_LEAFN_TO_FIRE leaf N fire loss gN/m^2/s F - 666 M_LEAFN_TO_LITTER leaf N mortality gN/m^2/s F - 667 M_LEAFN_XFER_TO_FIRE leaf N transfer fire loss gN/m^2/s F - 668 M_LEAFN_XFER_TO_LITTER leaf N transfer mortality gN/m^2/s F - 669 M_LIG_LITC_TO_FIRE lignin litter C fire loss gC/m^2/s F - 670 M_LIG_LITC_TO_FIRE_vr lignin litter C fire loss gC/m^3/s F - 671 M_LIG_LITC_TO_LEACHING lignin litter C leaching loss gC/m^2/s F - 672 M_LIG_LITN_TO_FIRE lignin litter N fire loss gN/m^2 F - 673 M_LIG_LITN_TO_FIRE_vr lignin litter N fire loss gN/m^3 F - 674 M_LIG_LITN_TO_LEACHING lignin litter N leaching loss gN/m^2/s F - 675 M_LIVECROOTC_STORAGE_TO_LITTER live coarse root C storage mortality gC/m^2/s F - 676 M_LIVECROOTC_STORAGE_TO_LITTER_FIRE live coarse root C fire mortality to litter gC/m^2/s F - 677 M_LIVECROOTC_TO_LITTER live coarse root C mortality gC/m^2/s F - 678 M_LIVECROOTC_XFER_TO_LITTER live coarse root C transfer mortality gC/m^2/s F - 679 M_LIVECROOTN_STORAGE_TO_FIRE live coarse root N storage fire loss gN/m^2/s F - 680 M_LIVECROOTN_STORAGE_TO_LITTER live coarse root N storage mortality gN/m^2/s F - 681 M_LIVECROOTN_TO_FIRE live coarse root N fire loss gN/m^2/s F - 682 M_LIVECROOTN_TO_LITTER live coarse root N mortality gN/m^2/s F - 683 M_LIVECROOTN_XFER_TO_FIRE live coarse root N transfer fire loss gN/m^2/s F - 684 M_LIVECROOTN_XFER_TO_LITTER live coarse root N transfer mortality gN/m^2/s F - 685 M_LIVEROOTC_STORAGE_TO_FIRE live root C storage fire loss gC/m^2/s F - 686 M_LIVEROOTC_STORAGE_TO_LITTER_FIRE live root C storage fire mortality to litter gC/m^2/s F - 687 M_LIVEROOTC_TO_DEADROOTC_FIRE live root C fire mortality to dead root C gC/m^2/s F - 688 M_LIVEROOTC_TO_FIRE live root C fire loss gC/m^2/s F - 689 M_LIVEROOTC_TO_LITTER_FIRE live root C fire mortality to litter gC/m^2/s F - 690 M_LIVEROOTC_XFER_TO_FIRE live root C transfer fire loss gC/m^2/s F - 691 M_LIVEROOTC_XFER_TO_LITTER_FIRE live root C transfer fire mortality to litter gC/m^2/s F - 692 M_LIVESTEMC_STORAGE_TO_FIRE live stem C storage fire loss gC/m^2/s F - 693 M_LIVESTEMC_STORAGE_TO_LITTER live stem C storage mortality gC/m^2/s F - 694 M_LIVESTEMC_STORAGE_TO_LITTER_FIRE live stem C storage fire mortality to litter gC/m^2/s F - 695 M_LIVESTEMC_TO_DEADSTEMC_FIRE live stem C fire mortality to dead stem C gC/m^2/s F - 696 M_LIVESTEMC_TO_FIRE live stem C fire loss gC/m^2/s F - 697 M_LIVESTEMC_TO_LITTER live stem C mortality gC/m^2/s F - 698 M_LIVESTEMC_TO_LITTER_FIRE live stem C fire mortality to litter gC/m^2/s F - 699 M_LIVESTEMC_XFER_TO_FIRE live stem C transfer fire loss gC/m^2/s F - 700 M_LIVESTEMC_XFER_TO_LITTER live stem C transfer mortality gC/m^2/s F - 701 M_LIVESTEMC_XFER_TO_LITTER_FIRE live stem C transfer fire mortality to litter gC/m^2/s F - 702 M_LIVESTEMN_STORAGE_TO_FIRE live stem N storage fire loss gN/m^2/s F - 703 M_LIVESTEMN_STORAGE_TO_LITTER live stem N storage mortality gN/m^2/s F - 704 M_LIVESTEMN_TO_FIRE live stem N fire loss gN/m^2/s F - 705 M_LIVESTEMN_TO_LITTER live stem N mortality gN/m^2/s F - 706 M_LIVESTEMN_XFER_TO_FIRE live stem N transfer fire loss gN/m^2/s F - 707 M_LIVESTEMN_XFER_TO_LITTER live stem N transfer mortality gN/m^2/s F - 708 M_MET_LITC_TO_FIRE metabolic litter C fire loss gC/m^2/s F - 709 M_MET_LITC_TO_FIRE_vr metabolic litter C fire loss gC/m^3/s F - 710 M_MET_LITC_TO_LEACHING metabolic litter C leaching loss gC/m^2/s F - 711 M_MET_LITN_TO_FIRE metabolic litter N fire loss gN/m^2 F - 712 M_MET_LITN_TO_FIRE_vr metabolic litter N fire loss gN/m^3 F - 713 M_MET_LITN_TO_LEACHING metabolic litter N leaching loss gN/m^2/s F - 714 M_PAS_SOMC_TO_LEACHING passive soil organic C leaching loss gC/m^2/s F - 715 M_PAS_SOMN_TO_LEACHING passive soil organic N leaching loss gN/m^2/s F - 716 M_RETRANSN_TO_FIRE retranslocated N pool fire loss gN/m^2/s F - 717 M_RETRANSN_TO_LITTER retranslocated N pool mortality gN/m^2/s F - 718 M_SLO_SOMC_TO_LEACHING slow soil organic ma C leaching loss gC/m^2/s F - 719 M_SLO_SOMN_TO_LEACHING slow soil organic ma N leaching loss gN/m^2/s F - 720 NACTIVE Mycorrhizal N uptake flux gN/m^2/s T - 721 NACTIVE_NH4 Mycorrhizal N uptake flux gN/m^2/s T - 722 NACTIVE_NO3 Mycorrhizal N uptake flux gN/m^2/s T - 723 NAM AM-associated N uptake flux gN/m^2/s T - 724 NAM_NH4 AM-associated N uptake flux gN/m^2/s T - 725 NAM_NO3 AM-associated N uptake flux gN/m^2/s T - 726 NBP net biome production, includes fire, landuse, harvest and hrv_xsmrpool flux (latter smoothed o gC/m^2/s T - 727 NDEPLOY total N deployed in new growth gN/m^2/s T - 728 NDEP_PROF profile for atmospheric N deposition 1/m F - 729 NDEP_TO_SMINN atmospheric N deposition to soil mineral N gN/m^2/s T - 730 NECM ECM-associated N uptake flux gN/m^2/s T - 731 NECM_NH4 ECM-associated N uptake flux gN/m^2/s T - 732 NECM_NO3 ECM-associated N uptake flux gN/m^2/s T - 733 NEE net ecosystem exchange of carbon, includes fire and hrv_xsmrpool (latter smoothed over the yea gC/m^2/s T - 734 NEM Gridcell net adjustment to net carbon exchange passed to atm. for methane production gC/m2/s T - 735 NEP net ecosystem production, excludes fire, landuse, and harvest flux, positive for sink gC/m^2/s T - 736 NET_NMIN net rate of N mineralization gN/m^2/s T - 737 NET_NMIN_vr net rate of N mineralization gN/m^3/s F - 738 NFERTILIZATION fertilizer added gN/m^2/s T - 739 NFIRE fire counts valid only in Reg.C counts/km2/sec T - 740 NFIX Symbiotic BNF uptake flux gN/m^2/s T - 741 NFIXATION_PROF profile for biological N fixation 1/m F - 742 NFIX_TO_SMINN symbiotic/asymbiotic N fixation to soil mineral N gN/m^2/s F - 743 NNONMYC Non-mycorrhizal N uptake flux gN/m^2/s T - 744 NNONMYC_NH4 Non-mycorrhizal N uptake flux gN/m^2/s T - 745 NNONMYC_NO3 Non-mycorrhizal N uptake flux gN/m^2/s T - 746 NPASSIVE Passive N uptake flux gN/m^2/s T - 747 NPOOL temporary plant N pool gN/m^2 T - 748 NPOOL_TO_DEADCROOTN allocation to dead coarse root N gN/m^2/s F - 749 NPOOL_TO_DEADCROOTN_STORAGE allocation to dead coarse root N storage gN/m^2/s F - 750 NPOOL_TO_DEADSTEMN allocation to dead stem N gN/m^2/s F - 751 NPOOL_TO_DEADSTEMN_STORAGE allocation to dead stem N storage gN/m^2/s F - 752 NPOOL_TO_FROOTN allocation to fine root N gN/m^2/s F - 753 NPOOL_TO_FROOTN_STORAGE allocation to fine root N storage gN/m^2/s F - 754 NPOOL_TO_LEAFN allocation to leaf N gN/m^2/s F - 755 NPOOL_TO_LEAFN_STORAGE allocation to leaf N storage gN/m^2/s F - 756 NPOOL_TO_LIVECROOTN allocation to live coarse root N gN/m^2/s F - 757 NPOOL_TO_LIVECROOTN_STORAGE allocation to live coarse root N storage gN/m^2/s F - 758 NPOOL_TO_LIVESTEMN allocation to live stem N gN/m^2/s F - 759 NPOOL_TO_LIVESTEMN_STORAGE allocation to live stem N storage gN/m^2/s F - 760 NPP net primary production gC/m^2/s T - 761 NPP_BURNEDOFF C that cannot be used for N uptake gC/m^2/s F - 762 NPP_GROWTH Total C used for growth in FUN gC/m^2/s T - 763 NPP_NACTIVE Mycorrhizal N uptake used C gC/m^2/s T - 764 NPP_NACTIVE_NH4 Mycorrhizal N uptake use C gC/m^2/s T - 765 NPP_NACTIVE_NO3 Mycorrhizal N uptake used C gC/m^2/s T - 766 NPP_NAM AM-associated N uptake used C gC/m^2/s T - 767 NPP_NAM_NH4 AM-associated N uptake use C gC/m^2/s T - 768 NPP_NAM_NO3 AM-associated N uptake use C gC/m^2/s T - 769 NPP_NECM ECM-associated N uptake used C gC/m^2/s T - 770 NPP_NECM_NH4 ECM-associated N uptake use C gC/m^2/s T - 771 NPP_NECM_NO3 ECM-associated N uptake used C gC/m^2/s T - 772 NPP_NFIX Symbiotic BNF uptake used C gC/m^2/s T - 773 NPP_NNONMYC Non-mycorrhizal N uptake used C gC/m^2/s T - 774 NPP_NNONMYC_NH4 Non-mycorrhizal N uptake use C gC/m^2/s T - 775 NPP_NNONMYC_NO3 Non-mycorrhizal N uptake use C gC/m^2/s T - 776 NPP_NRETRANS Retranslocated N uptake flux gC/m^2/s T - 777 NPP_NUPTAKE Total C used by N uptake in FUN gC/m^2/s T - 778 NRETRANS Retranslocated N uptake flux gN/m^2/s T - 779 NRETRANS_REG Retranslocated N uptake flux gN/m^2/s T - 780 NRETRANS_SEASON Retranslocated N uptake flux gN/m^2/s T - 781 NRETRANS_STRESS Retranslocated N uptake flux gN/m^2/s T - 782 NSUBSTEPS number of adaptive timesteps in CLM timestep unitless F - 783 NUPTAKE Total N uptake of FUN gN/m^2/s T - 784 NUPTAKE_NPP_FRACTION frac of NPP used in N uptake - T - 785 N_ALLOMETRY N allocation index none F - 786 O2_DECOMP_DEPTH_UNSAT O2 consumption from HR and AR for non-inundated area mol/m3/s F - 787 OBU Monin-Obukhov length m F - 788 OCDEP total OC deposition (dry+wet) from atmosphere kg/m^2/s T - 789 OFFSET_COUNTER offset days counter days F - 790 OFFSET_FDD offset freezing degree days counter C degree-days F - 791 OFFSET_FLAG offset flag none F - 792 OFFSET_SWI offset soil water index none F - 793 ONSET_COUNTER onset days counter days F - 794 ONSET_FDD onset freezing degree days counter C degree-days F - 795 ONSET_FLAG onset flag none F - 796 ONSET_GDD onset growing degree days C degree-days F - 797 ONSET_GDDFLAG onset flag for growing degree day sum none F - 798 ONSET_SWI onset soil water index none F - 799 O_SCALAR fraction by which decomposition is reduced due to anoxia unitless T - 800 PAR240DZ 10-day running mean of daytime patch absorbed PAR for leaves for top canopy layer W/m^2 F - 801 PAR240XZ 10-day running mean of maximum patch absorbed PAR for leaves for top canopy layer W/m^2 F - 802 PAR240_shade shade PAR (240 hrs) umol/m2/s F - 803 PAR240_sun sunlit PAR (240 hrs) umol/m2/s F - 804 PAR24_shade shade PAR (24 hrs) umol/m2/s F - 805 PAR24_sun sunlit PAR (24 hrs) umol/m2/s F - 806 PARVEGLN absorbed par by vegetation at local noon W/m^2 T - 807 PAR_shade shade PAR umol/m2/s F - 808 PAR_sun sunlit PAR umol/m2/s F - 809 PAS_SOMC PAS_SOM C gC/m^2 T - 810 PAS_SOMC_1m PAS_SOM C to 1 meter gC/m^2 F - 811 PAS_SOMC_TNDNCY_VERT_TRA passive soil organic C tendency due to vertical transport gC/m^3/s F - 812 PAS_SOMC_TO_ACT_SOMC decomp. of passive soil organic C to active soil organic C gC/m^2/s F - 813 PAS_SOMC_TO_ACT_SOMC_vr decomp. of passive soil organic C to active soil organic C gC/m^3/s F - 814 PAS_SOMC_vr PAS_SOM C (vertically resolved) gC/m^3 T - 815 PAS_SOMN PAS_SOM N gN/m^2 T - 816 PAS_SOMN_1m PAS_SOM N to 1 meter gN/m^2 F - 817 PAS_SOMN_TNDNCY_VERT_TRA passive soil organic N tendency due to vertical transport gN/m^3/s F - 818 PAS_SOMN_TO_ACT_SOMN decomp. of passive soil organic N to active soil organic N gN/m^2 F - 819 PAS_SOMN_TO_ACT_SOMN_vr decomp. of passive soil organic N to active soil organic N gN/m^3 F - 820 PAS_SOMN_vr PAS_SOM N (vertically resolved) gN/m^3 T - 821 PAS_SOM_HR Het. Resp. from passive soil organic gC/m^2/s F - 822 PAS_SOM_HR_vr Het. Resp. from passive soil organic gC/m^3/s F - 823 PBOT atmospheric pressure at surface (downscaled to columns in glacier regions) Pa T - 824 PBOT_240 10 day running mean of air pressure Pa F - 825 PCH4 atmospheric partial pressure of CH4 Pa T - 826 PCO2 atmospheric partial pressure of CO2 Pa T - 827 PCO2_240 10 day running mean of CO2 pressure Pa F - 828 PFT_CTRUNC patch-level sink for C truncation gC/m^2 F - 829 PFT_FIRE_CLOSS total patch-level fire C loss for non-peat fires outside land-type converted region gC/m^2/s T - 830 PFT_FIRE_NLOSS total patch-level fire N loss gN/m^2/s T - 831 PFT_NTRUNC patch-level sink for N truncation gN/m^2 F - 832 PLANTCN Plant C:N used by FUN unitless F - 833 PLANT_CALLOC total allocated C flux gC/m^2/s F - 834 PLANT_NALLOC total allocated N flux gN/m^2/s F - 835 PLANT_NDEMAND N flux required to support initial GPP gN/m^2/s T - 836 PNLCZ Proportion of nitrogen allocated for light capture unitless F - 837 PO2_240 10 day running mean of O2 pressure Pa F - 838 POTENTIAL_IMMOB potential N immobilization gN/m^2/s T - 839 POTENTIAL_IMMOB_vr potential N immobilization gN/m^3/s F - 840 POT_F_DENIT potential denitrification flux gN/m^2/s T - 841 POT_F_DENIT_vr potential denitrification flux gN/m^3/s F - 842 POT_F_NIT potential nitrification flux gN/m^2/s T - 843 POT_F_NIT_vr potential nitrification flux gN/m^3/s F - 844 PREC10 10-day running mean of PREC MM H2O/S F - 845 PREC60 60-day running mean of PREC MM H2O/S F - 846 PREV_DAYL daylength from previous timestep s F - 847 PREV_FROOTC_TO_LITTER previous timestep froot C litterfall flux gC/m^2/s F - 848 PREV_LEAFC_TO_LITTER previous timestep leaf C litterfall flux gC/m^2/s F - 849 PROD100C 100-yr wood product C gC/m^2 F - 850 PROD100C_LOSS loss from 100-yr wood product pool gC/m^2/s F - 851 PROD100N 100-yr wood product N gN/m^2 F - 852 PROD100N_LOSS loss from 100-yr wood product pool gN/m^2/s F - 853 PROD10C 10-yr wood product C gC/m^2 F - 854 PROD10C_LOSS loss from 10-yr wood product pool gC/m^2/s F - 855 PROD10N 10-yr wood product N gN/m^2 F - 856 PROD10N_LOSS loss from 10-yr wood product pool gN/m^2/s F - 857 PSNSHA shaded leaf photosynthesis umolCO2/m^2/s T - 858 PSNSHADE_TO_CPOOL C fixation from shaded canopy gC/m^2/s T - 859 PSNSUN sunlit leaf photosynthesis umolCO2/m^2/s T - 860 PSNSUN_TO_CPOOL C fixation from sunlit canopy gC/m^2/s T - 861 PSurf atmospheric pressure at surface (downscaled to columns in glacier regions) Pa F - 862 Q2M 2m specific humidity kg/kg T - 863 QAF canopy air humidity kg/kg F - 864 QBOT atmospheric specific humidity (downscaled to columns in glacier regions) kg/kg T - 865 QDIRECT_THROUGHFALL direct throughfall of liquid (rain + above-canopy irrigation) mm/s F - 866 QDIRECT_THROUGHFALL_SNOW direct throughfall of snow mm/s F - 867 QDRAI sub-surface drainage mm/s T - 868 QDRAI_PERCH perched wt drainage mm/s T - 869 QDRAI_XS saturation excess drainage mm/s T - 870 QDRIP rate of excess canopy liquid falling off canopy mm/s F - 871 QDRIP_SNOW rate of excess canopy snow falling off canopy mm/s F - 872 QFLOOD runoff from river flooding mm/s T - 873 QFLX_EVAP_TOT qflx_evap_soi + qflx_evap_can + qflx_tran_veg kg m-2 s-1 T - 874 QFLX_EVAP_VEG vegetation evaporation mm H2O/s F - 875 QFLX_ICE_DYNBAL ice dynamic land cover change conversion runoff flux mm/s T - 876 QFLX_LIQDEW_TO_TOP_LAYER rate of liquid water deposited on top soil or snow layer (dew) mm H2O/s T - 877 QFLX_LIQEVAP_FROM_TOP_LAYER rate of liquid water evaporated from top soil or snow layer mm H2O/s T - 878 QFLX_LIQ_DYNBAL liq dynamic land cover change conversion runoff flux mm/s T - 879 QFLX_LIQ_GRND liquid (rain+irrigation) on ground after interception mm H2O/s F - 880 QFLX_SNOW_DRAIN drainage from snow pack mm/s T - 881 QFLX_SNOW_DRAIN_ICE drainage from snow pack melt (ice landunits only) mm/s T - 882 QFLX_SNOW_GRND snow on ground after interception mm H2O/s F - 883 QFLX_SOLIDDEW_TO_TOP_LAYER rate of solid water deposited on top soil or snow layer (frost) mm H2O/s T - 884 QFLX_SOLIDEVAP_FROM_TOP_LAYER rate of ice evaporated from top soil or snow layer (sublimation) (also includes bare ice subli mm H2O/s T - 885 QFLX_SOLIDEVAP_FROM_TOP_LAYER_ICE rate of ice evaporated from top soil or snow layer (sublimation) (also includes bare ice subli mm H2O/s F - 886 QH2OSFC surface water runoff mm/s T - 887 QH2OSFC_TO_ICE surface water converted to ice mm/s F - 888 QHR hydraulic redistribution mm/s T - 889 QICE ice growth/melt mm/s T - 890 QICE_FORC qice forcing sent to GLC mm/s F - 891 QICE_FRZ ice growth mm/s T - 892 QICE_MELT ice melt mm/s T - 893 QINFL infiltration mm/s T - 894 QINTR interception mm/s T - 895 QIRRIG_DEMAND irrigation demand mm/s F - 896 QIRRIG_DRIP water added via drip irrigation mm/s F - 897 QIRRIG_FROM_GW_CONFINED water added through confined groundwater irrigation mm/s T - 898 QIRRIG_FROM_GW_UNCONFINED water added through unconfined groundwater irrigation mm/s T - 899 QIRRIG_FROM_SURFACE water added through surface water irrigation mm/s T - 900 QIRRIG_SPRINKLER water added via sprinkler irrigation mm/s F - 901 QOVER total surface runoff (includes QH2OSFC) mm/s T - 902 QOVER_LAG time-lagged surface runoff for soil columns mm/s F - 903 QPHSNEG net negative hydraulic redistribution flux mm/s F - 904 QRGWL surface runoff at glaciers (liquid only), wetlands, lakes; also includes melted ice runoff fro mm/s T - 905 QROOTSINK water flux from soil to root in each soil-layer mm/s F - 906 QRUNOFF total liquid runoff not including correction for land use change mm/s T - 907 QRUNOFF_ICE total liquid runoff not incl corret for LULCC (ice landunits only) mm/s T - 908 QRUNOFF_ICE_TO_COUPLER total ice runoff sent to coupler (includes corrections for land use change) mm/s T - 909 QRUNOFF_ICE_TO_LIQ liquid runoff from converted ice runoff mm/s F - 910 QRUNOFF_R Rural total runoff mm/s F - 911 QRUNOFF_TO_COUPLER total liquid runoff sent to coupler (includes corrections for land use change) mm/s T - 912 QRUNOFF_U Urban total runoff mm/s F - 913 QSNOCPLIQ excess liquid h2o due to snow capping not including correction for land use change mm H2O/s T - 914 QSNOEVAP evaporation from snow (only when snl<0, otherwise it is equal to qflx_ev_soil) mm/s T - 915 QSNOFRZ column-integrated snow freezing rate kg/m2/s T - 916 QSNOFRZ_ICE column-integrated snow freezing rate (ice landunits only) mm/s T - 917 QSNOMELT snow melt rate mm/s T - 918 QSNOMELT_ICE snow melt (ice landunits only) mm/s T - 919 QSNOUNLOAD canopy snow unloading mm/s T - 920 QSNO_TEMPUNLOAD canopy snow temp unloading mm/s T - 921 QSNO_WINDUNLOAD canopy snow wind unloading mm/s T - 922 QSNWCPICE excess solid h2o due to snow capping not including correction for land use change mm H2O/s T - 923 QSOIL Ground evaporation (soil/snow evaporation + soil/snow sublimation - dew) mm/s T - 924 QSOIL_ICE Ground evaporation (ice landunits only) mm/s T - 925 QTOPSOIL water input to surface mm/s F - 926 QVEGE canopy evaporation mm/s T - 927 QVEGT canopy transpiration mm/s T - 928 Qair atmospheric specific humidity (downscaled to columns in glacier regions) kg/kg F - 929 Qh sensible heat W/m^2 F - 930 Qle total evaporation W/m^2 F - 931 Qstor storage heat flux (includes snowmelt) W/m^2 F - 932 Qtau momentum flux kg/m/s^2 F - 933 RAH1 aerodynamical resistance s/m F - 934 RAH2 aerodynamical resistance s/m F - 935 RAIN atmospheric rain, after rain/snow repartitioning based on temperature mm/s T - 936 RAIN_FROM_ATM atmospheric rain received from atmosphere (pre-repartitioning) mm/s T - 937 RAIN_ICE atmospheric rain, after rain/snow repartitioning based on temperature (ice landunits only) mm/s F - 938 RAM1 aerodynamical resistance s/m F - 939 RAM_LAKE aerodynamic resistance for momentum (lakes only) s/m F - 940 RAW1 aerodynamical resistance s/m F - 941 RAW2 aerodynamical resistance s/m F - 942 RB leaf boundary resistance s/m F - 943 RB10 10 day running mean boundary layer resistance s/m F - 944 RETRANSN plant pool of retranslocated N gN/m^2 T - 945 RETRANSN_TO_NPOOL deployment of retranslocated N gN/m^2/s T - 946 RH atmospheric relative humidity % F - 947 RH2M 2m relative humidity % T - 948 RH2M_R Rural 2m specific humidity % F - 949 RH2M_U Urban 2m relative humidity % F - 950 RH30 30-day running mean of relative humidity % F - 951 RHAF fractional humidity of canopy air fraction F - 952 RHAF10 10 day running mean of fractional humidity of canopy air fraction F - 953 RH_LEAF fractional humidity at leaf surface fraction F - 954 ROOTR effective fraction of roots in each soil layer (SMS method) proportion F - 955 RR root respiration (fine root MR + total root GR) gC/m^2/s T - 956 RRESIS root resistance in each soil layer proportion F - 957 RSSHA shaded leaf stomatal resistance s/m T - 958 RSSUN sunlit leaf stomatal resistance s/m T - 959 Rainf atmospheric rain, after rain/snow repartitioning based on temperature mm/s F - 960 Rnet net radiation W/m^2 F - 961 SABG solar rad absorbed by ground W/m^2 T - 962 SABG_PEN Rural solar rad penetrating top soil or snow layer watt/m^2 T - 963 SABV solar rad absorbed by veg W/m^2 T - 964 SEEDC pool for seeding new PFTs via dynamic landcover gC/m^2 T - 965 SEEDN pool for seeding new PFTs via dynamic landcover gN/m^2 T - 966 SLASH_HARVESTC slash harvest carbon (to litter) gC/m^2/s T - 967 SLO_SOMC SLO_SOM C gC/m^2 T - 968 SLO_SOMC_1m SLO_SOM C to 1 meter gC/m^2 F - 969 SLO_SOMC_TNDNCY_VERT_TRA slow soil organic ma C tendency due to vertical transport gC/m^3/s F - 970 SLO_SOMC_TO_ACT_SOMC decomp. of slow soil organic ma C to active soil organic C gC/m^2/s F - 971 SLO_SOMC_TO_ACT_SOMC_vr decomp. of slow soil organic ma C to active soil organic C gC/m^3/s F - 972 SLO_SOMC_TO_PAS_SOMC decomp. of slow soil organic ma C to passive soil organic C gC/m^2/s F - 973 SLO_SOMC_TO_PAS_SOMC_vr decomp. of slow soil organic ma C to passive soil organic C gC/m^3/s F - 974 SLO_SOMC_vr SLO_SOM C (vertically resolved) gC/m^3 T - 975 SLO_SOMN SLO_SOM N gN/m^2 T - 976 SLO_SOMN_1m SLO_SOM N to 1 meter gN/m^2 F - 977 SLO_SOMN_TNDNCY_VERT_TRA slow soil organic ma N tendency due to vertical transport gN/m^3/s F - 978 SLO_SOMN_TO_ACT_SOMN decomp. of slow soil organic ma N to active soil organic N gN/m^2 F - 979 SLO_SOMN_TO_ACT_SOMN_vr decomp. of slow soil organic ma N to active soil organic N gN/m^3 F - 980 SLO_SOMN_TO_PAS_SOMN decomp. of slow soil organic ma N to passive soil organic N gN/m^2 F - 981 SLO_SOMN_TO_PAS_SOMN_vr decomp. of slow soil organic ma N to passive soil organic N gN/m^3 F - 982 SLO_SOMN_vr SLO_SOM N (vertically resolved) gN/m^3 T - 983 SLO_SOM_HR_S1 Het. Resp. from slow soil organic ma gC/m^2/s F - 984 SLO_SOM_HR_S1_vr Het. Resp. from slow soil organic ma gC/m^3/s F - 985 SLO_SOM_HR_S3 Het. Resp. from slow soil organic ma gC/m^2/s F - 986 SLO_SOM_HR_S3_vr Het. Resp. from slow soil organic ma gC/m^3/s F - 987 SMINN soil mineral N gN/m^2 T - 988 SMINN_TO_NPOOL deployment of soil mineral N uptake gN/m^2/s T - 989 SMINN_TO_PLANT plant uptake of soil mineral N gN/m^2/s T - 990 SMINN_TO_PLANT_FUN Total soil N uptake of FUN gN/m^2/s T - 991 SMINN_TO_PLANT_vr plant uptake of soil mineral N gN/m^3/s F - 992 SMINN_TO_S1N_L1 mineral N flux for decomp. of MET_LITto ACT_SOM gN/m^2 F - 993 SMINN_TO_S1N_L1_vr mineral N flux for decomp. of MET_LITto ACT_SOM gN/m^3 F - 994 SMINN_TO_S1N_L2 mineral N flux for decomp. of CEL_LITto ACT_SOM gN/m^2 F - 995 SMINN_TO_S1N_L2_vr mineral N flux for decomp. of CEL_LITto ACT_SOM gN/m^3 F - 996 SMINN_TO_S1N_S2 mineral N flux for decomp. of SLO_SOMto ACT_SOM gN/m^2 F - 997 SMINN_TO_S1N_S2_vr mineral N flux for decomp. of SLO_SOMto ACT_SOM gN/m^3 F - 998 SMINN_TO_S1N_S3 mineral N flux for decomp. of PAS_SOMto ACT_SOM gN/m^2 F - 999 SMINN_TO_S1N_S3_vr mineral N flux for decomp. of PAS_SOMto ACT_SOM gN/m^3 F -1000 SMINN_TO_S2N_L3 mineral N flux for decomp. of LIG_LITto SLO_SOM gN/m^2 F -1001 SMINN_TO_S2N_L3_vr mineral N flux for decomp. of LIG_LITto SLO_SOM gN/m^3 F -1002 SMINN_TO_S2N_S1 mineral N flux for decomp. of ACT_SOMto SLO_SOM gN/m^2 F -1003 SMINN_TO_S2N_S1_vr mineral N flux for decomp. of ACT_SOMto SLO_SOM gN/m^3 F -1004 SMINN_TO_S3N_S1 mineral N flux for decomp. of ACT_SOMto PAS_SOM gN/m^2 F -1005 SMINN_TO_S3N_S1_vr mineral N flux for decomp. of ACT_SOMto PAS_SOM gN/m^3 F -1006 SMINN_TO_S3N_S2 mineral N flux for decomp. of SLO_SOMto PAS_SOM gN/m^2 F -1007 SMINN_TO_S3N_S2_vr mineral N flux for decomp. of SLO_SOMto PAS_SOM gN/m^3 F -1008 SMINN_vr soil mineral N gN/m^3 T -1009 SMIN_NH4 soil mineral NH4 gN/m^2 T -1010 SMIN_NH4_TO_PLANT plant uptake of NH4 gN/m^3/s F -1011 SMIN_NH4_vr soil mineral NH4 (vert. res.) gN/m^3 T -1012 SMIN_NO3 soil mineral NO3 gN/m^2 T -1013 SMIN_NO3_LEACHED soil NO3 pool loss to leaching gN/m^2/s T -1014 SMIN_NO3_LEACHED_vr soil NO3 pool loss to leaching gN/m^3/s F -1015 SMIN_NO3_MASSDENS SMIN_NO3_MASSDENS ugN/cm^3 soil F -1016 SMIN_NO3_RUNOFF soil NO3 pool loss to runoff gN/m^2/s T -1017 SMIN_NO3_RUNOFF_vr soil NO3 pool loss to runoff gN/m^3/s F -1018 SMIN_NO3_TO_PLANT plant uptake of NO3 gN/m^3/s F -1019 SMIN_NO3_vr soil mineral NO3 (vert. res.) gN/m^3 T -1020 SMP soil matric potential (natural vegetated and crop landunits only) mm T -1021 SNOBCMCL mass of BC in snow column kg/m2 T -1022 SNOBCMSL mass of BC in top snow layer kg/m2 T -1023 SNOCAN intercepted snow mm T -1024 SNODSTMCL mass of dust in snow column kg/m2 T -1025 SNODSTMSL mass of dust in top snow layer kg/m2 T -1026 SNOFSDSND direct nir incident solar radiation on snow W/m^2 F -1027 SNOFSDSNI diffuse nir incident solar radiation on snow W/m^2 F -1028 SNOFSDSVD direct vis incident solar radiation on snow W/m^2 F -1029 SNOFSDSVI diffuse vis incident solar radiation on snow W/m^2 F -1030 SNOFSRND direct nir reflected solar radiation from snow W/m^2 T -1031 SNOFSRNI diffuse nir reflected solar radiation from snow W/m^2 T -1032 SNOFSRVD direct vis reflected solar radiation from snow W/m^2 T -1033 SNOFSRVI diffuse vis reflected solar radiation from snow W/m^2 T -1034 SNOINTABS Fraction of incoming solar absorbed by lower snow layers - T -1035 SNOLIQFL top snow layer liquid water fraction (land) fraction F -1036 SNOOCMCL mass of OC in snow column kg/m2 T -1037 SNOOCMSL mass of OC in top snow layer kg/m2 T -1038 SNORDSL top snow layer effective grain radius m^-6 F -1039 SNOTTOPL snow temperature (top layer) K F -1040 SNOTTOPL_ICE snow temperature (top layer, ice landunits only) K F -1041 SNOTXMASS snow temperature times layer mass, layer sum; to get mass-weighted temperature, divide by (SNO K kg/m2 T -1042 SNOTXMASS_ICE snow temperature times layer mass, layer sum (ice landunits only); to get mass-weighted temper K kg/m2 F -1043 SNOW atmospheric snow, after rain/snow repartitioning based on temperature mm/s T -1044 SNOWDP gridcell mean snow height m T -1045 SNOWICE snow ice kg/m2 T -1046 SNOWICE_ICE snow ice (ice landunits only) kg/m2 F -1047 SNOWLIQ snow liquid water kg/m2 T -1048 SNOWLIQ_ICE snow liquid water (ice landunits only) kg/m2 F -1049 SNOW_5D 5day snow avg m F -1050 SNOW_DEPTH snow height of snow covered area m T -1051 SNOW_DEPTH_ICE snow height of snow covered area (ice landunits only) m F -1052 SNOW_FROM_ATM atmospheric snow received from atmosphere (pre-repartitioning) mm/s T -1053 SNOW_ICE atmospheric snow, after rain/snow repartitioning based on temperature (ice landunits only) mm/s F -1054 SNOW_PERSISTENCE Length of time of continuous snow cover (nat. veg. landunits only) seconds T -1055 SNOW_SINKS snow sinks (liquid water) mm/s T -1056 SNOW_SOURCES snow sources (liquid water) mm/s T -1057 SNO_ABS Absorbed solar radiation in each snow layer W/m^2 F -1058 SNO_ABS_ICE Absorbed solar radiation in each snow layer (ice landunits only) W/m^2 F -1059 SNO_BW Partial density of water in the snow pack (ice + liquid) kg/m3 F -1060 SNO_BW_ICE Partial density of water in the snow pack (ice + liquid, ice landunits only) kg/m3 F -1061 SNO_EXISTENCE Fraction of averaging period for which each snow layer existed unitless F -1062 SNO_FRZ snow freezing rate in each snow layer kg/m2/s F -1063 SNO_FRZ_ICE snow freezing rate in each snow layer (ice landunits only) mm/s F -1064 SNO_GS Mean snow grain size Microns F -1065 SNO_GS_ICE Mean snow grain size (ice landunits only) Microns F -1066 SNO_ICE Snow ice content kg/m2 F -1067 SNO_LIQH2O Snow liquid water content kg/m2 F -1068 SNO_MELT snow melt rate in each snow layer mm/s F -1069 SNO_MELT_ICE snow melt rate in each snow layer (ice landunits only) mm/s F -1070 SNO_T Snow temperatures K F -1071 SNO_TK Thermal conductivity W/m-K F -1072 SNO_TK_ICE Thermal conductivity (ice landunits only) W/m-K F -1073 SNO_T_ICE Snow temperatures (ice landunits only) K F -1074 SNO_Z Snow layer thicknesses m F -1075 SNO_Z_ICE Snow layer thicknesses (ice landunits only) m F -1076 SNOdTdzL top snow layer temperature gradient (land) K/m F -1077 SOIL10 10-day running mean of 12cm layer soil K F -1078 SOILC_CHANGE C change in soil gC/m^2/s T -1079 SOILC_HR soil C heterotrophic respiration gC/m^2/s T -1080 SOILC_vr SOIL C (vertically resolved) gC/m^3 T -1081 SOILICE soil ice (natural vegetated and crop landunits only) kg/m2 T -1082 SOILLIQ soil liquid water (natural vegetated and crop landunits only) kg/m2 T -1083 SOILN_vr SOIL N (vertically resolved) gN/m^3 T -1084 SOILPSI soil water potential in each soil layer MPa F -1085 SOILRESIS soil resistance to evaporation s/m T -1086 SOILWATER_10CM soil liquid water + ice in top 10cm of soil (veg landunits only) kg/m2 T -1087 SOMC_FIRE C loss due to peat burning gC/m^2/s T -1088 SOMFIRE soil organic matter fire losses gC/m^2/s F -1089 SOM_ADV_COEF advection term for vertical SOM translocation m/s F -1090 SOM_C_LEACHED total flux of C from SOM pools due to leaching gC/m^2/s T -1091 SOM_DIFFUS_COEF diffusion coefficient for vertical SOM translocation m^2/s F -1092 SOM_N_LEACHED total flux of N from SOM pools due to leaching gN/m^2/s F -1093 SR total soil respiration (HR + root resp) gC/m^2/s T -1094 SSRE_FSR surface snow effect on reflected solar radiation W/m^2 T -1095 SSRE_FSRND surface snow effect on direct nir reflected solar radiation W/m^2 T -1096 SSRE_FSRNDLN surface snow effect on direct nir reflected solar radiation at local noon W/m^2 T -1097 SSRE_FSRNI surface snow effect on diffuse nir reflected solar radiation W/m^2 T -1098 SSRE_FSRVD surface snow radiatve effect on direct vis reflected solar radiation W/m^2 T -1099 SSRE_FSRVDLN surface snow radiatve effect on direct vis reflected solar radiation at local noon W/m^2 T -1100 SSRE_FSRVI surface snow radiatve effect on diffuse vis reflected solar radiation W/m^2 T -1101 STEM_PROF profile for litter C and N inputs from stems 1/m F -1102 STORAGE_CDEMAND C use from the C storage pool gC/m^2 F -1103 STORAGE_GR growth resp for growth sent to storage for later display gC/m^2/s F -1104 STORAGE_NDEMAND N demand during the offset period gN/m^2 F -1105 STORVEGC stored vegetation carbon, excluding cpool gC/m^2 T -1106 STORVEGN stored vegetation nitrogen gN/m^2 T -1107 SUPPLEMENT_TO_SMINN supplemental N supply gN/m^2/s T -1108 SUPPLEMENT_TO_SMINN_vr supplemental N supply gN/m^3/s F -1109 SWBGT 2 m Simplified Wetbulb Globe Temp C T -1110 SWBGT_R Rural 2 m Simplified Wetbulb Globe Temp C T -1111 SWBGT_U Urban 2 m Simplified Wetbulb Globe Temp C T -1112 SWMP65 2 m Swamp Cooler Temp 65% Eff C T -1113 SWMP65_R Rural 2 m Swamp Cooler Temp 65% Eff C T -1114 SWMP65_U Urban 2 m Swamp Cooler Temp 65% Eff C T -1115 SWMP80 2 m Swamp Cooler Temp 80% Eff C T -1116 SWMP80_R Rural 2 m Swamp Cooler Temp 80% Eff C T -1117 SWMP80_U Urban 2 m Swamp Cooler Temp 80% Eff C T -1118 SWdown atmospheric incident solar radiation W/m^2 F -1119 SWup upwelling shortwave radiation W/m^2 F -1120 SoilAlpha factor limiting ground evap unitless F -1121 SoilAlpha_U urban factor limiting ground evap unitless F -1122 T10 10-day running mean of 2-m temperature K F -1123 TAF canopy air temperature K F -1124 TAUX zonal surface stress kg/m/s^2 T -1125 TAUY meridional surface stress kg/m/s^2 T -1126 TBOT atmospheric air temperature (downscaled to columns in glacier regions) K T -1127 TBUILD internal urban building air temperature K T -1128 TBUILD_MAX prescribed maximum interior building temperature K F -1129 TEMPAVG_T2M temporary average 2m air temperature K F -1130 TEMPMAX_RETRANSN temporary annual max of retranslocated N pool gN/m^2 F -1131 TEMPSUM_POTENTIAL_GPP temporary annual sum of potential GPP gC/m^2/yr F -1132 TEQ 2 m Equiv Temp K T -1133 TEQ_R Rural 2 m Equiv Temp K T -1134 TEQ_U Urban 2 m Equiv Temp K T -1135 TFLOOR floor temperature K F -1136 TG ground temperature K T -1137 TG_ICE ground temperature (ice landunits only) K F -1138 TG_R Rural ground temperature K F -1139 TG_U Urban ground temperature K F -1140 TH2OSFC surface water temperature K T -1141 THBOT atmospheric air potential temperature (downscaled to columns in glacier regions) K T -1142 THIC 2 m Temp Hum Index Comfort C T -1143 THIC_R Rural 2 m Temp Hum Index Comfort C T -1144 THIC_U Urban 2 m Temp Hum Index Comfort C T -1145 THIP 2 m Temp Hum Index Physiology C T -1146 THIP_R Rural 2 m Temp Hum Index Physiology C T -1147 THIP_U Urban 2 m Temp Hum Index Physiology C T -1148 TKE1 top lake level eddy thermal conductivity W/(mK) T -1149 TLAI total projected leaf area index m^2/m^2 T -1150 TLAKE lake temperature K T -1151 TOPO_COL column-level topographic height m F -1152 TOPO_COL_ICE column-level topographic height (ice landunits only) m F -1153 TOPO_FORC topograephic height sent to GLC m F -1154 TOPT topt coefficient for VOC calc non F -1155 TOTCOLC total column carbon, incl veg and cpool but excl product pools gC/m^2 T -1156 TOTCOLCH4 total belowground CH4 (0 for non-lake special landunits in the absence of dynamic landunits) gC/m2 T -1157 TOTCOLN total column-level N, excluding product pools gN/m^2 T -1158 TOTECOSYSC total ecosystem carbon, incl veg but excl cpool and product pools gC/m^2 T -1159 TOTECOSYSN total ecosystem N, excluding product pools gN/m^2 T -1160 TOTFIRE total ecosystem fire losses gC/m^2/s F -1161 TOTLITC total litter carbon gC/m^2 T -1162 TOTLITC_1m total litter carbon to 1 meter depth gC/m^2 T -1163 TOTLITN total litter N gN/m^2 T -1164 TOTLITN_1m total litter N to 1 meter gN/m^2 T -1165 TOTPFTC total patch-level carbon, including cpool gC/m^2 T -1166 TOTPFTN total patch-level nitrogen gN/m^2 T -1167 TOTSOILICE vertically summed soil cie (veg landunits only) kg/m2 T -1168 TOTSOILLIQ vertically summed soil liquid water (veg landunits only) kg/m2 T -1169 TOTSOMC total soil organic matter carbon gC/m^2 T -1170 TOTSOMC_1m total soil organic matter carbon to 1 meter depth gC/m^2 T -1171 TOTSOMN total soil organic matter N gN/m^2 T -1172 TOTSOMN_1m total soil organic matter N to 1 meter gN/m^2 T -1173 TOTVEGC total vegetation carbon, excluding cpool gC/m^2 T -1174 TOTVEGN total vegetation nitrogen gN/m^2 T -1175 TOT_WOODPRODC total wood product C gC/m^2 T -1176 TOT_WOODPRODC_LOSS total loss from wood product pools gC/m^2/s T -1177 TOT_WOODPRODN total wood product N gN/m^2 T -1178 TOT_WOODPRODN_LOSS total loss from wood product pools gN/m^2/s T -1179 TPU25T canopy profile of tpu umol/m2/s T -1180 TRAFFICFLUX sensible heat flux from urban traffic W/m^2 F -1181 TRANSFER_DEADCROOT_GR dead coarse root growth respiration from storage gC/m^2/s F -1182 TRANSFER_DEADSTEM_GR dead stem growth respiration from storage gC/m^2/s F -1183 TRANSFER_FROOT_GR fine root growth respiration from storage gC/m^2/s F -1184 TRANSFER_GR growth resp for transfer growth displayed in this timestep gC/m^2/s F -1185 TRANSFER_LEAF_GR leaf growth respiration from storage gC/m^2/s F -1186 TRANSFER_LIVECROOT_GR live coarse root growth respiration from storage gC/m^2/s F -1187 TRANSFER_LIVESTEM_GR live stem growth respiration from storage gC/m^2/s F -1188 TREFMNAV daily minimum of average 2-m temperature K T -1189 TREFMNAV_R Rural daily minimum of average 2-m temperature K F -1190 TREFMNAV_U Urban daily minimum of average 2-m temperature K F -1191 TREFMXAV daily maximum of average 2-m temperature K T -1192 TREFMXAV_R Rural daily maximum of average 2-m temperature K F -1193 TREFMXAV_U Urban daily maximum of average 2-m temperature K F -1194 TROOF_INNER roof inside surface temperature K F -1195 TSA 2m air temperature K T -1196 TSAI total projected stem area index m^2/m^2 T -1197 TSA_ICE 2m air temperature (ice landunits only) K F -1198 TSA_R Rural 2m air temperature K F -1199 TSA_U Urban 2m air temperature K F -1200 TSHDW_INNER shadewall inside surface temperature K F -1201 TSKIN skin temperature K T -1202 TSL temperature of near-surface soil layer (natural vegetated and crop landunits only) K T -1203 TSOI soil temperature (natural vegetated and crop landunits only) K T -1204 TSOI_10CM soil temperature in top 10cm of soil K T -1205 TSOI_ICE soil temperature (ice landunits only) K T -1206 TSRF_FORC surface temperature sent to GLC K F -1207 TSUNW_INNER sunwall inside surface temperature K F -1208 TV vegetation temperature K T -1209 TV24 vegetation temperature (last 24hrs) K F -1210 TV240 vegetation temperature (last 240hrs) K F -1211 TVEGD10 10 day running mean of patch daytime vegetation temperature Kelvin F -1212 TVEGN10 10 day running mean of patch night-time vegetation temperature Kelvin F -1213 TWS total water storage mm T -1214 T_SCALAR temperature inhibition of decomposition unitless T -1215 Tair atmospheric air temperature (downscaled to columns in glacier regions) K F -1216 Tair_from_atm atmospheric air temperature received from atmosphere (pre-downscaling) K F -1217 U10 10-m wind m/s T -1218 U10_DUST 10-m wind for dust model m/s T -1219 U10_ICE 10-m wind (ice landunits only) m/s F -1220 UAF canopy air speed m/s F -1221 ULRAD upward longwave radiation above the canopy W/m^2 F -1222 UM wind speed plus stability effect m/s F -1223 URBAN_AC urban air conditioning flux W/m^2 T -1224 URBAN_HEAT urban heating flux W/m^2 T -1225 USTAR aerodynamical resistance s/m F -1226 UST_LAKE friction velocity (lakes only) m/s F -1227 VA atmospheric wind speed plus convective velocity m/s F -1228 VCMX25T canopy profile of vcmax25 umol/m2/s T -1229 VEGWP vegetation water matric potential for sun/sha canopy,xyl,root segments mm T -1230 VEGWPLN vegetation water matric potential for sun/sha canopy,xyl,root at local noon mm T -1231 VEGWPPD predawn vegetation water matric potential for sun/sha canopy,xyl,root mm T -1232 VOCFLXT total VOC flux into atmosphere moles/m2/sec F -1233 VOLR river channel total water storage m3 T -1234 VOLRMCH river channel main channel water storage m3 T -1235 VPD vpd Pa F -1236 VPD2M 2m vapor pressure deficit Pa T -1237 VPD_CAN canopy vapor pressure deficit kPa T -1238 Vcmx25Z canopy profile of vcmax25 predicted by LUNA model umol/m2/s T -1239 WASTEHEAT sensible heat flux from heating/cooling sources of urban waste heat W/m^2 T -1240 WBA 2 m Wet Bulb C T -1241 WBA_R Rural 2 m Wet Bulb C T -1242 WBA_U Urban 2 m Wet Bulb C T -1243 WBT 2 m Stull Wet Bulb C T -1244 WBT_R Rural 2 m Stull Wet Bulb C T -1245 WBT_U Urban 2 m Stull Wet Bulb C T -1246 WF soil water as frac. of whc for top 0.05 m proportion F -1247 WFPS WFPS percent F -1248 WIND atmospheric wind velocity magnitude m/s T -1249 WOODC wood C gC/m^2 T -1250 WOODC_ALLOC wood C eallocation gC/m^2/s T -1251 WOODC_LOSS wood C loss gC/m^2/s T -1252 WOOD_HARVESTC wood harvest carbon (to product pools) gC/m^2/s T -1253 WOOD_HARVESTN wood harvest N (to product pools) gN/m^2/s T -1254 WTGQ surface tracer conductance m/s T -1255 W_SCALAR Moisture (dryness) inhibition of decomposition unitless T -1256 Wind atmospheric wind velocity magnitude m/s F -1257 XSMRPOOL temporary photosynthate C pool gC/m^2 T -1258 XSMRPOOL_LOSS temporary photosynthate C pool loss gC/m^2 F -1259 XSMRPOOL_RECOVER C flux assigned to recovery of negative xsmrpool gC/m^2/s T -1260 Z0HG roughness length over ground, sensible heat m F -1261 Z0HV roughness length over vegetation, sensible heat m F -1262 Z0M momentum roughness length m F -1263 Z0MG roughness length over ground, momentum m F -1264 Z0MV roughness length over vegetation, momentum m F -1265 Z0M_TO_COUPLER roughness length, momentum: gridcell average sent to coupler m F -1266 Z0QG roughness length over ground, latent heat m F -1267 Z0QV roughness length over vegetation, latent heat m F -1268 ZBOT atmospheric reference height m T -1269 ZETA dimensionless stability parameter unitless F -1270 ZII convective boundary height m F -1271 ZWT water table depth (natural vegetated and crop landunits only) m T -1272 ZWT_CH4_UNSAT depth of water table for methane production used in non-inundated area m T -1273 ZWT_PERCH perched water table depth (natural vegetated and crop landunits only) m T -1274 anaerobic_frac anaerobic_frac m3/m3 F -1275 bsw clap and hornberger B unitless F -1276 currentPatch currentPatch coefficient for VOC calc non F -1277 diffus diffusivity m^2/s F -1278 fr_WFPS fr_WFPS fraction F -1279 n2_n2o_ratio_denit n2_n2o_ratio_denit gN/gN F -1280 num_iter number of iterations unitless F -1281 r_psi r_psi m F -1282 ratio_k1 ratio_k1 none F -1283 ratio_no3_co2 ratio_no3_co2 ratio F -1284 soil_bulkdensity soil_bulkdensity kg/m3 F -1285 soil_co2_prod soil_co2_prod ug C / g soil / day F -1286 watfc water field capacity m^3/m^3 F -1287 watsat water saturated m^3/m^3 F -==== =================================== ============================================================================================== ================================================================= ======= diff --git a/python/ctsm/crop_calendars/check_rxboth_run.py b/python/ctsm/crop_calendars/check_rxboth_run.py new file mode 100644 index 0000000000..6dae071937 --- /dev/null +++ b/python/ctsm/crop_calendars/check_rxboth_run.py @@ -0,0 +1,123 @@ +# %% Setup + +import numpy as np +import sys, argparse +import cropcal_module as cc +import glob, os + + +def main(argv): + # Set arguments + parser = argparse.ArgumentParser(description="ADD DESCRIPTION HERE") + parser.add_argument( + "-d", "--directory", help="Directory with CLM output history files", required=True + ) + parser.add_argument( + "--rx_sdates_file", "--rx-sdates-file", help="Prescribed sowing dates file", required=True + ) + parser.add_argument( + "--rx_gdds_file", + "--rx-gdds-file", + help="Prescribed maturity requirements file", + required=True, + ) + parser.add_argument( + "-y1", + "--first_usable_year", + "--first-usable-year", + type=int, + help="First usable year in the outputs", + required=True, + ) + parser.add_argument( + "-yN", + "--last_usable_year", + "--last-usable-year", + type=int, + help="Last usable year in the outputs", + required=True, + ) + args = parser.parse_args(argv) + + # Note that _PERHARV will be stripped off upon import + myVars = [ + "GRAINC_TO_FOOD_PERHARV", + "GRAINC_TO_FOOD_ANN", + "SDATES", + "SDATES_PERHARV", + "SYEARS_PERHARV", + "HDATES", + "HYEARS", + "GDDHARV_PERHARV", + "GDDACCUM_PERHARV", + "HUI_PERHARV", + "SOWING_REASON_PERHARV", + "HARVEST_REASON_PERHARV", + ] + + annual_outfiles = glob.glob(os.path.join(args.directory, "*.clm2.h1.*.nc")) + + # These should be constant in a Prescribed Calendars (rxboth) run, as long as the inputs were + # static. + case = { + "constantVars": ["SDATES", "GDDHARV"], + "rx_sdates_file": args.rx_sdates_file, + "rx_gdds_file": args.rx_gdds_file, + } + + case["ds"] = cc.import_output( + annual_outfiles, + myVars=myVars, + y1=args.first_usable_year, + yN=args.last_usable_year, + ) + cc.check_constant_vars(case["ds"], case, ignore_nan=True, verbose=True, throw_error=True) + + # Import GGCMI sowing and harvest dates, and check sims + casename = "Prescribed Calendars" + gdd_min = None + if "rx_sdates_file" in case: + if case["rx_sdates_file"]: + case["rx_sdates_ds"] = cc.import_rx_dates("sdate", case["rx_sdates_file"], case["ds"]) + if case["rx_gdds_file"]: + case["rx_gdds_ds"] = cc.import_rx_dates("gdd", case["rx_gdds_file"], case["ds"]) + + # Equalize lons/lats + lonlat_tol = 1e-4 + for v in ["rx_sdates_ds", "rx_gdds_ds"]: + if v in case: + for l in ["lon", "lat"]: + max_diff_orig = np.max(np.abs(case[v][l].values - case["ds"][l].values)) + if max_diff_orig > lonlat_tol: + raise RuntimeError( + f"{v} {l} values differ too much ({max_diff_orig} > {lonlat_tol})" + ) + elif max_diff_orig > 0: + case[v] = case[v].assign_coords({l: case["ds"][l].values}) + max_diff = np.max(np.abs(case[v][l].values - case["ds"][l].values)) + print(f"{v} {l} max_diff {max_diff_orig} → {max_diff}") + else: + print(f"{v} {l} max_diff {max_diff_orig}") + + # Check + if case["rx_sdates_file"]: + cc.check_rx_obeyed( + case["ds"].vegtype_str.values, + case["rx_sdates_ds"].isel(time=0), + case["ds"], + casename, + "SDATES", + ) + if case["rx_gdds_file"]: + cc.check_rx_obeyed( + case["ds"].vegtype_str.values, + case["rx_gdds_ds"].isel(time=0), + case["ds"], + casename, + "GDDHARV", + gdd_min=gdd_min, + ) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/python/ctsm/crop_calendars/cropcal_figs_module.py b/python/ctsm/crop_calendars/cropcal_figs_module.py new file mode 100644 index 0000000000..8d7f472fec --- /dev/null +++ b/python/ctsm/crop_calendars/cropcal_figs_module.py @@ -0,0 +1,208 @@ +import numpy as np + +import cartopy.crs as ccrs +import matplotlib.pyplot as plt +import matplotlib.colors as mcolors +from matplotlib import cm +import matplotlib.collections as mplcol + + +# Colormaps (maps) +cropcal_colors = { + "seq_timeofyear": "twilight_shifted", + "seq_other": "plasma", # magma_r? CMRmap_r? + "div_yieldirr": "BrBG", + "div_timeofyear": "twilight_shifted", + "div_other_nonnorm": "PuOr_r", + "div_other_norm": "RdBu_r", + "underlay": [0.75, 0.75, 0.75, 1], + "underlay_lighter": [0.85, 0.85, 0.85, 1], + "underlay_lightest": [0.92, 0.92, 0.92, 1], +} + + +# Cases (line and scatter plots) +def cropcal_colors_cases(casename): + case_color_dict = { + "clm default": [x / 255 for x in [92, 219, 219]], + "prescribed calendars": [x / 255 for x in [250, 102, 240]], + "prescribed maturity": [x / 255 for x in [128, 0, 0]], + "prescribed sowing": [x / 255 for x in [133, 92, 255]], + } + case_color_dict["5.0 lu"] = case_color_dict["clm default"] + case_color_dict["5.2 lu"] = case_color_dict["prescribed calendars"] + + case_color = None + casename_for_colors = casename.lower().replace(" (0)", "").replace(" (1)", "") + if casename_for_colors in case_color_dict: + case_color = case_color_dict[casename_for_colors] + return case_color + + +def make_map( + ax, + this_map, + fontsize, + bounds=None, + cbar=None, + cbar_labelpad=4.0, + cbar_max=None, + cbar_spacing="uniform", + cmap=cropcal_colors["seq_other"], + extend_bounds="both", + extend_nonbounds="both", + linewidth=1.0, + lonlat_bin_width=None, + show_cbar=False, + subplot_label=None, + this_title=None, + ticklabels=None, + ticklocations=None, + underlay=None, + underlay_color=None, + units=None, + vmax=None, + vmin=None, + vrange=None, +): + if underlay is not None: + if underlay_color is None: + underlay_color = cropcal_colors["underlay"] + underlay_cmap = mcolors.ListedColormap(np.array([underlay_color, [1, 1, 1, 1]])) + ax.pcolormesh(underlay.lon.values, underlay.lat.values, underlay, cmap=underlay_cmap) + + if bounds is not None: + norm = mcolors.BoundaryNorm(bounds, cmap.N, extend=extend_bounds) + im = ax.pcolormesh( + this_map.lon.values, this_map.lat.values, this_map, shading="auto", norm=norm, cmap=cmap + ) + else: + im = ax.pcolormesh( + this_map.lon.values, + this_map.lat.values, + this_map, + shading="auto", + cmap=cmap, + vmin=vmin, + vmax=vmax, + ) + if vrange: + im.set_clim(vrange[0], vrange[1]) + ax.set_extent([-180, 180, -63, 90], crs=ccrs.PlateCarree()) + + if subplot_label is not None: + plt.text( + 0, 0.95, f"({subplot_label})", transform=ax.transAxes, fontsize=fontsize["axislabels"] + ) + + # # Country borders + # ax.add_feature(cfeature.BORDERS, linewidth=linewidth, edgecolor="white", alpha=0.5) + # ax.add_feature(cfeature.BORDERS, linewidth=linewidth*0.6, alpha=0.3) + + # Coastlines + ax.coastlines(linewidth=linewidth, color="white", alpha=0.5) + ax.coastlines(linewidth=linewidth * 0.6, alpha=0.3) + + if this_title: + ax.set_title(this_title, fontsize=fontsize["titles"]) + if show_cbar: + if cbar: + cbar.remove() + + if bounds is not None: + cbar = plt.colorbar( + cm.ScalarMappable(norm=norm, cmap=cmap), + ax=ax, + orientation="horizontal", + fraction=0.1, + pad=0.02, + spacing=cbar_spacing, + ) + else: + cbar = plt.colorbar( + im, + ax=ax, + orientation="horizontal", + fraction=0.1, + pad=0.02, + extend=extend_nonbounds, + spacing=cbar_spacing, + ) + + deal_with_ticklabels(cbar, cbar_max, ticklabels, ticklocations, units, im) + cbar.set_label( + label=units, + fontsize=fontsize["axislabels"], + verticalalignment="center", + labelpad=cbar_labelpad, + ) + cbar.ax.tick_params(labelsize=fontsize["ticklabels"]) + if units is not None and "month" in units.lower(): + cbar.ax.tick_params(length=0) + + if lonlat_bin_width: + set_ticks(lonlat_bin_width, fontsize, "y") + # set_ticks(lonlat_bin_width, fontsize, "x") + else: + # Need to do this for subplot row labels + set_ticks(-1, fontsize, "y") + plt.yticks([]) + for x in ax.spines: + ax.spines[x].set_visible(False) + + if show_cbar: + return im, cbar + else: + return im, None + + +def deal_with_ticklabels(cbar, cbar_max, ticklabels, ticklocations, units, im): + if ticklocations is not None: + cbar.set_ticks(ticklocations) + if units is not None and units.lower() == "month": + cbar.set_ticklabels( + ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] + ) + units == "Month" + elif ticklabels is not None: + cbar.set_ticklabels(ticklabels) + if isinstance(im, mplcol.QuadMesh): + clim_max = im.get_clim()[1] + else: + clim_max = im + if cbar_max is not None and clim_max > cbar_max: + if ticklabels is not None: + raise RuntimeError( + "How to handle this now that you are specifying ticklocations separate from ticklabels?" + ) + ticks = cbar.get_ticks() + if ticks[-2] > cbar_max: + raise RuntimeError( + f"Specified cbar_max is {cbar_max} but highest bin BEGINS at {ticks[-2]}" + ) + ticklabels = ticks.copy() + ticklabels[-1] = cbar_max + for i, x in enumerate(ticklabels): + if x == int(x): + ticklabels[i] = str(int(x)) + cbar.set_ticks( + ticks + ) # Calling this before set_xticklabels() avoids "UserWarning: FixedFormatter should only be used together with FixedLocator" (https://stackoverflow.com/questions/63723514/userwarning-fixedformatter-should-only-be-used-together-with-fixedlocator) + cbar.set_ticklabels(ticklabels) + + +def set_ticks(lonlat_bin_width, fontsize, x_or_y): + if x_or_y == "x": + ticks = np.arange(-180, 181, lonlat_bin_width) + else: + ticks = np.arange(-60, 91, lonlat_bin_width) + + ticklabels = [str(x) for x in ticks] + for i, x in enumerate(ticks): + if x % 2: + ticklabels[i] = "" + + if x_or_y == "x": + plt.xticks(ticks, labels=ticklabels, fontsize=fontsize["ticklabels"]) + else: + plt.yticks(ticks, labels=ticklabels, fontsize=fontsize["ticklabels"]) diff --git a/python/ctsm/crop_calendars/cropcal_module.py b/python/ctsm/crop_calendars/cropcal_module.py new file mode 100644 index 0000000000..76c295974d --- /dev/null +++ b/python/ctsm/crop_calendars/cropcal_module.py @@ -0,0 +1,1266 @@ +import numpy as np +import xarray as xr +import warnings +import sys +import os +import glob + +# Import the CTSM Python utilities. +# sys.path.insert() is necessary for RXCROPMATURITY to work. The fact that it's calling this script in the RUN phase seems to require the python/ directory to be manually added to path. +_CTSM_PYTHON = os.path.join( + os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir, os.pardir, "python" +) +sys.path.insert(1, _CTSM_PYTHON) +import ctsm.crop_calendars.cropcal_utils as utils + +try: + import pandas as pd +except: + pass + + +# Define conversion multipliers, {from: {to1, to2, ...}, ...} +multiplier_dict = { + # Mass + "g": { + "Mt": 1e-12, + }, + "t": { + "Mt": 1e-6, + }, + # Volume + "m3": { + "km3": 1e-9, + }, + # Yield + "g/m2": { + "t/ha": 1e-6 * 1e4, + }, +} + + +# After importing a file, restrict it to years of interest. +def check_and_trim_years(y1, yN, ds_in): + ### In annual outputs, file with name Y is actually results from year Y-1. + ### Note that time values refer to when it was SAVED. So 1981-01-01 is for year 1980. + + def get_year_from_cftime(cftime_date): + # Subtract 1 because the date for annual files is when it was SAVED + return cftime_date.year - 1 + + # Check that all desired years are included + if get_year_from_cftime(ds_in.time.values[0]) > y1: + raise RuntimeError( + f"Requested y1 is {y1} but first year in outputs is {get_year_from_cftime(ds_in.time.values[0])}" + ) + elif get_year_from_cftime(ds_in.time.values[-1]) < y1: + raise RuntimeError( + f"Requested yN is {yN} but last year in outputs is {get_year_from_cftime(ds_in.time.values[-1])}" + ) + + # Remove years outside range of interest + ### Include an extra year at the end to finish out final seasons. + ds_in = utils.safer_timeslice(ds_in, slice(f"{y1+1}-01-01", f"{yN+2}-01-01")) + + # Make sure you have the expected number of timesteps (including extra year) + Nyears_expected = yN - y1 + 2 + if ds_in.dims["time"] != Nyears_expected: + raise RuntimeError( + f"Expected {Nyears_expected} timesteps in output but got {ds_in.dims['time']}" + ) + + return ds_in + + +def open_lu_ds(filename, y1, yN, existing_ds, ungrid=True): + # Open and trim to years of interest + dsg = xr.open_dataset(filename).sel(time=slice(y1, yN)) + + # Assign actual lon/lat coordinates + dsg = dsg.assign_coords( + lon=("lsmlon", existing_ds.lon.values), lat=("lsmlat", existing_ds.lat.values) + ) + dsg = dsg.swap_dims({"lsmlon": "lon", "lsmlat": "lat"}) + + if "AREA" in dsg: + dsg["AREA_CFT"] = dsg.AREA * 1e6 * dsg.LANDFRAC_PFT * dsg.PCT_CROP / 100 * dsg.PCT_CFT / 100 + dsg["AREA_CFT"].attrs = {"units": "m2"} + dsg["AREA_CFT"].load() + else: + print("Warning: AREA missing from Dataset, so AREA_CFT will not be created") + + if not ungrid: + return dsg + + # Un-grid + query_ilons = [int(x) - 1 for x in existing_ds["patches1d_ixy"].values] + query_ilats = [int(x) - 1 for x in existing_ds["patches1d_jxy"].values] + query_ivts = [list(dsg.cft.values).index(x) for x in existing_ds["patches1d_itype_veg"].values] + + ds = xr.Dataset(attrs=dsg.attrs) + for v in ["AREA", "LANDFRAC_PFT", "PCT_CFT", "PCT_CROP", "AREA_CFT"]: + if v not in dsg: + continue + if "time" in dsg[v].dims: + new_coords = existing_ds["GRAINC_TO_FOOD_ANN"].coords + else: + new_coords = existing_ds["patches1d_lon"].coords + if "cft" in dsg[v].dims: + ds[v] = ( + dsg[v] + .isel( + lon=xr.DataArray(query_ilons, dims="patch"), + lat=xr.DataArray(query_ilats, dims="patch"), + cft=xr.DataArray(query_ivts, dims="patch"), + drop=True, + ) + .assign_coords(new_coords) + ) + else: + ds[v] = ( + dsg[v] + .isel( + lon=xr.DataArray(query_ilons, dims="patch"), + lat=xr.DataArray(query_ilats, dims="patch"), + drop=True, + ) + .assign_coords(new_coords) + ) + for v in existing_ds: + if "patches1d_" in v or "grid1d_" in v: + ds[v] = existing_ds[v] + ds["lon"] = dsg["lon"] + ds["lat"] = dsg["lat"] + + # Which crops are irrigated? + is_irrigated = np.full_like(ds["patches1d_itype_veg"], False) + for vegtype_str in np.unique(ds["patches1d_itype_veg_str"].values): + if "irrigated" not in vegtype_str: + continue + vegtype_int = utils.ivt_str2int(vegtype_str) + is_this_vegtype = np.where(ds["patches1d_itype_veg"].values == vegtype_int)[0] + is_irrigated[is_this_vegtype] = True + ["irrigated" in x for x in ds["patches1d_itype_veg_str"].values] + ds["IRRIGATED"] = xr.DataArray( + data=is_irrigated, + coords=ds["patches1d_itype_veg_str"].coords, + attrs={"long_name": "Is patch irrigated?"}, + ) + + # How much area is irrigated? + ds["IRRIGATED_AREA_CFT"] = ds["IRRIGATED"] * ds["AREA_CFT"] + ds["IRRIGATED_AREA_CFT"].attrs = { + "long name": "CFT area (irrigated types only)", + "units": "m^2", + } + ds["IRRIGATED_AREA_GRID"] = ( + ds["IRRIGATED_AREA_CFT"] + .groupby(ds["patches1d_gi"]) + .sum() + .rename({"patches1d_gi": "gridcell"}) + ) + ds["IRRIGATED_AREA_GRID"].attrs = {"long name": "Irrigated area in gridcell", "units": "m^2"} + + return ds + + +def check_constant_vars( + this_ds, case, ignore_nan, constantGSs=None, verbose=True, throw_error=True +): + if isinstance(case, str): + constantVars = [case] + elif isinstance(case, list): + constantVars = case + elif isinstance(case, dict): + constantVars = case["constantVars"] + else: + raise TypeError(f"case must be str or dict, not {type(case)}") + + if not constantVars: + return None + + if constantGSs: + gs0 = this_ds.gs.values[0] + gsN = this_ds.gs.values[-1] + if constantGSs.start > gs0 or constantGSs.stop < gsN: + print( + f"❗ Only checking constantVars over {constantGSs.start}-{constantGSs.stop} (run includes {gs0}-{gsN})" + ) + this_ds = this_ds.sel(gs=constantGSs) + + any_bad = False + any_bad_before_checking_rx = False + if throw_error: + emojus = "❌" + else: + emojus = "❗" + if not isinstance(constantVars, list): + constantVars = [constantVars] + + for v in constantVars: + ok = True + + if "gs" in this_ds[v].dims: + time_coord = "gs" + elif "time" in this_ds[v].dims: + time_coord = "time" + else: + raise RuntimeError(f"Which of these is the time coordinate? {this_ds[v].dims}") + i_time_coord = this_ds[v].dims.index(time_coord) + + this_da = this_ds[v] + ra_sp = np.moveaxis(this_da.copy().values, i_time_coord, 0) + incl_patches = [] + bad_patches = np.array([]) + strList = [] + + # Read prescription file, if needed + rx_ds = None + if isinstance(case, dict): + if v == "GDDHARV" and "rx_gdds_file" in case: + rx_ds = import_rx_dates( + "gdd", case["rx_gdds_file"], this_ds, set_neg1_to_nan=False + ).squeeze() + + for t1 in np.arange(this_ds.dims[time_coord] - 1): + condn = ~np.isnan(ra_sp[t1, ...]) + if t1 > 0: + condn = np.bitwise_and(condn, np.all(np.isnan(ra_sp[:t1, ...]), axis=0)) + thesePatches = np.where(condn)[0] + if thesePatches.size == 0: + continue + thesePatches = list(np.where(condn)[0]) + incl_patches += thesePatches + # print(f't1 {t1}: {thesePatches}') + + t1_yr = this_ds[time_coord].values[t1] + t1_vals = np.squeeze(this_da.isel({time_coord: t1, "patch": thesePatches}).values) + + for t in np.arange(t1 + 1, this_ds.dims[time_coord]): + t_yr = this_ds[time_coord].values[t] + t_vals = np.squeeze(this_da.isel({time_coord: t, "patch": thesePatches}).values) + ok_p = t1_vals == t_vals + + # If allowed, ignore where either t or t1 is NaN. Should only be used for runs where land use varies over time. + if ignore_nan: + ok_p = np.squeeze(np.bitwise_or(ok_p, np.isnan(t1_vals + t_vals))) + + if not np.all(ok_p): + any_bad_before_checking_rx = True + bad_patches_thisT = list(np.where(np.bitwise_not(ok_p))[0]) + bad_patches = np.concatenate( + (bad_patches, np.array(thesePatches)[bad_patches_thisT]) + ) + if rx_ds: + found_in_rx = np.array([False for x in bad_patches]) + varyPatches = list(np.array(thesePatches)[bad_patches_thisT]) + varyLons = this_ds.patches1d_lon.values[bad_patches_thisT] + varyLats = this_ds.patches1d_lat.values[bad_patches_thisT] + varyCrops = this_ds.patches1d_itype_veg_str.values[bad_patches_thisT] + varyCrops_int = this_ds.patches1d_itype_veg.values[bad_patches_thisT] + + any_bad_anyCrop = False + for c in np.unique(varyCrops_int): + rx_var = f"gs1_{c}" + varyLons_thisCrop = varyLons[np.where(varyCrops_int == c)] + varyLats_thisCrop = varyLats[np.where(varyCrops_int == c)] + theseRxVals = np.diag( + rx_ds[rx_var].sel(lon=varyLons_thisCrop, lat=varyLats_thisCrop).values + ) + if len(theseRxVals) != len(varyLats_thisCrop): + raise RuntimeError( + f"Expected {len(varyLats_thisCrop)} rx values; got {len(theseRxVals)}" + ) + if not np.any(theseRxVals != -1): + continue + any_bad_anyCrop = True + break + if not any_bad_anyCrop: + continue + + # This bit is pretty inefficient, but I'm not going to optimize it until I actually need to use it. + for i, p in enumerate(bad_patches_thisT): + thisPatch = varyPatches[i] + thisLon = varyLons[i] + thisLat = varyLats[i] + thisCrop = varyCrops[i] + thisCrop_int = varyCrops_int[i] + + # If prescribed input had missing value (-1), it's fine for it to vary. + if rx_ds: + rx_var = f"gs1_{thisCrop_int}" + if thisLon in rx_ds.lon.values and thisLat in rx_ds.lat.values: + rx = rx_ds[rx_var].sel(lon=thisLon, lat=thisLat).values + Nunique = len(np.unique(rx)) + if Nunique == 1: + found_in_rx[i] = True + if rx == -1: + continue + elif Nunique > 1: + raise RuntimeError( + f"How does lon {thisLon} lat {thisLat} {thisCrop} have time-varying {v}?" + ) + else: + raise RuntimeError( + "lon {thisLon} lat {thisLat} {thisCrop} not in rx dataset?" + ) + + # Print info (or save to print later) + any_bad = True + if verbose: + thisStr = f" Patch {thisPatch} (lon {thisLon} lat {thisLat}) {thisCrop} ({thisCrop_int})" + if rx_ds and not found_in_rx[i]: + thisStr = thisStr.replace("(lon", "* (lon") + if not np.isnan(t1_vals[p]): + t1_val_print = int(t1_vals[p]) + else: + t1_val_print = "NaN" + if not np.isnan(t_vals[p]): + t_val_print = int(t_vals[p]) + else: + t_val_print = "NaN" + if v == "SDATES": + strList.append( + f"{thisStr}: Sowing {t1_yr} jday {t1_val_print}, {t_yr} jday {t_val_print}" + ) + else: + strList.append( + f"{thisStr}: {t1_yr} {v} {t1_val_print}, {t_yr} {v} {t_val_print}" + ) + else: + if ok: + print(f"{emojus} CLM output {v} unexpectedly vary over time:") + ok = False + print(f"{v} timestep {t} does not match timestep {t1}") + break + if verbose and any_bad: + print(f"{emojus} CLM output {v} unexpectedly vary over time:") + strList.sort() + if rx_ds and np.any(~found_in_rx): + strList = [ + "*: Not found in prescribed input file (maybe minor lon/lat mismatch)" + ] + strList + elif not rx_ds: + strList = ["(No rx file checked)"] + strList + print("\n".join(strList)) + + # Make sure every patch was checked once (or is all-NaN except possibly final season) + incl_patches = np.sort(incl_patches) + if not np.array_equal(incl_patches, np.unique(incl_patches)): + raise RuntimeError("Patch(es) checked more than once!") + incl_patches = list(incl_patches) + incl_patches += list( + np.where( + np.all( + np.isnan( + ra_sp[ + :-1, + ] + ), + axis=0, + ) + )[0] + ) + incl_patches = np.sort(incl_patches) + if not np.array_equal(incl_patches, np.unique(incl_patches)): + raise RuntimeError("Patch(es) checked but also all-NaN??") + if not np.array_equal(incl_patches, np.arange(this_ds.dims["patch"])): + for p in np.arange(this_ds.dims["patch"]): + if p not in incl_patches: + break + raise RuntimeError( + f"Not all patches checked! E.g., {p}: {this_da.isel(patch=p).values}" + ) + + if not any_bad: + if any_bad_before_checking_rx: + print( + f"✅ CLM output {v} do not vary through {this_ds.dims[time_coord]} growing seasons of output (except for patch(es) with missing rx)." + ) + else: + print( + f"✅ CLM output {v} do not vary through {this_ds.dims[time_coord]} growing seasons of output." + ) + + if any_bad and throw_error: + raise RuntimeError("Stopping due to failed check_constant_vars().") + + bad_patches = np.unique(bad_patches) + return [int(p) for p in bad_patches] + + +def check_rx_obeyed( + vegtype_list, rx_ds, dates_ds, which_ds, output_var, gdd_min=None, verbose=False +): + all_ok = 2 + diff_str_list = [] + gdd_tolerance = 1 + + if "GDDHARV" in output_var and verbose: + harvest_reason_da = dates_ds["HARVEST_REASON"] + unique_harvest_reasons = np.unique( + harvest_reason_da.values[np.where(~np.isnan(harvest_reason_da.values))] + ) + pct_harv_at_mature = get_pct_harv_at_mature(harvest_reason_da) + print( + f"{which_ds} harvest reasons: {unique_harvest_reasons} ({pct_harv_at_mature}% harv at maturity)" + ) + + for vegtype_str in vegtype_list: + thisVeg_patches = np.where(dates_ds.patches1d_itype_veg_str == vegtype_str)[0] + if thisVeg_patches.size == 0: + continue + ds_thisVeg = dates_ds.isel(patch=thisVeg_patches) + patch_inds_lon_thisVeg = ds_thisVeg.patches1d_ixy.values.astype(int) - 1 + patch_inds_lat_thisVeg = ds_thisVeg.patches1d_jxy.values.astype(int) - 1 + patch_lons_thisVeg = ds_thisVeg.patches1d_lon + patch_lats_thisVeg = ds_thisVeg.patches1d_lat + + vegtype_int = utils.vegtype_str2int(vegtype_str)[0] + rx_da = rx_ds[f"gs1_{vegtype_int}"] + rx_array = rx_da.values[patch_inds_lat_thisVeg, patch_inds_lon_thisVeg] + rx_array = np.expand_dims(rx_array, axis=1) + sim_array = ds_thisVeg[output_var].values + sim_array_dims = ds_thisVeg[output_var].dims + + # Ignore patches without prescribed value + with np.errstate(invalid="ignore"): + rx_array[np.where(rx_array < 0)] = np.nan + + # Account for... + if "GDDHARV" in output_var: + # ...GDD harvest threshold minimum set in PlantCrop() + if gdd_min == None: + gdd_min = default_gdd_min() + print( + f"gdd_min not provided when doing check_rx_obeyed() for {output_var}; using default {gdd_min}" + ) + with np.errstate(invalid="ignore"): + rx_array[(rx_array >= 0) & (rx_array < gdd_min)] = gdd_min + + # ...harvest reason + # 0: Should never happen in any simulation + # 1: Harvesting at maturity + # 2: Harvesting at max season length (mxmat) + # 3: Crop was incorrectly planted in last time step of Dec. 31 + # 4: Today was supposed to be the planting day, but the previous crop still hasn't been harvested. + # 5: Harvest the day before the next sowing date this year. + # 6: Same as #5. + # 7: Harvest the day before the next sowing date (today is Dec. 31 and the sowing date is Jan. 1) + harvest_reason_da = ds_thisVeg["HARVEST_REASON"] + unique_harvest_reasons = np.unique( + harvest_reason_da.values[np.where(~np.isnan(harvest_reason_da.values))] + ) + pct_harv_at_mature = get_pct_harv_at_mature(harvest_reason_da) + + if np.any(sim_array != rx_array): + diff_array = sim_array - rx_array + + # Allow negative GDDHARV values when harvest occurred because sowing was scheduled for the next day + if output_var == "GDDHARV_PERHARV": + diff_array = np.ma.masked_array( + diff_array, + mask=(diff_array < 0) & (ds_thisVeg["HARVEST_REASON_PERHARV"].values == 5), + ) + elif output_var == "GDDHARV": + with np.errstate(invalid="ignore"): + diff_lt_0 = diff_array < 0 + harv_reason_5 = ds_thisVeg["HARVEST_REASON"].values == 5 + diff_array = np.ma.masked_array(diff_array, mask=diff_lt_0 & harv_reason_5) + + with np.errstate(invalid="ignore"): + abs_gt_0 = abs(diff_array) > 0 + if np.any(np.abs(diff_array[abs_gt_0]) > 0): + min_diff, minLon, minLat, minGS, minRx = get_extreme_info( + diff_array, + rx_array, + np.nanmin, + sim_array_dims, + dates_ds.gs, + patch_lons_thisVeg, + patch_lats_thisVeg, + ) + max_diff, maxLon, maxLat, maxGS, maxRx = get_extreme_info( + diff_array, + rx_array, + np.nanmax, + sim_array_dims, + dates_ds.gs, + patch_lons_thisVeg, + patch_lats_thisVeg, + ) + + diffs_eg_txt = f"{vegtype_str} ({vegtype_int}): diffs range {min_diff} (lon {minLon}, lat {minLat}, gs {minGS}, rx ~{minRx}) to {max_diff} (lon {maxLon}, lat {maxLat}, gs {maxGS}, rx ~{maxRx})" + if "GDDHARV" in output_var: + diffs_eg_txt += f"; harvest reasons: {unique_harvest_reasons} ({pct_harv_at_mature}% harvested at maturity)" + if "GDDHARV" in output_var and np.nanmax(abs(diff_array)) <= gdd_tolerance: + if all_ok > 0: + all_ok = 1 + diff_str_list.append(f" {diffs_eg_txt}") + else: + all_ok = 0 + if verbose: + print( + f"❌ {which_ds}: Prescribed {output_var} *not* always obeyed. E.g., {diffs_eg_txt}" + ) + else: + break + + if all_ok == 2: + print(f"✅ {which_ds}: Prescribed {output_var} always obeyed") + elif all_ok == 1: + # print(f"🟨 {which_ds}: Prescribed {output_var} *not* always obeyed, but acceptable:") + # for x in diff_str_list: print(x) + print( + f"🟨 {which_ds}: Prescribed {output_var} *not* always obeyed, but acceptable (diffs <= {gdd_tolerance})" + ) + elif not verbose: + print(f"❌ {which_ds}: Prescribed {output_var} *not* always obeyed. E.g., {diffs_eg_txt}") + + +# Make sure that, e.g., GDDACCUM_PERHARV is always <= HUI_PERHARV +def check_v0_le_v1(this_ds, vars, msg_txt=" ", both_nan_ok=False, throw_error=False): + v0 = vars[0] + v1 = vars[1] + gdd_lt_hui = this_ds[v0] <= this_ds[v1] + if both_nan_ok: + gdd_lt_hui = gdd_lt_hui | (np.isnan(this_ds[v0]) & np.isnan(this_ds[v1])) + if np.all(gdd_lt_hui): + print(f"✅{msg_txt}{v0} always <= {v1}") + else: + msg = f"❌{msg_txt}{v0} *not* always <= {v1}" + gdd_lt_hui_vals = gdd_lt_hui.values + p = np.where(~gdd_lt_hui_vals)[0][0] + msg = ( + msg + + f"\ne.g., patch {p}: {this_ds.patches1d_itype_veg_str.values[p]}, lon {this_ds.patches1d_lon.values[p]} lat {this_ds.patches1d_lat.values[p]}:" + ) + msg = msg + f"\n{this_ds[v0].values[p,:]}" + msg = msg + f"\n{this_ds[v1].values[p,:]}" + if throw_error: + print(msg) + else: + raise RuntimeError(msg) + + +# Convert time*mxharvests axes to growingseason axis +def convert_axis_time2gs(this_ds, verbose=False, myVars=None, incl_orig=False): + # How many non-NaN patch-seasons do we expect to have once we're done organizing things? + Npatch = this_ds.dims["patch"] + # Because some patches will be planted in the last year but not complete, we have to ignore any finalyear-planted seasons that do complete. + Ngs = this_ds.dims["time"] - 1 + expected_valid = Npatch * Ngs + + mxharvests = this_ds.dims["mxharvests"] + + if verbose: + print( + f"Start: discrepancy of {np.sum(~np.isnan(this_ds.HDATES.values)) - expected_valid} patch-seasons" + ) + + # Set all non-positive date values to NaN. These are seasons that were never harvested (or never started): "non-seasons." + if this_ds.HDATES.dims != ("time", "mxharvests", "patch"): + raise RuntimeError( + f"This code relies on HDATES dims ('time', 'mxharvests', 'patch'), not {this_ds.HDATES.dims}" + ) + hdates_ymp = this_ds.HDATES.copy().where(this_ds.HDATES > 0).values + hdates_pym = np.transpose(hdates_ymp.copy(), (2, 0, 1)) + sdates_ymp = this_ds.SDATES_PERHARV.copy().where(this_ds.SDATES_PERHARV > 0).values + sdates_pym = np.transpose(sdates_ymp.copy(), (2, 0, 1)) + with np.errstate(invalid="ignore"): + hdates_pym[hdates_pym <= 0] = np.nan + + # Find years where patch was inactive + inactive_py = np.transpose( + np.isnan(this_ds.HDATES).all(dim="mxharvests").values + & np.isnan(this_ds.SDATES_PERHARV).all(dim="mxharvests").values + ) + # Find seasons that were planted while the patch was inactive + with np.errstate(invalid="ignore"): + sown_inactive_py = inactive_py[:, :-1] & (hdates_pym[:, 1:, 0] < sdates_pym[:, 1:, 0]) + sown_inactive_py = np.concatenate((np.full((Npatch, 1), False), sown_inactive_py), axis=1) + + # "Ignore harvests from seasons sown (a) before this output began or (b) when the crop was inactive" + with np.errstate(invalid="ignore"): + first_season_before_first_year_p = hdates_pym[:, 0, 0] < sdates_pym[:, 0, 0] + first_season_before_first_year_py = np.full(hdates_pym.shape[:-1], fill_value=False) + first_season_before_first_year_py[:, 0] = first_season_before_first_year_p + sown_prerun_or_inactive_py = first_season_before_first_year_py | sown_inactive_py + sown_prerun_or_inactive_pym = np.concatenate( + ( + np.expand_dims(sown_prerun_or_inactive_py, axis=2), + np.full((Npatch, Ngs + 1, mxharvests - 1), False), + ), + axis=2, + ) + where_sown_prerun_or_inactive_pym = np.where(sown_prerun_or_inactive_pym) + hdates_pym[where_sown_prerun_or_inactive_pym] = np.nan + sdates_pym[where_sown_prerun_or_inactive_pym] = np.nan + if verbose: + print( + f'After "Ignore harvests from before this output began: discrepancy of {np.sum(~np.isnan(hdates_pym)) - expected_valid} patch-seasons' + ) + + # We need to keep some non-seasons---it's possible that "the yearY growing season" never happened (sowing conditions weren't met), but we still need something there so that we can make an array of dimension Npatch*Ngs. We do this by changing those non-seasons from NaN to -Inf before doing the filtering and reshaping, after which we'll convert them back to NaNs. + + # "In years with no sowing, pretend the first no-harvest is meaningful, unless that was intentionally ignored above." + sdates_orig_ymp = this_ds.SDATES.copy().values + sdates_orig_pym = np.transpose(sdates_orig_ymp.copy(), (2, 0, 1)) + hdates_pym2 = hdates_pym.copy() + sdates_pym2 = sdates_pym.copy() + with np.errstate(invalid="ignore"): + sdates_gt_0 = sdates_orig_pym > 0 + nosow_py = np.all(~sdates_gt_0, axis=2) + nosow_py_1st = nosow_py & np.isnan(hdates_pym[:, :, 0]) + where_nosow_py_1st = np.where(nosow_py_1st) + hdates_pym2[where_nosow_py_1st[0], where_nosow_py_1st[1], 0] = -np.inf + sdates_pym2[where_nosow_py_1st[0], where_nosow_py_1st[1], 0] = -np.inf + for h in np.arange(mxharvests - 1): + if h == 0: + continue + elif h == 1: + print("Warning: Untested with mxharvests > 2") + where_nosow_py = np.where( + nosow_py + & ~np.any(np.isnan(hdates_pym[:, :, 0:h]), axis=2) + & np.isnan(hdates_pym[:, :, h]) + ) + hdates_pym2[where_nosow_py[0], where_nosow_py[1], h + 1] = -np.inf + sdates_pym2[where_nosow_py[0], where_nosow_py[1], h + 1] = -np.inf + + # "In years with sowing that are followed by inactive years, check whether the last sowing was harvested before the patch was deactivated. If not, pretend the LAST [easier to implement!] no-harvest is meaningful." + sdates_orig_masked_pym = sdates_orig_pym.copy() + with np.errstate(invalid="ignore"): + sdates_le_0 = sdates_orig_masked_pym <= 0 + sdates_orig_masked_pym[np.where(sdates_le_0)] = np.nan + with warnings.catch_warnings(): + warnings.filterwarnings(action="ignore", message="All-NaN slice encountered") + last_sdate_firstNgs_py = np.nanmax(sdates_orig_masked_pym[:, :-1, :], axis=2) + last_hdate_firstNgs_py = np.nanmax(hdates_pym2[:, :-1, :], axis=2) + with np.errstate(invalid="ignore"): + hdate_lt_sdate = last_hdate_firstNgs_py < last_sdate_firstNgs_py + last_sowing_not_harvested_sameyear_firstNgs_py = hdate_lt_sdate | np.isnan( + last_hdate_firstNgs_py + ) + inactive_lastNgs_py = inactive_py[:, 1:] + last_sowing_never_harvested_firstNgs_py = ( + last_sowing_not_harvested_sameyear_firstNgs_py & inactive_lastNgs_py + ) + last_sowing_never_harvested_py = np.concatenate( + (last_sowing_never_harvested_firstNgs_py, np.full((Npatch, 1), False)), axis=1 + ) + last_sowing_never_harvested_pym = np.concatenate( + ( + np.full((Npatch, Ngs + 1, mxharvests - 1), False), + np.expand_dims(last_sowing_never_harvested_py, axis=2), + ), + axis=2, + ) + where_last_sowing_never_harvested_pym = last_sowing_never_harvested_pym + hdates_pym3 = hdates_pym2.copy() + sdates_pym3 = sdates_pym2.copy() + hdates_pym3[where_last_sowing_never_harvested_pym] = -np.inf + sdates_pym3[where_last_sowing_never_harvested_pym] = -np.inf + + # Convert to growingseason axis + def pym_to_pg(pym, quiet=False): + pg = np.reshape(pym, (pym.shape[0], -1)) + ok_pg = pg[~np.isnan(pg)] + if not quiet: + print( + f"{ok_pg.size} included; unique N seasons = {np.unique(np.sum(~np.isnan(pg), axis=1))}" + ) + return pg + + hdates_pg = pym_to_pg(hdates_pym3.copy(), quiet=~verbose) + sdates_pg = pym_to_pg(sdates_pym3.copy(), quiet=True) + if verbose: + print( + f'After "In years with no sowing, pretend the first no-harvest is meaningful: discrepancy of {np.sum(~np.isnan(hdates_pg)) - expected_valid} patch-seasons' + ) + + # "Ignore any harvests that were planted in the final year, because some cells will have incomplete growing seasons for the final year." + with np.errstate(invalid="ignore"): + hdates_ge_sdates = hdates_pg[:, -mxharvests:] >= sdates_pg[:, -mxharvests:] + lastyear_complete_season = hdates_ge_sdates | np.isinf(hdates_pg[:, -mxharvests:]) + + def ignore_lastyear_complete_season(pg, excl, mxharvests): + tmp_L = pg[:, :-mxharvests] + tmp_R = pg[:, -mxharvests:] + tmp_R[np.where(excl)] = np.nan + pg = np.concatenate((tmp_L, tmp_R), axis=1) + return pg + + hdates_pg2 = ignore_lastyear_complete_season( + hdates_pg.copy(), lastyear_complete_season, mxharvests + ) + sdates_pg2 = ignore_lastyear_complete_season( + sdates_pg.copy(), lastyear_complete_season, mxharvests + ) + is_valid = ~np.isnan(hdates_pg2) + is_fake = np.isneginf(hdates_pg2) + is_fake = np.reshape(is_fake[is_valid], (this_ds.dims["patch"], Ngs)) + discrepancy = np.sum(is_valid) - expected_valid + unique_Nseasons = np.unique(np.sum(is_valid, axis=1)) + if verbose: + print( + f'After "Ignore any harvests that were planted in the final year, because other cells will have incomplete growing seasons for the final year": discrepancy of {discrepancy} patch-seasons' + ) + if "pandas" in sys.modules: + bc = np.bincount(np.sum(is_valid, axis=1)) + bc = bc[bc > 0] + df = pd.DataFrame({"Ngs": unique_Nseasons, "Count": bc}) + print(df) + else: + print(f"unique N seasons = {unique_Nseasons}") + print(" ") + + # Create Dataset with time axis as "gs" (growing season) instead of what CLM puts out + if discrepancy == 0: + this_ds_gs = set_up_ds_with_gs_axis(this_ds) + for v in this_ds.data_vars: + if this_ds[v].dims != ("time", "mxharvests", "patch") or (myVars and v not in myVars): + continue + + # Set invalid values to NaN + da_yhp = this_ds[v].copy() + da_yhp = da_yhp.where(~np.isneginf(da_yhp)) + + # Remove the nans and reshape to patches*growingseasons + da_pyh = da_yhp.transpose("patch", "time", "mxharvests") + ar_pg = np.reshape(da_pyh.values, (this_ds.dims["patch"], -1)) + ar_valid_pg = np.reshape(ar_pg[is_valid], (this_ds.dims["patch"], Ngs)) + # Change -infs to nans + ar_valid_pg[is_fake] = np.nan + # Save as DataArray to new Dataset, stripping _PERHARV from variable name + newname = v.replace("_PERHARV", "") + if newname in this_ds_gs: + raise RuntimeError(f"{newname} already in dataset!") + da_pg = xr.DataArray( + data=ar_valid_pg, + coords=[this_ds_gs.coords["patch"], this_ds_gs.coords["gs"]], + name=newname, + attrs=da_yhp.attrs, + ) + this_ds_gs[newname] = da_pg + this_ds_gs[newname].attrs["units"] = this_ds[v].attrs["units"] + else: + # Print details about example bad patch(es) + if min(unique_Nseasons) < Ngs: + print(f"Too few seasons (min {min(unique_Nseasons)} < {Ngs})") + p = np.where(np.sum(~np.isnan(hdates_pg2), axis=1) == min(unique_Nseasons))[0][0] + print_onepatch_wrongNgs( + p, + this_ds, + sdates_ymp, + hdates_ymp, + sdates_pym, + hdates_pym, + sdates_pym2, + hdates_pym2, + sdates_pym3, + hdates_pym3, + sdates_pg, + hdates_pg, + sdates_pg2, + hdates_pg2, + ) + if max(unique_Nseasons) > Ngs: + print(f"Too many seasons (max {max(unique_Nseasons)} > {Ngs})") + p = np.where(np.sum(~np.isnan(hdates_pg2), axis=1) == max(unique_Nseasons))[0][0] + print_onepatch_wrongNgs( + p, + this_ds, + sdates_ymp, + hdates_ymp, + sdates_pym, + hdates_pym, + sdates_pym2, + hdates_pym2, + sdates_pym3, + hdates_pym3, + sdates_pg, + hdates_pg, + sdates_pg2, + hdates_pg2, + ) + raise RuntimeError( + f"Can't convert time*mxharvests axes to growingseason axis: discrepancy of {discrepancy} patch-seasons" + ) + + # Preserve units + for v1 in this_ds_gs: + v0 = v1 + if v0 not in this_ds: + v0 += "_PERHARV" + if v0 not in this_ds: + continue + if "units" in this_ds[v0].attrs: + this_ds_gs[v1].attrs["units"] = this_ds[v0].attrs["units"] + + if incl_orig: + return this_ds_gs, this_ds + else: + return this_ds_gs + + +# Minimum harvest threshold allowed in PlantCrop() +# Was 50 before cropcal runs 2023-01-28 +def default_gdd_min(): + return 1.0 + + +# Get information about extreme gridcells (for debugging) +def get_extreme_info(diff_array, rx_array, mxn, dims, gs, patches1d_lon, patches1d_lat): + if mxn == np.min: + diff_array = np.ma.masked_array(diff_array, mask=(np.abs(diff_array) == 0)) + themxn = mxn(diff_array) + + # Find the first patch-gs that has the mxn value + matching_indices = np.where(diff_array == themxn) + first_indices = [x[0] for x in matching_indices] + + # Get the lon, lat, and growing season of that patch-gs + p = first_indices[dims.index("patch")] + thisLon = patches1d_lon.values[p] + thisLat = patches1d_lat.values[p] + s = first_indices[dims.index("gs")] + thisGS = gs.values[s] + + # Get the prescribed value for this patch-gs + thisRx = rx_array[p][0] + + return round(themxn, 3), round(thisLon, 3), round(thisLat, 3), thisGS, round(thisRx) + + +# Get growing season lengths from a DataArray of hdate-sdate +def get_gs_len_da(this_da): + tmp = this_da.values + with np.errstate(invalid="ignore"): + tmp_lt_0 = tmp < 0 + tmp[tmp_lt_0] = 365 + tmp[tmp_lt_0] + this_da.values = tmp + this_da.attrs["units"] = "days" + return this_da + + +def get_pct_harv_at_mature(harvest_reason_da): + Nharv_at_mature = len(np.where(harvest_reason_da.values == 1)[0]) + with np.errstate(invalid="ignore"): + harv_reason_gt_0 = harvest_reason_da.values > 0 + Nharv = len(np.where(harv_reason_gt_0)[0]) + if Nharv == 0: + return np.nan + pct_harv_at_mature = Nharv_at_mature / Nharv * 100 + pct_harv_at_mature = np.format_float_positional( + pct_harv_at_mature, precision=2, unique=False, fractional=False, trim="k" + ) # Round to 2 significant digits + return pct_harv_at_mature + + +def import_max_gs_length(paramfile_dir, my_clm_ver, my_clm_subver): + # Get parameter file + pattern = os.path.join(paramfile_dir, f"*{my_clm_ver}_params.{my_clm_subver}.nc") + paramfile = glob.glob(pattern) + if len(paramfile) != 1: + raise RuntimeError(f"Expected to find 1 match of {pattern}; found {len(paramfile)}") + paramfile_ds = xr.open_dataset(paramfile[0]) + + # Import max growing season length (stored in netCDF as nanoseconds!) + paramfile_mxmats = paramfile_ds["mxmat"].values / np.timedelta64(1, "D") + + # Import PFT name list + paramfile_pftnames = [ + x.decode("UTF-8").replace(" ", "") for x in paramfile_ds["pftname"].values + ] + + # Build dict + mxmat_dict = {} + for i, pftname in enumerate(paramfile_pftnames): + mxmat = paramfile_mxmats[i] + if not np.isnan(mxmat): + mxmat_dict[pftname] = int(mxmat) + else: + mxmat_dict[pftname] = np.inf + + return mxmat_dict + + +# E.g. import_rx_dates("sdate", sdates_rx_file, dates_ds0_orig) +def import_rx_dates(var_prefix, date_inFile, dates_ds, set_neg1_to_nan=True): + # Get run info: + # Max number of growing seasons per year + if "mxsowings" in dates_ds: + mxsowings = dates_ds.dims["mxsowings"] + else: + mxsowings = 1 + + # Which vegetation types were simulated? + itype_veg_toImport = np.unique(dates_ds.patches1d_itype_veg) + + date_varList = [] + for i in itype_veg_toImport: + for g in np.arange(mxsowings): + thisVar = f"{var_prefix}{g+1}_{i}" + date_varList = date_varList + [thisVar] + + ds = utils.import_ds(date_inFile, myVars=date_varList) + + did_warn = False + for v in ds: + v_new = v.replace(var_prefix, "gs") + ds = ds.rename({v: v_new}) + + # Set -1 prescribed GDD values to NaN. Only warn the first time. + if set_neg1_to_nan and var_prefix == "gdd" and v_new != v and np.any(ds[v_new].values < 0): + if np.any((ds[v_new].values < 0) & (ds[v_new].values != -1)): + raise RuntimeError(f"Unexpected negative value in {v}") + if not did_warn: + print(f"Setting -1 rx GDD values to NaN") + did_warn = True + ds[v_new] = ds[v_new].where(ds[v_new] != -1) + + return ds + + +def import_output( + filename, + myVars, + y1=None, + yN=None, + myVegtypes=utils.define_mgdcrop_list(), + sdates_rx_ds=None, + gdds_rx_ds=None, + verbose=False, +): + # Import + this_ds = utils.import_ds(filename, myVars=myVars, myVegtypes=myVegtypes) + + # Trim to years of interest (do not include extra year needed for finishing last growing season) + if y1 and yN: + this_ds = check_and_trim_years(y1, yN, this_ds) + else: # Assume including all growing seasons except last complete one are "of interest" + y1 = this_ds.time.values[0].year + yN = this_ds.time.values[-1].year - 2 + this_ds = check_and_trim_years(y1, yN, this_ds) + + # What vegetation types are included? + vegtype_list = [ + x for x in this_ds.vegtype_str.values if x in this_ds.patches1d_itype_veg_str.values + ] + + # Check for consistency among sowing/harvest date/year info + date_vars = ["SDATES_PERHARV", "SYEARS_PERHARV", "HDATES", "HYEARS"] + all_nan = np.full(this_ds[date_vars[0]].shape, True) + all_nonpos = np.full(this_ds[date_vars[0]].shape, True) + all_pos = np.full(this_ds[date_vars[0]].shape, True) + for v in date_vars: + all_nan = all_nan & np.isnan(this_ds[v].values) + with np.errstate(invalid="ignore"): + all_nonpos = all_nonpos & (this_ds[v].values <= 0) + all_pos = all_pos & (this_ds[v].values > 0) + if np.any(np.bitwise_not(all_nan | all_nonpos | all_pos)): + raise RuntimeError("Inconsistent missing/present values on mxharvests axis") + + # When doing transient runs, it's somehow possible for crops in newly-active patches to be *already alive*. They even have a sowing date (idop)! This will of course not show up in SDATES, but it does show up in SDATES_PERHARV. + # I could put the SDATES_PERHARV dates into where they "should" be, but instead I'm just going to invalidate those "seasons." + # + # In all but the last calendar year, which patches had no sowing? + no_sowing_yp = np.all(np.isnan(this_ds.SDATES.values[:-1, :, :]), axis=1) + # In all but the first calendar year, which harvests' jdays are < their sowings' jdays? (Indicates sowing the previous calendar year.) + with np.errstate(invalid="ignore"): + hsdate1_gt_hdate1_yp = ( + this_ds.SDATES_PERHARV.values[1:, 0, :] > this_ds.HDATES.values[1:, 0, :] + ) + # Where both, we have the problem. + falsely_alive_yp = no_sowing_yp & hsdate1_gt_hdate1_yp + if np.any(falsely_alive_yp): + print( + f"Warning: {np.sum(falsely_alive_yp)} patch-seasons being ignored: Seemingly sown the year before harvest, but no sowings occurred that year." + ) + falsely_alive_yp = np.concatenate( + (np.full((1, this_ds.dims["patch"]), False), falsely_alive_yp), axis=0 + ) + falsely_alive_y1p = np.expand_dims(falsely_alive_yp, axis=1) + dummy_false_y1p = np.expand_dims(np.full_like(falsely_alive_yp, False), axis=1) + falsely_alive_yhp = np.concatenate((falsely_alive_y1p, dummy_false_y1p), axis=1) + for v in this_ds.data_vars: + if this_ds[v].dims != ("time", "mxharvests", "patch"): + continue + this_ds[v] = this_ds[v].where(~falsely_alive_yhp) + + def check_no_negative(this_ds_in, varList_no_negative, which_file, verbose=False): + tiny_negOK = 1e-12 + this_ds = this_ds_in.copy() + for v in this_ds: + if not any(x in v for x in varList_no_negative): + continue + the_min = np.nanmin(this_ds[v].values) + if the_min < 0: + if np.abs(the_min) <= tiny_negOK: + if verbose: + print( + f"Tiny negative value(s) in {v} (abs <= {tiny_negOK}) being set to 0 ({which_file})" + ) + else: + print( + f"WARNING: Unexpected negative value(s) in {v}; minimum {the_min} ({which_file})" + ) + values = this_ds[v].copy().values + with np.errstate(invalid="ignore"): + do_setto_0 = (values < 0) & (values >= -tiny_negOK) + values[np.where(do_setto_0)] = 0 + this_ds[v] = xr.DataArray( + values, coords=this_ds[v].coords, dims=this_ds[v].dims, attrs=this_ds[v].attrs + ) + + elif verbose: + print(f"No negative value(s) in {v}; min {the_min} ({which_file})") + return this_ds + + def check_no_zeros(this_ds, varList_no_zero, which_file): + for v in this_ds: + if not any(x in v for x in varList_no_zero): + continue + if np.any(this_ds[v].values == 0): + print(f"WARNING: Unexpected zero(s) in {v} ({which_file})") + elif verbose: + print(f"No zero value(s) in {v} ({which_file})") + + # Check for no zero values where there shouldn't be + varList_no_zero = ["DATE", "YEAR"] + check_no_zeros(this_ds, varList_no_zero, "original file") + + # Convert time*mxharvests axes to growingseason axis + this_ds_gs = convert_axis_time2gs(this_ds, verbose=verbose, incl_orig=False) + + # These are needed for calculating yield later + this_ds_gs["GRAINC_TO_FOOD_PERHARV"] = this_ds["GRAINC_TO_FOOD_PERHARV"] + this_ds_gs["GDDHARV_PERHARV"] = this_ds["GDDHARV_PERHARV"] + + # Get growing season length + this_ds["GSLEN_PERHARV"] = get_gs_len_da(this_ds["HDATES"] - this_ds["SDATES_PERHARV"]) + this_ds_gs["GSLEN"] = get_gs_len_da(this_ds_gs["HDATES"] - this_ds_gs["SDATES"]) + this_ds_gs["GSLEN_PERHARV"] = this_ds["GSLEN_PERHARV"] + + # Get HUI accumulation as fraction of required + this_ds_gs["HUIFRAC"] = this_ds_gs["HUI"] / this_ds_gs["GDDHARV"] + this_ds_gs["HUIFRAC_PERHARV"] = this_ds["HUI_PERHARV"] / this_ds["GDDHARV_PERHARV"] + for v in ["HUIFRAC", "HUIFRAC_PERHARV"]: + this_ds_gs[v].attrs["units"] = "Fraction of required" + + # Avoid tiny negative values + varList_no_negative = ["GRAIN", "REASON", "GDD", "HUI", "YEAR", "DATE", "GSLEN"] + this_ds_gs = check_no_negative(this_ds_gs, varList_no_negative, "new file", verbose=verbose) + + # Check for no zero values where there shouldn't be + varList_no_zero = ["REASON", "DATE"] + check_no_zeros(this_ds_gs, varList_no_zero, "new file") + + # Check that e.g., GDDACCUM <= HUI + for vars in [["GDDACCUM", "HUI"], ["SYEARS", "HYEARS"]]: + if all(v in this_ds_gs for v in vars): + check_v0_le_v1(this_ds_gs, vars, both_nan_ok=True, throw_error=True) + + # Check that prescribed calendars were obeyed + if sdates_rx_ds: + check_rx_obeyed(vegtype_list, sdates_rx_ds, this_ds, "this_ds", "SDATES") + if gdds_rx_ds: + check_rx_obeyed( + vegtype_list, + gdds_rx_ds, + this_ds, + "this_ds", + "SDATES", + "GDDHARV", + gdd_min=default_gdd_min(), + ) + + # Convert time axis to integer year, saving original as 'cftime' + this_ds_gs = this_ds_gs.assign_coords( + {"cftime": this_ds["time_bounds"].isel({"hist_interval": 0})} + ) + this_ds_gs = this_ds_gs.assign_coords({"time": [t.year for t in this_ds_gs["cftime"].values]}) + + # Get number of harvests + this_ds_gs["NHARVESTS"] = (this_ds_gs["GDDHARV_PERHARV"] > 0).sum(dim="mxharvests") + # Get number of harvests that would be missed if only seeing max 1 per calendar year + if np.any(this_ds_gs["NHARVESTS"] > 2): + raise RuntimeError("How to get NHARVEST_DISCREP for NHARVESTS > 2?") + this_ds_gs["NHARVEST_DISCREP"] = (this_ds_gs["NHARVESTS"] == 2).astype(int) + + return this_ds_gs + + +# Print information about a patch (for debugging) +def print_onepatch_wrongNgs( + p, + this_ds_orig, + sdates_ymp, + hdates_ymp, + sdates_pym, + hdates_pym, + sdates_pym2, + hdates_pym2, + sdates_pym3, + hdates_pym3, + sdates_pg, + hdates_pg, + sdates_pg2, + hdates_pg2, +): + try: + import pandas as pd + except: + print("Couldn't import pandas, so not displaying example bad patch ORIGINAL.") + + print( + f"patch {p}: {this_ds_orig.patches1d_itype_veg_str.values[p]}, lon" + f" {this_ds_orig.patches1d_lon.values[p]} lat {this_ds_orig.patches1d_lat.values[p]}" + ) + + print("Original SDATES (per sowing):") + print(this_ds_orig.SDATES.values[:, :, p]) + + print("Original HDATES (per harvest):") + print(this_ds_orig.HDATES.values[:, :, p]) + + if "pandas" in sys.modules: + + def print_pandas_ymp(msg, cols, arrs_tuple): + print(f"{msg} ({np.sum(~np.isnan(arrs_tuple[0]))})") + mxharvests = arrs_tuple[0].shape[1] + arrs_list2 = [] + cols2 = [] + for h in np.arange(mxharvests): + for i, a in enumerate(arrs_tuple): + arrs_list2.append(a[:, h]) + cols2.append(cols[i] + str(h)) + arrs_tuple2 = tuple(arrs_list2) + df = pd.DataFrame(np.stack(arrs_tuple2, axis=1)) + df.columns = cols2 + print(df) + + print_pandas_ymp( + "Original", + ["sdate", "hdate"], + (this_ds_orig.SDATES_PERHARV.values[:, :, p], this_ds_orig.HDATES.values[:, :, p]), + ) + + print_pandas_ymp("Masked", ["sdate", "hdate"], (sdates_ymp[:, :, p], hdates_ymp[:, :, p])) + + print_pandas_ymp( + 'After "Ignore harvests from before this output began"', + ["sdate", "hdate"], + ( + np.transpose(sdates_pym, (1, 2, 0))[:, :, p], + np.transpose(hdates_pym, (1, 2, 0))[:, :, p], + ), + ) + + print_pandas_ymp( + 'After "In years with no sowing, pretend the first no-harvest is meaningful"', + ["sdate", "hdate"], + ( + np.transpose(sdates_pym2, (1, 2, 0))[:, :, p], + np.transpose(hdates_pym2, (1, 2, 0))[:, :, p], + ), + ) + + print_pandas_ymp( + ( + 'After "In years with sowing that are followed by inactive years, check whether the' + " last sowing was harvested before the patch was deactivated. If not, pretend the" + ' LAST no-harvest is meaningful."' + ), + ["sdate", "hdate"], + ( + np.transpose(sdates_pym3, (1, 2, 0))[:, :, p], + np.transpose(hdates_pym3, (1, 2, 0))[:, :, p], + ), + ) + + def print_pandas_pg(msg, cols, arrs_tuple): + print(f"{msg} ({np.sum(~np.isnan(arrs_tuple[0]))})") + arrs_list = list(arrs_tuple) + for i, a in enumerate(arrs_tuple): + arrs_list[i] = np.reshape(a, (-1)) + arrs_tuple2 = tuple(arrs_list) + df = pd.DataFrame(np.stack(arrs_tuple2, axis=1)) + df.columns = cols + print(df) + + print_pandas_pg( + "Same, but converted to gs axis", ["sdate", "hdate"], (sdates_pg[p, :], hdates_pg[p, :]) + ) + + print_pandas_pg( + ( + 'After "Ignore any harvests that were planted in the final year, because some cells' + ' will have incomplete growing seasons for the final year"' + ), + ["sdate", "hdate"], + (sdates_pg2[p, :], hdates_pg2[p, :]), + ) + else: + + def print_nopandas(a1, a2, msg): + print(msg) + if a1.ndim == 1: + # I don't know why these aren't side-by-side! + print(np.stack((a1, a2), axis=1)) + else: + print(np.concatenate((a1, a2), axis=1)) + + print_nopandas(sdates_ymp[:, :, p], hdates_ymp[:, :, p], "Masked:") + + print_nopandas( + np.transpose(sdates_pym, (1, 2, 0))[:, :, p], + np.transpose(hdates_pym, (1, 2, 0))[:, :, p], + 'After "Ignore harvests from before this output began"', + ) + + print_nopandas( + np.transpose(sdates_pym2, (1, 2, 0))[:, :, p], + np.transpose(hdates_pym2, (1, 2, 0))[:, :, p], + 'After "In years with no sowing, pretend the first no-harvest is meaningful"', + ) + + print_nopandas( + np.transpose(sdates_pym3, (1, 2, 0))[:, :, p], + np.transpose(hdates_pym3, (1, 2, 0))[:, :, p], + ( + 'After "In years with sowing that are followed by inactive years, check whether the' + " last sowing was harvested before the patch was deactivated. If not, pretend the" + ' LAST [easier to implement!] no-harvest is meaningful."' + ), + ) + + print_nopandas(sdates_pg[p, :], hdates_pg[p, :], "Same, but converted to gs axis") + + print_nopandas( + sdates_pg2[p, :], + hdates_pg2[p, :], + ( + 'After "Ignore any harvests that were planted in the final year, because some cells' + ' will have incomplete growing seasons for the final year"' + ), + ) + + print("\n\n") + + +# Set up empty Dataset with time axis as "gs" (growing season) instead of what CLM puts out. +# Includes all the same variables as the input dataset, minus any that had dimensions mxsowings or mxharvests. +def set_up_ds_with_gs_axis(ds_in): + # Get the data variables to include in the new dataset + data_vars = dict() + for v in ds_in.data_vars: + if not any([x in ["mxsowings", "mxharvests"] for x in ds_in[v].dims]): + data_vars[v] = ds_in[v] + # Set up the new dataset + gs_years = [t.year - 1 for t in ds_in.time.values[:-1]] + coords = ds_in.coords + coords["gs"] = gs_years + ds_out = xr.Dataset(data_vars=data_vars, coords=coords, attrs=ds_in.attrs) + return ds_out diff --git a/python/ctsm/crop_calendars/cropcal_utils.py b/python/ctsm/crop_calendars/cropcal_utils.py new file mode 100644 index 0000000000..ba6c0b6e41 --- /dev/null +++ b/python/ctsm/crop_calendars/cropcal_utils.py @@ -0,0 +1,934 @@ +"""utility functions""" +"""copied from klindsay, https://github.com/klindsay28/CESM2_coup_carb_cycle_JAMES/blob/master/utils.py""" + +import re +import warnings +import importlib + +with warnings.catch_warnings(): + warnings.filterwarnings(action="ignore", category=DeprecationWarning) + if importlib.find_loader("cf_units") is not None: + import cf_units as cf + if importlib.find_loader("cartopy") is not None: + from cartopy.util import add_cyclic_point +import cftime +import numpy as np +import xarray as xr + +# from xr_ds_ex import xr_ds_ex + + +# generate annual means, weighted by days / month +def weighted_annual_mean(array, time_in="time", time_out="time"): + if isinstance(array[time_in].values[0], cftime.datetime): + month_length = array[time_in].dt.days_in_month + + # After https://docs.xarray.dev/en/v0.5.1/examples/monthly-means.html + group = f"{time_in}.year" + weights = month_length.groupby(group) / month_length.groupby(group).sum() + np.testing.assert_allclose(weights.groupby(group).sum().values, 1) + array = (array * weights).groupby(group).sum(dim=time_in, skipna=True) + if time_out != "year": + array = array.rename({"year": time_out}) + + else: + mon_day = xr.DataArray( + np.array([31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]), dims=["month"] + ) + mon_wgt = mon_day / mon_day.sum() + array = ( + array.rolling({time_in: 12}, center=False) # rolling + .construct("month") # construct the array + .isel( + {time_in: slice(11, None, 12)} + ) # slice so that the first element is [1..12], second is [13..24] + .dot(mon_wgt, dims=["month"]) + ) + if time_in != time_out: + array = array.rename({time_in: time_out}) + + return array + + +# List of PFTs used in CLM +def define_pftlist(): + pftlist = [ + "not_vegetated", + "needleleaf_evergreen_temperate_tree", + "needleleaf_evergreen_boreal_tree", + "needleleaf_deciduous_boreal_tree", + "broadleaf_evergreen_tropical_tree", + "broadleaf_evergreen_temperate_tree", + "broadleaf_deciduous_tropical_tree", + "broadleaf_deciduous_temperate_tree", + "broadleaf_deciduous_boreal_tree", + "broadleaf_evergreen_shrub", + "broadleaf_deciduous_temperate_shrub", + "broadleaf_deciduous_boreal_shrub", + "c3_arctic_grass", + "c3_non-arctic_grass", + "c4_grass", + "unmanaged_c3_crop", + "unmanaged_c3_irrigated", + "temperate_corn", + "irrigated_temperate_corn", + "spring_wheat", + "irrigated_spring_wheat", + "winter_wheat", + "irrigated_winter_wheat", + "soybean", + "irrigated_soybean", + "barley", + "irrigated_barley", + "winter_barley", + "irrigated_winter_barley", + "rye", + "irrigated_rye", + "winter_rye", + "irrigated_winter_rye", + "cassava", + "irrigated_cassava", + "citrus", + "irrigated_citrus", + "cocoa", + "irrigated_cocoa", + "coffee", + "irrigated_coffee", + "cotton", + "irrigated_cotton", + "datepalm", + "irrigated_datepalm", + "foddergrass", + "irrigated_foddergrass", + "grapes", + "irrigated_grapes", + "groundnuts", + "irrigated_groundnuts", + "millet", + "irrigated_millet", + "oilpalm", + "irrigated_oilpalm", + "potatoes", + "irrigated_potatoes", + "pulses", + "irrigated_pulses", + "rapeseed", + "irrigated_rapeseed", + "rice", + "irrigated_rice", + "sorghum", + "irrigated_sorghum", + "sugarbeet", + "irrigated_sugarbeet", + "sugarcane", + "irrigated_sugarcane", + "sunflower", + "irrigated_sunflower", + "miscanthus", + "irrigated_miscanthus", + "switchgrass", + "irrigated_switchgrass", + "tropical_corn", + "irrigated_tropical_corn", + "tropical_soybean", + "irrigated_tropical_soybean", + ] + return pftlist + + +# Get CLM ivt number corresponding to a given name +def ivt_str2int(ivt_str): + pftlist = define_pftlist() + if isinstance(ivt_str, str): + ivt_int = pftlist.index(ivt_str) + elif isinstance(ivt_str, list) or isinstance(ivt_str, np.ndarray): + ivt_int = [ivt_str2int(x) for x in ivt_str] + if isinstance(ivt_str, np.ndarray): + ivt_int = np.array(ivt_int) + else: + raise RuntimeError( + f"Update ivt_str_to_int() to handle input of type {type(ivt_str)} (if possible)" + ) + + return ivt_int + + +# Get CLM ivt name corresponding to a given number +def ivt_int2str(ivt_int): + pftlist = define_pftlist() + if np.issubdtype(type(ivt_int), np.integer) or int(ivt_int) == ivt_int: + ivt_str = pftlist[int(ivt_int)] + elif isinstance(ivt_int, list) or isinstance(ivt_int, np.ndarray): + ivt_str = [ivt_int2str(x) for x in ivt_int] + if isinstance(ivt_int, np.ndarray): + ivt_str = np.array(ivt_str) + elif isinstance(ivt_int, float): + raise RuntimeError("List indices must be integers") + else: + raise RuntimeError( + f"Update ivt_str_to_int() to handle input of type {type(ivt_int)} (if possible)" + ) + + return ivt_str + + +# Does this vegetation type's name match (for a given comparison method) any member of a filtering list? +""" +Methods: + ok_contains: True if any member of this_filter is found in this_vegtype. + notok_contains: True of no member of this_filter is found in this_vegtype. + ok_exact: True if this_vegtype matches any member of this_filter + exactly. + notok_exact: True if this_vegtype does not match any member of + this_filter exactly. +""" + + +def is_this_vegtype(this_vegtype, this_filter, this_method): + # Make sure data type of this_vegtype is acceptable + if isinstance(this_vegtype, float) and int(this_vegtype) == this_vegtype: + this_vegtype = int(this_vegtype) + data_type_ok = lambda x: isinstance(x, str) or isinstance(x, int) or isinstance(x, np.int64) + ok_input = True + if not data_type_ok(this_vegtype): + if isinstance(this_vegtype, xr.core.dataarray.DataArray): + this_vegtype = this_vegtype.values + if isinstance(this_vegtype, (list, np.ndarray)): + if len(this_vegtype) == 1 and data_type_ok(this_vegtype[0]): + this_vegtype = this_vegtype[0] + elif data_type_ok(this_vegtype[0]): + raise TypeError( + "is_this_vegtype(): this_vegtype must be a single string or integer, not a list" + " of them. Did you mean to call is_each_vegtype() instead?" + ) + else: + ok_input = False + else: + ok_input = False + if not ok_input: + raise TypeError( + "is_this_vegtype(): First argument (this_vegtype) must be a string or integer, not" + f" {type(this_vegtype)}" + ) + + # Make sure data type of this_filter is acceptable + if not np.iterable(this_filter): + raise TypeError( + "is_this_vegtype(): Second argument (this_filter) must be iterable (e.g., a list), not" + f" {type(this_filter)}" + ) + + # Perform the comparison + if this_method == "ok_contains": + return any(n in this_vegtype for n in this_filter) + elif this_method == "notok_contains": + return not any(n in this_vegtype for n in this_filter) + elif this_method == "ok_exact": + return any(n == this_vegtype for n in this_filter) + elif this_method == "notok_exact": + return not any(n == this_vegtype for n in this_filter) + else: + raise ValueError(f"Unknown comparison method: '{this_method}'") + + +# Get boolean list of whether each vegetation type in list is a managed crop +""" + this_vegtypelist: The list of vegetation types whose members you want to + test. + this_filter: The list of strings against which you want to compare + each member of this_vegtypelist. + this_method: How you want to do the comparison. See is_this_vegtype(). +""" + + +def is_each_vegtype(this_vegtypelist, this_filter, this_method): + if isinstance(this_vegtypelist, xr.DataArray): + this_vegtypelist = this_vegtypelist.values + + return [is_this_vegtype(x, this_filter, this_method) for x in this_vegtypelist] + + +# List (strings) of managed crops in CLM. +def define_mgdcrop_list(): + notcrop_list = ["tree", "grass", "shrub", "unmanaged", "not_vegetated"] + defined_pftlist = define_pftlist() + is_crop = is_each_vegtype(defined_pftlist, notcrop_list, "notok_contains") + return [defined_pftlist[i] for i, x in enumerate(is_crop) if x] + + +# Convert list of vegtype strings to integer index equivalents. +def vegtype_str2int(vegtype_str, vegtype_mainlist=None): + convert_to_ndarray = not isinstance(vegtype_str, np.ndarray) + if convert_to_ndarray: + vegtype_str = np.array(vegtype_str) + + if isinstance(vegtype_mainlist, xr.Dataset): + vegtype_mainlist = vegtype_mainlist.vegtype_str.values + elif isinstance(vegtype_mainlist, xr.DataArray): + vegtype_mainlist = vegtype_mainlist.values + elif vegtype_mainlist == None: + vegtype_mainlist = define_pftlist() + if not isinstance(vegtype_mainlist, list) and isinstance(vegtype_mainlist[0], str): + if isinstance(vegtype_mainlist, list): + raise TypeError( + f"Not sure how to handle vegtype_mainlist as list of {type(vegtype_mainlist[0])}" + ) + else: + raise TypeError( + f"Not sure how to handle vegtype_mainlist as type {type(vegtype_mainlist[0])}" + ) + + if vegtype_str.shape == (): + indices = np.array([-1]) + else: + indices = np.full(len(vegtype_str), -1) + for v in np.unique(vegtype_str): + indices[np.where(vegtype_str == v)] = vegtype_mainlist.index(v) + if convert_to_ndarray: + indices = [int(x) for x in indices] + return indices + + +# Flexibly subset time(s) and/or vegetation type(s) from an xarray Dataset or DataArray. Keyword arguments like dimension=selection. Selections can be individual values or slice()s. Optimize memory usage by beginning keyword argument list with the selections that will result in the largest reduction of object size. Use dimension "vegtype" to extract patches of designated vegetation type (can be string or integer). +# Can also do dimension=function---e.g., time=np.mean will take the mean over the time dimension. +def xr_flexsel(xr_object, patches1d_itype_veg=None, warn_about_seltype_interp=True, **kwargs): + # Setup + havewarned = False + delimiter = "__" + + for key, selection in kwargs.items(): + if callable(selection): + # It would have been really nice to do selection(xr_object, axis=key), but numpy methods and xarray methods disagree on "axis" vs. "dimension." So instead, just do this manually. + if selection == np.mean: + try: + xr_object = xr_object.mean(dim=key) + except: + raise ValueError( + f"Failed to take mean of dimension {key}. Try doing so outside of" + " xr_flexsel()." + ) + else: + raise ValueError(f"xr_flexsel() doesn't recognize function {selection}") + + elif key == "vegtype": + # Convert to list, if needed + if not isinstance(selection, list): + selection = [selection] + + # Convert to indices, if needed + if isinstance(selection[0], str): + selection = vegtype_str2int(selection) + + # Get list of boolean(s) + if isinstance(selection[0], int): + if isinstance(patches1d_itype_veg, type(None)): + patches1d_itype_veg = xr_object.patches1d_itype_veg.values + elif isinstance(patches1d_itype_veg, xr.core.dataarray.DataArray): + patches1d_itype_veg = patches1d_itype_veg.values + is_vegtype = is_each_vegtype(patches1d_itype_veg, selection, "ok_exact") + elif isinstance(selection[0], bool): + if len(selection) != len(xr_object.patch): + raise ValueError( + "If providing boolean 'vegtype' argument to xr_flexsel(), it must be the" + f" same length as xr_object.patch ({len(selection)} vs." + f" {len(xr_object.patch)})" + ) + is_vegtype = selection + else: + raise TypeError(f"Not sure how to handle 'vegtype' of type {type(selection[0])}") + xr_object = xr_object.isel(patch=[i for i, x in enumerate(is_vegtype) if x]) + if "ivt" in xr_object: + xr_object = xr_object.isel( + ivt=is_each_vegtype(xr_object.ivt.values, selection, "ok_exact") + ) + + else: + # Parse selection type, if provided + if delimiter in key: + key, selection_type = key.split(delimiter) + + # Check type of selection + else: + is_inefficient = False + if isinstance(selection, slice): + slice_members = [] + if selection == slice(0): + raise ValueError("slice(0) will be empty") + if selection.start != None: + slice_members = slice_members + [selection.start] + if selection.stop != None: + slice_members = slice_members + [selection.stop] + if selection.step != None: + slice_members = slice_members + [selection.step] + if slice_members == []: + raise TypeError("slice is all None?") + this_type = int + for x in slice_members: + if x < 0 or not isinstance(x, int): + this_type = "values" + break + elif isinstance(selection, np.ndarray): + if selection.dtype.kind in np.typecodes["AllInteger"]: + this_type = int + else: + is_inefficient = True + this_type = None + for x in selection: + if x < 0 or x % 1 > 0: + if isinstance(x, int): + this_type = "values" + else: + this_type = type(x) + break + if this_type == None: + this_type = int + selection = selection.astype(int) + else: + this_type = type(selection) + + warn_about_this_seltype_interp = warn_about_seltype_interp + if this_type == list and isinstance(selection[0], str): + selection_type = "values" + warn_about_this_seltype_interp = False + elif this_type == int: + selection_type = "indices" + else: + selection_type = "values" + + if warn_about_this_seltype_interp: + # Suggest suppressing selection type interpretation warnings + if not havewarned: + print( + "xr_flexsel(): Suppress all 'selection type interpretation' messages by" + " specifying warn_about_seltype_interp=False" + ) + havewarned = True + if is_inefficient: + extra = " This will also improve efficiency for large selections." + else: + extra = "" + print( + f"xr_flexsel(): Selecting {key} as {selection_type} because selection was" + f" interpreted as {this_type}. If not correct, specify selection type" + " ('indices' or 'values') in keyword like" + f" '{key}{delimiter}SELECTIONTYPE=...' instead of '{key}=...'.{extra}" + ) + + # Trim along relevant 1d axes + if isinstance(xr_object, xr.Dataset) and key in ["lat", "lon"]: + if selection_type == "indices": + inclCoords = xr_object[key].values[selection] + elif selection_type == "values": + if isinstance(selection, slice): + inclCoords = xr_object.sel({key: selection}, drop=False)[key].values + else: + inclCoords = selection + else: + raise TypeError(f"selection_type {selection_type} not recognized") + if key == "lat": + thisXY = "jxy" + elif key == "lon": + thisXY = "ixy" + else: + raise KeyError( + f"Key '{key}' not recognized: What 1d_ suffix should I use for variable" + " name?" + ) + pattern = re.compile(f"1d_{thisXY}") + matches = [x for x in list(xr_object.keys()) if pattern.search(x) != None] + for thisVar in matches: + if len(xr_object[thisVar].dims) != 1: + raise RuntimeError( + f"Expected {thisVar} to have 1 dimension, but it has" + f" {len(xr_object[thisVar].dims)}: {xr_object[thisVar].dims}" + ) + thisVar_dim = xr_object[thisVar].dims[0] + # print(f"Variable {thisVar} has dimension {thisVar_dim}") + thisVar_coords = xr_object[key].values[ + xr_object[thisVar].values.astype(int) - 1 + ] + # print(f"{thisVar_dim} size before: {xr_object.sizes[thisVar_dim]}") + ok_ind = [] + new_1d_thisXY = [] + for i, x in enumerate(thisVar_coords): + if x in inclCoords: + ok_ind = ok_ind + [i] + new_1d_thisXY = new_1d_thisXY + [(inclCoords == x).nonzero()[0] + 1] + xr_object = xr_object.isel({thisVar_dim: ok_ind}) + new_1d_thisXY = np.array(new_1d_thisXY).squeeze() + xr_object[thisVar].values = new_1d_thisXY + # print(f"{thisVar_dim} size after: {xr_object.sizes[thisVar_dim]}") + + # Perform selection + if selection_type == "indices": + # Have to select like this instead of with index directly because otherwise assign_coords() will throw an error. Not sure why. + if isinstance(selection, int): + # Single integer? Turn it into a slice. + selection = slice(selection, selection + 1) + elif ( + isinstance(selection, np.ndarray) + and not selection.dtype.kind in np.typecodes["AllInteger"] + ): + selection = selection.astype(int) + xr_object = xr_object.isel({key: selection}) + elif selection_type == "values": + xr_object = xr_object.sel({key: selection}) + else: + raise TypeError(f"selection_type {selection_type} not recognized") + + return xr_object + + +# Get PFT of each patch, in both integer and string forms. +def get_patch_ivts(this_ds, this_pftlist): + # First, get all the integer values; should be time*pft or pft*time. We will eventually just take the first timestep. + vegtype_int = this_ds.patches1d_itype_veg + vegtype_int.values = vegtype_int.values.astype(int) + + # Convert to strings. + vegtype_str = list(np.array(this_pftlist)[vegtype_int.values]) + + # Return a dictionary with both results + return {"int": vegtype_int, "str": vegtype_str, "all_str": this_pftlist} + + +# Convert a list of strings with vegetation type names into a DataArray. Used to add vegetation type info in import_ds(). +def get_vegtype_str_da(vegtype_str): + nvt = len(vegtype_str) + thisName = "vegtype_str" + vegtype_str_da = xr.DataArray( + vegtype_str, coords={"ivt": np.arange(0, nvt)}, dims=["ivt"], name=thisName + ) + return vegtype_str_da + + +# Function to drop unwanted variables in preprocessing of open_mfdataset(), making sure to NOT drop any unspecified variables that will be useful in gridding. Also adds vegetation type info in the form of a DataArray of strings. +# Also renames "pft" dimension (and all like-named variables, e.g., pft1d_itype_veg_str) to be named like "patch". This can later be reversed, for compatibility with other code, using patch2pft(). +def mfdataset_preproc(ds, vars_to_import, vegtypes_to_import, timeSlice): + # Rename "pft" dimension and variables to "patch", if needed + if "pft" in ds.dims: + pattern = re.compile("pft.*1d") + matches = [x for x in list(ds.keys()) if pattern.search(x) != None] + pft2patch_dict = {"pft": "patch"} + for m in matches: + pft2patch_dict[m] = m.replace("pft", "patch").replace("patchs", "patches") + ds = ds.rename(pft2patch_dict) + + derived_vars = [] + if vars_to_import != None: + # Split vars_to_import into variables that are vs. aren't already in ds + derived_vars = [v for v in vars_to_import if v not in ds] + present_vars = [v for v in vars_to_import if v in ds] + vars_to_import = present_vars + + # Get list of dimensions present in variables in vars_to_import. + dimList = [] + for thisVar in vars_to_import: + # list(set(x)) returns a list of the unique items in x + dimList = list(set(dimList + list(ds.variables[thisVar].dims))) + + # Get any _1d variables that are associated with those dimensions. These will be useful in gridding. Also, if any dimension is "pft", set up to rename it and all like-named variables to "patch" + onedVars = [] + for thisDim in dimList: + pattern = re.compile(f"{thisDim}.*1d") + matches = [x for x in list(ds.keys()) if pattern.search(x) != None] + onedVars = list(set(onedVars + matches)) + + # Add dimensions and _1d variables to vars_to_import + vars_to_import = list(set(vars_to_import + list(ds.dims) + onedVars)) + + # Add any _bounds variables + bounds_vars = [] + for v in vars_to_import: + bounds_var = v + "_bounds" + if bounds_var in ds: + bounds_vars = bounds_vars + [bounds_var] + vars_to_import = vars_to_import + bounds_vars + + # Get list of variables to drop + varlist = list(ds.variables) + vars_to_drop = list(np.setdiff1d(varlist, vars_to_import)) + + # Drop them + ds = ds.drop_vars(vars_to_drop) + + # Add vegetation type info + if "patches1d_itype_veg" in list(ds): + this_pftlist = define_pftlist() + get_patch_ivts( + ds, this_pftlist + ) # Includes check of whether vegtype changes over time anywhere + vegtype_da = get_vegtype_str_da(this_pftlist) + patches1d_itype_veg_str = vegtype_da.values[ + ds.isel(time=0).patches1d_itype_veg.values.astype(int) + ] + npatch = len(patches1d_itype_veg_str) + patches1d_itype_veg_str = xr.DataArray( + patches1d_itype_veg_str, + coords={"patch": np.arange(0, npatch)}, + dims=["patch"], + name="patches1d_itype_veg_str", + ) + ds = xr.merge([ds, vegtype_da, patches1d_itype_veg_str]) + + # Restrict to veg. types of interest, if any + if vegtypes_to_import != None: + ds = xr_flexsel(ds, vegtype=vegtypes_to_import) + + # Restrict to time slice, if any + if timeSlice: + ds = safer_timeslice(ds, timeSlice) + + # Finish import + ds = xr.decode_cf(ds, decode_times=True) + + # Compute derived variables + for v in derived_vars: + if v == "HYEARS" and "HDATES" in ds and ds.HDATES.dims == ("time", "mxharvests", "patch"): + yearList = np.array([np.float32(x.year - 1) for x in ds.time.values]) + hyears = ds["HDATES"].copy() + hyears.values = np.tile( + np.expand_dims(yearList, (1, 2)), (1, ds.dims["mxharvests"], ds.dims["patch"]) + ) + with np.errstate(invalid="ignore"): + is_le_zero = ~np.isnan(ds.HDATES.values) & (ds.HDATES.values <= 0) + hyears.values[is_le_zero] = ds.HDATES.values[is_le_zero] + hyears.values[np.isnan(ds.HDATES.values)] = np.nan + hyears.attrs["long_name"] = "DERIVED: actual crop harvest years" + hyears.attrs["units"] = "year" + ds["HYEARS"] = hyears + + return ds + + +# Import a dataset that can be spread over multiple files, only including specified variables and/or vegetation types and/or timesteps, concatenating by time. DOES actually read the dataset into memory, but only AFTER dropping unwanted variables and/or vegetation types. +def import_ds( + filelist, + myVars=None, + myVegtypes=None, + timeSlice=None, + myVars_missing_ok=[], + only_active_patches=False, + rename_lsmlatlon=False, + chunks=None, +): + # Convert myVegtypes here, if needed, to avoid repeating the process each time you read a file in xr.open_mfdataset(). + if myVegtypes is not None: + if not isinstance(myVegtypes, list): + myVegtypes = [myVegtypes] + if isinstance(myVegtypes[0], str): + myVegtypes = vegtype_str2int(myVegtypes) + + # Same for these variables. + if myVars != None: + if not isinstance(myVars, list): + myVars = [myVars] + if myVars_missing_ok: + if not isinstance(myVars_missing_ok, list): + myVars_missing_ok = [myVars_missing_ok] + + # Make sure lists are actually lists + if not isinstance(filelist, list): + filelist = [filelist] + if not isinstance(myVars_missing_ok, list): + myVars_missing_ok = [myVars_missing_ok] + + # Remove files from list if they don't contain requested timesteps. + # timeSlice should be in the format slice(start,end[,step]). start or end can be None to be unbounded on one side. Note that the standard slice() documentation suggests that only elements through end-1 will be selected, but that seems not to be the case in the xarray implementation. + if timeSlice: + new_filelist = [] + for file in sorted(filelist): + filetime = xr.open_dataset(file).time + filetime_sel = safer_timeslice(filetime, timeSlice) + include_this_file = filetime_sel.size + if include_this_file: + new_filelist.append(file) + + # If you found some matching files, but then you find one that doesn't, stop going through the list. + elif new_filelist: + break + if not new_filelist: + raise RuntimeError(f"No files found in timeSlice {timeSlice}") + filelist = new_filelist + + # The xarray open_mfdataset() "preprocess" argument requires a function that takes exactly one variable (an xarray.Dataset object). Wrapping mfdataset_preproc() in this lambda function allows this. Could also just allow mfdataset_preproc() to access myVars and myVegtypes directly, but that's bad practice as it could lead to scoping issues. + mfdataset_preproc_closure = lambda ds: mfdataset_preproc(ds, myVars, myVegtypes, timeSlice) + + # Import + if isinstance(filelist, list) and len(filelist) == 1: + filelist = filelist[0] + if isinstance(filelist, list): + with warnings.catch_warnings(): + warnings.filterwarnings(action="ignore", category=DeprecationWarning) + if importlib.find_loader("dask") is None: + raise ModuleNotFoundError( + "You have asked xarray to import a list of files as a single Dataset using" + " open_mfdataset(), but this requires dask, which is not available.\nFile" + f" list: {filelist}" + ) + this_ds = xr.open_mfdataset( + sorted(filelist), + data_vars="minimal", + preprocess=mfdataset_preproc_closure, + compat="override", + coords="all", + concat_dim="time", + combine="nested", + chunks=chunks, + ) + elif isinstance(filelist, str): + this_ds = xr.open_dataset(filelist, chunks=chunks) + this_ds = mfdataset_preproc(this_ds, myVars, myVegtypes, timeSlice) + this_ds = this_ds.compute() + + # Include only active patches (or whatever) + if only_active_patches: + is_active = this_ds.patches1d_active.values + p_active = np.where(is_active)[0] + this_ds_active = this_ds.isel(patch=p_active) + + # Warn and/or error about variables that couldn't be imported or derived + if myVars: + missing_vars = [v for v in myVars if v not in this_ds] + ok_missing_vars = [v for v in missing_vars if v in myVars_missing_ok] + bad_missing_vars = [v for v in missing_vars if v not in myVars_missing_ok] + if ok_missing_vars: + print( + "Could not import some variables; either not present or not deriveable:" + f" {ok_missing_vars}" + ) + if bad_missing_vars: + raise RuntimeError( + "Could not import some variables; either not present or not deriveable:" + f" {bad_missing_vars}" + ) + + if rename_lsmlatlon: + if "lsmlat" in this_ds.dims: + this_ds = this_ds.rename({"lsmlat": "lat"}) + if "lsmlon" in this_ds.dims: + this_ds = this_ds.rename({"lsmlon": "lon"}) + + return this_ds + + +# Return a DataArray, with defined coordinates, for a given variable in a dataset. +def get_thisVar_da(thisVar, this_ds): + # Make DataArray for this variable + thisvar_da = np.array(this_ds.variables[thisVar]) + theseDims = this_ds.variables[thisVar].dims + thisvar_da = xr.DataArray(thisvar_da, dims=theseDims) + + # Define coordinates of this variable's DataArray + dimsDict = dict() + for thisDim in theseDims: + dimsDict[thisDim] = this_ds[thisDim] + thisvar_da = thisvar_da.assign_coords(dimsDict) + thisvar_da.attrs = this_ds[thisVar].attrs + + return thisvar_da + + +# Make a geographically gridded DataArray (with dimensions time, vegetation type [as string], lat, lon) of one variable within a Dataset. Optional keyword arguments will be passed to xr_flexsel() to select single steps or slices along the specified ax(ie)s. +# +# fillValue: Default None means grid will be filled with NaN, unless the variable in question already has a fillValue, in which case that will be used. +def grid_one_variable(this_ds, thisVar, fillValue=None, **kwargs): + # Get this Dataset's values for selection(s), if provided + this_ds = xr_flexsel(this_ds, **kwargs) + + # Get DataArrays needed for gridding + thisvar_da = get_thisVar_da(thisVar, this_ds) + vt_da = None + if "patch" in thisvar_da.dims: + spatial_unit = "patch" + xy_1d_prefix = "patches" + if "patches1d_itype_veg" in this_ds: + vt_da = get_thisVar_da("patches1d_itype_veg", this_ds) + elif "gridcell" in thisvar_da.dims: + spatial_unit = "gridcell" + xy_1d_prefix = "grid" + else: + raise RuntimeError( + f"What variables to use for _ixy and _jxy of variable with dims {thisvar_da.dims}?" + ) + ixy_da = get_thisVar_da(xy_1d_prefix + "1d_ixy", this_ds) + jxy_da = get_thisVar_da(xy_1d_prefix + "1d_jxy", this_ds) + + if not fillValue and "_FillValue" in thisvar_da.attrs: + fillValue = thisvar_da.attrs["_FillValue"] + + # Renumber vt_da to work as indices on new ivt dimension, if needed. + ### Ensures that the unique set of vt_da values begins with 1 and + ### contains no missing steps. + if "ivt" in this_ds and vt_da is not None: + vt_da.values = np.array([np.where(this_ds.ivt.values == x)[0][0] for x in vt_da.values]) + + # Get new dimension list + new_dims = list(thisvar_da.dims) + ### Remove "[spatial_unit]". + if spatial_unit in new_dims: + new_dims.remove(spatial_unit) + # Add "ivt_str" (vegetation type, as string). This needs to go at the end, to avoid a possible situation where you wind up with multiple Ellipsis members of fill_indices. + if "ivt" in this_ds and spatial_unit == "patch": + new_dims.append("ivt_str") + ### Add lat and lon to end of list + new_dims = new_dims + ["lat", "lon"] + + # Set up empty array + n_list = [] + for dim in new_dims: + if dim == "ivt_str": + n = this_ds.sizes["ivt"] + elif dim in thisvar_da.coords: + n = thisvar_da.sizes[dim] + else: + n = this_ds.sizes[dim] + n_list = n_list + [n] + thisvar_gridded = np.empty(n_list) + if fillValue: + thisvar_gridded[:] = fillValue + else: + thisvar_gridded[:] = np.NaN + + # Fill with this variable + fill_indices = [] + for dim in new_dims: + if dim == "lat": + fill_indices.append(jxy_da.values.astype(int) - 1) + elif dim == "lon": + fill_indices.append(ixy_da.values.astype(int) - 1) + elif dim == "ivt_str": + fill_indices.append(vt_da) + elif not fill_indices: + # I.e., if fill_indices is empty. Could also do "elif len(fill_indices)==0". + fill_indices.append(Ellipsis) + try: + thisvar_gridded[tuple(fill_indices[: len(fill_indices)])] = thisvar_da.values + except: + thisvar_gridded[tuple(fill_indices[: len(fill_indices)])] = thisvar_da.values.transpose() + if not np.any(np.bitwise_not(np.isnan(thisvar_gridded))): + if np.all(np.isnan(thisvar_da.values)): + print("Warning: This DataArray (and thus map) is all NaN") + else: + raise RuntimeError("thisvar_gridded was not filled!") + + # Assign coordinates, attributes and name + thisvar_gridded = xr.DataArray(thisvar_gridded, dims=tuple(new_dims), attrs=thisvar_da.attrs) + for dim in new_dims: + if dim == "ivt_str": + values = this_ds.vegtype_str.values + elif dim in thisvar_da.coords: + values = thisvar_da[dim] + else: + values = this_ds[dim].values + thisvar_gridded = thisvar_gridded.assign_coords({dim: values}) + thisvar_gridded.name = thisVar + + # Add FillValue attribute + if fillValue: + thisvar_gridded.attrs["_FillValue"] = fillValue + + return thisvar_gridded + + +# ctsm_pylib can't handle time slicing like Dataset.sel(time=slice("1998-01-01", "2005-12-31")) for some reason. This function tries to fall back to slicing by integers. It should work with both Datasets and DataArrays. +def safer_timeslice(ds, timeSlice, timeVar="time"): + try: + ds = ds.sel({timeVar: timeSlice}) + except: + # If the issue might have been slicing using strings, try to fall back to integer slicing + if ( + isinstance(timeSlice.start, str) + and isinstance(timeSlice.stop, str) + and len(timeSlice.start.split("-")) == 3 + and timeSlice.start.split("-")[1:] == ["01", "01"] + and len(timeSlice.stop.split("-")) == 3 + and ( + timeSlice.stop.split("-")[1:] == ["12", "31"] + or timeSlice.stop.split("-")[1:] == ["01", "01"] + ) + ): + fileyears = np.array([x.year for x in ds.time.values]) + if len(np.unique(fileyears)) != len(fileyears): + print("Could not fall back to integer slicing of years: Time axis not annual") + raise + yStart = int(timeSlice.start.split("-")[0]) + yStop = int(timeSlice.stop.split("-")[0]) + where_in_timeSlice = np.where((fileyears >= yStart) & (fileyears <= yStop))[0] + ds = ds.isel({timeVar: where_in_timeSlice}) + else: + print(f"Could not fall back to integer slicing for timeSlice {timeSlice}") + raise + + return ds + + +# Convert a longitude axis that's -180 to 180 around the international date line to one that's 0 to 360 around the prime meridian. If you pass in a Dataset or DataArray, the "lon" coordinates will be changed. Otherwise, it assumes you're passing in numeric data. +def lon_idl2pm(lons_in, fail_silently=False): + def check_ok(tmp, fail_silently): + msg = "" + + if np.any(tmp > 180): + msg = f"Maximum longitude is already > 180 ({np.max(tmp)})" + elif np.any(tmp < -180): + msg = f"Minimum longitude is < -180 ({np.min(tmp)})" + + if msg == "": + return True + elif fail_silently: + return False + else: + raise ValueError(msg) + + def do_it(tmp): + tmp = tmp + 360 + tmp = np.mod(tmp, 360) + return tmp + + if isinstance(lons_in, (xr.DataArray, xr.Dataset)): + if not check_ok(lons_in.lon.values, fail_silently): + return lons_in + lons_out = lons_in + lons_out = lons_out.assign_coords(lon=do_it(lons_in.lon.values)) + lons_out = make_lon_increasing(lons_out) + else: + if not check_ok(lons_in, fail_silently): + return lons_in + lons_out = do_it(lons_in) + if not is_strictly_increasing(lons_out): + print( + "WARNING: You passed in numeric longitudes to lon_idl2pm() and these have been" + " converted, but they're not strictly increasing." + ) + print( + "To assign the new longitude coordinates to an Xarray object, use" + " xarrayobject.assign_coordinates()! (Pass the object directly in to lon_idl2pm() in" + " order to suppress this message.)" + ) + + return lons_out + + +# Helper function to check that a list is strictly increasing +def is_strictly_increasing(L): + # https://stackoverflow.com/a/4983359/2965321 + return all(x < y for x, y in zip(L, L[1:])) + + +# Ensure that longitude axis coordinates are monotonically increasing +def make_lon_increasing(xr_obj): + if not "lon" in xr_obj.dims: + return xr_obj + + lons = xr_obj.lon.values + if is_strictly_increasing(lons): + return xr_obj + + shift = 0 + while not is_strictly_increasing(lons) and shift < lons.size: + shift = shift + 1 + lons = np.roll(lons, 1, axis=0) + if not is_strictly_increasing(lons): + raise RuntimeError("Unable to rearrange longitude axis so it's monotonically increasing") + + return xr_obj.roll(lon=shift, roll_coords=True) diff --git a/python/ctsm/crop_calendars/generate_gdds.py b/python/ctsm/crop_calendars/generate_gdds.py new file mode 100644 index 0000000000..b54e7df40f --- /dev/null +++ b/python/ctsm/crop_calendars/generate_gdds.py @@ -0,0 +1,492 @@ +paramfile_dir = "/glade/p/cesmdata/cseg/inputdata/lnd/clm2/paramdata" + +# Import other shared functions +import os +import inspect +import sys + +# Import the CTSM Python utilities. +# sys.path.insert() is necessary for RXCROPMATURITY to work. The fact that it's calling this script in the RUN phase seems to require the python/ directory to be manually added to path. +_CTSM_PYTHON = os.path.join( + os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir, os.pardir, "python" +) +sys.path.insert(1, _CTSM_PYTHON) +import ctsm.crop_calendars.cropcal_module as cc +import ctsm.crop_calendars.generate_gdds_functions as gddfn + +# Import everything else +import os +import sys +import numpy as np +import xarray as xr +import pickle +import datetime as dt +import argparse +import logging + +# Info re: PFT parameter set +my_clm_ver = 51 +my_clm_subver = "c211112" + + +def main( + input_dir=None, + first_season=None, + last_season=None, + sdates_file=None, + hdates_file=None, + output_dir=None, + save_figs=True, + only_make_figs=False, + run1_name=None, + run2_name=None, + land_use_file=None, + first_land_use_year=None, + last_land_use_year=None, + unlimited_season_length=False, + skip_crops=None, + logger=None, +): + # Directories to save output files and figures + if not output_dir: + if only_make_figs: + output_dir = input_dir + else: + output_dir = os.path.join(input_dir, "generate_gdds") + if not unlimited_season_length: + output_dir += ".mxmat" + output_dir += "." + dt.datetime.now().strftime("%Y-%m-%d-%H%M%S") + if not os.path.exists(output_dir): + os.makedirs(output_dir) + outdir_figs = os.path.join(output_dir, "figs") + + # Set up log file and function, if needed + if logger is None: + logging.basicConfig( + level=logging.INFO, + format="", + filename=os.path.join(output_dir, "generate_gdds.log"), + filemode="a", + ) + logger = logging.getLogger("") + + # Disable plotting if any plotting module is unavailable + if save_figs: + try: + import cartopy + import matplotlib + except: + if only_make_figs: + raise RuntimeError("only_make_figs True but not all plotting modules are available") + gddfn.log(logger, "Not all plotting modules are available; disabling save_figs") + save_figs = False + + # Print some info + gddfn.log(logger, f"Saving to {output_dir}") + + # Parse list of crops to skip + if "," in skip_crops: + skip_crops = skip_crops.split(",") + else: + skip_crops = skip_crops.split(" ") + + ########################## + ### Import and process ### + ########################## + + if not only_make_figs: + # Keep 1 extra year to avoid incomplete final growing season for crops harvested after Dec. 31. + y1_import_str = f"{first_season+1}-01-01" + yN_import_str = f"{last_season+2}-01-01" + + gddfn.log( + logger, + f"Importing netCDF time steps {y1_import_str} through {yN_import_str} (years are +1 because of CTSM output naming)", + ) + + pickle_file = os.path.join(output_dir, f"{first_season}-{last_season}.pickle") + h2_ds_file = os.path.join(output_dir, f"{first_season}-{last_season}.h2_ds.nc") + if os.path.exists(pickle_file): + with open(pickle_file, "rb") as f: + ( + first_season, + last_season, + pickle_year, + gddaccum_yp_list, + gddharv_yp_list, + skip_patches_for_isel_nan_lastyear, + lastYear_active_patch_indices_list, + incorrectly_daily, + save_figs, + incl_vegtypes_str, + incl_patches1d_itype_veg, + mxsowings, + skip_crops, + ) = pickle.load(f) + print(f"Will resume import at {pickle_year+1}") + h2_ds = None + else: + incorrectly_daily = False + skip_patches_for_isel_nan_lastyear = np.ndarray([]) + pickle_year = -np.inf + gddaccum_yp_list = [] + gddharv_yp_list = [] + incl_vegtypes_str = None + lastYear_active_patch_indices_list = None + sdates_rx = sdates_file + hdates_rx = hdates_file + + if not unlimited_season_length: + mxmats = cc.import_max_gs_length(paramfile_dir, my_clm_ver, my_clm_subver) + else: + mxmats = None + + for y, thisYear in enumerate(np.arange(first_season + 1, last_season + 3)): + if thisYear <= pickle_year: + continue + + ( + h2_ds, + sdates_rx, + hdates_rx, + gddaccum_yp_list, + gddharv_yp_list, + skip_patches_for_isel_nan_lastyear, + lastYear_active_patch_indices_list, + incorrectly_daily, + incl_vegtypes_str, + incl_patches1d_itype_veg, + mxsowings, + ) = gddfn.import_and_process_1yr( + first_season, + last_season, + y, + thisYear, + sdates_rx, + hdates_rx, + gddaccum_yp_list, + gddharv_yp_list, + skip_patches_for_isel_nan_lastyear, + lastYear_active_patch_indices_list, + incorrectly_daily, + input_dir, + incl_vegtypes_str, + h2_ds_file, + mxmats, + cc.get_gs_len_da, + skip_crops, + logger, + ) + + gddfn.log(logger, f" Saving pickle file ({pickle_file})...") + with open(pickle_file, "wb") as f: + pickle.dump( + [ + first_season, + last_season, + thisYear, + gddaccum_yp_list, + gddharv_yp_list, + skip_patches_for_isel_nan_lastyear, + lastYear_active_patch_indices_list, + incorrectly_daily, + save_figs, + incl_vegtypes_str, + incl_patches1d_itype_veg, + mxsowings, + skip_crops, + ], + f, + protocol=-1, + ) + + if isinstance(incl_vegtypes_str, list): + incl_vegtypes_str = np.array(incl_vegtypes_str) + plot_vegtypes_str = incl_vegtypes_str[ + [i for i, c in enumerate(gddaccum_yp_list) if not isinstance(c, type(None))] + ] + + gddfn.log(logger, "Done") + + if not h2_ds: + h2_ds = xr.open_dataset(h2_ds_file) + + ###################################################### + ### Get and grid mean GDDs in GGCMI growing season ### + ###################################################### + + if not only_make_figs: + longname_prefix = "GDD harvest target for " + + # Could skip this by saving sdates_rx['time_bounds'] + sdates_rx = gddfn.import_rx_dates( + "s", sdates_rx, incl_patches1d_itype_veg, mxsowings, logger + ) + + gddfn.log(logger, "Getting and gridding mean GDDs...") + gdd_maps_ds = gddfn.yp_list_to_ds( + gddaccum_yp_list, h2_ds, incl_vegtypes_str, sdates_rx, longname_prefix, logger + ) + gddharv_maps_ds = gddfn.yp_list_to_ds( + gddharv_yp_list, h2_ds, incl_vegtypes_str, sdates_rx, longname_prefix, logger + ) + + # Fill NAs with dummy values + dummy_fill = -1 + gdd_maps_ds = gdd_maps_ds.fillna(dummy_fill) + gddfn.log(logger, "Done getting and gridding means.") + + # Add dummy variables for crops not actually simulated + gddfn.log(logger, "Adding dummy variables...") + # Unnecessary? + template_ds = xr.open_dataset(sdates_file, decode_times=True) + all_vars = [v.replace("sdate", "gdd") for v in template_ds if "sdate" in v] + all_longnames = [ + template_ds[v].attrs["long_name"].replace("Planting day ", longname_prefix) + " (dummy)" + for v in template_ds + if "sdate" in v + ] + dummy_vars = [] + dummy_longnames = [] + for v, thisVar in enumerate(all_vars): + if thisVar not in gdd_maps_ds: + dummy_vars.append(thisVar) + dummy_longnames.append(all_longnames[v]) + + def make_dummy(thisCrop_gridded, addend): + dummy_gridded = thisCrop_gridded + dummy_gridded.values = dummy_gridded.values * 0 + addend + return dummy_gridded + + for v in gdd_maps_ds: + thisCrop_gridded = gdd_maps_ds[v].copy() + break + dummy_gridded = make_dummy(thisCrop_gridded, -1) + + for v, thisVar in enumerate(dummy_vars): + if thisVar in gdd_maps_ds: + gddfn.error( + logger, f"{thisVar} is already in gdd_maps_ds. Why overwrite it with dummy?" + ) + dummy_gridded.name = thisVar + dummy_gridded.attrs["long_name"] = dummy_longnames[v] + gdd_maps_ds[thisVar] = dummy_gridded + + # Add lon/lat attributes + def add_lonlat_attrs(ds): + ds.lon.attrs = {"long_name": "coordinate_longitude", "units": "degrees_east"} + ds.lat.attrs = {"long_name": "coordinate_latitude", "units": "degrees_north"} + return ds + + gdd_maps_ds = add_lonlat_attrs(gdd_maps_ds) + gddharv_maps_ds = add_lonlat_attrs(gddharv_maps_ds) + + gddfn.log(logger, "Done.") + + ###################### + ### Save to netCDF ### + ###################### + + if not only_make_figs: + gddfn.log(logger, "Saving...") + + # Get output file path + datestr = dt.datetime.now().strftime("%Y%m%d_%H%M%S") + outfile = os.path.join(output_dir, "gdds_" + datestr + ".nc") + + def save_gdds(sdates_file, hdates_file, outfile, gdd_maps_ds, sdates_rx): + # Set up output file from template (i.e., prescribed sowing dates). + template_ds = xr.open_dataset(sdates_file, decode_times=True) + for v in template_ds: + if "sdate" in v: + template_ds = template_ds.drop(v) + template_ds.to_netcdf(path=outfile, format="NETCDF3_CLASSIC") + template_ds.close() + + # Add global attributes + comment = f"Derived from CLM run plus crop calendar input files {os.path.basename(sdates_file) and {os.path.basename(hdates_file)}}." + gdd_maps_ds.attrs = { + "author": "Sam Rabin (sam.rabin@gmail.com)", + "comment": comment, + "created": dt.datetime.now().astimezone().isoformat(), + } + + # Add time_bounds + if "time_bounds" in sdates_rx: + gdd_maps_ds["time_bounds"] = sdates_rx.time_bounds + + # Save cultivar GDDs + gdd_maps_ds.to_netcdf(outfile, mode="w", format="NETCDF3_CLASSIC") + + save_gdds(sdates_file, hdates_file, outfile, gdd_maps_ds, sdates_rx) + + gddfn.log(logger, "Done saving.") + + ######################################## + ### Save things needed for mapmaking ### + ######################################## + + def add_attrs_to_map_ds( + map_ds, incl_vegtypes_str, dummy_fill, outdir_figs, first_season, last_season + ): + return map_ds.assign_attrs( + { + "incl_vegtypes_str": incl_vegtypes_str, + "dummy_fill": dummy_fill, + "outdir_figs": outdir_figs, + "y1": first_season, + "yN": last_season, + } + ) + + if not only_make_figs: + if not os.path.exists(outdir_figs): + os.makedirs(outdir_figs) + + gdd_maps_ds = add_attrs_to_map_ds( + gdd_maps_ds, plot_vegtypes_str, dummy_fill, outdir_figs, first_season, last_season + ) + gddharv_maps_ds = add_attrs_to_map_ds( + gddharv_maps_ds, plot_vegtypes_str, dummy_fill, outdir_figs, first_season, last_season + ) + + gdd_maps_ds.to_netcdf(os.path.join(outdir_figs, "gdd_maps.nc")) + gddharv_maps_ds.to_netcdf(os.path.join(outdir_figs, "gddharv_maps.nc")) + + ################################################# + ### Save before/after map and boxplot figures ### + ################################################# + + if save_figs: + if only_make_figs: + gdd_maps_ds = xr.open_dataset(os.path.join(input_dir, "figs", "gdd_maps.nc")) + gddharv_maps_ds = xr.open_dataset(os.path.join(input_dir, "figs", "gddharv_maps.nc")) + gddfn.make_figures( + first_land_use_year, + last_land_use_year, + land_use_file, + run1_name, + run2_name, + logger, + gdd_maps_ds=gdd_maps_ds, + gddharv_maps_ds=gddharv_maps_ds, + outdir_figs=outdir_figs, + ) + + +if __name__ == "__main__": + ############################### + ### Process input arguments ### + ############################### + parser = argparse.ArgumentParser(description="ADD DESCRIPTION HERE") + + # Required + parser.add_argument( + "-i", + "--input-dir", + help="Directory where run outputs can be found (and where outputs will go). If --only-make-figs, this is the directory with the preprocessed files (e.g., *.pickle file).", + required=True, + ) + parser.add_argument( + "-1", + "--first-season", + help="First growing season to include in calculation of mean", + required=True, + type=int, + ) + parser.add_argument( + "-n", + "-N", + "--last-season", + help="Last growing season to include in calculation of mean", + required=True, + type=int, + ) + parser.add_argument( + "-o", + "--output-dir", + help="Output directory. Default is auto-generated subdir of -i/--input-dir.", + ) + parser.add_argument( + "-sd", "--sdates-file", help="File of prescribed sowing dates", required=True + ) + parser.add_argument( + "-hd", "--hdates-file", help="File of prescribed harvest dates", required=True + ) + + # Optional + figsgroup = parser.add_mutually_exclusive_group() + figsgroup.add_argument( + "--dont-save-figs", help="Do not save figures", action="store_true", default=False + ) + figsgroup.add_argument( + "--only-make-figs", + help="Use preprocessed files to make figures only", + action="store_true", + default=False, + ) + parser.add_argument( + "--run1-name", help="Name of original values to show in figures", default="Old" + ) + parser.add_argument("--run2-name", help="Name of new values to show in figures", default="New") + parser.add_argument( + "-lu", + "--land-use-file", + help="Path to CLM land use timeseries file, for masking figures", + default=None, + ) + parser.add_argument( + "--first-land-use-year", + help="First year in land use file to use for masking. Default --first-season.", + default=None, + type=int, + ) + parser.add_argument( + "--last-land-use-year", + help="Last year in land use file to use for masking. Default --last-season.", + default=None, + type=int, + ) + parser.add_argument( + "--unlimited-season-length", + help="Limit mean growing season length based on CLM CFT parameter mxmat.", + action="store_true", + default=False, + ) + parser.add_argument( + "--skip-crops", + help="Skip processing of these crops. Comma- or space-separated list.", + type=str, + default="", + ) + + # Get arguments + args = parser.parse_args(sys.argv[1:]) + for k, v in sorted(vars(args).items()): + print(f"{k}: {v}") + save_figs = not args.dont_save_figs + + # Call main() + main( + input_dir=args.input_dir, + first_season=args.first_season, + last_season=args.last_season, + sdates_file=args.sdates_file, + hdates_file=args.hdates_file, + output_dir=args.output_dir, + save_figs=save_figs, + only_make_figs=args.only_make_figs, + run1_name=args.run1_name, + run2_name=args.run2_name, + land_use_file=args.land_use_file, + first_land_use_year=args.first_land_use_year, + last_land_use_year=args.last_land_use_year, + unlimited_season_length=args.unlimited_season_length, + skip_crops=args.skip_crops, + ) + +# main(input_dir="/Users/Shared/CESM_runs/tests_10x15_20230329_gddgen/202303301820", +# sdates_file="/Users/Shared/CESM_work/crop_dates_mostrice/sdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f10_f10_mg37.2000-2000.20230330_165301.nc", +# hdates_file="/Users/Shared/CESM_work/crop_dates_mostrice/hdates_ggcmi_crop_calendar_phase3_v1.01_nninterp-f10_f10_mg37.2000-2000.20230330_165301.nc", +# first_season=1997, last_season=2003, +# save_figs=False) diff --git a/python/ctsm/crop_calendars/generate_gdds_functions.py b/python/ctsm/crop_calendars/generate_gdds_functions.py new file mode 100644 index 0000000000..cb05f1920d --- /dev/null +++ b/python/ctsm/crop_calendars/generate_gdds_functions.py @@ -0,0 +1,1215 @@ +import numpy as np +import xarray as xr +import warnings +import os +import glob +import datetime as dt +from importlib import util as importlib_util + +# Import the CTSM Python utilities. +# sys.path.insert() is necessary for RXCROPMATURITY to work. The fact that it's calling this script in the RUN phase seems to require the python/ directory to be manually added to path. +_CTSM_PYTHON = os.path.join( + os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir, os.pardir, "python" +) +import sys + +sys.path.insert(1, _CTSM_PYTHON) +import ctsm.crop_calendars.cropcal_utils as utils +import ctsm.crop_calendars.cropcal_module as cc + +can_plot = True +try: + from ctsm.crop_calendars.cropcal_figs_module import * + from matplotlib.transforms import Bbox + + warnings.filterwarnings( + "ignore", + message="__len__ for multi-part geometries is deprecated and will be removed in Shapely 2.0. Check the length of the `geoms` property instead to get the number of parts of a multi-part geometry.", + ) + warnings.filterwarnings( + "ignore", + message="Iteration over multi-part geometries is deprecated and will be removed in Shapely 2.0. Use the `geoms` property to access the constituent parts of a multi-part geometry.", + ) + + print("Will (attempt to) produce harvest requirement map figure files.") + +except: + print("Will NOT produce harvest requirement map figure files.") + can_plot = False + + +# Functions to simultaneously print to console and to log file +def log(logger, string): + print(string) + logger.info(string) + + +def error(logger, string): + logger.error(string) + raise RuntimeError(string) + + +def check_sdates(dates_ds, sdates_rx, logger, verbose=False): + log(logger, " Checking that input and output sdates match...") + + sdates_grid = utils.grid_one_variable(dates_ds, "SDATES") + + all_ok = True + any_found = False + vegtypes_skipped = [] + vegtypes_included = [] + for i, vt_str in enumerate(dates_ds.vegtype_str.values): + # Input + vt = dates_ds.ivt.values[i] + thisVar = f"gs1_{vt}" + if thisVar not in sdates_rx: + vegtypes_skipped = vegtypes_skipped + [vt_str] + # log(logger, f" {vt_str} ({vt}) SKIPPED...") + continue + vegtypes_included = vegtypes_included + [vt_str] + any_found = True + if verbose: + log(logger, f" {vt_str} ({vt})...") + in_map = sdates_rx[thisVar].squeeze(drop=True) + + # Output + out_map = sdates_grid.sel(ivt_str=vt_str).squeeze(drop=True) + + # Check for differences + diff_map = out_map - in_map + diff_map_notnan = diff_map.values[np.invert(np.isnan(diff_map.values))] + if np.any(diff_map_notnan): + log(logger, f"Difference(s) found in {vt_str}") + here = np.where(diff_map_notnan) + log(logger, "in:") + in_map_notnan = in_map.values[np.invert(np.isnan(diff_map.values))] + log(logger, in_map_notnan[here][0:4]) + out_map_notnan = out_map.values[np.invert(np.isnan(diff_map.values))] + log(logger, "out:") + log(logger, out_map_notnan[here][0:4]) + log(logger, "diff:") + log(logger, diff_map_notnan[here][0:4]) + all_ok = False + + if not (any_found): + error(logger, "No matching variables found in sdates_rx!") + + # Sanity checks for included vegetation types + vegtypes_skipped = np.unique([x.replace("irrigated_", "") for x in vegtypes_skipped]) + vegtypes_skipped_weird = [x for x in vegtypes_skipped if x in vegtypes_included] + if np.array_equal(vegtypes_included, [x.replace("irrigated_", "") for x in vegtypes_included]): + log(logger, "\nWARNING: No irrigated crops included!!!\n") + elif vegtypes_skipped_weird: + log( + logger, + f"\nWarning: Some crop types had output rainfed patches but no irrigated patches: {vegtypes_skipped_weird}", + ) + + if all_ok: + log(logger, " ✅ Input and output sdates match!") + else: + error(logger, " ❌ Input and output sdates differ.") + + +def import_rx_dates(s_or_h, date_inFile, incl_patches1d_itype_veg, mxsowings, logger): + if isinstance(date_inFile, xr.Dataset): + return date_inFile + elif not isinstance(date_inFile, str): + error( + logger, + f"Importing {s_or_h}dates_rx: Expected date_inFile to be str or DataArray, not {type(date_inFile)}", + ) + + # Which vegetation types were simulated? + itype_veg_toImport = np.unique(incl_patches1d_itype_veg) + + date_varList = [] + for i in itype_veg_toImport: + for g in np.arange(mxsowings): + thisVar = f"{s_or_h}date{g+1}_{i}" + date_varList = date_varList + [thisVar] + + ds = utils.import_ds(date_inFile, myVars=date_varList) + + for v in ds: + ds = ds.rename({v: v.replace(f"{s_or_h}date", "gs")}) + + return ds + + +def thisCrop_map_to_patches(lon_points, lat_points, map_ds, vegtype_int): + # xarray pointwise indexing; see https://xarray.pydata.org/en/stable/user-guide/indexing.html#more-advanced-indexing + return ( + map_ds[f"gs1_{vegtype_int}"] + .sel(lon=xr.DataArray(lon_points, dims="patch"), lat=xr.DataArray(lat_points, dims="patch")) + .squeeze(drop=True) + ) + + +# Get and grid mean GDDs in GGCMI growing season +def yp_list_to_ds(yp_list, daily_ds, incl_vegtypes_str, dates_rx, longname_prefix, logger): + # Get means + warnings.filterwarnings( + "ignore", message="Mean of empty slice" + ) # Happens when you do np.nanmean() of an all-NaN array (or slice, if doing selected axis/es) + p_list = [np.nanmean(x, axis=0) if not isinstance(x, type(None)) else x for x in yp_list] + warnings.filterwarnings("always", message="Mean of empty slice") + + if isinstance(incl_vegtypes_str, xr.DataArray): + incl_vegtypes_str = incl_vegtypes_str.values + + # Grid + ds_out = xr.Dataset() + for c, ra in enumerate(p_list): + if isinstance(ra, type(None)): + continue + thisCrop_str = incl_vegtypes_str[c] + log(logger, f" {thisCrop_str}...") + newVar = f"gdd1_{utils.ivt_str2int(thisCrop_str)}" + ds = daily_ds.isel( + patch=np.where(daily_ds.patches1d_itype_veg_str.values == thisCrop_str)[0] + ) + template_da = ds.patches1d_itype_veg_str + da = xr.DataArray( + data=ra, + coords=template_da.coords, + attrs={"units": "GDD", "long_name": f"{longname_prefix}{thisCrop_str}"}, + ) + + # Grid this crop + ds["tmp"] = da + da_gridded = utils.grid_one_variable(ds, "tmp", vegtype=thisCrop_str).squeeze(drop=True) + + # Add singleton time dimension and save to output Dataset + da_gridded = da_gridded.expand_dims(time=dates_rx.time) + ds_out[newVar] = da_gridded + + return ds_out + + +def import_and_process_1yr( + y1, + yN, + y, + thisYear, + sdates_rx, + hdates_rx, + gddaccum_yp_list, + gddharv_yp_list, + skip_patches_for_isel_nan_lastyear, + lastYear_active_patch_indices_list, + incorrectly_daily, + indir, + incl_vegtypes_str_in, + h2_ds_file, + mxmats, + get_gs_len_da, + skip_crops, + logger, +): + save_figs = True + log(logger, f"netCDF year {thisYear}...") + log(logger, dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + + # Without dask, this can take a LONG time at resolutions finer than 2-deg + if importlib_util.find_spec("dask"): + chunks = {"time": 1} + else: + chunks = None + + # Get h2 file (list) + h1_pattern = os.path.join(indir, "*h1.*.nc") + h1_filelist = glob.glob(h1_pattern) + if not h1_filelist: + h1_pattern = os.path.join(indir, "*h1.*.nc.base") + h1_filelist = glob.glob(h1_pattern) + if not h1_filelist: + error(logger, "No files found matching pattern '*h1.*.nc(.base)'") + + # Get list of crops to include + if skip_crops is not None: + crops_to_read = [c for c in utils.define_mgdcrop_list() if c not in skip_crops] + else: + crops_to_read = utils.define_mgdcrop_list() + + print(h1_filelist) + dates_ds = utils.import_ds( + h1_filelist, + myVars=["SDATES", "HDATES"], + myVegtypes=crops_to_read, + timeSlice=slice(f"{thisYear}-01-01", f"{thisYear}-12-31"), + chunks=chunks, + ) + + if dates_ds.dims["time"] > 1: + if dates_ds.dims["time"] == 365: + if not incorrectly_daily: + log( + logger, + " ℹ️ You saved SDATES and HDATES daily, but you only needed annual. Fixing.", + ) + incorrectly_daily = True + dates_ds = dates_ds.isel(time=-1) + else: + dates_ds = dates_ds.isel(time=0) + + # Make sure NaN masks match + sdates_all_nan = ( + np.sum(~np.isnan(dates_ds.SDATES.values), axis=dates_ds.SDATES.dims.index("mxsowings")) == 0 + ) + hdates_all_nan = ( + np.sum(~np.isnan(dates_ds.HDATES.values), axis=dates_ds.HDATES.dims.index("mxharvests")) + == 0 + ) + N_unmatched_nans = np.sum(sdates_all_nan != hdates_all_nan) + if N_unmatched_nans > 0: + error(logger, "Output SDATE and HDATE NaN masks do not match.") + if np.sum(~np.isnan(dates_ds.SDATES.values)) == 0: + error(logger, "All SDATES are NaN!") + + # Just work with non-NaN patches for now + skip_patches_for_isel_nan = np.where(sdates_all_nan)[0] + incl_patches_for_isel_nan = np.where(~sdates_all_nan)[0] + different_nan_mask = y > 0 and not np.array_equal( + skip_patches_for_isel_nan_lastyear, skip_patches_for_isel_nan + ) + if different_nan_mask: + log(logger, " Different NaN mask than last year") + incl_thisyr_but_nan_lastyr = [ + dates_ds.patch.values[p] + for p in incl_patches_for_isel_nan + if p in skip_patches_for_isel_nan_lastyear + ] + else: + incl_thisyr_but_nan_lastyr = [] + skipping_patches_for_isel_nan = len(skip_patches_for_isel_nan) > 0 + if skipping_patches_for_isel_nan: + log( + logger, + f" Ignoring {len(skip_patches_for_isel_nan)} patches with all-NaN sowing and harvest dates.", + ) + dates_incl_ds = dates_ds.isel(patch=incl_patches_for_isel_nan) + else: + dates_incl_ds = dates_ds + incl_patches1d_itype_veg = dates_incl_ds.patches1d_itype_veg + + if y == 0: + incl_vegtypes_str = [c for c in dates_incl_ds.vegtype_str.values if c not in skip_crops] + else: + incl_vegtypes_str = incl_vegtypes_str_in + if isinstance(incl_vegtypes_str, xr.DataArray): + incl_vegtypes_str = incl_vegtypes_str.values + if isinstance(incl_vegtypes_str, np.ndarray): + incl_vegtypes_str = list(incl_vegtypes_str) + if incl_vegtypes_str != list(dates_incl_ds.vegtype_str.values): + error( + logger, + f"Included veg types differ. Previously {incl_vegtypes_str}, now {dates_incl_ds.vegtype_str.values}", + ) + + if np.sum(~np.isnan(dates_incl_ds.SDATES.values)) == 0: + error(logger, "All SDATES are NaN after ignoring those patches!") + + # Some patches can have -1 sowing date?? Hopefully just an artifact of me incorrectly saving SDATES/HDATES daily. + mxsowings = dates_ds.dims["mxsowings"] + mxsowings_dim = dates_ds.SDATES.dims.index("mxsowings") + skip_patches_for_isel_sdatelt1 = np.where(dates_incl_ds.SDATES.values < 1)[1] + skipping_patches_for_isel_sdatelt1 = len(skip_patches_for_isel_sdatelt1) > 0 + if skipping_patches_for_isel_sdatelt1: + unique_hdates = np.unique( + dates_incl_ds.HDATES.isel(mxharvests=0, patch=skip_patches_for_isel_sdatelt1).values + ) + if incorrectly_daily and list(unique_hdates) == [364]: + log( + logger, + f" ❗ {len(skip_patches_for_isel_sdatelt1)} patches have SDATE < 1, but this might have just been because of incorrectly daily outputs. Setting them to 365.", + ) + new_sdates_ar = dates_incl_ds.SDATES.values + if mxsowings_dim != 0: + error(logger, "Code this up") + new_sdates_ar[0, skip_patches_for_isel_sdatelt1] = 365 + dates_incl_ds["SDATES"] = xr.DataArray( + data=new_sdates_ar, + coords=dates_incl_ds["SDATES"].coords, + attrs=dates_incl_ds["SDATES"].attrs, + ) + else: + error( + logger, + f"{len(skip_patches_for_isel_sdatelt1)} patches have SDATE < 1. Unique affected hdates: {unique_hdates}", + ) + + # Some patches can have -1 harvest date?? Hopefully just an artifact of me incorrectly saving SDATES/HDATES daily. Can also happen if patch wasn't active last year + mxharvests = dates_ds.dims["mxharvests"] + mxharvests_dim = dates_ds.HDATES.dims.index("mxharvests") + # If a patch was inactive last year but was either (a) harvested the last time it was active or (b) was never active, it will have -1 as its harvest date this year. Such instances are okay. + hdates_thisyr = dates_incl_ds.HDATES.isel(mxharvests=0) + skip_patches_for_isel_hdatelt1 = np.where(hdates_thisyr.values < 1)[0] + skipping_patches_for_isel_hdatelt1 = len(skip_patches_for_isel_hdatelt1) > 0 + if incl_thisyr_but_nan_lastyr and list(skip_patches_for_isel_hdatelt1): + hdates_thisyr_where_nan_lastyr = hdates_thisyr.sel(patch=incl_thisyr_but_nan_lastyr) + sdates_thisyr_where_nan_lastyr = dates_incl_ds.SDATES.isel(mxsowings=0).sel( + patch=incl_thisyr_but_nan_lastyr + ) + if np.any(hdates_thisyr_where_nan_lastyr < 1): + # patches_to_fix = hdates_thisyr_where_nan_lastyr.isel(patch=np.where(hdates_thisyr_where_nan_lastyr < 1)[0]).patch.values + new_hdates = dates_incl_ds.HDATES.values + if mxharvests_dim != 0: + error(logger, "Code this up") + patch_list = list(hdates_thisyr.patch.values) + here = [patch_list.index(x) for x in incl_thisyr_but_nan_lastyr] + log( + logger, + f" ❗ {len(here)} patches have harvest date -1 because they weren't active last year (and were either never active or were harvested when last active). Ignoring, but you should have done a run with patches always active if they are ever active in the real LU timeseries.", + ) + new_hdates[0, here] = sdates_thisyr_where_nan_lastyr.values - 1 + dates_incl_ds["HDATES"] = xr.DataArray( + data=new_hdates, + coords=dates_incl_ds.HDATES.coords, + attrs=dates_incl_ds.HDATES.attrs, + ) + # Recalculate these + skip_patches_for_isel_hdatelt1 = np.where( + dates_incl_ds.HDATES.isel(mxharvests=0).values < 1 + )[0] + skipping_patches_for_isel_hdatelt1 = len(skip_patches_for_isel_hdatelt1) > 0 + + # Resolve other issues + if skipping_patches_for_isel_hdatelt1: + unique_sdates = np.unique( + dates_incl_ds.SDATES.isel(patch=skip_patches_for_isel_hdatelt1).values + ) + if incorrectly_daily and list(unique_sdates) == [1]: + log( + logger, + f" ❗ {len(skip_patches_for_isel_hdatelt1)} patches have HDATE < 1??? Seems like this might have just been because of incorrectly daily outputs; setting them to 365.", + ) + new_hdates_ar = dates_incl_ds.HDATES.values + if mxharvests_dim != 0: + error(logger, "Code this up") + new_hdates_ar[0, skip_patches_for_isel_hdatelt1] = 365 + dates_incl_ds["HDATES"] = xr.DataArray( + data=new_hdates_ar, + coords=dates_incl_ds["HDATES"].coords, + attrs=dates_incl_ds["HDATES"].attrs, + ) + else: + error( + logger, + f"{len(skip_patches_for_isel_hdatelt1)} patches have HDATE < 1. Possible causes:\n * Not using constant crop areas (e.g., flanduse_timeseries from make_lu_for_gddgen.py)\n * Not skipping the first 2 years of output\nUnique affected sdates: {unique_sdates}", + ) + + # Make sure there was only one harvest per year + N_extra_harv = np.sum( + np.nanmax( + dates_incl_ds.HDATES.isel(mxharvests=slice(1, mxharvests)).values, axis=mxharvests_dim + ) + >= 1 + ) + if N_extra_harv > 0: + error(logger, f"{N_extra_harv} patches have >1 harvest.") + + # Make sure harvest happened the day before sowing + sdates_clm = dates_incl_ds.SDATES.values.squeeze() + hdates_clm = dates_incl_ds.HDATES.isel(mxharvests=0).values + diffdates_clm = sdates_clm - hdates_clm + diffdates_clm[(sdates_clm == 1) & (hdates_clm == 365)] = 1 + if list(np.unique(diffdates_clm)) != [1]: + error(logger, f"Not all sdates-hdates are 1: {np.unique(diffdates_clm)}") + + # Import expected sowing dates. This will also be used as our template output file. + imported_sdates = isinstance(sdates_rx, str) + sdates_rx = import_rx_dates("s", sdates_rx, incl_patches1d_itype_veg, mxsowings, logger) + check_sdates(dates_incl_ds, sdates_rx, logger) + + # Import hdates, if needed + imported_hdates = isinstance(hdates_rx, str) + hdates_rx_orig = import_rx_dates( + "h", hdates_rx, incl_patches1d_itype_veg, mxsowings, logger + ) # Yes, mxsowings even when importing harvests + + # Limit growing season to CLM max growing season length, if needed + if mxmats and (imported_sdates or imported_hdates): + print(" Limiting growing season length...") + hdates_rx = hdates_rx_orig.copy() + for v in hdates_rx_orig: + if v == "time_bounds": + continue + + # Get max growing season length + vegtype_int = int( + v.split("_")[1] + ) # netCDF variable name v should be something like gs1_17 + vegtype_str = utils.ivt_int2str(vegtype_int) + if vegtype_str == "soybean": + vegtype_str = "temperate_soybean" + elif vegtype_str == "irrigated_soybean": + vegtype_str = "irrigated_temperate_soybean" + + mxmat = mxmats[vegtype_str] + if np.isinf(mxmat): + print(f" Not limiting {vegtype_str}: No mxmat value") + continue + + # Get "prescribed" growing season length + gs_len_rx_da = get_gs_len_da(hdates_rx_orig[v] - sdates_rx[v]) + not_ok = gs_len_rx_da.values > mxmat + if not np.any(not_ok): + print(f" Not limiting {vegtype_str}: No rx season > {mxmat} days") + continue + + hdates_limited = hdates_rx_orig[v].copy().values + hdates_limited[np.where(not_ok)] = sdates_rx[v].values[np.where(not_ok)] + mxmat + hdates_limited[np.where(hdates_limited > 365)] -= 365 + if np.any(hdates_limited < 1): + raise RuntimeError("Limited hdates < 1") + elif np.any(hdates_limited > 365): + raise RuntimeError("Limited hdates > 365") + hdates_rx[v] = xr.DataArray( + data=hdates_limited, coords=hdates_rx_orig[v].coords, attrs=hdates_rx_orig[v].attrs + ) + print( + f" Limited {vegtype_str} growing season length to {mxmat}. Longest was {int(np.max(gs_len_rx_da.values))}, now {int(np.max(get_gs_len_da(hdates_rx[v] - sdates_rx[v]).values))}." + ) + else: + hdates_rx = hdates_rx_orig + + log(logger, f" Importing accumulated GDDs...") + clm_gdd_var = "GDDACCUM" + myVars = [clm_gdd_var, "GDDHARV"] + pattern = os.path.join(indir, f"*h2.{thisYear-1}-01-01*.nc") + h2_files = glob.glob(pattern) + if not h2_files: + pattern = os.path.join(indir, f"*h2.{thisYear-1}-01-01*.nc.base") + h2_files = glob.glob(pattern) + if not h2_files: + error(logger, f"No files found matching pattern '*h2.{thisYear-1}-01-01*.nc(.base)'") + h2_ds = utils.import_ds( + h2_files, + myVars=myVars, + myVegtypes=crops_to_read, + chunks=chunks, + ) + + # Restrict to patches we're including + if skipping_patches_for_isel_nan: + if not np.array_equal(dates_ds.patch.values, h2_ds.patch.values): + error(logger, "dates_ds and h2_ds don't have the same patch list!") + h2_incl_ds = h2_ds.isel(patch=incl_patches_for_isel_nan) + else: + h2_incl_ds = h2_ds + + if not np.any(h2_incl_ds[clm_gdd_var].values != 0): + error(logger, f"All {clm_gdd_var} values are zero!") + + # Get standard datetime axis for outputs + Nyears = yN - y1 + 1 + + if len(gddaccum_yp_list) == 0: + lastYear_active_patch_indices_list = [None for vegtype_str in incl_vegtypes_str] + gddaccum_yp_list = [None for vegtype_str in incl_vegtypes_str] + if save_figs: + gddharv_yp_list = [None for vegtype_str in incl_vegtypes_str] + + incl_vegtype_indices = [] + for v, vegtype_str in enumerate(incl_vegtypes_str): + if vegtype_str in skip_crops: + log(logger, f" SKIPPING {vegtype_str}") + continue + + vegtype_int = utils.vegtype_str2int(vegtype_str)[0] + thisCrop_full_patchlist = list(utils.xr_flexsel(h2_ds, vegtype=vegtype_str).patch.values) + + # Get time series for each patch of this type + thisCrop_ds = utils.xr_flexsel(h2_incl_ds, vegtype=vegtype_str) + thisCrop_gddaccum_da = thisCrop_ds[clm_gdd_var] + if save_figs: + thisCrop_gddharv_da = thisCrop_ds["GDDHARV"] + if not thisCrop_gddaccum_da.size: + continue + log(logger, f" {vegtype_str}...") + incl_vegtype_indices = incl_vegtype_indices + [v] + + # Get prescribed harvest dates for these patches + lon_points = thisCrop_ds.patches1d_lon.values + lat_points = thisCrop_ds.patches1d_lat.values + thisCrop_hdates_rx = thisCrop_map_to_patches(lon_points, lat_points, hdates_rx, vegtype_int) + + if isinstance(gddaccum_yp_list[v], type(None)): + gddaccum_yp_list[v] = np.full((Nyears + 1, len(thisCrop_full_patchlist)), np.nan) + if save_figs: + gddharv_yp_list[v] = np.full((Nyears + 1, len(thisCrop_full_patchlist)), np.nan) + + # Get the accumulated GDDs at each prescribed harvest date + gddaccum_atharv_p = np.full(thisCrop_hdates_rx.shape, np.nan) + if save_figs: + gddharv_atharv_p = np.full(thisCrop_hdates_rx.shape, np.nan) + unique_rx_hdates = np.unique(thisCrop_hdates_rx.values) + # Build an indexing tuple + patches = [] + i_patches = [] + i_times = [] + for i, hdate in enumerate(unique_rx_hdates): + here = np.where(thisCrop_hdates_rx.values == hdate)[0] + patches += list(thisCrop_gddaccum_da.patch.values[here]) + i_patches += list(here) + i_times += list(np.full((len(here),), int(hdate - 1))) + # Sort back to correct order + if not np.all( + thisCrop_gddaccum_da.patch.values[:-1] <= thisCrop_gddaccum_da.patch.values[1:] + ): + error(logger, "This code depends on DataArray patch list being sorted.") + sortorder = np.argsort(patches) + i_patches = list(np.array(i_patches)[np.array(sortorder)]) + i_times = list(np.array(i_times)[np.array(sortorder)]) + # Select using the indexing tuple + gddaccum_atharv_p = thisCrop_gddaccum_da.values[(i_times, i_patches)] + if save_figs: + gddharv_atharv_p = thisCrop_gddharv_da.values[(i_times, i_patches)] + if np.any(np.isnan(gddaccum_atharv_p)): + log( + logger, + f" ❗ {np.sum(np.isnan(gddaccum_atharv_p))}/{len(gddaccum_atharv_p)} NaN after extracting GDDs accumulated at harvest", + ) + if save_figs and np.any(np.isnan(gddharv_atharv_p)): + log( + logger, + f" ❗ {np.sum(np.isnan(gddharv_atharv_p))}/{len(gddharv_atharv_p)} NaN after extracting GDDHARV", + ) + + # Assign these to growing seasons based on whether gs crossed new year + thisYear_active_patch_indices = [ + thisCrop_full_patchlist.index(x) for x in thisCrop_ds.patch.values + ] + thisCrop_sdates_rx = thisCrop_map_to_patches(lon_points, lat_points, sdates_rx, vegtype_int) + where_gs_thisyr = np.where(thisCrop_sdates_rx < thisCrop_hdates_rx)[0] + tmp_gddaccum = np.full(thisCrop_sdates_rx.shape, np.nan) + tmp_gddaccum[where_gs_thisyr] = gddaccum_atharv_p[where_gs_thisyr] + if save_figs: + tmp_gddharv = np.full(tmp_gddaccum.shape, np.nan) + tmp_gddharv[where_gs_thisyr] = gddharv_atharv_p[where_gs_thisyr] + if y > 0: + lastYear_active_patch_indices = lastYear_active_patch_indices_list[v] + where_gs_lastyr = np.where(thisCrop_sdates_rx > thisCrop_hdates_rx)[0] + active_thisYear_where_gs_lastyr_indices = [ + thisYear_active_patch_indices[x] for x in where_gs_lastyr + ] + if not np.array_equal(lastYear_active_patch_indices, thisYear_active_patch_indices): + if incorrectly_daily: + log( + logger, + " ❗ This year's active patch indices differ from last year's. Allowing because this might just be an artifact of incorrectly daily outputs, BUT RESULTS MUST NOT BE TRUSTED.", + ) + else: + error(logger, "This year's active patch indices differ from last year's.") + # Make sure we're not about to overwrite any existing values. + if np.any( + ~np.isnan(gddaccum_yp_list[v][y - 1, active_thisYear_where_gs_lastyr_indices]) + ): + if incorrectly_daily: + log( + logger, + " ❗ Unexpected non-NaN for last season's GDD accumulation. Allowing because this might just be an artifact of incorrectly daily outputs, BUT RESULTS MUST NOT BE TRUSTED.", + ) + else: + error(logger, "Unexpected non-NaN for last season's GDD accumulation") + if save_figs and np.any( + ~np.isnan(gddharv_yp_list[v][y - 1, active_thisYear_where_gs_lastyr_indices]) + ): + if incorrectly_daily: + log( + logger, + " ❗ Unexpected non-NaN for last season's GDDHARV. Allowing because this might just be an artifact of incorrectly daily outputs, BUT RESULTS MUST NOT BE TRUSTED.", + ) + else: + error(logger, "Unexpected non-NaN for last season's GDDHARV") + # Fill. + gddaccum_yp_list[v][y - 1, active_thisYear_where_gs_lastyr_indices] = gddaccum_atharv_p[ + where_gs_lastyr + ] + if save_figs: + gddharv_yp_list[v][ + y - 1, active_thisYear_where_gs_lastyr_indices + ] = gddharv_atharv_p[where_gs_lastyr] + # Last year's season should be filled out now; make sure. + if np.any( + np.isnan(gddaccum_yp_list[v][y - 1, active_thisYear_where_gs_lastyr_indices]) + ): + if incorrectly_daily: + log( + logger, + " ❗ Unexpected NaN for last season's GDD accumulation. Allowing because this might just be an artifact of incorrectly daily outputs, BUT RESULTS MUST NOT BE TRUSTED.", + ) + else: + error(logger, "Unexpected NaN for last season's GDD accumulation.") + if save_figs and np.any( + np.isnan(gddharv_yp_list[v][y - 1, active_thisYear_where_gs_lastyr_indices]) + ): + if incorrectly_daily: + log( + logger, + " ❗ Unexpected NaN for last season's GDDHARV. Allowing because this might just be an artifact of incorrectly daily outputs, BUT RESULTS MUST NOT BE TRUSTED.", + ) + else: + error(logger, "Unexpected NaN for last season's GDDHARV.") + gddaccum_yp_list[v][y, thisYear_active_patch_indices] = tmp_gddaccum + if save_figs: + gddharv_yp_list[v][y, thisYear_active_patch_indices] = tmp_gddharv + + # Make sure that NaN masks are the same for this year's sdates and 'filled-out' GDDs from last year + if y > 0: + nanmask_output_sdates = np.isnan( + dates_ds.SDATES.isel( + mxsowings=0, patch=np.where(dates_ds.patches1d_itype_veg_str == vegtype_str)[0] + ).values + ) + nanmask_output_gdds_lastyr = np.isnan(gddaccum_yp_list[v][y - 1, :]) + if not np.array_equal(nanmask_output_gdds_lastyr, nanmask_output_sdates): + if incorrectly_daily: + log( + logger, + " ❗ NaN masks differ between this year's sdates and 'filled-out' GDDs from last year. Allowing because this might just be an artifact of incorrectly daily outputs, BUT RESULTS MUST NOT BE TRUSTED.", + ) + else: + error( + logger, + "NaN masks differ between this year's sdates and 'filled-out' GDDs from last year", + ) + lastYear_active_patch_indices_list[v] = thisYear_active_patch_indices + + skip_patches_for_isel_nan_lastyear = skip_patches_for_isel_nan + + # Could save space by only saving variables needed for gridding + log(logger, " Saving h2_ds...") + h2_ds.to_netcdf(h2_ds_file) + + return ( + h2_ds, + sdates_rx, + hdates_rx, + gddaccum_yp_list, + gddharv_yp_list, + skip_patches_for_isel_nan_lastyear, + lastYear_active_patch_indices_list, + incorrectly_daily, + incl_vegtypes_str, + incl_patches1d_itype_veg, + mxsowings, + ) + + +def get_multicrop_maps(ds, theseVars, crop_fracs_yx, dummy_fill, gdd_units): + # Get GDDs for these crops + da_eachCFT = xr.concat((ds[x] for i, x in enumerate(theseVars)), dim="cft") + if "time" in ds.dims: + da_eachCFT = da_eachCFT.isel(time=0, drop=True) + da_eachCFT = da_eachCFT.where(da_eachCFT != dummy_fill) + da_eachCFT.attrs["units"] = gdd_units + + # What are the maximum differences seen between different crop types? + if len(theseVars) > 1: + maxDiff = np.nanmax(da_eachCFT.max(dim="cft") - da_eachCFT.min(dim="cft")) + if maxDiff > 0: + print(f" Max difference among crop types: {np.round(maxDiff)}") + + if crop_fracs_yx is None: + return da_eachCFT.isel(cft=0, drop=True) + + # Warn if GDD is NaN anywhere that there is area + da_eachCFT["cft"] = crop_fracs_yx["cft"] + gddNaN_areaPos = np.isnan(da_eachCFT) & (crop_fracs_yx > 0) + if np.any(gddNaN_areaPos): + total_bad_croparea = np.nansum(crop_fracs_yx.where(gddNaN_areaPos).values) + total_croparea = np.nansum(crop_fracs_yx.values) + print( + f" GDD reqt NaN but area positive ({np.round(total_bad_croparea/total_croparea*100, 1)}% of this crop's area)" + ) + + # Get areas and weights, masking cell-crops with NaN GDDs + crop_fracs_yx = crop_fracs_yx.where(~np.isnan(da_eachCFT)) + crop_area_yx = crop_fracs_yx.sum(dim="cft") + weights_yx = crop_fracs_yx / crop_area_yx + weights_sum_gt0 = weights_yx.sum(dim="cft").where(weights_yx > 0) + assert np.isclose(np.nanmin(weights_sum_gt0.values), 1.0) + assert np.isclose(np.nanmax(weights_sum_gt0.values), 1.0) + + # Mask GDDs and weights where there is no area + da_eachCFT = da_eachCFT.where(crop_fracs_yx > 0) + if len(theseVars) == 1: + return da_eachCFT.isel(cft=0, drop=True) + weights_yx = weights_yx.where(crop_fracs_yx > 0) + weights_sum = weights_yx.sum(dim="cft").where(crop_area_yx > 0) + assert np.isclose(np.nanmin(weights_sum.values), 1.0) + assert np.isclose(np.nanmax(weights_sum.values), 1.0) + + # Ensure grid match between GDDs and weights + if not np.array_equal(da_eachCFT["lon"].values, weights_yx["lon"].values): + raise RuntimeError("lon mismatch") + if not np.array_equal(da_eachCFT["lat"].values, weights_yx["lat"].values): + raise RuntimeError("lat mismatch") + + # Get area-weighted mean GDD requirements for all crops + da = (da_eachCFT * weights_yx).sum(dim="cft") + da.attrs["units"] = gdd_units + da = da.where(crop_area_yx > 0) + + # Ensure that weighted mean is between each cell's min and max + whereBad = (da < da_eachCFT.min(dim="cft")) | (da > da_eachCFT.max(dim="cft")) + if np.any(whereBad): + where_belowMin = da.where(da < da_eachCFT.min(dim="cft")) + worst_belowMin = np.min((da_eachCFT.min(dim="cft") - where_belowMin).values) + where_aboveMax = da.where(da > da_eachCFT.max(dim="cft")) + worst_aboveMax = np.max((where_aboveMax - da_eachCFT.max(dim="cft")).values) + worst = max(worst_belowMin, worst_aboveMax) + tol = 1e-12 + if worst > 1e-12: + raise RuntimeError( + f"Some value is outside expected range by {worst} (exceeds tolerance {tol})" + ) + + return da + + +if can_plot: + + def get_bounds_ncolors(gdd_spacing, diff_map_yx): + vmax = np.floor(np.nanmax(diff_map_yx.values) / gdd_spacing) * gdd_spacing + vmin = -vmax + epsilon = np.nextafter(0, 1) + bounds = list(np.arange(vmin, vmax, gdd_spacing)) + [vmax - epsilon] + if 0 in bounds: + bounds.remove(0) + bounds[bounds.index(-gdd_spacing)] /= 2 + bounds[bounds.index(gdd_spacing)] /= 2 + Ncolors = len(bounds) + 1 + return vmax, bounds, Ncolors + + def make_map( + ax, + this_map, + this_title, + vmax, + bin_width, + fontsize_ticklabels, + fontsize_titles, + bounds=None, + extend="both", + cmap=None, + cbar_ticks=None, + vmin=None, + ): + if bounds: + if not cmap: + raise RuntimeError("Calling make_map() with bounds requires cmap to be specified") + norm = mcolors.BoundaryNorm(bounds, cmap.N, extend=extend) + im1 = ax.pcolormesh( + this_map.lon.values, + this_map.lat.values, + this_map, + shading="auto", + norm=norm, + cmap=cmap, + ) + else: + if np.any(this_map.values < 0): + gdd_spacing = 500 + vmax = np.floor(np.nanmax(this_map.values) / gdd_spacing) * gdd_spacing + if vmin is not None: + raise RuntimeError("Do not specify vmin in this call of make_map()") + vmin = -vmax + Ncolors = vmax / gdd_spacing + if Ncolors % 2 == 0: + Ncolors += 1 + if not cmap: + cmap = cm.get_cmap(cropcal_colors["div_other_nonnorm"], Ncolors) + + if np.any(this_map.values > vmax) and np.any(this_map.values < vmin): + extend = "both" + elif np.any(this_map.values > vmax): + extend = "max" + elif np.any(this_map.values < vmin): + extend = "min" + else: + extend = "neither" + + else: + if vmin is None: + vmin = 0 + else: + vmin = np.floor(vmin / 500) * 500 + vmax = np.floor(vmax / 500) * 500 + Ncolors = int(vmax / 500) + if not cmap: + cmap = cm.get_cmap(cropcal_colors["seq_other"], Ncolors + 1) + extend = "max" + extend_color = cmap.colors[-1] + cmap = mcolors.ListedColormap(cmap.colors[:Ncolors]) + cmap.set_over(extend_color) + + im1 = ax.pcolormesh( + this_map.lon.values, + this_map.lat.values, + this_map, + shading="auto", + vmin=vmin, + vmax=vmax, + cmap=cmap, + ) + + ax.set_extent([-180, 180, -63, 90], crs=ccrs.PlateCarree()) + ax.coastlines(linewidth=0.3) + ax.set_title(this_title, fontsize=fontsize_titles, fontweight="bold", y=0.96) + cbar = plt.colorbar( + im1, + orientation="horizontal", + fraction=0.1, + pad=0.02, + aspect=40, + extend=extend, + spacing="proportional", + ) + cbar.ax.tick_params(labelsize=fontsize_ticklabels) + cbar.ax.set_xlabel(this_map.attrs["units"], fontsize=fontsize_ticklabels) + cbar.ax.xaxis.set_label_coords(x=0.115, y=2.6) + if cbar_ticks: + cbar.ax.set_xticks(cbar_ticks) + + ticks = np.arange(-60, 91, bin_width) + ticklabels = [str(x) for x in ticks] + for i, x in enumerate(ticks): + if x % 2: + ticklabels[i] = "" + plt.yticks(np.arange(-60, 91, 15), labels=ticklabels, fontsize=fontsize_ticklabels) + plt.axis("off") + + def get_non_nans(in_da, fillValue): + in_da = in_da.where(in_da != fillValue) + return in_da.values[~np.isnan(in_da.values)] + + def set_boxplot_props(bp, color, linewidth): + linewidth = 1.5 + plt.setp(bp["boxes"], color=color, linewidth=linewidth) + plt.setp(bp["whiskers"], color=color, linewidth=linewidth) + plt.setp(bp["caps"], color=color, linewidth=linewidth) + plt.setp(bp["medians"], color=color, linewidth=linewidth) + plt.setp( + bp["fliers"], + markeredgecolor=color, + markersize=6, + linewidth=linewidth, + markeredgewidth=linewidth / 2, + ) + + def make_plot(data, offset, linewidth): + offset = 0.4 * offset + bpl = plt.boxplot( + data, + positions=np.array(range(len(data))) * 2.0 + offset, + widths=0.6, + boxprops=dict(linewidth=linewidth), + whiskerprops=dict(linewidth=linewidth), + capprops=dict(linewidth=linewidth), + medianprops=dict(linewidth=linewidth), + flierprops=dict(markeredgewidth=0.5), + ) + return bpl + + def make_figures( + first_land_use_year, + last_land_use_year, + land_use_file, + run1_name, + run2_name, + logger, + thisDir=None, + gdd_maps_ds=None, + gddharv_maps_ds=None, + outdir_figs=None, + linewidth=1.5, + ): + if not gdd_maps_ds: + if not thisDir: + error( + logger, + "If not providing gdd_maps_ds, you must provide thisDir (location of gdd_maps.nc)", + ) + gdd_maps_ds = xr.open_dataset(thisDir + "gdd_maps.nc") + if not gddharv_maps_ds: + if not thisDir: + error( + logger, + "If not providing gddharv_maps_ds, you must provide thisDir (location of gddharv_maps.nc)", + ) + gddharv_maps_ds = xr.open_dataset(thisDir + "gdd_maps.nc") + + # Get info + incl_vegtypes_str = gdd_maps_ds.attrs["incl_vegtypes_str"] + if incl_vegtypes_str is None: + incl_vegtypes_str = [] + elif isinstance(incl_vegtypes_str, np.ndarray): + incl_vegtypes_str = list(incl_vegtypes_str) + dummy_fill = gdd_maps_ds.attrs["dummy_fill"] + if not outdir_figs: + outdir_figs = gdd_maps_ds.attrs["outdir_figs"] + try: + y1 = gdd_maps_ds.attrs["y1"] + yN = gdd_maps_ds.attrs["yN"] + # Backwards compatibility with a bug (fixed 2023-01-03) + except: + y1 = gdd_maps_ds.attrs["first_season"] + yN = gdd_maps_ds.attrs["last_season"] + # Import LU data, if doing so + if land_use_file: + y1_lu = y1 if first_land_use_year == None else first_land_use_year + yN_lu = yN if last_land_use_year == None else last_land_use_year + lu_ds = cc.open_lu_ds(land_use_file, y1_lu, yN_lu, gdd_maps_ds, ungrid=False) + lu_years_text = f" (masked by {y1_lu}-{yN_lu} area)" + lu_years_file = f"_mask{y1_lu}-{yN_lu}" + else: + lu_ds = None + lu_years_text = "" + lu_years_file = "" + + # layout = "3x1" + # layout = "2x2" + layout = "3x2" + bin_width = 15 + lat_bin_edges = np.arange(0, 91, bin_width) + + fontsize_titles = 12 + fontsize_axislabels = 12 + fontsize_ticklabels = 12 + + Nbins = len(lat_bin_edges) - 1 + bin_names = ["All"] + for b in np.arange(Nbins): + lower = lat_bin_edges[b] + upper = lat_bin_edges[b + 1] + bin_names.append(f"{lower}–{upper}") + + color_old = cropcal_colors_cases(run1_name) + if color_old is None: + color_old = "#beaed4" + color_new = cropcal_colors_cases(run2_name) + if color_new is None: + color_new = "#7fc97f" + gdd_units = "GDD (°C • day)" + + # Maps + ny = 3 + nx = 1 + log(logger, "Making before/after maps...") + vegtype_list = incl_vegtypes_str + if land_use_file: + vegtype_list += ["Corn", "Cotton", "Rice", "Soybean", "Sugarcane", "Wheat"] + for v, vegtype_str in enumerate(vegtype_list): + print(f"{vegtype_str}...") + + # Get component types + if vegtype_str in incl_vegtypes_str: + vegtypes_str = [vegtype_str] + elif not lu_ds: + raise RuntimeError(f"If mapping {vegtype_str}, you must provide land use dataset") + else: + vegtypes_str = [x for x in incl_vegtypes_str if vegtype_str.lower() in x] + vegtypes_int = [utils.vegtype_str2int(x)[0] for x in vegtypes_str] + + # Crop fraction map (for masking and weighting) + if lu_ds: + crop_fracs_yx = ( + lu_ds.LANDFRAC_PFT * lu_ds.PCT_CROP * lu_ds.PCT_CFT.sel(cft=vegtypes_int) + ).sum(dim="time") + if np.sum(crop_fracs_yx) == 0: + print(f"Skipping {vegtype_str} (no area)") + continue + else: + crop_fracs_yx = None + + theseVars = [f"gdd1_{x}" for x in vegtypes_int] + gddharv_map_yx = get_multicrop_maps( + gddharv_maps_ds, theseVars, crop_fracs_yx, dummy_fill, gdd_units + ) + gdd_map_yx = get_multicrop_maps( + gdd_maps_ds, theseVars, crop_fracs_yx, dummy_fill, gdd_units + ) + + # Get figure title + if len(vegtypes_str) > 1: + vegtype_str_title = vegtype_str + else: + vegtype_str_title = vegtype_str.replace("_", " ") + if "irrigated" not in vegtype_str: + vegtype_str_title = "rainfed " + vegtype_str_title + vegtype_str_title = vegtype_str_title.capitalize() + + vmin = min(np.min(gdd_map_yx), np.min(gddharv_map_yx)).values + vmax = max(np.max(gdd_map_yx), np.max(gddharv_map_yx)).values + + # Set up figure and first subplot + if layout == "3x1": + fig = plt.figure(figsize=(7.5, 14)) + ax = fig.add_subplot(ny, nx, 1, projection=ccrs.PlateCarree()) + elif layout == "2x2": + fig = plt.figure(figsize=(12, 6)) + spec = fig.add_gridspec(nrows=2, ncols=2, width_ratios=[0.4, 0.6]) + ax = fig.add_subplot(spec[0, 0], projection=ccrs.PlateCarree()) + elif layout == "3x2": + fig = plt.figure(figsize=(14, 9)) + spec = fig.add_gridspec(nrows=3, ncols=2, width_ratios=[0.5, 0.5], wspace=0.2) + ax = fig.add_subplot(spec[0, 0], projection=ccrs.PlateCarree()) + else: + error(logger, f"layout {layout} not recognized") + + thisMin = int(np.round(np.nanmin(gddharv_map_yx))) + thisMax = int(np.round(np.nanmax(gddharv_map_yx))) + thisTitle = f"{run1_name} (range {thisMin}–{thisMax})" + make_map( + ax, + gddharv_map_yx, + thisTitle, + vmax, + bin_width, + fontsize_ticklabels, + fontsize_titles, + vmin=vmin, + ) + + if layout == "3x1": + ax = fig.add_subplot(ny, nx, 2, projection=ccrs.PlateCarree()) + elif layout in ["2x2", "3x2"]: + ax = fig.add_subplot(spec[1, 0], projection=ccrs.PlateCarree()) + else: + error(logger, f"layout {layout} not recognized") + thisMin = int(np.round(np.nanmin(gdd_map_yx))) + thisMax = int(np.round(np.nanmax(gdd_map_yx))) + thisTitle = f"{run2_name} (range {thisMin}–{thisMax})" + make_map( + ax, + gdd_map_yx, + thisTitle, + vmax, + bin_width, + fontsize_ticklabels, + fontsize_titles, + vmin=vmin, + ) + + # Difference + if layout == "3x2": + ax = fig.add_subplot(spec[2, 0], projection=ccrs.PlateCarree()) + thisMin = int(np.round(np.nanmin(gdd_map_yx))) + thisMax = int(np.round(np.nanmax(gdd_map_yx))) + thisTitle = f"{run2_name} minus {run1_name}" + diff_map_yx = gdd_map_yx - gddharv_map_yx + diff_map_yx.attrs["units"] = gdd_units + + gdd_spacing = 500 + vmax, bounds, Ncolors = get_bounds_ncolors(gdd_spacing, diff_map_yx) + if Ncolors < 9: + gdd_spacing = 250 + vmax, bounds, Ncolors = get_bounds_ncolors(gdd_spacing, diff_map_yx) + + cmap = cm.get_cmap(cropcal_colors["div_other_nonnorm"], Ncolors) + cbar_ticks = [] + include_0bin_ticks = Ncolors <= 13 + if vmax <= 3000: + tick_spacing = gdd_spacing * 2 + elif vmax <= 5000: + tick_spacing = 1500 + else: + tick_spacing = 2000 + previous = -np.inf + for x in bounds: + if (not include_0bin_ticks) and (x > 0) and (previous < 0): + cbar_ticks.append(0) + if x % tick_spacing == 0 or (include_0bin_ticks and abs(x) == gdd_spacing / 2): + cbar_ticks.append(x) + previous = x + + make_map( + ax, + diff_map_yx, + thisTitle, + vmax, + bin_width, + fontsize_ticklabels, + fontsize_titles, + bounds=bounds, + extend="both", + cmap=cmap, + cbar_ticks=cbar_ticks, + ) + + # Boxplots ##################### + + gdd_vector = get_non_nans(gdd_map_yx, dummy_fill) + gddharv_vector = get_non_nans(gddharv_map_yx, dummy_fill) + + lat_abs = np.abs(gdd_map_yx.lat.values) + gdd_bybin_old = [gddharv_vector] + gdd_bybin_new = [gdd_vector] + for b in np.arange(Nbins): + lower = lat_bin_edges[b] + upper = lat_bin_edges[b + 1] + lat_inds = np.where((lat_abs >= lower) & (lat_abs < upper))[0] + gdd_vector_thisBin = get_non_nans(gdd_map_yx[lat_inds, :], dummy_fill) + gddharv_vector_thisBin = get_non_nans(gddharv_map_yx[lat_inds, :], dummy_fill) + gdd_bybin_old.append(gddharv_vector_thisBin) + gdd_bybin_new.append(gdd_vector_thisBin) + + if layout == "3x1": + ax = fig.add_subplot(ny, nx, 3) + elif layout in ["2x2", "3x2"]: + ax = fig.add_subplot(spec[:, 1]) + else: + error(logger, f"layout {layout} not recognized") + + # Shift bottom of plot up to make room for legend + ax_pos = ax.get_position() + ax.set_position(Bbox.from_extents(ax_pos.x0, 0.19, ax_pos.x1, ax_pos.y1)) + # Define legend position + legend_bbox_to_anchor = (0, -0.15, 1, 0.2) + + bpl = make_plot(gdd_bybin_old, -1, linewidth) + bpr = make_plot(gdd_bybin_new, 1, linewidth) + set_boxplot_props(bpl, color_old, linewidth) + set_boxplot_props(bpr, color_new, linewidth) + + # draw temporary lines to create a legend + plt.plot([], c=color_old, label=run1_name, linewidth=linewidth) + plt.plot([], c=color_new, label=run2_name, linewidth=linewidth) + plt.legend( + fontsize=fontsize_titles, + bbox_to_anchor=legend_bbox_to_anchor, + ncol=2, + loc="lower left", + mode="expand", + ) + + plt.xticks(range(0, len(bin_names) * 2, 2), bin_names, fontsize=fontsize_ticklabels) + plt.yticks(fontsize=fontsize_ticklabels) + ax.spines["right"].set_visible(False) + ax.spines["top"].set_visible(False) + + plt.xlabel("Latitude zone (absolute value)", fontsize=fontsize_axislabels) + plt.ylabel(gdd_units, fontsize=fontsize_axislabels) + ax.yaxis.set_label_coords(-0.11, 0.5) + plt.title(f"Zonal changes", fontsize=fontsize_titles, fontweight="bold") + + plt.suptitle( + f"Maturity requirements: {vegtype_str_title}" + lu_years_text, + fontsize=fontsize_titles * 1.2, + fontweight="bold", + y=0.95, + ) + + if vegtype_str in incl_vegtypes_str: + outfile = os.path.join( + outdir_figs, f"{theseVars[0]}_{vegtype_str}_gs{y1}-{yN}{lu_years_file}.png" + ) + else: + outfile = os.path.join(outdir_figs, f"{vegtype_str}_gs{y1}-{yN}{lu_years_file}.png") + plt.savefig(outfile, dpi=300, transparent=False, facecolor="white", bbox_inches="tight") + plt.close() + + log(logger, "Done.") diff --git a/python/ctsm/crop_calendars/process_ggcmi_shdates.py b/python/ctsm/crop_calendars/process_ggcmi_shdates.py new file mode 100644 index 0000000000..b2ffcfe1f8 --- /dev/null +++ b/python/ctsm/crop_calendars/process_ggcmi_shdates.py @@ -0,0 +1,395 @@ +import numpy as np +import xarray as xr +import shutil +import os +import datetime as dt +import cftime +import sys +import argparse + +import cropcal_utils as utils +import regrid_ggcmi_shdates + + +def get_cft(y): + return cftime.DatetimeNoLeap(y, 1, 1, 0, 0, 0, 0, has_year_zero=True) + + +def get_dayssince_jan1y1(y1, y): + cft_y1 = get_cft(y1) + cft_y = get_cft(y) + time_delta = cft_y - cft_y1 + time_delta_secs = time_delta.total_seconds() + return time_delta_secs / (60 * 60 * 24) + + +def main( + input_directory, + output_directory, + author, + file_specifier, + first_year, + last_year, + verbose, + ggcmi_author, + regrid_resolution, + regrid_template_file, +): + + ############################################################ + ### Regrid original GGCMI files to target CLM resolution ### + ############################################################ + + regridded_ggcmi_files_dir = os.path.join( + output_directory, f"regridded_ggcmi_files-{regrid_resolution}" + ) + + regrid_ggcmi_shdates.main( + regrid_resolution, regrid_template_file, input_directory, regridded_ggcmi_files_dir + ) + + ########################### + ### Define dictionaries ### + ########################### + + # First, we associate CLM crop names with (1) their integer counterpart and (2) their GGCMI counterpart. + # Some notes: + # - As "CLMname: {clm_num, thiscrop_ggcmi}" + # - CLM names and numbers taken from commit `3dcbc7499a57904750a994672fc36b4221b9def5` + # - Using one global GGCMI value for both temperate and tropical versions of corn and soybean. + # - There is no GGCMI equivalent of CLM's winter barley and rye. Using winter wheat instead. + # - Using GGCMI `pea` for CLM pulses, as suggested by GGCMI phase 3 protocol. + # - Only using GGCMI `ri1` for rice; ignoring `ri2`. + def set_crop_dict(thisnum, thisname): + return {"clm_num": thisnum, "thiscrop_ggcmi": thisname} + + crop_dict = { + "temperate_corn": set_crop_dict(17, "mai_rf"), + "irrigated_temperate_corn": set_crop_dict(18, "mai_ir"), + "spring_wheat": set_crop_dict(19, "swh_rf"), + "irrigated_spring_wheat": set_crop_dict(20, "swh_ir"), + "winter_wheat": set_crop_dict(21, "wwh_rf"), + "irrigated_winter_wheat": set_crop_dict(22, "wwh_ir"), + "temperate_soybean": set_crop_dict(23, "soy_rf"), + "irrigated_temperate_soybean": set_crop_dict(24, "soy_ir"), + "barley": set_crop_dict(25, "bar_rf"), + "irrigated_barley": set_crop_dict(26, "bar_ir"), + "winter_barley": set_crop_dict(27, "wwh_rf"), + "irrigated_winter_barley": set_crop_dict(28, "wwh_ir"), + "rye": set_crop_dict(29, "rye_rf"), + "irrigated_rye": set_crop_dict(30, "rye_ir"), + "winter_rye": set_crop_dict(31, "wwh_rf"), + "irrigated_winter_rye": set_crop_dict(32, "wwh_ir"), + "cassava": set_crop_dict(33, "cas_rf"), + "irrigated_cassava": set_crop_dict(34, "cas_ir"), + "citrus": set_crop_dict(35, None), + "irrigated_citrus": set_crop_dict(36, None), + "cocoa": set_crop_dict(37, None), + "irrigated_cocoa": set_crop_dict(38, None), + "coffee": set_crop_dict(39, None), + "irrigated_coffee": set_crop_dict(40, None), + "cotton": set_crop_dict(41, "cot_rf"), + "irrigated_cotton": set_crop_dict(42, "cot_ir"), + "datepalm": set_crop_dict(43, None), + "irrigated_datepalm": set_crop_dict(44, None), + "foddergrass": set_crop_dict(45, None), + "irrigated_foddergrass": set_crop_dict(46, None), + "grapes": set_crop_dict(47, None), + "irrigated_grapes": set_crop_dict(48, None), + "groundnuts": set_crop_dict(49, "nut_rf"), + "irrigated_groundnuts": set_crop_dict(50, "nut_ir"), + "millet": set_crop_dict(51, "mil_rf"), + "irrigated_millet": set_crop_dict(52, "mil_ir"), + "oilpalm": set_crop_dict(53, None), + "irrigated_oilpalm": set_crop_dict(54, None), + "potatoes": set_crop_dict(55, "pot_rf"), + "irrigated_potatoes": set_crop_dict(56, "pot_ir"), + "pulses": set_crop_dict(57, "pea_rf"), + "irrigated_pulses": set_crop_dict(58, "pea_ir"), + "rapeseed": set_crop_dict(59, "rap_rf"), + "irrigated_rapeseed": set_crop_dict(60, "rap_ir"), + "rice": set_crop_dict(61, "ric_rf"), + "irrigated_rice": set_crop_dict(62, "ric_ir"), + "sorghum": set_crop_dict(63, "sor_rf"), + "irrigated_sorghum": set_crop_dict(64, "sor_ir"), + "sugarbeet": set_crop_dict(65, "sgb_rf"), + "irrigated_sugarbeet": set_crop_dict(66, "sgb_ir"), + "sugarcane": set_crop_dict(67, "sgc_rf"), + "irrigated_sugarcane": set_crop_dict(68, "sgc_ir"), + "sunflower": set_crop_dict(69, "sun_rf"), + "irrigated_sunflower": set_crop_dict(70, "sun_ir"), + "miscanthus": set_crop_dict(71, None), + "irrigated_miscanthus": set_crop_dict(72, None), + "switchgrass": set_crop_dict(73, None), + "irrigated_switchgrass": set_crop_dict(74, None), + "tropical_corn": set_crop_dict(75, "mai_rf"), + "irrigated_tropical_corn": set_crop_dict(76, "mai_ir"), + "tropical_soybean": set_crop_dict(77, "soy_rf"), + "irrigated_tropical_soybean": set_crop_dict(78, "soy_ir"), + "c3_crop": set_crop_dict(15, None), + "c3_irrigated": set_crop_dict(16, None), + } + + # Next, we associate CLM variable names with their GGCMI counterparts. We also save a placeholder for output file paths associated with each variable. + # As CLMname: {GGCMIname, output_file} + def set_var_dict(name_ggcmi, outfile): + return {"name_ggcmi": name_ggcmi, "outfile": outfile} + + variable_dict = { + "sdate": set_var_dict("planting_day", ""), + "hdate": set_var_dict("maturity_day", ""), + } + + ################################ + ### Instantiate output files ### + ################################ + + # Global attributes for output files + out_attrs = { + "title": "GGCMI crop calendar for Phase 3, v1.01", + "author_thisfile": author, + "author_original": ggcmi_author, + "comment": "Day of year is 1-indexed (i.e., Jan. 1 = 1). Filled using cdo -remapnn,$original -setmisstonn", + "created": dt.datetime.now().replace(microsecond=0).astimezone().isoformat(), + } + + # Create template dataset + time_array = np.array( + [get_dayssince_jan1y1(first_year, y) for y in np.arange(first_year, last_year + 1)] + ) + time_coord = xr.IndexVariable( + "time", + data=time_array, + attrs={ + "long_name": "time", + "units": f"days since {first_year}-01-01", + "calendar": "noleap", + }, + ) + template_ds = xr.Dataset(coords={"time": time_coord}, attrs=out_attrs) + + # Create output files + datetime_string = dt.datetime.now().strftime("%Y%m%d_%H%M%S") + for v in variable_dict: + outfile = os.path.join( + output_directory, f"{v}s_{file_specifier}.{first_year}-{last_year}.{datetime_string}.nc" + ) + variable_dict[v]["outfile"] = outfile + template_ds.to_netcdf( + path=variable_dict[v]["outfile"], + format="NETCDF3_CLASSIC", + ) + + ######################### + ### Process all crops ### + ######################### + + for thiscrop_clm in crop_dict: + + # Which crop are we on? + c = list(crop_dict.keys()).index(thiscrop_clm) + 1 + + # Get information about this crop + this_dict = crop_dict[thiscrop_clm] + thiscrop_int = this_dict["clm_num"] + thiscrop_ggcmi = this_dict["thiscrop_ggcmi"] + + # If no corresponding GGCMI crop, skip opening dataset. + # Will use previous cropcal_ds as a template. + if thiscrop_ggcmi == None: + if c == 1: + raise ValueError(f"First crop ({thiscrop_clm}) must have a GGCMI type") + print( + "Filling %s with dummy data (%d of %d)..." % (str(thiscrop_clm), c, len(crop_dict)) + ) + + # Otherwise, import crop calendar file + else: + if verbose: + print( + "Importing %s -> %s (%d of %d)..." + % (str(thiscrop_ggcmi), str(thiscrop_clm), c, len(crop_dict)) + ) + + file_ggcmi = os.path.join( + regridded_ggcmi_files_dir, f"{thiscrop_ggcmi}_{file_specifier}.nc4" + ) + if not os.path.exists(file_ggcmi): + raise Exception("Input file not found: " + file_ggcmi) + cropcal_ds = xr.open_dataset(file_ggcmi) + # Flip latitude to match destination + cropcal_ds = cropcal_ds.reindex(lat=cropcal_ds.lat[::-1]) + # Rearrange longitude to match destination (does nothing if not needed) + cropcal_ds = utils.lon_idl2pm(cropcal_ds, fail_silently=True) + + for thisvar_clm in variable_dict: + # Get GGCMI netCDF info + varname_ggcmi = variable_dict[thisvar_clm]["name_ggcmi"] + if verbose: + print(" Processing %s..." % varname_ggcmi) + + # Get CLM netCDF info + varname_clm = thisvar_clm + "1_" + str(thiscrop_int) + file_clm = variable_dict[thisvar_clm]["outfile"] + if not os.path.exists(file_clm): + raise Exception("Output file not found: " + file_clm) + + # Strip dataset to just this variable + droplist = [] + for i in list(cropcal_ds.keys()): + if i != varname_ggcmi: + droplist.append(i) + thisvar_ds = cropcal_ds.drop(droplist) + thisvar_ds = thisvar_ds.load() + + # Convert to integer + new_fillvalue = -1 + dummyvalue = -1 + thisvar_ds.variables[varname_ggcmi].encoding["_FillValue"] = new_fillvalue + if thiscrop_ggcmi == None: + thisvar_ds.variables[varname_ggcmi].values.fill(dummyvalue) + else: + thisvar_ds.variables[varname_ggcmi].values[ + np.isnan(thisvar_ds.variables[varname_ggcmi].values) + ] = new_fillvalue + thisvar_ds.variables[varname_ggcmi].values = thisvar_ds.variables[ + varname_ggcmi + ].values.astype("int16") + + # Add time dimension (https://stackoverflow.com/a/62862440) + # (Repeats original map for every timestep) + # Probably not necessary to use this method, since I only end up extracting thisvar_ds.values anyway---I could probably use some numpy method instead. + thisvar_ds = thisvar_ds.expand_dims(time=template_ds.time) + thisvar_da_tmp = thisvar_ds[varname_ggcmi] + thisvar_da = xr.DataArray( + data=thisvar_da_tmp.values.astype("int16"), + attrs=thisvar_da_tmp.attrs, + coords=thisvar_da_tmp.coords, + name=varname_clm, + ) + + # Edit/add variable attributes etc. + longname = thisvar_da.attrs["long_name"] + longname = longname.replace("rainfed", thiscrop_clm).replace("irrigated", thiscrop_clm) + + def set_var_attrs( + thisvar_da, longname, thiscrop_clm, thiscrop_ggcmi, varname_ggcmi, new_fillvalue + ): + thisvar_da.attrs["long_name"] = longname + if thiscrop_ggcmi == None: + thisvar_da.attrs["crop_name_clm"] = "none" + thisvar_da.attrs["crop_name_ggcmi"] = "none" + else: + thisvar_da.attrs["crop_name_clm"] = thiscrop_clm + thisvar_da.attrs["crop_name_ggcmi"] = thiscrop_ggcmi + thisvar_da.attrs["short_name_ggcmi"] = varname_ggcmi + thisvar_da.attrs["units"] = "day of year" + thisvar_da.encoding["_FillValue"] = new_fillvalue + # scale_factor and add_offset are required by I/O library for short data + # From https://www.unidata.ucar.edu/software/netcdf/workshops/2010/bestpractices/Packing.html: + # unpacked_value = packed_value * scale_factor + add_offset + thisvar_da.attrs["scale_factor"] = np.int16(1) + thisvar_da.attrs["add_offset"] = np.int16(0) + return thisvar_da + + thisvar_da = set_var_attrs( + thisvar_da, longname, thiscrop_clm, thiscrop_ggcmi, varname_ggcmi, new_fillvalue + ) + + # Save + if verbose: + print(" Saving %s..." % varname_ggcmi) + thisvar_da.to_netcdf(file_clm, mode="a", format="NETCDF3_CLASSIC") + + cropcal_ds.close() + + print("Done!") + + +if __name__ == "__main__": + ############################### + ### Process input arguments ### + ############################### + parser = argparse.ArgumentParser( + description="Converts raw sowing and harvest date files provided by GGCMI into a format that CLM can read, optionally at a target resolution." + ) + + # Required + parser.add_argument( + "-i", + "--input-directory", + help="Directory containing the raw GGCMI sowing/harvest date files", + type=str, + required=True, + ) + parser.add_argument( + "-o", + "--output-directory", + help="Where to save the CLM-compatible sowing and harvest date files", + type=str, + required=True, + ) + parser.add_argument( + "-a", + "--author", + help="String to be saved in author_thisfile attribute of output files. E.g., 'Author Name (authorname@ucar.edu)'", + type=str, + required=True, + ) + + # Optional + parser.add_argument( + "--file-specifier", + help="String following CROP_IRR_ in input filenames. E.g., mai_ir_FILESPECIFIER.nc4. Will also be saved to output filenames.", + type=str, + default="ggcmi_crop_calendar_phase3_v1.01", + ) + parser.add_argument( + "-y1", + "--first-year", + help="First year in output files. Must be present in template file, unless it's the same as the last year.", + type=int, + default=2000, + ) + parser.add_argument( + "-yN", + "--last-year", + help="Last year in output files. Must be present in template file, unless it's the same as the first year.", + type=int, + default=2000, + ) + parser.add_argument( + "-v", + "--verbose", + help="Whether to print verbose messages", + type=bool, + default=True, + ) + parser.add_argument( + "--ggcmi-author", + help="Author of original GGCMI files", + type=str, + default="Jonas Jägermeyr (jonas.jaegermeyr@columbia.edu)", + ) + + # Arguments for regridding + parser = regrid_ggcmi_shdates.define_arguments(parser) + + # Get arguments + args = parser.parse_args(sys.argv[1:]) + + ########### + ### Run ### + ########### + main( + os.path.realpath(args.input_directory), + os.path.realpath(args.output_directory), + args.author, + args.file_specifier, + args.first_year, + args.last_year, + args.verbose, + args.ggcmi_author, + args.regrid_resolution, + args.regrid_template_file, + ) diff --git a/python/ctsm/crop_calendars/regrid_ggcmi_shdates.py b/python/ctsm/crop_calendars/regrid_ggcmi_shdates.py new file mode 100644 index 0000000000..85e9ddeb4d --- /dev/null +++ b/python/ctsm/crop_calendars/regrid_ggcmi_shdates.py @@ -0,0 +1,133 @@ +from subprocess import run +import os +import shutil +import glob +import argparse +import sys + + +def run_and_check(cmd): + result = run( + cmd, + shell=True, + capture_output=True, + text=True, + ) + if result.returncode != 0: + raise RuntimeError( + f"Trouble running `{result.args}` in shell:\n{result.stdout}\n{result.stderr}" + ) + + +# Functionized because these are shared by process_ggcmi_shdates +def define_arguments(parser): + # Required + parser.add_argument( + "-rr", + "--regrid-resolution", + help="Target CLM resolution, to be saved in output filenames.", + type=str, + required=True, + ) + parser.add_argument( + "-rt", + "--regrid-template-file", + help="Template file to be used in regridding of inputs.", + type=str, + required=True, + ) + return parser + + +def main( + regrid_resolution, regrid_template_file_in, regrid_input_directory, regrid_output_directory +): + + # Ensure we can call necessary shell scripts + for cmd in ["ncks", "ncrename", "ncpdq", "cdo"]: + run_and_check(f"{cmd} --help") + + os.chdir(regrid_input_directory) + if not os.path.exists(regrid_output_directory): + os.makedirs(regrid_output_directory) + + templatefile = os.path.join(regrid_output_directory, "template.nc") + + # For some reason, doing ncks -v directly doesn't work. Have to copy it over first. + regrid_template_file = os.path.join( + regrid_output_directory, + os.path.basename(regrid_template_file_in), + ) + shutil.copyfile(regrid_template_file_in, regrid_template_file) + + if os.path.exists(templatefile): + os.remove(templatefile) + + for v in ["planting_day", "maturity_day", "growing_season_length"]: + run_and_check(f"ncks -A -v area '{regrid_template_file}' '{templatefile}'") + run_and_check(f"ncrename -v area,{v} '{templatefile}'") + os.remove(regrid_template_file) + run_and_check(f"ncpdq -O -h -a -lat '{templatefile}' '{templatefile}'") + + input_files = glob.glob("*nc4") + input_files.sort() + for f in input_files: + print(f[0:6]) + f2 = os.path.join(regrid_output_directory, f) + f3 = f2.replace(".nc4", f"_nninterp-{regrid_resolution}.nc4") + + if os.path.exists(f3): + os.remove(f3) + + # Sometimes cdo fails for no apparent reason. In testing this never happened more than 3x in a row. + try: + run_and_check(f"cdo -L -remapnn,'{templatefile}' -setmisstonn '{f}' '{f3}'") + except: + try: + run_and_check(f"cdo -L -remapnn,'{templatefile}' -setmisstonn '{f}' '{f3}'") + except: + try: + run_and_check(f"cdo -L -remapnn,'{templatefile}' -setmisstonn '{f}' '{f3}'") + except: + run_and_check(f"cdo -L -remapnn,'{templatefile}' -setmisstonn '{f}' '{f3}'") + + os.remove(templatefile) + + +if __name__ == "__main__": + ############################### + ### Process input arguments ### + ############################### + parser = argparse.ArgumentParser( + description="Regrids raw sowing and harvest date files provided by GGCMI to a target CLM resolution." + ) + + # Define arguments + parser = define_arguments(parser) + parser.add_argument( + "-i", + "--regrid-input-directory", + help="Directory containing the raw GGCMI sowing/harvest date files.", + type=str, + required=True, + ) + parser.add_argument( + "-o", + "--regrid-output-directory", + help="Directory where regridded output files should be saved.", + type=str, + required=True, + ) + + # Get arguments + args = parser.parse_args(sys.argv[1:]) + + ########### + ### Run ### + ########### + main( + args.regrid_resolution, + os.path.realpath(args.regrid_template_file), + os.path.realpath(args.regrid_input_directory), + os.path.realpath(args.regrid_output_directory), + ) diff --git a/python/ctsm/modify_input_files/fsurdat_modifier.py b/python/ctsm/modify_input_files/fsurdat_modifier.py index 492fa74230..6d350171cc 100644 --- a/python/ctsm/modify_input_files/fsurdat_modifier.py +++ b/python/ctsm/modify_input_files/fsurdat_modifier.py @@ -237,6 +237,7 @@ def modify_optional( std_elev, soil_color, dom_pft, + evenly_split_cropland, lai, sai, hgt_top, @@ -281,6 +282,10 @@ def modify_optional( ) logger.info("dom_pft complete") + if evenly_split_cropland: + modify_fsurdat.evenly_split_cropland() + logger.info("evenly_split_cropland complete") + def read_cfg_optional_basic_opts(modify_fsurdat, config, cfg_path, section): """Read the optional parts of the main section of the config file. @@ -429,10 +434,30 @@ def read_cfg_option_control( logger.info("dom_pft option is on and = %s", str(dom_pft)) else: logger.info("dom_pft option is off") + evenly_split_cropland = get_config_value( + config=config, + section=section, + item="evenly_split_cropland", + file_path=cfg_path, + convert_to_type=bool, + ) + if ( + evenly_split_cropland + and dom_pft is not None + and dom_pft > int(max(modify_fsurdat.file.natpft.values)) + ): + abort("dom_pft must not be set to a crop PFT when evenly_split_cropland is True") if process_subgrid and idealized: abort("idealized AND process_subgrid_section can NOT both be on, pick one or the other") - return (idealized, process_subgrid, process_var_list, include_nonveg, dom_pft) + return ( + idealized, + process_subgrid, + process_var_list, + include_nonveg, + dom_pft, + evenly_split_cropland, + ) def read_cfg_required_basic_opts(config, section, cfg_path): @@ -555,6 +580,7 @@ def fsurdat_modifier(parser): process_var_list, include_nonveg, dom_pft, + evenly_split_cropland, ) = read_cfg_option_control( modify_fsurdat, config, @@ -584,6 +610,7 @@ def fsurdat_modifier(parser): std_elev, soil_color, dom_pft, + evenly_split_cropland, lai, sai, hgt_top, diff --git a/python/ctsm/modify_input_files/modify_fsurdat.py b/python/ctsm/modify_input_files/modify_fsurdat.py index 9b3760e303..53f06d7dc8 100644 --- a/python/ctsm/modify_input_files/modify_fsurdat.py +++ b/python/ctsm/modify_input_files/modify_fsurdat.py @@ -165,6 +165,18 @@ def write_output(self, fsurdat_in, fsurdat_out): logger.info("Successfully created fsurdat_out: %s", fsurdat_out) self.file.close() + def evenly_split_cropland(self): + """ + Description + ----------- + In rectangle selected by user (or default -90 to 90 and 0 to 360), + replace fsurdat file's PCT_CFT with equal values for all crop types. + """ + pct_cft = np.full_like(self.file["PCT_CFT"].values, 100 / self.file.dims["cft"]) + self.file["PCT_CFT"] = xr.DataArray( + data=pct_cft, attrs=self.file["PCT_CFT"].attrs, dims=self.file["PCT_CFT"].dims + ) + def set_dom_pft(self, dom_pft, lai, sai, hgt_top, hgt_bot): """ Description diff --git a/python/ctsm/run_sys_tests.py b/python/ctsm/run_sys_tests.py index 992f2b544a..e4a0bcf009 100644 --- a/python/ctsm/run_sys_tests.py +++ b/python/ctsm/run_sys_tests.py @@ -213,6 +213,13 @@ def run_sys_tests( rerun_existing_failures=rerun_existing_failures, extra_create_test_args=extra_create_test_args, ) + + running_ctsm_py_tests = ( + testfile == "/path/to/testfile" + or testlist in [["test1", "test2"], ["foo"]] + or suite_name == "my_suite" + ) + if suite_name: if not dry_run: _make_cs_status_for_suite(testroot, testid_base) @@ -225,16 +232,24 @@ def run_sys_tests( testroot=testroot, create_test_args=create_test_args, dry_run=dry_run, + running_ctsm_py_tests=running_ctsm_py_tests, ) else: if not dry_run: _make_cs_status_non_suite(testroot, testid_base) + running_ctsm_py_tests = testfile == "/path/to/testfile" if testfile: test_args = ["--testfile", os.path.abspath(testfile)] + if not running_ctsm_py_tests: + with open(test_args[1], "r") as testfile_abspath: + testname_list = testfile_abspath.readlines() elif testlist: test_args = testlist + testname_list = testlist else: raise RuntimeError("None of suite_name, testfile or testlist were provided") + if not running_ctsm_py_tests: + _try_systemtests(testname_list) _run_create_test( cime_path=cime_path, test_args=test_args, @@ -668,9 +683,10 @@ def _run_test_suite( testroot, create_test_args, dry_run, + running_ctsm_py_tests, ): if not suite_compilers: - suite_compilers = _get_compilers_for_suite(suite_name, machine.name) + suite_compilers = _get_compilers_for_suite(suite_name, machine.name, running_ctsm_py_tests) for compiler in suite_compilers: test_args = [ "--xml-category", @@ -692,12 +708,29 @@ def _run_test_suite( ) -def _get_compilers_for_suite(suite_name, machine_name): +def _try_systemtests(testname_list): + err_msg = " can't be loaded. Do you need to activate the ctsm_pylib conda environment?" + # Suppress pylint import-outside-toplevel warning because (a) we only want to import + # this when certain tests are requested, and (b) the import needs to be in a try-except + # block to produce a nice error message. + # pylint: disable=import-outside-toplevel disable + # Suppress pylint unused-import warning because the import itself IS the use. + # pylint: disable=unused-import disable + if any("FSURDATMODIFYCTSM" in t for t in testname_list): + try: + import ctsm.modify_input_files.modify_fsurdat + except ModuleNotFoundError as err: + raise ModuleNotFoundError("modify_fsurdat" + err_msg) from err + + +def _get_compilers_for_suite(suite_name, machine_name, running_ctsm_py_tests): test_data = get_tests_from_xml(xml_machine=machine_name, xml_category=suite_name) if not test_data: raise RuntimeError( "No tests found for suite {} on machine {}".format(suite_name, machine_name) ) + if not running_ctsm_py_tests: + _try_systemtests([t["testname"] for t in test_data]) compilers = sorted({one_test["compiler"] for one_test in test_data}) logger.info("Running with compilers: %s", compilers) return compilers diff --git a/python/ctsm/site_and_regional/single_point_case.py b/python/ctsm/site_and_regional/single_point_case.py index 96544ff9c1..456bebee91 100644 --- a/python/ctsm/site_and_regional/single_point_case.py +++ b/python/ctsm/site_and_regional/single_point_case.py @@ -52,6 +52,8 @@ class SinglePointCase(BaseCase): flag for creating user mods directories and files dom_pft : int dominant pft type for this single point (None if not specified) + evenly_split_cropland : bool + flag for splitting cropland evenly among all crop types pct_pft : list weight or percentage of each pft. num_pft : list @@ -105,6 +107,7 @@ def __init__( create_datm, create_user_mods, dom_pft, + evenly_split_cropland, pct_pft, num_pft, include_nonveg, @@ -125,6 +128,7 @@ def __init__( self.plon = plon self.site_name = site_name self.dom_pft = dom_pft + self.evenly_split_cropland = evenly_split_cropland self.pct_pft = pct_pft self.num_pft = num_pft self.include_nonveg = include_nonveg @@ -437,6 +441,9 @@ def modify_surfdata_atpoint(self, f_orig): f_mod["PCT_CROP"] = f_mod["PCT_CROP"] / tot_pct * 100 f_mod["PCT_NATVEG"] = f_mod["PCT_NATVEG"] / tot_pct * 100 + if self.evenly_split_cropland: + f_mod["PCT_CFT"][:, :, :] = 100.0 / f_mod["PCT_CFT"].shape[2] + else: logger.info( "You chose --include-nonveg --> \ diff --git a/python/ctsm/subset_data.py b/python/ctsm/subset_data.py index 4a3a5801f1..a99d42cc14 100644 --- a/python/ctsm/subset_data.py +++ b/python/ctsm/subset_data.py @@ -551,6 +551,7 @@ def subset_point(args, file_dict: dict): create_datm=args.create_datm, create_user_mods=args.create_user_mods, dom_pft=args.dom_pft, + evenly_split_cropland=args.evenly_split_cropland, pct_pft=args.pct_pft, num_pft=num_pft, include_nonveg=args.include_nonveg, diff --git a/python/ctsm/test/test_sys_fsurdat_modifier.py b/python/ctsm/test/test_sys_fsurdat_modifier.py index 72d38732cf..1a5045c14d 100755 --- a/python/ctsm/test/test_sys_fsurdat_modifier.py +++ b/python/ctsm/test/test_sys_fsurdat_modifier.py @@ -215,7 +215,6 @@ def test_opt_sections(self): np.testing.assert_array_equal(fsurdat_out_data.PCT_CROP, zero0d) np.testing.assert_array_equal(fsurdat_out_data.PCT_LAKE, zero0d) np.testing.assert_array_equal(fsurdat_out_data.PCT_WETLAND, zero0d) - np.testing.assert_array_equal(fsurdat_out_data.PCT_LAKE, zero0d) np.testing.assert_array_equal(fsurdat_out_data.PCT_GLACIER, zero0d) np.testing.assert_array_equal(fsurdat_out_data.PCT_URBAN, pct_urban) np.testing.assert_array_equal(fsurdat_out_data.LAKEDEPTH, one0d * 200.0) @@ -223,6 +222,30 @@ def test_opt_sections(self): np.testing.assert_array_equal(fsurdat_out_data.ALB_ROOF_DIR, lev2_two) np.testing.assert_array_equal(fsurdat_out_data.TK_ROOF, lev2_five) + def test_evenly_split_cropland(self): + """ + Test that evenly splitting cropland works + """ + self._create_config_file_evenlysplitcrop() + sys.argv = [ + "fsurdat_modifier", + self._cfg_file_path, + ] + parser = fsurdat_modifier_arg_process() + fsurdat_modifier(parser) + # Read the resultant output file and make sure the fields are changed as expected + fsurdat_in_data = xr.open_dataset(self._fsurdat_in) + fsurdat_out_data = xr.open_dataset(self._fsurdat_out) + Ncrops = fsurdat_out_data.dims["cft"] + pct_cft = np.full_like(fsurdat_out_data.PCT_CFT, 100 / Ncrops) + np.testing.assert_array_equal(fsurdat_in_data.PCT_NATVEG, fsurdat_out_data.PCT_NATVEG) + np.testing.assert_array_equal(fsurdat_in_data.PCT_CROP, fsurdat_out_data.PCT_CROP) + np.testing.assert_array_equal(fsurdat_in_data.PCT_LAKE, fsurdat_out_data.PCT_LAKE) + np.testing.assert_array_equal(fsurdat_in_data.PCT_WETLAND, fsurdat_out_data.PCT_WETLAND) + np.testing.assert_array_equal(fsurdat_in_data.PCT_GLACIER, fsurdat_out_data.PCT_GLACIER) + np.testing.assert_array_equal(fsurdat_in_data.PCT_URBAN, fsurdat_out_data.PCT_URBAN) + np.testing.assert_array_equal(fsurdat_out_data.PCT_CFT, pct_cft) + def test_1x1_mexicocity(self): """ Test that the mexicocity file is handled correctly @@ -407,6 +430,23 @@ def _create_config_file_minimal(self): line = f"fsurdat_out = {self._fsurdat_out}" cfg_out.write(line) + def _create_config_file_evenlysplitcrop(self): + """ + Open the new and the template .cfg files + Loop line by line through the template .cfg file + When string matches, replace that line's content + """ + with open(self._cfg_file_path, "w", encoding="utf-8") as cfg_out: + with open(self._cfg_template_path, "r", encoding="utf-8") as cfg_in: + for line in cfg_in: + if re.match(r" *evenly_split_cropland *=", line): + line = "evenly_split_cropland = True" + elif re.match(r" *fsurdat_in *=", line): + line = f"fsurdat_in = {self._fsurdat_in}" + elif re.match(r" *fsurdat_out *=", line): + line = f"fsurdat_out = {self._fsurdat_out}" + cfg_out.write(line) + def _create_config_file_crop(self): """ Open the new and the template .cfg files @@ -430,6 +470,8 @@ def _create_config_file_crop(self): line = "lnd_lon_2 = 300\n" elif re.match(r" *dom_pft *=", line): line = "dom_pft = 15" + elif re.match(r" *evenly_split_cropland *=", line): + line = "evenly_split_cropland = False" elif re.match(r" *lai *=", line): line = "lai = 0 1 2 3 4 5 5 4 3 2 1 0\n" elif re.match(r" *sai *=", line): @@ -465,6 +507,8 @@ def _create_config_file_complete(self): line = "lnd_lon_2 = 300\n" elif re.match(r" *dom_pft *=", line): line = "dom_pft = 1" + elif re.match(r" *evenly_split_cropland *=", line): + line = "evenly_split_cropland = False" elif re.match(r" *lai *=", line): line = "lai = 0 1 2 3 4 5 5 4 3 2 1 0\n" elif re.match(r" *sai *=", line): diff --git a/python/ctsm/test/test_unit_fsurdat_modifier.py b/python/ctsm/test/test_unit_fsurdat_modifier.py index 0ea862a8e4..166924903b 100755 --- a/python/ctsm/test/test_unit_fsurdat_modifier.py +++ b/python/ctsm/test/test_unit_fsurdat_modifier.py @@ -95,6 +95,18 @@ def test_subgrid_and_idealized_fails(self): ): read_cfg_option_control(self.modify_fsurdat, self.config, section, self.cfg_path) + def test_dompft_and_splitcropland_fails(self): + """test that setting dompft crop with evenly_split_cropland True fails gracefully""" + section = "modify_fsurdat_basic_options" + crop_pft = max(self.modify_fsurdat.file.natpft.values) + 1 + self.config.set(section, "dom_pft", str(crop_pft)) + self.config.set(section, "evenly_split_cropland", "True") + with self.assertRaisesRegex( + SystemExit, + "dom_pft must not be set to a crop PFT when evenly_split_cropland is True", + ): + read_cfg_option_control(self.modify_fsurdat, self.config, section, self.cfg_path) + def test_optional_only_true_and_false(self): """test that optional settings can only be true or false""" section = "modify_fsurdat_basic_options" @@ -114,12 +126,18 @@ def test_optional_only_true_and_false(self): read_cfg_option_control(self.modify_fsurdat, self.config, section, self.cfg_path) self.config.set(section, "dom_pft", "UNSET") read_cfg_option_control(self.modify_fsurdat, self.config, section, self.cfg_path) - var = "idealized" - self.config.set(section, var, "Thing") - with self.assertRaisesRegex( - SystemExit, "Non-boolean value found for .cfg file variable: " + var - ): - read_cfg_option_control(self.modify_fsurdat, self.config, section, self.cfg_path) + varlist = ( + "idealized", + "evenly_split_cropland", + ) + for var in varlist: + orig_value = self.config.get(section, var) + self.config.set(section, var, "Thing") + with self.assertRaisesRegex( + SystemExit, "Non-boolean value found for .cfg file variable: " + var + ): + read_cfg_option_control(self.modify_fsurdat, self.config, section, self.cfg_path) + self.config.set(section, var, orig_value) def test_read_subgrid(self): """test a simple read of subgrid""" @@ -164,6 +182,24 @@ def test_read_subgrid_allurban(self): self.config.set(section, "pct_crop", "0.") read_cfg_subgrid(self.config, self.cfg_path) + def test_read_subgrid_split_cropland(self): + """ + test a read of subgrid that's 50/50 natural and + cropland, with cropland split evenly among + crop types + """ + section = "modify_fsurdat_basic_options" + self.config.set(section, "idealized", "False") + self.config.set(section, "evenly_split_cropland", "True") + section = "modify_fsurdat_subgrid_fractions" + self.config.set(section, "pct_urban", "0.0 0.0 0.0") + self.config.set(section, "pct_lake", "0.") + self.config.set(section, "pct_wetland", "0.") + self.config.set(section, "pct_glacier", "0.") + self.config.set(section, "pct_natveg", "50.") + self.config.set(section, "pct_crop", "50.") + read_cfg_subgrid(self.config, self.cfg_path) + def test_read_var_list(self): """test a simple read of var_list""" read_cfg_var_list(self.config, idealized=True) diff --git a/python/ctsm/test/test_unit_singlept_data.py b/python/ctsm/test/test_unit_singlept_data.py index 570207fa26..6fdc3109d9 100755 --- a/python/ctsm/test/test_unit_singlept_data.py +++ b/python/ctsm/test/test_unit_singlept_data.py @@ -36,6 +36,7 @@ class TestSinglePointCase(unittest.TestCase): create_datm = True create_user_mods = True dom_pft = [8] + evenly_split_cropland = False pct_pft = None num_pft = 16 include_nonveg = False @@ -58,6 +59,7 @@ def test_create_tag_noname(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -84,6 +86,7 @@ def test_create_tag_name(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -111,6 +114,7 @@ def test_check_dom_pft_too_big(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -138,6 +142,7 @@ def test_check_dom_pft_too_small(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -165,6 +170,7 @@ def test_check_dom_pft_numpft(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -193,6 +199,7 @@ def test_check_dom_pft_mixed_range(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -223,6 +230,7 @@ def test_check_nonveg_nodompft(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -254,6 +262,7 @@ def test_check_pct_pft_notsamenumbers(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -284,6 +293,7 @@ def test_check_pct_pft_sum_not1(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -314,6 +324,7 @@ def test_check_pct_pft_fraction_topct(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, diff --git a/python/ctsm/test/test_unit_singlept_data_surfdata.py b/python/ctsm/test/test_unit_singlept_data_surfdata.py index 9623975452..0052e796d1 100755 --- a/python/ctsm/test/test_unit_singlept_data_surfdata.py +++ b/python/ctsm/test/test_unit_singlept_data_surfdata.py @@ -44,6 +44,7 @@ class TestSinglePointCaseSurfaceNoCrop(unittest.TestCase): create_datm = True create_user_mods = True dom_pft = [8] + evenly_split_cropland = False pct_pft = None num_pft = 16 include_nonveg = False @@ -155,6 +156,7 @@ def test_modify_surfdata_atpoint_nocrop_1pft_pctnatpft(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -187,6 +189,7 @@ def test_modify_surfdata_atpoint_nocrop_1pft_pctnatveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -215,6 +218,7 @@ def test_modify_surfdata_atpoint_nocrop_1pft_pctcrop(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -243,6 +247,7 @@ def test_modify_surfdata_atpoint_nocrop_1pft_glacier(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -272,6 +277,7 @@ def test_modify_surfdata_atpoint_nocrop_1pft_wetland(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -301,6 +307,7 @@ def test_modify_surfdata_atpoint_nocrop_1pft_lake(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -330,6 +337,7 @@ def test_modify_surfdata_atpoint_nocrop_1pft_unisnow(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -360,6 +368,7 @@ def test_modify_surfdata_atpoint_nocrop_1pft_capsat(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -390,6 +399,7 @@ def test_modify_surfdata_atpoint_nocrop_multipft(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -426,6 +436,7 @@ def test_modify_surfdata_atpoint_nocrop_urban_nononveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -460,6 +471,7 @@ def test_modify_surfdata_atpoint_nocrop_urban_include_nonveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -497,6 +509,7 @@ def test_modify_surfdata_atpoint_nocrop_wetland_include_nonveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -527,6 +540,7 @@ def test_modify_surfdata_atpoint_nocrop_nopft_zero_nonveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -560,6 +574,7 @@ def test_modify_surfdata_atpoint_nocrop_nopft_include_nonveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -594,6 +609,7 @@ class TestSinglePointCaseSurfaceCrop(unittest.TestCase): create_datm = True create_user_mods = True dom_pft = [17] + evenly_split_cropland = False pct_pft = None num_pft = 78 include_nonveg = False @@ -705,6 +721,7 @@ def test_modify_surfdata_atpoint_crop_1pft_pctnatpft(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -737,6 +754,7 @@ def test_modify_surfdata_atpoint_crop_1pft_pctnatveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -765,6 +783,7 @@ def test_modify_surfdata_atpoint_crop_1pft_pctcrop(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -793,6 +812,7 @@ def test_modify_surfdata_atpoint_crop_1pft_glacier(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -822,6 +842,7 @@ def test_modify_surfdata_atpoint_crop_1pft_wetland(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -851,6 +872,7 @@ def test_modify_surfdata_atpoint_crop_1pft_lake(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -880,6 +902,7 @@ def test_modify_surfdata_atpoint_crop_1pft_unisnow(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -909,6 +932,7 @@ def test_modify_surfdata_atpoint_crop_1pft_capsat(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -939,6 +963,7 @@ def test_modify_surfdata_atpoint_crop_multipft(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -973,6 +998,7 @@ def test_modify_surfdata_atpoint_crop_urban_nononveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -1007,6 +1033,7 @@ def test_modify_surfdata_atpoint_crop_urban_include_nonveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -1044,6 +1071,7 @@ def test_modify_surfdata_atpoint_crop_lake_include_nonveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -1074,6 +1102,7 @@ def test_modify_surfdata_atpoint_crop_nopft_zero_nonveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, @@ -1107,6 +1136,7 @@ def test_modify_surfdata_atpoint_crop_nopft_include_nonveg(self): create_datm=self.create_datm, create_user_mods=self.create_user_mods, dom_pft=self.dom_pft, + evenly_split_cropland=self.evenly_split_cropland, pct_pft=self.pct_pft, num_pft=self.num_pft, include_nonveg=self.include_nonveg, diff --git a/python/ctsm/test/testinputs/modify_fsurdat_1x1mexicocity.cfg b/python/ctsm/test/testinputs/modify_fsurdat_1x1mexicocity.cfg index a4118a3255..0d8a751f32 100644 --- a/python/ctsm/test/testinputs/modify_fsurdat_1x1mexicocity.cfg +++ b/python/ctsm/test/testinputs/modify_fsurdat_1x1mexicocity.cfg @@ -11,6 +11,7 @@ lat_dimname = lsmlat lon_dimname = lsmlon dom_pft = UNSET +evenly_split_cropland = False lai = UNSET sai = UNSET diff --git a/python/ctsm/test/testinputs/modify_fsurdat_opt_sections.cfg b/python/ctsm/test/testinputs/modify_fsurdat_opt_sections.cfg index c068c5d851..b1fcf8a2e1 100644 --- a/python/ctsm/test/testinputs/modify_fsurdat_opt_sections.cfg +++ b/python/ctsm/test/testinputs/modify_fsurdat_opt_sections.cfg @@ -11,6 +11,7 @@ lat_dimname = lsmlat lon_dimname = lsmlon dom_pft = UNSET +evenly_split_cropland = False lai = UNSET sai = UNSET diff --git a/python/ctsm/test/testinputs/modify_fsurdat_short.cfg b/python/ctsm/test/testinputs/modify_fsurdat_short.cfg index 74c6639899..38b88795e8 100644 --- a/python/ctsm/test/testinputs/modify_fsurdat_short.cfg +++ b/python/ctsm/test/testinputs/modify_fsurdat_short.cfg @@ -14,6 +14,7 @@ lat_dimname = lsmlat lon_dimname = lsmlon dom_pft = UNSET +evenly_split_cropland = False lai = UNSET sai = UNSET diff --git a/src/biogeochem/CNAllocationMod.F90 b/src/biogeochem/CNAllocationMod.F90 index ff8131c9f7..8d38ca4b87 100644 --- a/src/biogeochem/CNAllocationMod.F90 +++ b/src/biogeochem/CNAllocationMod.F90 @@ -398,7 +398,9 @@ subroutine calc_crop_allocation_fractions(bounds, num_pcropp, filter_pcropp, & ! allocation coefficients should be irrelevant because crops have no ! live carbon pools aleaf(p) = 1._r8 + aleafi(p) = 1._r8 astem(p) = 0._r8 + astemi(p) = 0._r8 aroot(p) = 0._r8 do k = 1, nrepr arepr(p,k) = 0._r8 @@ -413,7 +415,9 @@ subroutine calc_crop_allocation_fractions(bounds, num_pcropp, filter_pcropp, & ! allocation coefficients should be irrelevant because crops have no ! live carbon pools aleaf(p) = 1._r8 + aleafi(p) = 1._r8 astem(p) = 0._r8 + astemi(p) = 0._r8 aroot(p) = 0._r8 do k = 1, nrepr arepr(p,k) = 0._r8 diff --git a/src/biogeochem/CNAnnualUpdateMod.F90 b/src/biogeochem/CNAnnualUpdateMod.F90 index 682898259a..956042db63 100644 --- a/src/biogeochem/CNAnnualUpdateMod.F90 +++ b/src/biogeochem/CNAnnualUpdateMod.F90 @@ -10,6 +10,7 @@ module CNAnnualUpdateMod use CNvegStateType , only : cnveg_state_type use PatchType , only : patch use filterColMod , only : filter_col_type, col_filter_from_filter_and_logical_array + use ColumnType , only : col ! implicit none private @@ -21,7 +22,7 @@ module CNAnnualUpdateMod contains !----------------------------------------------------------------------- - subroutine CNAnnualUpdate(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & + subroutine CNAnnualUpdate(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & cnveg_state_inst, cnveg_carbonflux_inst) ! ! !DESCRIPTION: @@ -34,10 +35,10 @@ subroutine CNAnnualUpdate(bounds, num_soilc, filter_soilc, num_soilp, filter_soi ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of bgc soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for bgc soil columns + integer , intent(in) :: num_bgc_vegp ! number of bgc veg patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for bgc veg patches type(cnveg_state_type) , intent(inout) :: cnveg_state_inst type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst ! @@ -53,22 +54,25 @@ subroutine CNAnnualUpdate(bounds, num_soilc, filter_soilc, num_soilp, filter_soi dt = get_step_size_real() secspyear = get_curr_days_per_year() * secspday - do fc = 1,num_soilc - c = filter_soilc(fc) - cnveg_state_inst%annsum_counter_col(c) = cnveg_state_inst%annsum_counter_col(c) + dt - if (cnveg_state_inst%annsum_counter_col(c) >= secspyear) then - end_of_year(c) = .true. - cnveg_state_inst%annsum_counter_col(c) = 0._r8 - else - end_of_year(c) = .false. + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) + if(.not.col%is_fates(c))then + cnveg_state_inst%annsum_counter_col(c) = cnveg_state_inst%annsum_counter_col(c) + dt + if (cnveg_state_inst%annsum_counter_col(c) >= secspyear) then + end_of_year(c) = .true. + cnveg_state_inst%annsum_counter_col(c) = 0._r8 + else + end_of_year(c) = .false. + end if end if end do + - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) c = patch%column(p) - if (end_of_year(c)) then + if (end_of_year(c) .and. .not.col%is_fates(c)) then ! update annual plant ndemand accumulator cnveg_state_inst%annsum_potential_gpp_patch(p) = cnveg_state_inst%tempsum_potential_gpp_patch(p) @@ -94,20 +98,22 @@ subroutine CNAnnualUpdate(bounds, num_soilc, filter_soilc, num_soilp, filter_soi end do ! Get column-level averages, just for the columns that have reached their personal end-of-year - filter_endofyear_c = col_filter_from_filter_and_logical_array( & - bounds = bounds, & - num_orig = num_soilc, & - filter_orig = filter_soilc, & - logical_col = end_of_year(bounds%begc:bounds%endc)) - - call p2c(bounds, filter_endofyear_c%num, filter_endofyear_c%indices, & - cnveg_carbonflux_inst%annsum_npp_patch(bounds%begp:bounds%endp), & - cnveg_carbonflux_inst%annsum_npp_col(bounds%begc:bounds%endc)) - - call p2c(bounds, filter_endofyear_c%num, filter_endofyear_c%indices, & - cnveg_state_inst%annavg_t2m_patch(bounds%begp:bounds%endp), & - cnveg_state_inst%annavg_t2m_col(bounds%begc:bounds%endc)) - + if(num_bgc_vegp>0)then + filter_endofyear_c = col_filter_from_filter_and_logical_array( & + bounds = bounds, & + num_orig = num_bgc_soilc, & + filter_orig = filter_bgc_soilc, & + logical_col = end_of_year(bounds%begc:bounds%endc)) + + call p2c(bounds, filter_endofyear_c%num, filter_endofyear_c%indices, & + cnveg_carbonflux_inst%annsum_npp_patch(bounds%begp:bounds%endp), & + cnveg_carbonflux_inst%annsum_npp_col(bounds%begc:bounds%endc)) + + call p2c(bounds, filter_endofyear_c%num, filter_endofyear_c%indices, & + cnveg_state_inst%annavg_t2m_patch(bounds%begp:bounds%endp), & + cnveg_state_inst%annavg_t2m_col(bounds%begc:bounds%endc)) + end if + end subroutine CNAnnualUpdate end module CNAnnualUpdateMod diff --git a/src/biogeochem/CNBalanceCheckMod.F90 b/src/biogeochem/CNBalanceCheckMod.F90 index 014a55d7b1..35efd2e9aa 100644 --- a/src/biogeochem/CNBalanceCheckMod.F90 +++ b/src/biogeochem/CNBalanceCheckMod.F90 @@ -10,19 +10,23 @@ module CNBalanceCheckMod use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type, subgrid_level_gridcell, subgrid_level_column use abortutils , only : endrun - use clm_varctl , only : iulog, use_nitrif_denitrif + use clm_varctl , only : iulog, use_nitrif_denitrif, use_fates_bgc use clm_time_manager , only : get_step_size_real use CNVegNitrogenFluxType , only : cnveg_nitrogenflux_type use CNVegNitrogenStateType , only : cnveg_nitrogenstate_type use CNVegCarbonFluxType , only : cnveg_carbonflux_type use CNVegCarbonStateType , only : cnveg_carbonstate_type + use SoilBiogeochemCarbonStateType , only : soilbiogeochem_carbonstate_type + use SoilBiogeochemNitrogenStateType , only : soilbiogeochem_nitrogenstate_type use SoilBiogeochemNitrogenfluxType , only : soilbiogeochem_nitrogenflux_type use SoilBiogeochemCarbonfluxType , only : soilbiogeochem_carbonflux_type use CNProductsMod , only : cn_products_type use ColumnType , only : col use GridcellType , only : grc use CNSharedParamsMod , only : use_fun - + use CLMFatesInterfaceMod , only : hlm_fates_interface_type + use clm_varpar , only : nlevdecomp + ! implicit none private @@ -100,7 +104,7 @@ end subroutine InitAllocate !----------------------------------------------------------------------- subroutine BeginCNGridcellBalance(this, bounds, cnveg_carbonflux_inst, & - cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & + soilbiogeochem_carbonstate_inst, soilbiogeochem_nitrogenstate_inst, & c_products_inst, n_products_inst) ! ! !DESCRIPTION: @@ -113,13 +117,13 @@ subroutine BeginCNGridcellBalance(this, bounds, cnveg_carbonflux_inst, & ! !USES: ! ! !ARGUMENTS: - class(cn_balance_type) , intent(inout) :: this - type(bounds_type) , intent(in) :: bounds - type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst - type(cnveg_carbonstate_type) , intent(in) :: cnveg_carbonstate_inst - type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst - type(cn_products_type) , intent(in) :: c_products_inst - type(cn_products_type) , intent(in) :: n_products_inst + class(cn_balance_type) , intent(inout) :: this + type(bounds_type) , intent(in) :: bounds + type(soilbiogeochem_carbonstate_type), intent(in) :: soilbiogeochem_carbonstate_inst + type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst + type(soilbiogeochem_nitrogenstate_type) , intent(in) :: soilbiogeochem_nitrogenstate_inst + type(cn_products_type) , intent(in) :: c_products_inst + type(cn_products_type) , intent(in) :: n_products_inst ! ! !LOCAL VARIABLES: integer :: g @@ -132,8 +136,8 @@ subroutine BeginCNGridcellBalance(this, bounds, cnveg_carbonflux_inst, & associate( & begcb => this%begcb_grc , & ! Output: [real(r8) (:)] (gC/m2) gridcell carbon mass, beginning of time step begnb => this%begnb_grc , & ! Output: [real(r8) (:)] (gN/m2) gridcell nitrogen mass, beginning of time step - totc => cnveg_carbonstate_inst%totc_grc , & ! Input: [real(r8) (:)] (gC/m2) total gridcell carbon, incl veg and cpool - totn => cnveg_nitrogenstate_inst%totn_grc, & ! Input: [real(r8) (:)] (gN/m2) total gridcell nitrogen, incl veg + totc => soilbiogeochem_carbonstate_inst%totc_grc , & ! Input: [real(r8) (:)] (gC/m2) total gridcell carbon, incl veg and cpool + totn => soilbiogeochem_nitrogenstate_inst%totn_grc, & ! Input: [real(r8) (:)] (gN/m2) total gridcell nitrogen, incl veg c_cropprod1 => c_products_inst%cropprod1_grc , & ! Input: [real(r8) (:)] (gC/m2) carbon in crop products n_cropprod1 => n_products_inst%cropprod1_grc , & ! Input: [real(r8) (:)] (gC/m2) nitrogen in crop products c_tot_woodprod => c_products_inst%tot_woodprod_grc , & ! Input: [real(r8) (:)] (gC/m2) total carbon in wood products @@ -141,13 +145,19 @@ subroutine BeginCNGridcellBalance(this, bounds, cnveg_carbonflux_inst, & ) begg = bounds%begg; endg = bounds%endg - - call cnveg_carbonflux_inst%hrv_xsmrpool_to_atm_dribbler%get_amount_left_to_dribble_beg( & + + if(.not.use_fates_bgc)then + call cnveg_carbonflux_inst%hrv_xsmrpool_to_atm_dribbler%get_amount_left_to_dribble_beg( & bounds, hrv_xsmrpool_amount_left_to_dribble(bounds%begg:bounds%endg)) - call cnveg_carbonflux_inst%dwt_conv_cflux_dribbler%get_amount_left_to_dribble_beg( & - bounds, dwt_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg)) - call cnveg_carbonflux_inst%gru_conv_cflux_dribbler%get_amount_left_to_dribble_beg( & - bounds, gru_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg)) + call cnveg_carbonflux_inst%dwt_conv_cflux_dribbler%get_amount_left_to_dribble_beg( & + bounds, dwt_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg)) + call cnveg_carbonflux_inst%gru_conv_cflux_dribbler%get_amount_left_to_dribble_beg( & + bounds, gru_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg)) + else + hrv_xsmrpool_amount_left_to_dribble(bounds%begg:bounds%endg) = 0._r8 + dwt_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg) = 0._r8 + gru_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg) = 0._r8 + end if do g = begg, endg begcb(g) = totc(g) + c_tot_woodprod(g) + c_cropprod1(g) + & @@ -163,7 +173,7 @@ end subroutine BeginCNGridcellBalance !----------------------------------------------------------------------- subroutine BeginCNColumnBalance(this, bounds, num_soilc, filter_soilc, & - cnveg_carbonstate_inst, cnveg_nitrogenstate_inst) + soilbiogeochem_carbonstate_inst,soilbiogeochem_nitrogenstate_inst) ! ! !DESCRIPTION: ! Calculate beginning column-level carbon/nitrogen balance, for mass conservation check @@ -177,8 +187,8 @@ subroutine BeginCNColumnBalance(this, bounds, num_soilc, filter_soilc, & type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_soilc ! number of soil columns filter integer , intent(in) :: filter_soilc(:) ! filter for soil columns - type(cnveg_carbonstate_type) , intent(in) :: cnveg_carbonstate_inst - type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst + type(soilbiogeochem_carbonstate_type), intent(in) :: soilbiogeochem_carbonstate_inst + type(soilbiogeochem_nitrogenstate_type), intent(in) :: soilbiogeochem_nitrogenstate_inst ! ! !LOCAL VARIABLES: integer :: fc,c @@ -187,14 +197,16 @@ subroutine BeginCNColumnBalance(this, bounds, num_soilc, filter_soilc, & associate( & col_begcb => this%begcb_col , & ! Output: [real(r8) (:)] (gC/m2) column carbon mass, beginning of time step col_begnb => this%begnb_col , & ! Output: [real(r8) (:)] (gN/m2) column nitrogen mass, beginning of time step - totcolc => cnveg_carbonstate_inst%totc_col , & ! Input: [real(r8) (:)] (gC/m2) total column carbon, incl veg and cpool - totcoln => cnveg_nitrogenstate_inst%totn_col & ! Input: [real(r8) (:)] (gN/m2) total column nitrogen, incl veg + totcolc => soilbiogeochem_carbonstate_inst%totc_col , & ! Input: [real(r8) (:)] (gC/m2) total column carbon, incl veg and cpool + totcoln => soilbiogeochem_nitrogenstate_inst%totn_col & ! Input: [real(r8) (:)] (gN/m2) total column nitrogen, incl veg ) do fc = 1,num_soilc c = filter_soilc(fc) + col_begcb(c) = totcolc(c) col_begnb(c) = totcoln(c) + end do end associate @@ -203,14 +215,20 @@ end subroutine BeginCNColumnBalance !----------------------------------------------------------------------- subroutine CBalanceCheck(this, bounds, num_soilc, filter_soilc, & - soilbiogeochem_carbonflux_inst, cnveg_carbonflux_inst, & - cnveg_carbonstate_inst, c_products_inst) + soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, c_products_inst, & + clm_fates) ! ! !USES: use subgridAveMod, only: c2g + ! ! !DESCRIPTION: ! Perform carbon mass conservation check for column and patch + ! + ! Note on FATES: On fates colums, there is no vegetation biomass + ! and no gpp flux. There is a litter input flux. + ! ! !ARGUMENTS: class(cn_balance_type) , intent(inout) :: this @@ -218,13 +236,18 @@ subroutine CBalanceCheck(this, bounds, num_soilc, filter_soilc, & integer , intent(in) :: num_soilc ! number of soil columns in filter integer , intent(in) :: filter_soilc(:) ! filter for soil columns type(soilbiogeochem_carbonflux_type) , intent(in) :: soilbiogeochem_carbonflux_inst + type(soilbiogeochem_carbonstate_type), intent(inout) :: soilbiogeochem_carbonstate_inst type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst type(cn_products_type) , intent(in) :: c_products_inst + type(hlm_fates_interface_type) , intent(inout) :: clm_fates + ! ! !LOCAL VARIABLES: - integer :: c, g, err_index ! indices + integer :: c, g, err_index ! indices + integer :: s ! fates site index (follows c) integer :: fc ! lake filter indices + integer :: ic ! index of the current clump logical :: err_found ! error flag real(r8) :: dt ! radiation time step (seconds) real(r8) :: col_cinputs, grc_cinputs @@ -235,12 +258,14 @@ subroutine CBalanceCheck(this, bounds, num_soilc, filter_soilc, & real(r8) :: hrv_xsmrpool_amount_left_to_dribble(bounds%begg:bounds%endg) real(r8) :: gru_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg) real(r8) :: dwt_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg) + real(r8) :: fates_woodproduct_flux ! Total carbon wood products flux from FATES to CLM [gC/m2/s] + !----------------------------------------------------------------------- associate( & grc_begcb => this%begcb_grc , & ! Input: [real(r8) (:) ] (gC/m2) gridcell-level carbon mass, beginning of time step grc_endcb => this%endcb_grc , & ! Output: [real(r8) (:) ] (gC/m2) gridcell-level carbon mass, end of time step - totgrcc => cnveg_carbonstate_inst%totc_grc , & ! Input: [real(r8) (:)] (gC/m2) total gridcell carbon, incl veg and cpool + totgrcc => soilbiogeochem_carbonstate_inst%totc_grc , & ! Output: [real(r8) (:)] (gC/m2) total gridcell carbon, incl veg and cpool nbp_grc => cnveg_carbonflux_inst%nbp_grc , & ! Input: [real(r8) (:) ] (gC/m2/s) net biome production (positive for sink) cropprod1_grc => c_products_inst%cropprod1_grc , & ! Input: [real(r8) (:)] (gC/m2) carbon in crop products tot_woodprod_grc => c_products_inst%tot_woodprod_grc , & ! Input: [real(r8) (:)] (gC/m2) total carbon in wood products @@ -256,39 +281,67 @@ subroutine CBalanceCheck(this, bounds, num_soilc, filter_soilc, & er => cnveg_carbonflux_inst%er_col , & ! Input: [real(r8) (:) ] (gC/m2/s) total ecosystem respiration, autotrophic + heterotrophic col_fire_closs => cnveg_carbonflux_inst%fire_closs_col , & ! Input: [real(r8) (:) ] (gC/m2/s) total column-level fire C loss col_hrv_xsmrpool_to_atm => cnveg_carbonflux_inst%hrv_xsmrpool_to_atm_col , & ! Input: [real(r8) (:) ] (gC/m2/s) excess MR pool harvest mortality - col_xsmrpool_to_atm => cnveg_carbonflux_inst%xsmrpool_to_atm_col , & ! Input: [real(r8) (:) ] (gC/m2/s) excess MR pool crop harvest loss to atm + col_xsmrpool_to_atm => cnveg_carbonflux_inst%xsmrpool_to_atm_col , & ! Input: [real(r8) (:) ] (gC/m2/s) excess MR pool crop harvest loss to atm som_c_leached => soilbiogeochem_carbonflux_inst%som_c_leached_col , & ! Input: [real(r8) (:) ] (gC/m2/s) total SOM C loss from vertical transport - totcolc => cnveg_carbonstate_inst%totc_col & ! Input: [real(r8) (:) ] (gC/m2) total column carbon, incl veg and cpool + totcolc => soilbiogeochem_carbonstate_inst%totc_col , & ! Input: [real(r8) (:) ] (gC/m2) total column carbon, incl veg and cpool + fates_litter_flux => soilbiogeochem_carbonflux_inst%fates_litter_flux & ! Total carbon litter flux from FATES to CLM [gC/m2/s] ) ! set time steps dt = get_step_size_real() + ! clump index + ic = bounds%clump_index + err_found = .false. do fc = 1,num_soilc c = filter_soilc(fc) ! calculate the total column-level carbon storage, for mass conservation check + ! for bigleaf, totcolc includes soil and all of the veg c pools including cpool, xfer, etc + ! for fates, totcolc only includes soil and non-fates litter carbon, + ! see soibiogeochem_carbonstate_inst%summary for calculations col_endcb(c) = totcolc(c) + + + if( col%is_fates(c) ) then + + s = clm_fates%f2hmap(ic)%hsites(c) + + + fates_woodproduct_flux = clm_fates%fates(ic)%bc_out(s)%hrv_deadstemc_to_prod10c + & + clm_fates%fates(ic)%bc_out(s)%hrv_deadstemc_to_prod100c + + col_cinputs = fates_litter_flux(c) + fates_woodproduct_flux + + ! calculate total column-level outputs + ! fates has already exported burn losses and fluxes to the atm + ! So they are irrelevant here + ! (gC/m2/s) total heterotrophic respiration + col_coutputs = soilbiogeochem_carbonflux_inst%hr_col(c) - ! calculate total column-level inputs - col_cinputs = gpp(c) - - ! calculate total column-level outputs - ! er = ar + hr, col_fire_closs includes patch-level fire losses - col_coutputs = er(c) + col_fire_closs(c) + col_hrv_xsmrpool_to_atm(c) + & - col_xsmrpool_to_atm(c) + gru_conv_cflux(c) - - ! Fluxes to product pools are included in column-level outputs: the product - ! pools are not included in totcolc, so are outside the system with respect to - ! these balance checks. (However, the dwt flux to product pools is NOT included, - ! since col_begcb is initialized after the dynamic area adjustments - i.e., - ! after the dwt term has already been taken out.) - col_coutputs = col_coutputs + & - wood_harvestc(c) + & - gru_wood_productc_gain(c) + & - crop_harvestc_to_cropprodc(c) + else + + ! calculate total column-level inputs + col_cinputs = gpp(c) + + ! calculate total column-level outputs + ! er = ar + hr, col_fire_closs includes patch-level fire losses + col_coutputs = er(c) + col_fire_closs(c) + col_hrv_xsmrpool_to_atm(c) + & + col_xsmrpool_to_atm(c) + gru_conv_cflux(c) + + ! Fluxes to product pools are included in column-level outputs: the product + ! pools are not included in totcolc, so are outside the system with respect to + ! these balance checks. (However, the dwt flux to product pools is NOT included, + ! since col_begcb is initialized after the dynamic area adjustments - i.e., + ! after the dwt term has already been taken out.) + col_coutputs = col_coutputs + & + wood_harvestc(c) + & + gru_wood_productc_gain(c) + & + crop_harvestc_to_cropprodc(c) + + end if ! subtract leaching flux col_coutputs = col_coutputs - som_c_leached(c) @@ -311,19 +364,29 @@ subroutine CBalanceCheck(this, bounds, num_soilc, filter_soilc, & if (err_found) then c = err_index write(iulog,*)'column cbalance error = ', col_errcb(c), c + write(iulog,*)'is fates column? = ', col%is_fates(c) write(iulog,*)'Latdeg,Londeg=',grc%latdeg(col%gridcell(c)),grc%londeg(col%gridcell(c)) write(iulog,*)'begcb = ',col_begcb(c) write(iulog,*)'endcb = ',col_endcb(c) write(iulog,*)'delta store = ',col_endcb(c)-col_begcb(c) write(iulog,*)'--- Inputs ---' - write(iulog,*)'gpp = ',gpp(c)*dt + if( col%is_fates(c) ) then + write(iulog,*)'fates litter_flux = ',fates_litter_flux(c)*dt + write(iulog,*)'fates wood product flux = ',fates_woodproduct_flux*dt + else + write(iulog,*)'gpp = ',gpp(c)*dt + end if write(iulog,*)'--- Outputs ---' - write(iulog,*)'er = ',er(c)*dt - write(iulog,*)'col_fire_closs = ',col_fire_closs(c)*dt - write(iulog,*)'col_hrv_xsmrpool_to_atm = ',col_hrv_xsmrpool_to_atm(c)*dt - write(iulog,*)'col_xsmrpool_to_atm = ',col_xsmrpool_to_atm(c)*dt - write(iulog,*)'wood_harvestc = ',wood_harvestc(c)*dt - write(iulog,*)'crop_harvestc_to_cropprodc = ', crop_harvestc_to_cropprodc(c)*dt + if( .not.col%is_fates(c) ) then + write(iulog,*)'er = ',er(c)*dt + write(iulog,*)'col_fire_closs = ',col_fire_closs(c)*dt + write(iulog,*)'col_hrv_xsmrpool_to_atm = ',col_hrv_xsmrpool_to_atm(c)*dt + write(iulog,*)'col_xsmrpool_to_atm = ',col_xsmrpool_to_atm(c)*dt + write(iulog,*)'wood_harvestc = ',wood_harvestc(c)*dt + write(iulog,*)'crop_harvestc_to_cropprodc = ', crop_harvestc_to_cropprodc(c)*dt + else + write(iulog,*)'hr = ',soilbiogeochem_carbonflux_inst%hr_col(c)*dt + end if write(iulog,*)'-1*som_c_leached = ',som_c_leached(c)*dt call endrun(subgrid_index=c, subgrid_level=subgrid_level_column, msg=errMsg(sourcefile, __LINE__)) end if @@ -352,31 +415,45 @@ subroutine CBalanceCheck(this, bounds, num_soilc, filter_soilc, & ! We account for the latter fluxes as inputs below; the same ! fluxes have entered the pools earlier in the timestep. For true ! conservation we would need to add a flux out of npp into seed. - call cnveg_carbonflux_inst%hrv_xsmrpool_to_atm_dribbler%get_amount_left_to_dribble_end( & - bounds, hrv_xsmrpool_amount_left_to_dribble(bounds%begg:bounds%endg)) - call cnveg_carbonflux_inst%dwt_conv_cflux_dribbler%get_amount_left_to_dribble_end( & - bounds, dwt_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg)) - call cnveg_carbonflux_inst%gru_conv_cflux_dribbler%get_amount_left_to_dribble_end( & - bounds, gru_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg)) - grc_endcb(g) = totgrcc(g) + tot_woodprod_grc(g) + cropprod1_grc(g) + & - hrv_xsmrpool_amount_left_to_dribble(g) + & - gru_conv_cflux_amount_left_to_dribble(g) + & - dwt_conv_cflux_amount_left_to_dribble(g) - - ! calculate total gridcell-level inputs - ! slevis notes: - ! nbp_grc = nep_grc - fire_closs_grc - hrv_xsmrpool_to_atm_dribbled_grc - dwt_conv_cflux_dribbled_grc - gru_conv_cflux_dribbled_grc - product_closs_grc - grc_cinputs = nbp_grc(g) + & - dwt_seedc_to_leaf_grc(g) + dwt_seedc_to_deadstem_grc(g) - - ! calculate total gridcell-level outputs - grc_coutputs = - som_c_leached_grc(g) - - ! calculate the total gridcell-level carbon balance error - ! for this time step - grc_errcb(g) = (grc_cinputs - grc_coutputs) * dt - & - (grc_endcb(g) - grc_begcb(g)) + if(.not.use_fates_bgc)then + call cnveg_carbonflux_inst%hrv_xsmrpool_to_atm_dribbler%get_amount_left_to_dribble_end( & + bounds, hrv_xsmrpool_amount_left_to_dribble(bounds%begg:bounds%endg)) + call cnveg_carbonflux_inst%dwt_conv_cflux_dribbler%get_amount_left_to_dribble_end( & + bounds, dwt_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg)) + call cnveg_carbonflux_inst%gru_conv_cflux_dribbler%get_amount_left_to_dribble_end( & + bounds, gru_conv_cflux_amount_left_to_dribble(bounds%begg:bounds%endg)) + + grc_endcb(g) = totgrcc(g) + tot_woodprod_grc(g) + cropprod1_grc(g) + & + hrv_xsmrpool_amount_left_to_dribble(g) + & + gru_conv_cflux_amount_left_to_dribble(g) + & + dwt_conv_cflux_amount_left_to_dribble(g) + + ! calculate total gridcell-level inputs + ! slevis notes: + ! nbp_grc = nep_grc - fire_closs_grc - hrv_xsmrpool_to_atm_dribbled_grc - & + ! dwt_conv_cflux_dribbled_grc - gru_conv_cflux_dribbled_grc - product_closs_grc + grc_cinputs = nbp_grc(g) + & + dwt_seedc_to_leaf_grc(g) + dwt_seedc_to_deadstem_grc(g) + + ! calculate total gridcell-level outputs + grc_coutputs = - som_c_leached_grc(g) + + ! calculate the total gridcell-level carbon balance error + ! for this time step + grc_errcb(g) = (grc_cinputs - grc_coutputs) * dt - & + (grc_endcb(g) - grc_begcb(g)) + + else + + ! Totally punt on this for now. We just don't track these gridscale variables yet (RGK) + grc_cinputs = 0._r8 + grc_endcb(g) = grc_begcb(g) + grc_coutputs = 0._r8 + grc_errcb(g) = 0._r8 + + end if + ! check for significant errors if (abs(grc_errcb(g)) > this%cerror) then err_found = .true. @@ -409,8 +486,9 @@ end subroutine CBalanceCheck !----------------------------------------------------------------------- subroutine NBalanceCheck(this, bounds, num_soilc, filter_soilc, & - soilbiogeochem_nitrogenflux_inst, cnveg_nitrogenflux_inst, & - cnveg_nitrogenstate_inst, n_products_inst, atm2lnd_inst) + soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst, & + cnveg_nitrogenflux_inst, & + cnveg_nitrogenstate_inst, n_products_inst, atm2lnd_inst, clm_fates) ! ! !DESCRIPTION: ! Perform nitrogen mass conservation check @@ -426,17 +504,21 @@ subroutine NBalanceCheck(this, bounds, num_soilc, filter_soilc, & integer , intent(in) :: num_soilc ! number of soil columns in filter integer , intent(in) :: filter_soilc (:) ! filter for soil columns type(soilbiogeochem_nitrogenflux_type) , intent(in) :: soilbiogeochem_nitrogenflux_inst + type(soilbiogeochem_nitrogenstate_type) , intent(inout) :: soilbiogeochem_nitrogenstate_inst type(cnveg_nitrogenflux_type) , intent(in) :: cnveg_nitrogenflux_inst type(cnveg_nitrogenstate_type) , intent(inout) :: cnveg_nitrogenstate_inst type(cn_products_type) , intent(in) :: n_products_inst type(atm2lnd_type) , intent(in) :: atm2lnd_inst + type(hlm_fates_interface_type) , intent(inout) :: clm_fates + ! ! !LOCAL VARIABLES: - integer :: c,err_index,j ! indices - integer :: g ! gridcell index - integer :: fc ! lake filter indices - logical :: err_found ! error flag - real(r8):: dt ! radiation time step (seconds) + integer :: c,err_index,j,s ! indices + integer :: ic ! index of clump + integer :: g ! gridcell index + integer :: fc ! lake filter indices + logical :: err_found ! error flag + real(r8):: dt ! radiation time step (seconds) real(r8):: col_ninputs(bounds%begc:bounds%endc) real(r8):: col_noutputs(bounds%begc:bounds%endc) real(r8):: col_errnb(bounds%begc:bounds%endc) @@ -452,7 +534,7 @@ subroutine NBalanceCheck(this, bounds, num_soilc, filter_soilc, & associate( & grc_begnb => this%begnb_grc , & ! Input: [real(r8) (:) ] (gN/m2) gridcell nitrogen mass, beginning of time step grc_endnb => this%endnb_grc , & ! Output: [real(r8) (:) ] (gN/m2) gridcell nitrogen mass, end of time step - totgrcn => cnveg_nitrogenstate_inst%totn_grc , & ! Input: [real(r8) (:) ] (gN/m2) total gridcell nitrogen, incl veg + totgrcn => soilbiogeochem_nitrogenstate_inst%totn_grc , & ! Input: [real(r8) (:) ] (gN/m2) total gridcell nitrogen, incl veg cropprod1_grc => n_products_inst%cropprod1_grc , & ! Input: [real(r8) (:)] (gN/m2) nitrogen in crop products product_loss_grc => n_products_inst%product_loss_grc , & ! Input: [real(r8) (:)] (gN/m2) losses from wood & crop products tot_woodprod_grc => n_products_inst%tot_woodprod_grc , & ! Input: [real(r8) (:)] (gN/m2) total nitrogen in wood products @@ -482,9 +564,12 @@ subroutine NBalanceCheck(this, bounds, num_soilc, filter_soilc, & gru_wood_productn_gain_grc => cnveg_nitrogenflux_inst%gru_wood_productn_gain_grc, & ! Input: [real(r8) (:) ] (gC/m2/s) wood harvest (to product pools) summed to the gridcell level crop_harvestn_to_cropprodn => cnveg_nitrogenflux_inst%crop_harvestn_to_cropprodn_col , & ! Input: [real(r8) (:) ] (gN/m2/s) crop harvest N to 1-year crop product pool - totcoln => cnveg_nitrogenstate_inst%totn_col & ! Input: [real(r8) (:) ] (gN/m2) total column nitrogen, incl veg + totcoln => soilbiogeochem_nitrogenstate_inst%totn_col , & ! Input: [real(r8) (:) ] (gN/m2) total column nitrogen, incl veg + sminn_to_plant => soilbiogeochem_nitrogenflux_inst%sminn_to_plant_col, & + fates_litter_flux => soilbiogeochem_nitrogenflux_inst%fates_litter_flux & ! Total nitrogen litter flux from FATES to CLM [gN/m2/s] ) + ! set time steps dt = get_step_size_real() @@ -492,6 +577,9 @@ subroutine NBalanceCheck(this, bounds, num_soilc, filter_soilc, & col_ninputs_partial(:) = 0._r8 col_noutputs_partial(:) = 0._r8 + ! clump index + ic = bounds%clump_index + err_found = .false. do fc = 1,num_soilc c=filter_soilc(fc) @@ -501,6 +589,11 @@ subroutine NBalanceCheck(this, bounds, num_soilc, filter_soilc, & ! calculate total column-level inputs col_ninputs(c) = ndep_to_sminn(c) + nfix_to_sminn(c) + supplement_to_sminn(c) + + ! If using fates, pass in the decomposition flux + if( col%is_fates(c) ) then + col_ninputs(c) = col_ninputs(c) + fates_litter_flux(c) + end if if(use_fun)then col_ninputs(c) = col_ninputs(c) + ffix_to_sminn(c) ! for FUN, free living fixation is a seprate flux. RF. @@ -511,19 +604,30 @@ subroutine NBalanceCheck(this, bounds, num_soilc, filter_soilc, & end if col_ninputs_partial(c) = col_ninputs(c) - + ! calculate total column-level outputs - col_noutputs(c) = denit(c) + col_fire_nloss(c) + gru_conv_nflux(c) - - ! Fluxes to product pools are included in column-level outputs: the product - ! pools are not included in totcoln, so are outside the system with respect to - ! these balance checks. (However, the dwt flux to product pools is NOT included, - ! since col_begnb is initialized after the dynamic area adjustments - i.e., - ! after the dwt term has already been taken out.) - col_noutputs(c) = col_noutputs(c) + & - wood_harvestn(c) + & - gru_wood_productn_gain(c) + & - crop_harvestn_to_cropprodn(c) + + col_noutputs(c) = denit(c) + + if( .not.col%is_fates(c) ) then + + col_noutputs(c) = col_noutputs(c) + col_fire_nloss(c) + gru_conv_nflux(c) + + ! Fluxes to product pools are included in column-level outputs: the product + ! pools are not included in totcoln, so are outside the system with respect to + ! these balance checks. (However, the dwt flux to product pools is NOT included, + ! since col_begnb is initialized after the dynamic area adjustments - i.e., + ! after the dwt term has already been taken out.) + col_noutputs(c) = col_noutputs(c) + & + wood_harvestn(c) + & + gru_wood_productn_gain(c) + & + crop_harvestn_to_cropprodn(c) + else + + ! If we are using fates, remove plant uptake + col_noutputs(c) = col_noutputs(c) + sminn_to_plant(c) + + end if if (.not. use_nitrif_denitrif) then col_noutputs(c) = col_noutputs(c) + sminn_leached(c) @@ -534,11 +638,15 @@ subroutine NBalanceCheck(this, bounds, num_soilc, filter_soilc, & end if col_noutputs(c) = col_noutputs(c) - som_n_leached(c) + + col_noutputs_partial(c) = col_noutputs(c) - col_noutputs_partial(c) = col_noutputs(c) - & - wood_harvestn(c) - & - crop_harvestn_to_cropprodn(c) - + if( .not.col%is_fates(c) ) then + col_noutputs_partial(c) = col_noutputs_partial(c) - & + wood_harvestn(c) - & + crop_harvestn_to_cropprodn(c) + end if + ! calculate the total column-level nitrogen balance error for this time step col_errnb(c) = (col_ninputs(c) - col_noutputs(c))*dt - & (col_endnb(c) - col_begnb(c)) @@ -566,92 +674,103 @@ subroutine NBalanceCheck(this, bounds, num_soilc, filter_soilc, & write(iulog,*)'input mass = ',col_ninputs(c)*dt write(iulog,*)'output mass = ',col_noutputs(c)*dt write(iulog,*)'net flux = ',(col_ninputs(c)-col_noutputs(c))*dt - write(iulog,*)'inputs,ffix,nfix,ndep = ',ffix_to_sminn(c)*dt,nfix_to_sminn(c)*dt,ndep_to_sminn(c)*dt - write(iulog,*)'outputs,lch,roff,dnit = ',smin_no3_leached(c)*dt, smin_no3_runoff(c)*dt,f_n2o_nit(c)*dt + if(col%is_fates(c))then + write(iulog,*)'inputs,ndep,nfix,suppn= ',ndep_to_sminn(c)*dt,nfix_to_sminn(c)*dt,supplement_to_sminn(c)*dt + else + write(iulog,*)'inputs,ffix,nfix,ndep = ',ffix_to_sminn(c)*dt,nfix_to_sminn(c)*dt,ndep_to_sminn(c)*dt + end if + if(col%is_fates(c))then + write(iulog,*)'outputs,lch,roff,dnit,plnt = ',smin_no3_leached(c)*dt, smin_no3_runoff(c)*dt,f_n2o_nit(c)*dt,sminn_to_plant(c)*dt + else + write(iulog,*)'outputs,lch,roff,dnit = ',smin_no3_leached(c)*dt, smin_no3_runoff(c)*dt,f_n2o_nit(c)*dt + end if call endrun(subgrid_index=c, subgrid_level=subgrid_level_column, msg=errMsg(sourcefile, __LINE__)) end if - ! Repeat error check at the gridcell level - call c2g( bounds = bounds, & - carr = totcoln(bounds%begc:bounds%endc), & - garr = totgrcn(bounds%begg:bounds%endg), & - c2l_scale_type = 'unity', & - l2g_scale_type = 'unity') - call c2g( bounds = bounds, & - carr = col_ninputs_partial(bounds%begc:bounds%endc), & - garr = grc_ninputs_partial(bounds%begg:bounds%endg), & - c2l_scale_type = 'unity', & - l2g_scale_type = 'unity') - call c2g( bounds = bounds, & - carr = col_noutputs_partial(bounds%begc:bounds%endc), & - garr = grc_noutputs_partial(bounds%begg:bounds%endg), & - c2l_scale_type = 'unity', & - l2g_scale_type = 'unity') - - err_found = .false. - do g = bounds%begg, bounds%endg - ! calculate the total gridcell-level nitrogen storage, for mass conservation check - ! Notes: - ! Not including seedn_grc in grc_begnb and grc_endnb because - ! seedn_grc forms out of thin air, for now, and equals - ! -1 * (dwt_seedn_to_leaf_grc(g) + dwt_seedn_to_deadstem_grc(g)) - ! We account for the latter fluxes as inputs below; the same - ! fluxes have entered the pools earlier in the timestep. For true - ! conservation we would need to add a flux out of nfix into seed. - grc_endnb(g) = totgrcn(g) + tot_woodprod_grc(g) + cropprod1_grc(g) - - ! calculate total gridcell-level inputs - grc_ninputs(g) = grc_ninputs_partial(g) + & - dwt_seedn_to_leaf_grc(g) + & - dwt_seedn_to_deadstem_grc(g) - - ! calculate total gridcell-level outputs - grc_noutputs(g) = grc_noutputs_partial(g) + & - dwt_conv_nflux_grc(g) + & - product_loss_grc(g) - & - ! Subtract the next one because it is present in - ! grc_noutputs_partial but not needed at the - ! gridcell level - gru_wood_productn_gain_grc(g) - - ! calculate the total gridcell-level nitrogen balance error for this time step - grc_errnb(g) = (grc_ninputs(g) - grc_noutputs(g)) * dt - & - (grc_endnb(g) - grc_begnb(g)) - - if (abs(grc_errnb(g)) > this%nerror) then - err_found = .true. - err_index = g - end if - - if (abs(grc_errnb(g)) > this%nwarning) then - write(iulog,*) 'nbalance warning at g =', g, grc_errnb(g), grc_endnb(g) + if_notfates: if(.not.use_fates_bgc)then + + ! Repeat error check at the gridcell level + call c2g( bounds = bounds, & + carr = totcoln(bounds%begc:bounds%endc), & + garr = totgrcn(bounds%begg:bounds%endg), & + c2l_scale_type = 'unity', & + l2g_scale_type = 'unity') + call c2g( bounds = bounds, & + carr = col_ninputs_partial(bounds%begc:bounds%endc), & + garr = grc_ninputs_partial(bounds%begg:bounds%endg), & + c2l_scale_type = 'unity', & + l2g_scale_type = 'unity') + call c2g( bounds = bounds, & + carr = col_noutputs_partial(bounds%begc:bounds%endc), & + garr = grc_noutputs_partial(bounds%begg:bounds%endg), & + c2l_scale_type = 'unity', & + l2g_scale_type = 'unity') + + err_found = .false. + do g = bounds%begg, bounds%endg + ! calculate the total gridcell-level nitrogen storage, for mass conservation check + ! Notes: + ! Not including seedn_grc in grc_begnb and grc_endnb because + ! seedn_grc forms out of thin air, for now, and equals + ! -1 * (dwt_seedn_to_leaf_grc(g) + dwt_seedn_to_deadstem_grc(g)) + ! We account for the latter fluxes as inputs below; the same + ! fluxes have entered the pools earlier in the timestep. For true + ! conservation we would need to add a flux out of nfix into seed. + grc_endnb(g) = totgrcn(g) + tot_woodprod_grc(g) + cropprod1_grc(g) + + ! calculate total gridcell-level inputs + grc_ninputs(g) = grc_ninputs_partial(g) + & + dwt_seedn_to_leaf_grc(g) + & + dwt_seedn_to_deadstem_grc(g) + + ! calculate total gridcell-level outputs + grc_noutputs(g) = grc_noutputs_partial(g) + & + dwt_conv_nflux_grc(g) + & + product_loss_grc(g) - & + ! Subtract the next one because it is present in + ! grc_noutputs_partial but not needed at the + ! gridcell level + gru_wood_productn_gain_grc(g) + + ! calculate the total gridcell-level nitrogen balance error for this time step + grc_errnb(g) = (grc_ninputs(g) - grc_noutputs(g)) * dt - & + (grc_endnb(g) - grc_begnb(g)) + + if (abs(grc_errnb(g)) > this%nerror) then + err_found = .true. + err_index = g + end if + + if (abs(grc_errnb(g)) > this%nwarning) then + write(iulog,*) 'nbalance warning at g =', g, grc_errnb(g), grc_endnb(g) + end if + end do + if (err_found) then + g = err_index + write(iulog,*) 'gridcell nbalance error =', grc_errnb(g), g + write(iulog,*) 'latdeg, londeg =', grc%latdeg(g), grc%londeg(g) + write(iulog,*) 'begnb =', grc_begnb(g) + write(iulog,*) 'endnb =', grc_endnb(g) + write(iulog,*) 'delta store =', grc_endnb(g) - grc_begnb(g) + write(iulog,*) 'input mass =', grc_ninputs(g) * dt + write(iulog,*) 'output mass =', grc_noutputs(g) * dt + write(iulog,*) 'net flux =', (grc_ninputs(g) - grc_noutputs(g)) * dt + write(iulog,*) '--- Inputs ---' + write(iulog,*) 'grc_ninputs_partial =', grc_ninputs_partial(g) * dt + write(iulog,*) 'dwt_seedn_to_leaf_grc =', dwt_seedn_to_leaf_grc(g) * dt + write(iulog,*) 'dwt_seedn_to_deadstem_grc =', dwt_seedn_to_deadstem_grc(g) * dt + write(iulog,*) '--- Outputs ---' + write(iulog,*) 'grc_noutputs_partial =', grc_noutputs_partial(g) * dt + write(iulog,*) 'dwt_conv_nflux_grc =', dwt_conv_nflux_grc(g) * dt + write(iulog,*) '-gru_wood_productn_gain_grc =', -gru_wood_productn_gain_grc(g) * dt + write(iulog,*) 'product_loss_grc =', product_loss_grc(g) * dt + call endrun(subgrid_index=g, subgrid_level=subgrid_level_gridcell, msg=errMsg(sourcefile, __LINE__)) end if - end do - - if (err_found) then - g = err_index - write(iulog,*) 'gridcell nbalance error =', grc_errnb(g), g - write(iulog,*) 'latdeg, londeg =', grc%latdeg(g), grc%londeg(g) - write(iulog,*) 'begnb =', grc_begnb(g) - write(iulog,*) 'endnb =', grc_endnb(g) - write(iulog,*) 'delta store =', grc_endnb(g) - grc_begnb(g) - write(iulog,*) 'input mass =', grc_ninputs(g) * dt - write(iulog,*) 'output mass =', grc_noutputs(g) * dt - write(iulog,*) 'net flux =', (grc_ninputs(g) - grc_noutputs(g)) * dt - write(iulog,*) '--- Inputs ---' - write(iulog,*) 'grc_ninputs_partial =', grc_ninputs_partial(g) * dt - write(iulog,*) 'dwt_seedn_to_leaf_grc =', dwt_seedn_to_leaf_grc(g) * dt - write(iulog,*) 'dwt_seedn_to_deadstem_grc =', dwt_seedn_to_deadstem_grc(g) * dt - write(iulog,*) '--- Outputs ---' - write(iulog,*) 'grc_noutputs_partial =', grc_noutputs_partial(g) * dt - write(iulog,*) 'dwt_conv_nflux_grc =', dwt_conv_nflux_grc(g) * dt - write(iulog,*) '-gru_wood_productn_gain_grc =', -gru_wood_productn_gain_grc(g) * dt - write(iulog,*) 'product_loss_grc =', product_loss_grc(g) * dt - call endrun(subgrid_index=g, subgrid_level=subgrid_level_gridcell, msg=errMsg(sourcefile, __LINE__)) - end if + + end if if_notfates end associate - + end subroutine NBalanceCheck end module CNBalanceCheckMod diff --git a/src/biogeochem/CNCIsoFluxMod.F90 b/src/biogeochem/CNCIsoFluxMod.F90 index a4706442fa..608966d213 100644 --- a/src/biogeochem/CNCIsoFluxMod.F90 +++ b/src/biogeochem/CNCIsoFluxMod.F90 @@ -8,7 +8,6 @@ module CNCIsoFluxMod use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use clm_varpar , only : ndecomp_cascade_transitions, nlevdecomp, ndecomp_pools - use clm_varpar , only : max_patch_per_col, maxsoil_patches use clm_varpar , only : i_litr_min, i_litr_max, i_met_lit use abortutils , only : endrun use pftconMod , only : pftcon @@ -85,7 +84,7 @@ subroutine CIsoFlux1(num_soilc, filter_soilc, num_soilp, filter_soilp, & character(len=*) , intent(in) :: isotope ! 'c13' or 'c14' ! ! !LOCAL VARIABLES: - integer :: fp,pi,l,fc,cc,j,k,p + integer :: fp,l,fc,cc,j,k,p integer :: cdp !----------------------------------------------------------------------- @@ -535,7 +534,7 @@ subroutine CIsoFlux1(num_soilc, filter_soilc, num_soilp, filter_soilp, & ! For later clean-up, it would be possible to generalize this function to operate on a single ! patch-to-column flux. - call CNCIsoLitterToColumn(num_soilc, filter_soilc, soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) + call CNCIsoLitterToColumn(num_soilp, filter_soilp, soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) ! column-level non-mortality fluxes @@ -578,7 +577,7 @@ subroutine CIsoFlux1(num_soilc, filter_soilc, num_soilp, filter_soilp, & end subroutine CIsoFlux1 !----------------------------------------------------------------------- - subroutine CIsoFlux2(num_soilc, filter_soilc, num_soilp , filter_soilp, & + subroutine CIsoFlux2(num_soilp, filter_soilp, & soilbiogeochem_state_inst, & cnveg_carbonflux_inst, cnveg_carbonstate_inst, & iso_cnveg_carbonflux_inst, iso_cnveg_carbonstate_inst, isotope) @@ -587,8 +586,6 @@ subroutine CIsoFlux2(num_soilc, filter_soilc, num_soilp , filter_soilp, & ! On the radiation time step, set the carbon isotopic fluxes for gap mortality ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns integer , intent(in) :: num_soilp ! number of soil patches in filter integer , intent(in) :: filter_soilp(:) ! filter for soil patches type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst @@ -600,7 +597,6 @@ subroutine CIsoFlux2(num_soilc, filter_soilc, num_soilp , filter_soilp, & ! ! !LOCAL VARIABLES: - integer :: fp,pi !----------------------------------------------------------------------- associate( & @@ -713,14 +709,14 @@ subroutine CIsoFlux2(num_soilc, filter_soilc, num_soilp , filter_soilp, & ! call routine to shift patch-level gap mortality fluxes to column , for isotopes ! the non-isotope version of this routine is in CNGapMortalityMod.F90. - call CNCIsoGapPftToColumn(num_soilc, filter_soilc, soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) + call CNCIsoGapPftToColumn(num_soilp, filter_soilp, soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) end associate end subroutine CIsoFlux2 !----------------------------------------------------------------------- - subroutine CIsoFlux2h(num_soilc , filter_soilc, num_soilp , filter_soilp, & + subroutine CIsoFlux2h(num_soilp, filter_soilp, & soilbiogeochem_state_inst, & cnveg_carbonflux_inst, cnveg_carbonstate_inst, & iso_cnveg_carbonflux_inst, iso_cnveg_carbonstate_inst, isotope) @@ -729,8 +725,6 @@ subroutine CIsoFlux2h(num_soilc , filter_soilc, num_soilp , filter_soilp, & ! set the carbon isotopic fluxes for harvest mortality ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns integer , intent(in) :: num_soilp ! number of soil patches in filter integer , intent(in) :: filter_soilp(:) ! filter for soil patches type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst @@ -859,14 +853,14 @@ subroutine CIsoFlux2h(num_soilc , filter_soilc, num_soilp , filter_soilp, & ! call routine to shift patch-level gap mortality fluxes to column, ! for isotopes the non-isotope version of this routine is in CNGapMortalityMod.F90. - call CNCIsoHarvestPftToColumn(num_soilc, filter_soilc, soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) + call CNCIsoHarvestPftToColumn(num_soilp, filter_soilp, soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) end associate end subroutine CIsoFlux2h !----------------------------------------------------------------------- - subroutine CIsoFlux2g(num_soilc , filter_soilc, num_soilp , filter_soilp, & + subroutine CIsoFlux2g(num_soilp, filter_soilp, & soilbiogeochem_state_inst, & cnveg_carbonflux_inst, cnveg_carbonstate_inst, & iso_cnveg_carbonflux_inst, iso_cnveg_carbonstate_inst, isotope) @@ -875,8 +869,6 @@ subroutine CIsoFlux2g(num_soilc , filter_soilc, num_soilp , filter_soilp, & ! set the carbon isotopic fluxes for gross unrepresented landcover change mortality ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns integer , intent(in) :: num_soilp ! number of soil patches in filter integer , intent(in) :: filter_soilp(:) ! filter for soil patches type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst @@ -1010,14 +1002,14 @@ subroutine CIsoFlux2g(num_soilc , filter_soilc, num_soilp , filter_soilp, & ! call routine to shift patch-level gap mortality fluxes to column, ! for isotopes the non-isotope version of this routine is in CNGapMortalityMod.F90. - call CNCIsoGrossUnrepPftToColumn(num_soilc, filter_soilc, soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) + call CNCIsoGrossUnrepPftToColumn(num_soilp, filter_soilp, soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) end associate end subroutine CIsoFlux2g !----------------------------------------------------------------------- - subroutine CIsoFlux3(num_soilc , filter_soilc, num_soilp , filter_soilp, & + subroutine CIsoFlux3(num_soilp, filter_soilp, & soilbiogeochem_state_inst , soilbiogeochem_carbonstate_inst, & cnveg_carbonflux_inst, cnveg_carbonstate_inst, & iso_cnveg_carbonflux_inst, iso_cnveg_carbonstate_inst, & @@ -1027,8 +1019,6 @@ subroutine CIsoFlux3(num_soilc , filter_soilc, num_soilp , filter_soilp, & ! On the radiation time step, set the carbon isotopic fluxes for fire mortality ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns integer , intent(in) :: num_soilp ! number of soil patches in filter integer , intent(in) :: filter_soilp(:) ! filter for soil patches type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst @@ -1041,7 +1031,7 @@ subroutine CIsoFlux3(num_soilc , filter_soilc, num_soilp , filter_soilp, & character(len=*) , intent(in) :: isotope ! 'c13' or 'c14' ! ! !LOCAL VARIABLES: - integer :: pi,pp,l,fc,cc,j,i + integer :: fp,pp,l,cc,j,i !----------------------------------------------------------------------- associate( & @@ -1276,32 +1266,22 @@ subroutine CIsoFlux3(num_soilc , filter_soilc, num_soilp , filter_soilp, & ! calculate the column-level flux of deadstem and deadcrootc to cwdc as the result of fire mortality. - do pi = 1,max_patch_per_col - do fc = 1,num_soilc - cc = filter_soilc(fc) - if ( pi <= col%npatches(cc) ) then - pp = col%patchi(cc) + pi - 1 - if (patch%active(pp)) then - do j = 1, nlevdecomp - iso_cnveg_cf%fire_mortality_c_to_cwdc_col(cc,j) = & - iso_cnveg_cf%fire_mortality_c_to_cwdc_col(cc,j) + & - (iso_cnveg_cf%m_deadstemc_to_litter_fire_patch(pp) + & - iso_cnveg_cf%m_livestemc_to_litter_fire_patch(pp)) * & - patch%wtcol(pp) * stem_prof(pp,j) - iso_cnveg_cf%fire_mortality_c_to_cwdc_col(cc,j) = & - iso_cnveg_cf%fire_mortality_c_to_cwdc_col(cc,j) + & - (iso_cnveg_cf%m_deadcrootc_to_litter_fire_patch(pp) + & - iso_cnveg_cf%m_livecrootc_to_litter_fire_patch(pp)) * & - patch%wtcol(pp) * croot_prof(pp,j) - end do - end if - end if + do fp = 1,num_soilp + pp = filter_soilp(fp) + cc = patch%column(pp) + do j = 1, nlevdecomp + iso_cnveg_cf%fire_mortality_c_to_cwdc_col(cc,j) = & + iso_cnveg_cf%fire_mortality_c_to_cwdc_col(cc,j) + & + (iso_cnveg_cf%m_deadstemc_to_litter_fire_patch(pp) + & + iso_cnveg_cf%m_livestemc_to_litter_fire_patch(pp)) * & + patch%wtcol(pp) * stem_prof(pp,j) + iso_cnveg_cf%fire_mortality_c_to_cwdc_col(cc,j) = & + iso_cnveg_cf%fire_mortality_c_to_cwdc_col(cc,j) + & + (iso_cnveg_cf%m_deadcrootc_to_litter_fire_patch(pp) + & + iso_cnveg_cf%m_livecrootc_to_litter_fire_patch(pp)) * & + patch%wtcol(pp) * croot_prof(pp,j) end do - end do - - do fc = 1,num_soilc - cc = filter_soilc(fc) do j = 1, nlevdecomp do l = 1, ndecomp_pools if ( soilbiogeochem_cs%decomp_cpools_vr_col(cc,j,l) /= 0._r8) then @@ -1316,54 +1296,47 @@ subroutine CIsoFlux3(num_soilc , filter_soilc, num_soilp , filter_soilp, & end do end do - - do pi = 1,max_patch_per_col - do fc = 1,num_soilc - cc = filter_soilc(fc) - if ( pi <= col%npatches(cc) ) then - pp = col%patchi(cc) + pi - 1 - if (patch%active(pp)) then - do j = 1, nlevdecomp - iso_cnveg_cf%m_c_to_litr_fire_col(cc,j,i_met_lit) = & - iso_cnveg_cf%m_c_to_litr_fire_col(cc,j,i_met_lit) + & - ((iso_cnveg_cf%m_leafc_to_litter_fire_patch(pp) * lf_f(ivt(pp),i_met_lit) & - +iso_cnveg_cf%m_leafc_storage_to_litter_fire_patch(pp) + & - iso_cnveg_cf%m_leafc_xfer_to_litter_fire_patch(pp) + & - iso_cnveg_cf%m_gresp_storage_to_litter_fire_patch(pp) & - +iso_cnveg_cf%m_gresp_xfer_to_litter_fire_patch(pp))*leaf_prof(pp,j) + & - (iso_cnveg_cf%m_frootc_to_litter_fire_patch(pp) * fr_f(ivt(pp),i_met_lit) & - +iso_cnveg_cf%m_frootc_storage_to_litter_fire_patch(pp) + & - iso_cnveg_cf%m_frootc_xfer_to_litter_fire_patch(pp))*froot_prof(pp,j) & - +(iso_cnveg_cf%m_livestemc_storage_to_litter_fire_patch(pp) + & - iso_cnveg_cf%m_livestemc_xfer_to_litter_fire_patch(pp) & - +iso_cnveg_cf%m_deadstemc_storage_to_litter_fire_patch(pp) + & - iso_cnveg_cf%m_deadstemc_xfer_to_litter_fire_patch(pp))* stem_prof(pp,j)& - +(iso_cnveg_cf%m_livecrootc_storage_to_litter_fire_patch(pp) + & - iso_cnveg_cf%m_livecrootc_xfer_to_litter_fire_patch(pp) & - +iso_cnveg_cf%m_deadcrootc_storage_to_litter_fire_patch(pp) + & - iso_cnveg_cf%m_deadcrootc_xfer_to_litter_fire_patch(pp))* croot_prof(pp,j)) * patch%wtcol(pp) - - ! Here metabolic litter is treated differently than other - ! types of litter, so it remains outside this litter loop, - ! in the line above - do i = i_met_lit+1, i_litr_max - iso_cnveg_cf%m_c_to_litr_fire_col(cc,j,i) = & - iso_cnveg_cf%m_c_to_litr_fire_col(cc,j,i) + & - (iso_cnveg_cf%m_leafc_to_litter_fire_patch(pp) * lf_f(ivt(pp),i) * leaf_prof(pp,j) + & - iso_cnveg_cf%m_frootc_to_litter_fire_patch(pp) * fr_f(ivt(pp),i) * froot_prof(pp,j)) * patch%wtcol(pp) - end do - end do - end if - end if + do fp = 1,num_soilp + pp = filter_soilp(fp) + cc = patch%column(pp) + do j = 1, nlevdecomp + iso_cnveg_cf%m_c_to_litr_fire_col(cc,j,i_met_lit) = & + iso_cnveg_cf%m_c_to_litr_fire_col(cc,j,i_met_lit) + & + ((iso_cnveg_cf%m_leafc_to_litter_fire_patch(pp) * lf_f(ivt(pp),i_met_lit) & + +iso_cnveg_cf%m_leafc_storage_to_litter_fire_patch(pp) + & + iso_cnveg_cf%m_leafc_xfer_to_litter_fire_patch(pp) + & + iso_cnveg_cf%m_gresp_storage_to_litter_fire_patch(pp) & + +iso_cnveg_cf%m_gresp_xfer_to_litter_fire_patch(pp))*leaf_prof(pp,j) + & + (iso_cnveg_cf%m_frootc_to_litter_fire_patch(pp) * fr_f(ivt(pp),i_met_lit) & + +iso_cnveg_cf%m_frootc_storage_to_litter_fire_patch(pp) + & + iso_cnveg_cf%m_frootc_xfer_to_litter_fire_patch(pp))*froot_prof(pp,j) & + +(iso_cnveg_cf%m_livestemc_storage_to_litter_fire_patch(pp) + & + iso_cnveg_cf%m_livestemc_xfer_to_litter_fire_patch(pp) & + +iso_cnveg_cf%m_deadstemc_storage_to_litter_fire_patch(pp) + & + iso_cnveg_cf%m_deadstemc_xfer_to_litter_fire_patch(pp))* stem_prof(pp,j)& + +(iso_cnveg_cf%m_livecrootc_storage_to_litter_fire_patch(pp) + & + iso_cnveg_cf%m_livecrootc_xfer_to_litter_fire_patch(pp) & + +iso_cnveg_cf%m_deadcrootc_storage_to_litter_fire_patch(pp) + & + iso_cnveg_cf%m_deadcrootc_xfer_to_litter_fire_patch(pp))* croot_prof(pp,j)) * patch%wtcol(pp) + + ! Here metabolic litter is treated differently than other + ! types of litter, so it remains outside this litter loop, + ! in the line above + do i = i_met_lit+1, i_litr_max + iso_cnveg_cf%m_c_to_litr_fire_col(cc,j,i) = & + iso_cnveg_cf%m_c_to_litr_fire_col(cc,j,i) + & + (iso_cnveg_cf%m_leafc_to_litter_fire_patch(pp) * lf_f(ivt(pp),i) * leaf_prof(pp,j) + & + iso_cnveg_cf%m_frootc_to_litter_fire_patch(pp) * fr_f(ivt(pp),i) * froot_prof(pp,j)) * patch%wtcol(pp) + end do end do - end do + end do end associate end subroutine CIsoFlux3 !----------------------------------------------------------------------- - subroutine CNCIsoLitterToColumn (num_soilc, filter_soilc, & + subroutine CNCIsoLitterToColumn (num_soilp, filter_soilp, & soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) ! ! !DESCRIPTION: @@ -1377,13 +1350,13 @@ subroutine CNCIsoLitterToColumn (num_soilc, filter_soilc, & !DML ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_soilp ! number of soil patches in filter + integer , intent(in) :: filter_soilp(:) ! filter for soil patches type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst type(cnveg_carbonflux_type) , intent(inout) :: iso_cnveg_carbonflux_inst ! ! !LOCAL VARIABLES: - integer :: fc,c,pi,p,k,j,i + integer :: fp,c,p,k,j,i !----------------------------------------------------------------------- associate( & @@ -1405,59 +1378,50 @@ subroutine CNCIsoLitterToColumn (num_soilc, filter_soilc, & ) do j = 1, nlevdecomp - do pi = 1,max_patch_per_col - do fc = 1,num_soilc - c = filter_soilc(fc) - - if ( pi <= col%npatches(c) ) then - p = col%patchi(c) + pi - 1 - if (patch%active(p)) then - do i = i_litr_min, i_litr_max - phenology_c_to_litr_c(c,j,i) = & - phenology_c_to_litr_c(c,j,i) + & - ! leaf litter carbon fluxes - leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & - ! fine root litter carbon fluxes - frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) - end do + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) + + do i = i_litr_min, i_litr_max + phenology_c_to_litr_c(c,j,i) = & + phenology_c_to_litr_c(c,j,i) + & + ! leaf litter carbon fluxes + leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & + ! fine root litter carbon fluxes + frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) + end do !DML - if (ivt(p) >= npcropmin) then ! add livestemc to litter - ! stem litter carbon fluxes - do i = i_litr_min, i_litr_max - phenology_c_to_litr_c(c,j,i) = & - phenology_c_to_litr_c(c,j,i) + & - livestemc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - end do - - if (.not. use_grainproduct) then - ! grain litter carbon fluxes - do i = i_litr_min, i_litr_max - do k = repr_grain_min, repr_grain_max - phenology_c_to_litr_c(c,j,i) = & - phenology_c_to_litr_c(c,j,i) + & - repr_grainc_to_food(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - end do - end do - end if - - ! reproductive structure litter carbon fluxes - do i = i_litr_min, i_litr_max - do k = repr_structure_min, repr_structure_max - phenology_c_to_litr_c(c,j,i) = & - phenology_c_to_litr_c(c,j,i) + & - repr_structurec_to_litter(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - end do - end do - - end if -!DML - end if + if (ivt(p) >= npcropmin) then ! add livestemc to litter + ! stem litter carbon fluxes + do i = i_litr_min, i_litr_max + phenology_c_to_litr_c(c,j,i) = & + phenology_c_to_litr_c(c,j,i) + & + livestemc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + end do + + if (.not. use_grainproduct) then + ! grain litter carbon fluxes + do i = i_litr_min, i_litr_max + do k = repr_grain_min, repr_grain_max + phenology_c_to_litr_c(c,j,i) = & + phenology_c_to_litr_c(c,j,i) + & + repr_grainc_to_food(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + end do + end do end if - end do + ! reproductive structure litter carbon fluxes + do i = i_litr_min, i_litr_max + do k = repr_structure_min, repr_structure_max + phenology_c_to_litr_c(c,j,i) = & + phenology_c_to_litr_c(c,j,i) + & + repr_structurec_to_litter(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + end do + end do + end if + !DML end do - end do end associate @@ -1465,7 +1429,7 @@ subroutine CNCIsoLitterToColumn (num_soilc, filter_soilc, & end subroutine CNCIsoLitterToColumn !----------------------------------------------------------------------- - subroutine CNCIsoGapPftToColumn (num_soilc, filter_soilc, & + subroutine CNCIsoGapPftToColumn (num_soilp, filter_soilp, & soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) ! ! !DESCRIPTION: @@ -1473,13 +1437,13 @@ subroutine CNCIsoGapPftToColumn (num_soilc, filter_soilc, & ! to the column level and assign them to the three litter pools (+ cwd pool) ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! soil column filter + integer , intent(in) :: num_soilp ! number of soil patches in filter + integer , intent(in) :: filter_soilp(:) ! soil patch filter type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst type(cnveg_carbonflux_type) , intent(inout) :: iso_cnveg_carbonflux_inst ! ! !LOCAL VARIABLES: - integer :: fc,c,pi,p,j,i ! indices + integer :: fp,c,p,j,i ! indices !----------------------------------------------------------------------- associate( & @@ -1520,72 +1484,63 @@ subroutine CNCIsoGapPftToColumn (num_soilc, filter_soilc, & ) do j = 1, nlevdecomp - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) - - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - - if (patch%active(p)) then - - do i = i_litr_min, i_litr_max - ! leaf gap mortality carbon fluxes - gap_mortality_c_to_litr_c(c,j,i) = & - gap_mortality_c_to_litr_c(c,j,i) + & - m_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - ! fine root gap mortality carbon fluxes - gap_mortality_c_to_litr_c(c,j,i) = & - gap_mortality_c_to_litr_c(c,j,i) + & - m_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) - end do - - ! wood gap mortality carbon fluxes - gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & - m_livestemc_to_litter(p) * wtcol(p) * stem_prof(p,j) - gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & - m_deadstemc_to_litter(p) * wtcol(p) * stem_prof(p,j) - gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & - m_livecrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) - gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & - m_deadcrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) - - ! Metabolic litter is treated differently than other types - ! of litter, so it gets this additional line after the - ! most recent loop over all litter types - gap_mortality_c_to_litr_c(c,j,i_met_lit) = & - gap_mortality_c_to_litr_c(c,j,i_met_lit) + & - ! storage gap mortality carbon fluxes - m_leafc_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - m_frootc_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - m_livestemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - m_deadstemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - m_livecrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - m_deadcrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - m_gresp_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - ! transfer gap mortality carbon fluxes - m_leafc_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - m_frootc_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - m_livestemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - m_deadstemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - m_livecrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - m_deadcrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - m_gresp_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) - - end if - end if - + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) + + do i = i_litr_min, i_litr_max + ! leaf gap mortality carbon fluxes + gap_mortality_c_to_litr_c(c,j,i) = & + gap_mortality_c_to_litr_c(c,j,i) + & + m_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + ! fine root gap mortality carbon fluxes + gap_mortality_c_to_litr_c(c,j,i) = & + gap_mortality_c_to_litr_c(c,j,i) + & + m_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) end do + ! wood gap mortality carbon fluxes + gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & + m_livestemc_to_litter(p) * wtcol(p) * stem_prof(p,j) + gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & + m_deadstemc_to_litter(p) * wtcol(p) * stem_prof(p,j) + gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & + m_livecrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) + gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & + m_deadcrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) + + ! Metabolic litter is treated differently than other types + ! of litter, so it gets this additional line after the + ! most recent loop over all litter types + gap_mortality_c_to_litr_c(c,j,i_met_lit) = & + gap_mortality_c_to_litr_c(c,j,i_met_lit) + & + ! storage gap mortality carbon fluxes + m_leafc_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + m_frootc_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + m_livestemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + m_deadstemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + m_livecrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + m_deadcrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + m_gresp_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + ! transfer gap mortality carbon fluxes + m_leafc_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + m_frootc_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + m_livestemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + m_deadstemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + m_livecrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + m_deadcrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + m_gresp_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + end do end do + end associate end subroutine CNCIsoGapPftToColumn !----------------------------------------------------------------------- - subroutine CNCIsoHarvestPftToColumn (num_soilc, filter_soilc, & + subroutine CNCIsoHarvestPftToColumn (num_soilp, filter_soilp, & soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) ! ! !DESCRIPTION: @@ -1593,13 +1548,13 @@ subroutine CNCIsoHarvestPftToColumn (num_soilc, filter_soilc, & ! to the column level and assign them to the litter, cwd, and wood product pools ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! soil column filter + integer , intent(in) :: num_soilp ! number of soil patches in filter + integer , intent(in) :: filter_soilp(:) ! soil patch filter type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst type(cnveg_carbonflux_type) , intent(inout) :: iso_cnveg_carbonflux_inst ! ! !LOCAL VARIABLES: - integer :: fc,c,pi,p,j,i ! indices + integer :: fp,c,p,j,i ! indices !----------------------------------------------------------------------- associate( & @@ -1640,76 +1595,60 @@ subroutine CNCIsoHarvestPftToColumn (num_soilc, filter_soilc, & ) do j = 1, nlevdecomp - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - - if (patch%active(p)) then - - do i = i_litr_min, i_litr_max - ! leaf harvest mortality carbon fluxes - harvest_c_to_litr_c(c,j,i) = & - harvest_c_to_litr_c(c,j,i) + & - hrv_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - - ! fine root harvest mortality carbon fluxes - harvest_c_to_litr_c(c,j,i) = & - harvest_c_to_litr_c(c,j,i) + & - hrv_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) - end do - - ! wood harvest mortality carbon fluxes - harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & - hrv_livestemc_to_litter(p) * wtcol(p) * stem_prof(p,j) - harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & - hrv_livecrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) - harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & - hrv_deadcrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) - - ! Metabolic litter is treated differently than other types - ! of litter, so it gets this additional line after the - ! most recent loop over all litter types - harvest_c_to_litr_c(c,j,i_met_lit) = & - harvest_c_to_litr_c(c,j,i_met_lit) + & - ! storage harvest mortality carbon fluxes - hrv_leafc_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - hrv_frootc_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - hrv_livestemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_deadstemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_livecrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - hrv_deadcrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - hrv_gresp_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - ! transfer harvest mortality carbon fluxes - hrv_leafc_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - hrv_frootc_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - hrv_livestemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_deadstemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_livecrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - hrv_deadcrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - hrv_gresp_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) - end if - end if - + do i = i_litr_min, i_litr_max + ! leaf harvest mortality carbon fluxes + harvest_c_to_litr_c(c,j,i) = & + harvest_c_to_litr_c(c,j,i) + & + hrv_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + + ! fine root harvest mortality carbon fluxes + harvest_c_to_litr_c(c,j,i) = & + harvest_c_to_litr_c(c,j,i) + & + hrv_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) end do + ! wood harvest mortality carbon fluxes + harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & + hrv_livestemc_to_litter(p) * wtcol(p) * stem_prof(p,j) + harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & + hrv_livecrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) + harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & + hrv_deadcrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) + + ! Metabolic litter is treated differently than other types + ! of litter, so it gets this additional line after the + ! most recent loop over all litter types + harvest_c_to_litr_c(c,j,i_met_lit) = & + harvest_c_to_litr_c(c,j,i_met_lit) + & + ! storage harvest mortality carbon fluxes + hrv_leafc_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + hrv_frootc_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + hrv_livestemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_deadstemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_livecrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + hrv_deadcrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + hrv_gresp_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + ! transfer harvest mortality carbon fluxes + hrv_leafc_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + hrv_frootc_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + hrv_livestemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_deadstemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_livecrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + hrv_deadcrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + hrv_gresp_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + end do end do - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - - if (patch%active(p)) then - cwood_harvestc(c) = cwood_harvestc(c) + & - pwood_harvestc(p) * wtcol(p) - end if - end if - end do + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) + cwood_harvestc(c) = cwood_harvestc(c) + & + pwood_harvestc(p) * wtcol(p) end do end associate @@ -1717,7 +1656,7 @@ subroutine CNCIsoHarvestPftToColumn (num_soilc, filter_soilc, & end subroutine CNCIsoHarvestPftToColumn !----------------------------------------------------------------------- - subroutine CNCIsoGrossUnrepPftToColumn (num_soilc, filter_soilc, & + subroutine CNCIsoGrossUnrepPftToColumn (num_soilp, filter_soilp, & soilbiogeochem_state_inst, iso_cnveg_carbonflux_inst) ! ! !DESCRIPTION: @@ -1725,13 +1664,13 @@ subroutine CNCIsoGrossUnrepPftToColumn (num_soilc, filter_soilc, & ! to the column level and assign them to the litter, cwd, and wood product pools ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! soil column filter + integer , intent(in) :: num_soilp ! number of soil patches in filter + integer , intent(in) :: filter_soilp(:) ! soil patch filter type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst type(cnveg_carbonflux_type) , intent(inout) :: iso_cnveg_carbonflux_inst ! ! !LOCAL VARIABLES: - integer :: fc,c,pi,p,j,i ! indices + integer :: fp,c,p,j,i ! indices !----------------------------------------------------------------------- associate( & @@ -1774,54 +1713,35 @@ subroutine CNCIsoGrossUnrepPftToColumn (num_soilc, filter_soilc, & ) do j = 1, nlevdecomp - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) - - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - - if (patch%active(p)) then - - do i = i_litr_min, i_litr_max - gru_c_to_litr_c(c,j,i) = & - gru_c_to_litr_c(c,j,i) + & - ! leaf gross unrepresented landcover change mortality carbon fluxes - gru_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & - ! fine root gross unrepresented landcover change mortality carbon fluxes - gru_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) - end do - - ! coarse root gross unrepresented landcover change mortality carbon fluxes - gru_c_to_cwdc_c(c,j) = gru_c_to_cwdc_c(c,j) + & - gru_livecrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) - gru_c_to_cwdc_c(c,j) = gru_c_to_cwdc_c(c,j) + & - gru_deadcrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) - - end if - end if - + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) + + do i = i_litr_min, i_litr_max + gru_c_to_litr_c(c,j,i) = & + gru_c_to_litr_c(c,j,i) + & + ! leaf gross unrepresented landcover change mortality carbon fluxes + gru_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & + ! fine root gross unrepresented landcover change mortality carbon fluxes + gru_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) end do + ! coarse root gross unrepresented landcover change mortality carbon fluxes + gru_c_to_cwdc_c(c,j) = gru_c_to_cwdc_c(c,j) + & + gru_livecrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) + gru_c_to_cwdc_c(c,j) = gru_c_to_cwdc_c(c,j) + & + gru_deadcrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) + end do end do - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) - - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) - if (patch%active(p)) then - ! wood gross unrepresented landcover change mortality carbon fluxes to product pools - gru_wood_productc_gain_c(c) = gru_wood_productc_gain_c(c) + & - gru_wood_productc_gain(p) * wtcol(p) - - end if - end if - - end do + ! wood gross unrepresented landcover change mortality carbon fluxes to product pools + gru_wood_productc_gain_c(c) = gru_wood_productc_gain_c(c) + & + gru_wood_productc_gain(p) * wtcol(p) end do diff --git a/src/biogeochem/CNCStateUpdate1Mod.F90 b/src/biogeochem/CNCStateUpdate1Mod.F90 index 843754f3cd..41051d0c39 100644 --- a/src/biogeochem/CNCStateUpdate1Mod.F90 +++ b/src/biogeochem/CNCStateUpdate1Mod.F90 @@ -18,13 +18,16 @@ module CNCStateUpdate1Mod use CNVegCarbonStateType , only : cnveg_carbonstate_type use CNVegCarbonFluxType , only : cnveg_carbonflux_type use CropType , only : crop_type - use CropReprPoolsMod , only : nrepr, repr_grain_min, repr_grain_max, repr_structure_min, repr_structure_max + use CropReprPoolsMod , only : nrepr, repr_grain_min, repr_grain_max + use CropReprPoolsMod , only : repr_structure_min, repr_structure_max use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con, use_soil_matrixcn use SoilBiogeochemCarbonFluxType , only : soilbiogeochem_carbonflux_type use SoilBiogeochemCarbonStateType , only : soilbiogeochem_carbonstate_type use PatchType , only : patch - use clm_varctl , only : use_fates, use_cn, iulog, use_fates_sp use CNSharedParamsMod , only : use_matrixcn + use CLMFatesInterfaceMod , only : hlm_fates_interface_type + use ColumnType , only : col + ! implicit none private @@ -43,6 +46,7 @@ subroutine CStateUpdateDynPatch(bounds, num_soilc_with_inactive, filter_soilc_wi ! ! !DESCRIPTION: ! Update carbon states based on fluxes from dyn_cnbal_patch + ! This routine is not called with FATES active. ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -71,26 +75,23 @@ subroutine CStateUpdateDynPatch(bounds, num_soilc_with_inactive, filter_soilc_wi dt = get_step_size_real() - if (.not. use_fates) then - do j = 1,nlevdecomp - do fc = 1, num_soilc_with_inactive - c = filter_soilc_with_inactive(fc) - do i = i_litr_min, i_litr_max - cs_soil%decomp_cpools_vr_col(c,j,i) = & - cs_soil%decomp_cpools_vr_col(c,j,i) + & - cf_veg%dwt_frootc_to_litr_c_col(c,j,i) * dt - end do - cs_soil%decomp_cpools_vr_col(c,j,i_cwd) = cs_soil%decomp_cpools_vr_col(c,j,i_cwd) + & - ( cf_veg%dwt_livecrootc_to_cwdc_col(c,j) + cf_veg%dwt_deadcrootc_to_cwdc_col(c,j) ) * dt + do j = 1,nlevdecomp + do fc = 1, num_soilc_with_inactive + c = filter_soilc_with_inactive(fc) + do i = i_litr_min, i_litr_max + cs_soil%decomp_cpools_vr_col(c,j,i) = & + cs_soil%decomp_cpools_vr_col(c,j,i) + & + cf_veg%dwt_frootc_to_litr_c_col(c,j,i) * dt end do + cs_soil%decomp_cpools_vr_col(c,j,i_cwd) = cs_soil%decomp_cpools_vr_col(c,j,i_cwd) + & + ( cf_veg%dwt_livecrootc_to_cwdc_col(c,j) + cf_veg%dwt_deadcrootc_to_cwdc_col(c,j) ) * dt end do + end do - do g = bounds%begg, bounds%endg - cs_veg%seedc_grc(g) = cs_veg%seedc_grc(g) - cf_veg%dwt_seedc_to_leaf_grc(g) * dt - cs_veg%seedc_grc(g) = cs_veg%seedc_grc(g) - cf_veg%dwt_seedc_to_deadstem_grc(g) * dt - end do - - end if + do g = bounds%begg, bounds%endg + cs_veg%seedc_grc(g) = cs_veg%seedc_grc(g) - cf_veg%dwt_seedc_to_leaf_grc(g) * dt + cs_veg%seedc_grc(g) = cs_veg%seedc_grc(g) - cf_veg%dwt_seedc_to_deadstem_grc(g) * dt + end do end associate @@ -123,8 +124,6 @@ subroutine CStateUpdate0(num_soilp, filter_soilp, & ! set time steps dt = get_step_size_real() - - ! gross photosynthesis fluxes do fp = 1,num_soilp p = filter_soilp(fp) @@ -140,7 +139,8 @@ end subroutine CStateUpdate0 !----------------------------------------------------------------------- subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & crop_inst, cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - soilbiogeochem_carbonflux_inst, dribble_crophrv_xsmrpool_2atm) + soilbiogeochem_carbonflux_inst, dribble_crophrv_xsmrpool_2atm, & + clm_fates, clump_index) ! ! !DESCRIPTION: ! On the radiation time step, update all the prognostic carbon state @@ -157,6 +157,8 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst logical , intent(in) :: dribble_crophrv_xsmrpool_2atm + type(hlm_fates_interface_type) , intent(inout) :: clm_fates + integer , intent(in) :: clump_index ! ! !LOCAL VARIABLES: integer :: c,p,j,k,l,i ! indices @@ -186,12 +188,23 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & dt = get_step_size_real() ! Below is the input into the soil biogeochemistry model - - ! plant to litter fluxes - if (.not. use_fates) then - do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + + fc_loop: do fc = 1,num_soilc + c = filter_soilc(fc) + + fates_if: if( col%is_fates(c) ) then + + ! If this is a fates column, then we ask fates for the + ! litter fluxes, the following routine simply copies + ! prepared litter c flux boundary conditions into + ! cf_soil%decomp_cpools_sourcesink_col + + call clm_fates%UpdateCLitterfluxes(cf_soil,clump_index,c) + + else + + do j = 1,nlevdecomp + ! ! State update without the matrix solution ! @@ -206,35 +219,40 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & ! terms have been moved to CStateUpdateDynPatch. I think this is zeroed every ! time step, but to be safe, I'm explicitly setting it to zero here. cf_soil%decomp_cpools_sourcesink_col(c,j,i_cwd) = 0._r8 - ! - ! For the matrix solution the actual state update comes after the matrix - ! multiply in SoilMatrix, but the matrix needs to be setup with - ! the equivalent of above. Those changes can be here or in the - ! native subroutines dealing with that field - ! + ! + ! For the matrix solution the actual state update comes after the matrix + ! multiply in SoilMatrix, but the matrix needs to be setup with + ! the equivalent of above. Those changes can be here or in the + ! native subroutines dealing with that field + ! else ! phenology and dynamic land cover fluxes end if end do - end do - else if ( .not. use_fates_sp ) then !use_fates - ! here add all fates litterfall and CWD breakdown to litter fluxes + + end if fates_if + + end do fc_loop + + + ! litter and SOM HR fluxes + do k = 1, ndecomp_cascade_transitions do j = 1,nlevdecomp do fc = 1,num_soilc c = filter_soilc(fc) - ! TODO(wjs, 2017-01-02) Should some portion or all of the following fluxes - ! be moved to the updates in CStateUpdateDynPatch? - do i = i_litr_min, i_litr_max - cf_soil%decomp_cpools_sourcesink_col(c,j,i) = & - cf_soil%FATES_c_to_litr_c_col(c,j,i) * dt - end do + ! + ! State update without the matrix solution + ! + if (.not. use_soil_matrixcn) then + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) = & + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) & + - ( cf_soil%decomp_cascade_hr_vr_col(c,j,k) + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)) *dt + end if !not use_soil_matrixcn end do end do - endif - - if ( .not. use_fates_sp ) then !use_fates - ! litter and SOM HR fluxes - do k = 1, ndecomp_cascade_transitions + end do + do k = 1, ndecomp_cascade_transitions + if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions do j = 1,nlevdecomp do fc = 1,num_soilc c = filter_soilc(fc) @@ -242,34 +260,16 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & ! State update without the matrix solution ! if (.not. use_soil_matrixcn) then - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) = & - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_donor_pool(k)) & - - ( cf_soil%decomp_cascade_hr_vr_col(c,j,k) + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)) *dt - end if !not use_soil_matrixcn - end do - end do - end do - do k = 1, ndecomp_cascade_transitions - if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions - do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) - ! - ! State update without the matrix solution - ! - if (.not. use_soil_matrixcn) then - cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) = & + cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) = & cf_soil%decomp_cpools_sourcesink_col(c,j,cascade_receiver_pool(k)) & + cf_soil%decomp_cascade_ctransfer_vr_col(c,j,k)*dt - end if !not use_soil_matrixcn - end do + end if !not use_soil_matrixcn end do - end if - end do - end if + end do + end if + end do - if (.not. use_fates) then -ptch: do fp = 1,num_soilp + soilpatch_loop: do fp = 1,num_soilp p = filter_soilp(fp) c = patch%column(p) @@ -674,8 +674,7 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & end if end if - end do ptch ! end of patch loop - end if ! end of NOT fates + end do soilpatch_loop ! end of patch loop end associate diff --git a/src/biogeochem/CNDriverMod.F90 b/src/biogeochem/CNDriverMod.F90 index 425c32e084..4ab1e1f51e 100644 --- a/src/biogeochem/CNDriverMod.F90 +++ b/src/biogeochem/CNDriverMod.F90 @@ -6,12 +6,12 @@ module CNDriverMod ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varctl , only : use_c13, use_c14, use_fates, use_dynroot + use clm_varctl , only : use_c13, use_c14, use_fates, use_fates_bgc, use_dynroot use dynSubgridControlMod , only : get_do_harvest, get_do_grossunrep use decompMod , only : bounds_type use perf_mod , only : t_startf, t_stopf use clm_varctl , only : use_nitrif_denitrif, use_nguardrail - use clm_varctl , only : iulog, use_crop, use_crop_agsys + use clm_varctl , only : iulog, use_crop, use_crop_agsys, use_cn use SoilBiogeochemDecompCascadeConType, only : mimics_decomp, century_decomp, decomp_method use CNSharedParamsMod , only : use_fun use CNVegStateType , only : cnveg_state_type @@ -43,7 +43,7 @@ module CNDriverMod use ActiveLayerMod , only : active_layer_type use SoilWaterRetentionCurveMod , only : soil_water_retention_curve_type use CLMFatesInterfaceMod , only : hlm_fates_interface_type - use CropReprPoolsMod , only : nrepr + use CropReprPoolsMod , only : nrepr ! ! !PUBLIC TYPES: implicit none @@ -77,14 +77,15 @@ subroutine CNDriverInit(bounds, NLFilename, cnfire_method) class(fire_method_type) , intent(inout) :: cnfire_method !----------------------------------------------------------------------- call SoilBiogeochemCompetitionInit(bounds) - call CNPhenologyInit(bounds) - call cnfire_method%FireInit(bounds, NLFilename) - + if(use_cn)then + call CNPhenologyInit(bounds) + call cnfire_method%FireInit(bounds, NLFilename) + end if end subroutine CNDriverInit !----------------------------------------------------------------------- subroutine CNDriverNoLeaching(bounds, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & num_pcropp, filter_pcropp, num_soilnopcropp, filter_soilnopcropp, & num_actfirec, filter_actfirec, num_actfirep, filter_actfirep, & num_exposedvegp, filter_exposedvegp, num_noexposedvegp, filter_noexposedvegp, & @@ -151,10 +152,10 @@ subroutine CNDriverNoLeaching(bounds, ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_vegp ! number of veg patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for veg patches integer , intent(out) :: num_actfirep ! number of soil patches on fire in filter integer , intent(out) :: filter_actfirep(:) ! filter for soil patches on fire integer , intent(out) :: num_actfirec ! number of soil columns on fire in filter @@ -241,58 +242,59 @@ subroutine CNDriverNoLeaching(bounds, ! -------------------------------------------------- ! zero the column-level C and N fluxes ! -------------------------------------------------- - - call t_startf('CNZero') + call t_startf('CNZero') ! COMPILER_BUG(wjs, 2014-11-29, pgi 14.7) Without this, the filter is full of garbage ! in some situations call t_startf('CNZero-soilbgc-cflux') - dummy_to_make_pgi_happy = ubound(filter_soilc, 1) + dummy_to_make_pgi_happy = ubound(filter_bgc_soilc, 1) call soilbiogeochem_carbonflux_inst%SetValues( & - num_soilc, filter_soilc, 0._r8) + num_bgc_soilc, filter_bgc_soilc, 0._r8) if ( use_c13 ) then call c13_soilbiogeochem_carbonflux_inst%SetValues( & - num_soilc, filter_soilc, 0._r8) + num_bgc_soilc, filter_bgc_soilc, 0._r8) end if if ( use_c14 ) then call c14_soilbiogeochem_carbonflux_inst%SetValues( & - num_soilc, filter_soilc, 0._r8) + num_bgc_soilc, filter_bgc_soilc, 0._r8) end if call t_stopf('CNZero-soilbgc-cflux') - call t_startf('CNZero-vegbgc-cflux') - call cnveg_carbonflux_inst%SetValues( & - nvegcpool,& - num_soilp, filter_soilp, 0._r8, & - num_soilc, filter_soilc, 0._r8) - if ( use_c13 ) then - call c13_cnveg_carbonflux_inst%SetValues( & + if(num_bgc_vegp>0)then + call t_startf('CNZero-vegbgc-cflux') + call cnveg_carbonflux_inst%SetValues( & nvegcpool,& - num_soilp, filter_soilp, 0._r8, & - num_soilc, filter_soilc, 0._r8) - end if - if ( use_c14 ) then - call c14_cnveg_carbonflux_inst%SetValues( & - nvegcpool,& - num_soilp, filter_soilp, 0._r8, & - num_soilc, filter_soilc, 0._r8) + num_bgc_vegp, filter_bgc_vegp, 0._r8, & + num_bgc_soilc, filter_bgc_soilc, 0._r8) + if ( use_c13 ) then + call c13_cnveg_carbonflux_inst%SetValues( & + nvegcpool,& + num_bgc_vegp, filter_bgc_vegp, 0._r8, & + num_bgc_soilc, filter_bgc_soilc, 0._r8) + end if + if ( use_c14 ) then + call c14_cnveg_carbonflux_inst%SetValues( & + nvegcpool,& + num_bgc_vegp, filter_bgc_vegp, 0._r8, & + num_bgc_soilc, filter_bgc_soilc, 0._r8) + end if + call t_stopf('CNZero-vegbgc-cflux') + + call t_startf('CNZero-vegbgc-nflux') + call cnveg_nitrogenflux_inst%SetValues( & + nvegnpool, & + num_bgc_vegp, filter_bgc_vegp, 0._r8, & + num_bgc_soilc, filter_bgc_soilc, 0._r8) end if - call t_stopf('CNZero-vegbgc-cflux') - - call t_startf('CNZero-vegbgc-nflux') - call cnveg_nitrogenflux_inst%SetValues( & - nvegnpool, & - num_soilp, filter_soilp, 0._r8, & - num_soilc, filter_soilc, 0._r8) - + call t_stopf('CNZero-vegbgc-nflux') call t_startf('CNZero-soilbgc-nflux') call soilbiogeochem_nitrogenflux_inst%SetValues( & - num_soilc, filter_soilc, 0._r8) + num_bgc_soilc, filter_bgc_soilc, 0._r8) call t_stopf('CNZero-soilbgc-nflux') call t_stopf('CNZero') - + ! -------------------------------------------------- ! Nitrogen Deposition, Fixation and Respiration ! -------------------------------------------------- @@ -304,30 +306,31 @@ subroutine CNDriverNoLeaching(bounds, if(use_fun)then call t_startf('CNFLivFixation') - call CNFreeLivingFixation( num_soilc, filter_soilc, & + call CNFreeLivingFixation( num_bgc_soilc, filter_bgc_soilc, & waterfluxbulk_inst, soilbiogeochem_nitrogenflux_inst) call t_stopf('CNFLivFixation') else call t_startf('CNFixation') - call CNNFixation( num_soilc, filter_soilc, & - cnveg_carbonflux_inst, soilbiogeochem_nitrogenflux_inst) + call CNNFixation( num_bgc_soilc, filter_bgc_soilc, & + cnveg_carbonflux_inst, soilbiogeochem_nitrogenflux_inst, & + clm_fates, bounds%clump_index) call t_stopf('CNFixation') end if if (use_crop) then - call CNNFert(bounds, num_soilc,filter_soilc, & + call CNNFert(bounds, num_bgc_soilc,filter_bgc_soilc, & cnveg_nitrogenflux_inst, soilbiogeochem_nitrogenflux_inst) if (.not. use_fun) then ! if FUN is active, then soy fixation handled by FUN - call CNSoyfix (bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & + call CNSoyfix (bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & waterdiagnosticbulk_inst, crop_inst, cnveg_state_inst, cnveg_nitrogenflux_inst , & soilbiogeochem_state_inst, soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) end if end if call t_startf('CNMResp') - call CNMResp(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & + call CNMResp(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & canopystate_inst, soilstate_inst, temperature_inst, photosyns_inst, & cnveg_carbonflux_inst, cnveg_nitrogenstate_inst) call t_stopf('CNMResp') @@ -339,11 +342,11 @@ subroutine CNDriverNoLeaching(bounds, call t_startf('SoilBiogeochem') call t_startf('DecompRate') if (decomp_method == century_decomp) then - call decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & + call decomp_rate_constants_bgc(bounds, num_bgc_soilc, filter_bgc_soilc, & soilstate_inst, temperature_inst, ch4_inst, soilbiogeochem_carbonflux_inst) else if (decomp_method == mimics_decomp) then - call decomp_rates_mimics(bounds, num_soilc, filter_soilc, & - num_soilp, filter_soilp, clm_fates, & + call decomp_rates_mimics(bounds, num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, clm_fates, & soilstate_inst, temperature_inst, cnveg_carbonflux_inst, ch4_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst) end if @@ -351,7 +354,7 @@ subroutine CNDriverNoLeaching(bounds, call t_startf('SoilBiogeochemPotential') ! calculate potential decomp rates and total immobilization demand (previously inlined in CNDecompAlloc) - call SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & + call SoilBiogeochemPotential (bounds, num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_state_inst, soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst, & soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst, & cn_decomp_pools=cn_decomp_pools(begc:endc,1:nlevdecomp,1:ndecomp_pools), & @@ -361,13 +364,14 @@ subroutine CNDriverNoLeaching(bounds, p_decomp_npool_to_din=p_decomp_npool_to_din(begc:endc,1:nlevdecomp,1:ndecomp_cascade_transitions)) call t_stopf('SoilBiogeochemPotential') - ! calculate vertical profiles for distributing soil and litter C and N (previously subroutine decomp_vertprofiles called from CNDecompAlloc) - call SoilBiogeochemVerticalProfile(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & + ! calculate vertical profiles for distributing soil and litter C and N + ! (previously subroutine decomp_vertprofiles called from CNDecompAlloc) + call SoilBiogeochemVerticalProfile(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & active_layer_inst, soilstate_inst,soilbiogeochem_state_inst) ! calculate nitrification and denitrification rates (previously subroutine nitrif_denitrif called from CNDecompAlloc) if (use_nitrif_denitrif) then - call SoilBiogeochemNitrifDenitrif(bounds, num_soilc, filter_soilc, & + call SoilBiogeochemNitrifDenitrif(bounds, num_bgc_soilc, filter_bgc_soilc, & soilstate_inst, waterstatebulk_inst, temperature_inst, ch4_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) end if @@ -389,43 +393,45 @@ subroutine CNDriverNoLeaching(bounds, ! do_nutrient_competition should be modified, but that modification should not significantly change ! the current interface. - !RF: moved ths call to before nutrient_demand, so that croplive didn't change half way through crop N cycle. - if ( use_fun ) then - call t_startf('CNPhenology_phase1') - call CNPhenology (bounds, num_soilc, filter_soilc, num_soilp, & - filter_soilp, num_pcropp, filter_pcropp, & - waterdiagnosticbulk_inst, wateratm2lndbulk_inst, temperature_inst, atm2lnd_inst, & - crop_inst, canopystate_inst, soilstate_inst, dgvs_inst, & - cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & - c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & - leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp,1:nlevdecomp_full), & - froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), & - phase=1) - call t_stopf('CNPhenology_phase1') - - call t_startf('CNFUNInit') - call CNFUNInit(bounds,cnveg_state_inst,cnveg_carbonstate_inst,cnveg_nitrogenstate_inst) - call t_stopf('CNFUNInit') - - end if - - call t_startf('cnalloc') - call calc_gpp_mr_availc( & - bounds, num_soilp, filter_soilp, & - crop_inst, photosyns_inst, canopystate_inst, & - cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst) - - if (.not. use_crop_agsys) then - call calc_crop_allocation_fractions(bounds, num_pcropp, filter_pcropp, & - crop_inst, cnveg_state_inst) - end if - - call calc_allometry(num_soilp, filter_soilp, & - cnveg_carbonflux_inst, cnveg_state_inst) - call t_stopf('cnalloc') - + !RF: moved ths call to before nutrient_demand, so that croplive didn't change half way through crop N cycle. + if(num_bgc_vegp>0)then + if ( use_fun) then + call t_startf('CNPhenology_phase1') + call CNPhenology (bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, & + filter_bgc_vegp, num_pcropp, filter_pcropp, & + waterdiagnosticbulk_inst, wateratm2lndbulk_inst, temperature_inst, atm2lnd_inst, & + crop_inst, canopystate_inst, soilstate_inst, dgvs_inst, & + cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & + cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & + c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & + leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp,1:nlevdecomp_full), & + froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), & + phase=1) + call t_stopf('CNPhenology_phase1') + + call t_startf('CNFUNInit') + call CNFUNInit(bounds,cnveg_state_inst,cnveg_carbonstate_inst,cnveg_nitrogenstate_inst) + call t_stopf('CNFUNInit') + + end if + + call t_startf('cnalloc') + call calc_gpp_mr_availc( & + bounds, num_bgc_vegp, filter_bgc_vegp, & + crop_inst, photosyns_inst, canopystate_inst, & + cnveg_carbonstate_inst, cnveg_carbonflux_inst, & + c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst) + + if (.not. use_crop_agsys) then + call calc_crop_allocation_fractions(bounds, num_pcropp, filter_pcropp, & + crop_inst, cnveg_state_inst) + end if + + call calc_allometry(num_bgc_vegp, filter_bgc_vegp, & + cnveg_carbonflux_inst, cnveg_state_inst) + call t_stopf('cnalloc') + end if + call t_startf('calc_plant_nutrient_demand') ! We always call calc_plant_nutrient_demand for natural veg patches, but only call ! it for crop patches if NOT running with AgSys (since AgSys calculates the relevant @@ -451,16 +457,23 @@ subroutine CNDriverNoLeaching(bounds, ! get the column-averaged plant_ndemand (needed for following call to SoilBiogeochemCompetition) - call p2c(bounds, num_soilc, filter_soilc, & - cnveg_nitrogenflux_inst%plant_ndemand_patch(begp:endp), & - soilbiogeochem_state_inst%plant_ndemand_col(begc:endc)) + if(num_bgc_vegp>0)then + call p2c(bounds, num_bgc_soilc, filter_bgc_soilc, & + cnveg_nitrogenflux_inst%plant_ndemand_patch(begp:endp), & + soilbiogeochem_state_inst%plant_ndemand_col(begc:endc)) + else + ! With FATES N coupling, we will have a call to fill + ! this in on the filter_bgc_soilc + soilbiogeochem_state_inst%plant_ndemand_col(begc:endc) = 0._r8 + end if + call t_stopf('calc_plant_nutrient_demand') ! resolve plant/heterotroph competition for mineral N call t_startf('soilbiogeochemcompetition') - call SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, filter_soilp, & + call SoilBiogeochemCompetition (bounds, num_bgc_soilc, filter_bgc_soilc,num_bgc_vegp, filter_bgc_vegp, & p_decomp_cn_gain, pmnf_decomp_cascade, waterstatebulk_inst, & waterfluxbulk_inst,temperature_inst,soilstate_inst,cnveg_state_inst, & cnveg_carbonstate_inst ,& @@ -475,7 +488,7 @@ subroutine CNDriverNoLeaching(bounds, call t_startf('calc_plant_nutrient_competition') call nutrient_competition_method%calc_plant_nutrient_competition ( & - bounds, num_soilp, filter_soilp, & + bounds, num_bgc_vegp, filter_bgc_vegp, & cnveg_state_inst, crop_inst, canopystate_inst, & cnveg_carbonstate_inst, cnveg_carbonflux_inst, & c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & @@ -495,7 +508,7 @@ subroutine CNDriverNoLeaching(bounds, call t_startf('SoilBiogeochemDecomp') - call SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, & + call SoilBiogeochemDecomp (bounds, num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_state_inst, soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst, & soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst, & cn_decomp_pools=cn_decomp_pools(begc:endc,1:nlevdecomp,1:ndecomp_pools), & @@ -511,12 +524,22 @@ subroutine CNDriverNoLeaching(bounds, ! CNphenology needs to be called after above calls, since it depends on current ! time-step fluxes to new growth on the lastlitterfall timestep in deciduous systems - - call t_startf('CNPhenology') - - if ( .not. use_fun ) then - call CNPhenology (bounds, num_soilc, filter_soilc, num_soilp, & - filter_soilp, num_pcropp, filter_pcropp, & + if(num_bgc_vegp>0)then + call t_startf('CNPhenology') + if ( .not. use_fun ) then + call CNPhenology (bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, & + filter_bgc_vegp, num_pcropp, filter_pcropp, & + waterdiagnosticbulk_inst, wateratm2lndbulk_inst, temperature_inst, atm2lnd_inst, & + crop_inst, canopystate_inst, soilstate_inst, dgvs_inst, & + cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & + cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & + c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & + leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp,1:nlevdecomp_full), & + froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), & + phase=1) + end if + call CNPhenology (bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, & + filter_bgc_vegp, num_pcropp, filter_pcropp, & waterdiagnosticbulk_inst, wateratm2lndbulk_inst, temperature_inst, atm2lnd_inst, & crop_inst, canopystate_inst, soilstate_inst, dgvs_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & @@ -524,28 +547,17 @@ subroutine CNDriverNoLeaching(bounds, c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp,1:nlevdecomp_full), & froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), & - phase=1) + phase=2) + + call t_stopf('CNPhenology') end if - call CNPhenology (bounds, num_soilc, filter_soilc, num_soilp, & - filter_soilp, num_pcropp, filter_pcropp, & - waterdiagnosticbulk_inst, wateratm2lndbulk_inst, temperature_inst, atm2lnd_inst, & - crop_inst, canopystate_inst, soilstate_inst, dgvs_inst, & - cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & - c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & - leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp,1:nlevdecomp_full), & - froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), & - phase=2) - - call t_stopf('CNPhenology') - !-------------------------------------------- ! Growth respiration !-------------------------------------------- call t_startf('CNGResp') - call CNGResp(num_soilp, filter_soilp,& + call CNGResp(num_bgc_vegp, filter_bgc_vegp,& cnveg_carbonflux_inst, canopystate_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst) call t_stopf('CNGResp') @@ -557,7 +569,7 @@ subroutine CNDriverNoLeaching(bounds, if( use_dynroot ) then call t_startf('CNRootDyn') - call CNRootDyn(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & + call CNRootDyn(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, & cnveg_state_inst, crop_inst, soilstate_inst, soilbiogeochem_nitrogenstate_inst) @@ -573,24 +585,24 @@ subroutine CNDriverNoLeaching(bounds, call t_startf('CNUpdate0') - call CStateUpdate0(num_soilp, filter_soilp, & + call CStateUpdate0(num_bgc_vegp, filter_bgc_vegp, & cnveg_carbonflux_inst, cnveg_carbonstate_inst) if ( use_c13 ) then - call CStateUpdate0(num_soilp, filter_soilp, & + call CStateUpdate0(num_bgc_vegp, filter_bgc_vegp, & c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst) end if if ( use_c14 ) then - call CStateUpdate0(num_soilp, filter_soilp, & + call CStateUpdate0(num_bgc_vegp, filter_bgc_vegp, & c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst) end if call t_stopf('CNUpdate0') - if ( use_nguardrail ) then + if ( use_nguardrail .and. num_bgc_vegp>0 ) then call t_startf('CNPrecisionControl') - call CNPrecisionControl(bounds, num_soilp, filter_soilp, & + call CNPrecisionControl(bounds, num_bgc_vegp, filter_bgc_vegp, & cnveg_carbonstate_inst, c13_cnveg_carbonstate_inst, & c14_cnveg_carbonstate_inst, cnveg_nitrogenstate_inst) call t_stopf('CNPrecisionControl') @@ -607,7 +619,7 @@ subroutine CNDriverNoLeaching(bounds, ! Set the carbon isotopic flux variables (except for gap-phase mortality and fire fluxes) if ( use_c13 ) then - call CIsoFlux1(num_soilc, filter_soilc, num_soilp, filter_soilp, & + call CIsoFlux1(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & soilbiogeochem_state_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & cnveg_carbonflux_inst, cnveg_carbonstate_inst, & @@ -616,7 +628,7 @@ subroutine CNDriverNoLeaching(bounds, isotope='c13') end if if ( use_c14 ) then - call CIsoFlux1(num_soilc, filter_soilc, num_soilp, filter_soilp, & + call CIsoFlux1(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & soilbiogeochem_state_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & cnveg_carbonflux_inst, cnveg_carbonstate_inst, & @@ -626,36 +638,40 @@ subroutine CNDriverNoLeaching(bounds, end if ! Update all prognostic carbon state variables (except for gap-phase mortality and fire fluxes) - call CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & + call CStateUpdate1( num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & crop_inst, cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - soilbiogeochem_carbonflux_inst, dribble_crophrv_xsmrpool_2atm) + soilbiogeochem_carbonflux_inst, dribble_crophrv_xsmrpool_2atm, & + clm_fates, bounds%clump_index) if ( use_c13 ) then - call CStateUpdate1(num_soilc, filter_soilc, num_soilp, filter_soilp, & + call CStateUpdate1(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & crop_inst, c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, & - c13_soilbiogeochem_carbonflux_inst, dribble_crophrv_xsmrpool_2atm) + c13_soilbiogeochem_carbonflux_inst, dribble_crophrv_xsmrpool_2atm, & + clm_fates, bounds%clump_index) end if if ( use_c14 ) then - call CStateUpdate1(num_soilc, filter_soilc, num_soilp, filter_soilp, & + call CStateUpdate1(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & crop_inst, c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, & - c14_soilbiogeochem_carbonflux_inst, dribble_crophrv_xsmrpool_2atm) + c14_soilbiogeochem_carbonflux_inst, dribble_crophrv_xsmrpool_2atm, & + clm_fates, bounds%clump_index) end if ! Update all prognostic nitrogen state variables (except for gap-phase mortality and fire fluxes) - call NStateUpdate1(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) + call NStateUpdate1(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst, & + clm_fates, bounds%clump_index) call t_stopf('CNUpdate1') - if ( use_nguardrail ) then + if ( use_nguardrail .and. num_bgc_vegp>0 ) then call t_startf('CNPrecisionControl') - call CNPrecisionControl(bounds, num_soilp, filter_soilp, & + call CNPrecisionControl(bounds, num_bgc_vegp, filter_bgc_vegp, & cnveg_carbonstate_inst, c13_cnveg_carbonstate_inst, & c14_cnveg_carbonstate_inst, cnveg_nitrogenstate_inst) call t_stopf('CNPrecisionControl') end if call t_startf('SoilBiogeochemStateUpdate1') - call SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & + call SoilBiogeochemNStateUpdate1(num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_state_inst, soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst) call t_stopf('SoilBiogeochemStateUpdate1') @@ -666,7 +682,7 @@ subroutine CNDriverNoLeaching(bounds, call t_startf('SoilBiogeochemLittVertTransp') - call SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & + call SoilBiogeochemLittVertTransp(bounds, num_bgc_soilc, filter_bgc_soilc, & active_layer_inst, soilbiogeochem_state_inst, & soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst, & c13_soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonflux_inst, & @@ -679,282 +695,317 @@ subroutine CNDriverNoLeaching(bounds, ! Calculate the gap mortality carbon and nitrogen fluxes !-------------------------------------------- - call t_startf('CNGapMortality') + if_bgc_vegp1: if(num_bgc_vegp>0)then - call CNGapMortality (bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & - dgvs_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst, & - cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, canopystate_inst, & - !cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & - leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp, 1:nlevdecomp_full), & - froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp, 1:nlevdecomp_full), & - croot_prof_patch=soilbiogeochem_state_inst%croot_prof_patch(begp:endp, 1:nlevdecomp_full), & - stem_prof_patch=soilbiogeochem_state_inst%stem_prof_patch(begp:endp, 1:nlevdecomp_full)) + call t_startf('CNGapMortality') - call t_stopf('CNGapMortality') + call CNGapMortality (bounds, num_bgc_vegp, filter_bgc_vegp, & + dgvs_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst, & + cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, canopystate_inst, & + leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp, 1:nlevdecomp_full), & + froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp, 1:nlevdecomp_full), & + croot_prof_patch=soilbiogeochem_state_inst%croot_prof_patch(begp:endp, 1:nlevdecomp_full), & + stem_prof_patch=soilbiogeochem_state_inst%stem_prof_patch(begp:endp, 1:nlevdecomp_full)) - !-------------------------------------------------------------------------- - ! Update2 (gap mortality) - ! The state updates are still called for the matrix solution (use_matrixn - ! and use_soil_matrixcn) but most of the state updates are done after - ! the matrix multiply in VegMatrix and SoilMatrix. - !-------------------------------------------------------------------------- + call t_stopf('CNGapMortality') - call t_startf('CNUpdate2') + !-------------------------------------------------------------------------- + ! Update2 (gap mortality) + ! The state updates are still called for the matrix solution (use_matrixn + ! and use_soil_matrixcn) but most of the state updates are done after + ! the matrix multiply in VegMatrix and SoilMatrix. + !-------------------------------------------------------------------------- - ! Set the carbon isotopic fluxes for gap mortality - if ( use_c13 ) then - call CIsoFlux2(num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_state_inst, cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - iso_cnveg_carbonflux_inst=c13_cnveg_carbonflux_inst, & - iso_cnveg_carbonstate_inst=c13_cnveg_carbonstate_inst, & - isotope='c13') - end if - if ( use_c14 ) then - call CIsoFlux2(num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_state_inst, cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - iso_cnveg_carbonflux_inst=c14_cnveg_carbonflux_inst, & - iso_cnveg_carbonstate_inst=c14_cnveg_carbonstate_inst, & - isotope='c14') - end if + call t_startf('CNUpdate2') - ! Update all the prognostic carbon state variables affected by gap-phase mortality fluxes - call CStateUpdate2(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, soilbiogeochem_carbonstate_inst, & - soilbiogeochem_carbonflux_inst) - if ( use_c13 ) then - call CStateUpdate2(num_soilc, filter_soilc, num_soilp, filter_soilp, & - c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & - c13_soilbiogeochem_carbonflux_inst) - end if - if ( use_c14 ) then - call CStateUpdate2(num_soilc, filter_soilc, num_soilp, filter_soilp, & - c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst, & - c14_soilbiogeochem_carbonflux_inst) - end if - - ! Update all the prognostic nitrogen state variables affected by gap-phase mortality fluxes - call NStateUpdate2(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst,soilbiogeochem_nitrogenstate_inst, & - soilbiogeochem_nitrogenflux_inst) + ! Set the carbon isotopic fluxes for gap mortality + if ( use_c13 ) then + call CIsoFlux2(num_bgc_vegp, filter_bgc_vegp, & + soilbiogeochem_state_inst, cnveg_carbonflux_inst, cnveg_carbonstate_inst, & + iso_cnveg_carbonflux_inst=c13_cnveg_carbonflux_inst, & + iso_cnveg_carbonstate_inst=c13_cnveg_carbonstate_inst, & + isotope='c13') + end if + if ( use_c14 ) then + call CIsoFlux2(num_bgc_vegp, filter_bgc_vegp, & + soilbiogeochem_state_inst, cnveg_carbonflux_inst, cnveg_carbonstate_inst, & + iso_cnveg_carbonflux_inst=c14_cnveg_carbonflux_inst, & + iso_cnveg_carbonstate_inst=c14_cnveg_carbonstate_inst, & + isotope='c14') + end if - !-------------------------------------------------------------------------- - ! Update2h (harvest) - ! The state updates are still called for the matrix solution (use_matrixn - ! and use_soil_matrixcn) but most of the state updates are done after - ! the matrix multiply in VegMatrix and SoilMatrix. - !-------------------------------------------------------------------------- + ! Update all the prognostic carbon state variables affected by gap-phase mortality fluxes + call CStateUpdate2(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, soilbiogeochem_carbonstate_inst, & + soilbiogeochem_carbonflux_inst) + if ( use_c13 ) then + call CStateUpdate2(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & + c13_soilbiogeochem_carbonflux_inst) + end if + if ( use_c14 ) then + call CStateUpdate2(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst, & + c14_soilbiogeochem_carbonflux_inst) + end if - ! Set harvest mortality routine - if (get_do_harvest()) then - call CNHarvest(num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & - cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) - end if + ! Update all the prognostic nitrogen state variables affected by gap-phase mortality fluxes + call NStateUpdate2(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst,soilbiogeochem_nitrogenstate_inst, & + soilbiogeochem_nitrogenflux_inst) + + !-------------------------------------------------------------------------- + ! Update2h (harvest) + ! The state updates are still called for the matrix solution (use_matrixn + ! and use_soil_matrixcn) but most of the state updates are done after + ! the matrix multiply in VegMatrix and SoilMatrix. + !-------------------------------------------------------------------------- + + ! Set harvest mortality routine + if (get_do_harvest()) then + call CNHarvest(num_bgc_vegp, filter_bgc_vegp, & + soilbiogeochem_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & + cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) + end if - if ( use_c13 ) then - call CIsoFlux2h(num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_state_inst, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, & - isotope='c13') - end if - if ( use_c14 ) then - call CIsoFlux2h(num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_state_inst, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, & - isotope='c14') - end if + if ( use_c13 ) then + call CIsoFlux2h(num_bgc_vegp, filter_bgc_vegp, & + soilbiogeochem_state_inst, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, & + c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, & + isotope='c13') + end if + if ( use_c14 ) then + call CIsoFlux2h(num_bgc_vegp, filter_bgc_vegp, & + soilbiogeochem_state_inst, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, & + c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, & + isotope='c14') + end if - call CStateUpdate2h( num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, soilbiogeochem_carbonstate_inst, & - soilbiogeochem_carbonflux_inst) - if ( use_c13 ) then - call CStateUpdate2h(num_soilc, filter_soilc, num_soilp, filter_soilp, & + call CStateUpdate2h( num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, soilbiogeochem_carbonstate_inst, & + soilbiogeochem_carbonflux_inst) + if ( use_c13 ) then + call CStateUpdate2h(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & c13_soilbiogeochem_carbonflux_inst) - end if - if ( use_c14 ) then - call CStateUpdate2h(num_soilc, filter_soilc, num_soilp, filter_soilp, & - c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst, & - c14_soilbiogeochem_carbonflux_inst) - end if + end if + if ( use_c14 ) then + call CStateUpdate2h(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst, & + c14_soilbiogeochem_carbonflux_inst) + end if - call NStateUpdate2h(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenstate_inst, & - soilbiogeochem_nitrogenflux_inst) + call NStateUpdate2h(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenstate_inst, & + soilbiogeochem_nitrogenflux_inst) - !-------------------------------------------- - ! Update2g (gross unrepresented landcover change) - !-------------------------------------------- + !-------------------------------------------- + ! Update2g (gross unrepresented landcover change) + !-------------------------------------------- - ! Set gross unrepresented landcover change mortality routine - if (get_do_grossunrep()) then - call CNGrossUnrep(num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & - cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) - end if + ! Set gross unrepresented landcover change mortality routine + if (get_do_grossunrep()) then + call CNGrossUnrep(num_bgc_vegp, filter_bgc_vegp, & + soilbiogeochem_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & + cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) + end if - if ( use_c13 ) then - call CIsoFlux2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_state_inst, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, & - isotope='c13') - end if - if ( use_c14 ) then - call CIsoFlux2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_state_inst, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, & - isotope='c14') - end if + if ( use_c13 ) then + call CIsoFlux2g(num_bgc_vegp, filter_bgc_vegp, & + soilbiogeochem_state_inst, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, & + c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, & + isotope='c13') + end if + if ( use_c14 ) then + call CIsoFlux2g(num_bgc_vegp, filter_bgc_vegp, & + soilbiogeochem_state_inst, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, & + c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, & + isotope='c14') + end if - call CStateUpdate2g( num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, soilbiogeochem_carbonstate_inst) - if ( use_c13 ) then - call CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst) - end if - if ( use_c14 ) then - call CStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst) - end if + call CStateUpdate2g( num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, soilbiogeochem_carbonstate_inst) + if ( use_c13 ) then + call CStateUpdate2g(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst) + end if + if ( use_c14 ) then + call CStateUpdate2g(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst) + end if - call NStateUpdate2g(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenstate_inst) + call NStateUpdate2g(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenstate_inst) - call t_stopf('CNUpdate2') + call t_stopf('CNUpdate2') + + end if if_bgc_vegp1 + + if ( use_nguardrail .and. num_bgc_vegp>0 ) then - if ( use_nguardrail ) then call t_startf('CNPrecisionControl') - call CNPrecisionControl(bounds, num_soilp, filter_soilp, & + call CNPrecisionControl(bounds, num_bgc_vegp, filter_bgc_vegp, & cnveg_carbonstate_inst, c13_cnveg_carbonstate_inst, & c14_cnveg_carbonstate_inst, cnveg_nitrogenstate_inst) call t_stopf('CNPrecisionControl') + end if + !-------------------------------------------- ! Calculate loss fluxes from wood products pools ! and update product pool state variables !-------------------------------------------- call t_startf('CNWoodProducts') - call c_products_inst%UpdateProducts(bounds, & - num_soilp, filter_soilp, & - dwt_wood_product_gain_patch = cnveg_carbonflux_inst%dwt_wood_productc_gain_patch(begp:endp), & - gru_wood_product_gain_patch = cnveg_carbonflux_inst%gru_wood_productc_gain_patch(begp:endp), & - wood_harvest_patch = cnveg_carbonflux_inst%wood_harvestc_patch(begp:endp), & - dwt_crop_product_gain_patch = cnveg_carbonflux_inst%dwt_crop_productc_gain_patch(begp:endp), & - crop_harvest_to_cropprod_patch = cnveg_carbonflux_inst%crop_harvestc_to_cropprodc_patch(begp:endp)) - call t_stopf('CNWoodProducts') - - if (use_c13) then - call c13_products_inst%UpdateProducts(bounds, & - num_soilp, filter_soilp, & - dwt_wood_product_gain_patch = c13_cnveg_carbonflux_inst%dwt_wood_productc_gain_patch(begp:endp), & - gru_wood_product_gain_patch = c13_cnveg_carbonflux_inst%gru_wood_productc_gain_patch(begp:endp), & - wood_harvest_patch = c13_cnveg_carbonflux_inst%wood_harvestc_patch(begp:endp), & - dwt_crop_product_gain_patch = c13_cnveg_carbonflux_inst%dwt_crop_productc_gain_patch(begp:endp), & - crop_harvest_to_cropprod_patch = c13_cnveg_carbonflux_inst%crop_harvestc_to_cropprodc_patch(begp:endp)) + + call c_products_inst%SetValues(bounds,0._r8) + if (use_c13) call c13_products_inst%SetValues(bounds,0._r8) + if (use_c14) call c14_products_inst%SetValues(bounds,0._r8) + call n_products_inst%SetValues(bounds,0._r8) + + if(use_fates_bgc) then + call clm_fates%wrap_WoodProducts(bounds, num_bgc_soilc, filter_bgc_soilc, c_products_inst, n_products_inst) end if - if (use_c14) then - call c14_products_inst%UpdateProducts(bounds, & - num_soilp, filter_soilp, & - dwt_wood_product_gain_patch = c14_cnveg_carbonflux_inst%dwt_wood_productc_gain_patch(begp:endp), & - gru_wood_product_gain_patch = c14_cnveg_carbonflux_inst%gru_wood_productc_gain_patch(begp:endp), & - wood_harvest_patch = c14_cnveg_carbonflux_inst%wood_harvestc_patch(begp:endp), & - dwt_crop_product_gain_patch = c14_cnveg_carbonflux_inst%dwt_crop_productc_gain_patch(begp:endp), & - crop_harvest_to_cropprod_patch = c14_cnveg_carbonflux_inst%crop_harvestc_to_cropprodc_patch(begp:endp)) - end if + if_bgc_vegp2: if(num_bgc_vegp>0)then + call c_products_inst%UpdateProducts(bounds, & + num_bgc_vegp, filter_bgc_vegp, & + dwt_wood_product_gain_patch = cnveg_carbonflux_inst%dwt_wood_productc_gain_patch(begp:endp), & + gru_wood_product_gain_patch = cnveg_carbonflux_inst%gru_wood_productc_gain_patch(begp:endp), & + wood_harvest_patch = cnveg_carbonflux_inst%wood_harvestc_patch(begp:endp), & + dwt_crop_product_gain_patch = cnveg_carbonflux_inst%dwt_crop_productc_gain_patch(begp:endp), & + crop_harvest_to_cropprod_patch = cnveg_carbonflux_inst%crop_harvestc_to_cropprodc_patch(begp:endp)) + + if (use_c13) then + call c13_products_inst%UpdateProducts(bounds, & + num_bgc_vegp, filter_bgc_vegp, & + dwt_wood_product_gain_patch = c13_cnveg_carbonflux_inst%dwt_wood_productc_gain_patch(begp:endp), & + gru_wood_product_gain_patch = c13_cnveg_carbonflux_inst%gru_wood_productc_gain_patch(begp:endp), & + wood_harvest_patch = c13_cnveg_carbonflux_inst%wood_harvestc_patch(begp:endp), & + dwt_crop_product_gain_patch = c13_cnveg_carbonflux_inst%dwt_crop_productc_gain_patch(begp:endp), & + crop_harvest_to_cropprod_patch = c13_cnveg_carbonflux_inst%crop_harvestc_to_cropprodc_patch(begp:endp)) + end if + + if (use_c14) then + call c14_products_inst%UpdateProducts(bounds, & + num_bgc_vegp, filter_bgc_vegp, & + dwt_wood_product_gain_patch = c14_cnveg_carbonflux_inst%dwt_wood_productc_gain_patch(begp:endp), & + gru_wood_product_gain_patch = c14_cnveg_carbonflux_inst%gru_wood_productc_gain_patch(begp:endp), & + wood_harvest_patch = c14_cnveg_carbonflux_inst%wood_harvestc_patch(begp:endp), & + dwt_crop_product_gain_patch = c14_cnveg_carbonflux_inst%dwt_crop_productc_gain_patch(begp:endp), & + crop_harvest_to_cropprod_patch = c14_cnveg_carbonflux_inst%crop_harvestc_to_cropprodc_patch(begp:endp)) + end if + + call n_products_inst%UpdateProducts(bounds, & + num_bgc_vegp, filter_bgc_vegp, & + dwt_wood_product_gain_patch = cnveg_nitrogenflux_inst%dwt_wood_productn_gain_patch(begp:endp), & + gru_wood_product_gain_patch = cnveg_nitrogenflux_inst%gru_wood_productn_gain_patch(begp:endp), & + wood_harvest_patch = cnveg_nitrogenflux_inst%wood_harvestn_patch(begp:endp), & + dwt_crop_product_gain_patch = cnveg_nitrogenflux_inst%dwt_crop_productn_gain_patch(begp:endp), & + crop_harvest_to_cropprod_patch = cnveg_nitrogenflux_inst%crop_harvestn_to_cropprodn_patch(begp:endp)) + + end if if_bgc_vegp2 + + call c_products_inst%ComputeProductSummaryVars(bounds) + if (use_c13) call c13_products_inst%ComputeProductSummaryVars(bounds) + if (use_c14) call c14_products_inst%ComputeProductSummaryVars(bounds) + call n_products_inst%ComputeProductSummaryVars(bounds) - call n_products_inst%UpdateProducts(bounds, & - num_soilp, filter_soilp, & - dwt_wood_product_gain_patch = cnveg_nitrogenflux_inst%dwt_wood_productn_gain_patch(begp:endp), & - gru_wood_product_gain_patch = cnveg_nitrogenflux_inst%gru_wood_productn_gain_patch(begp:endp), & - wood_harvest_patch = cnveg_nitrogenflux_inst%wood_harvestn_patch(begp:endp), & - dwt_crop_product_gain_patch = cnveg_nitrogenflux_inst%dwt_crop_productn_gain_patch(begp:endp), & - crop_harvest_to_cropprod_patch = cnveg_nitrogenflux_inst%crop_harvestn_to_cropprodn_patch(begp:endp)) + call c_products_inst%ComputeSummaryVars(bounds) + if (use_c13) call c13_products_inst%ComputeSummaryVars(bounds) + if (use_c14) call c14_products_inst%ComputeSummaryVars(bounds) + call n_products_inst%ComputeSummaryVars(bounds) + + call t_stopf('CNWoodProducts') + !-------------------------------------------- ! Calculate fire area and fluxes !-------------------------------------------- - call t_startf('CNFire') - call cnfire_method%CNFireArea(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & - num_exposedvegp, filter_exposedvegp, num_noexposedvegp, filter_noexposedvegp, & - atm2lnd_inst, energyflux_inst, saturated_excess_runoff_inst, waterdiagnosticbulk_inst, wateratm2lndbulk_inst, & - waterstatebulk_inst, soilstate_inst, soil_water_retention_curve, & - cnveg_state_inst, cnveg_carbonstate_inst, & - totlitc_col=soilbiogeochem_carbonstate_inst%totlitc_col(begc:endc), & - decomp_cpools_vr_col=soilbiogeochem_carbonstate_inst%decomp_cpools_vr_col(begc:endc,1:nlevdecomp_full,1:ndecomp_pools), & - t_soi17cm_col=temperature_inst%t_soi17cm_col(begc:endc)) - - call cnfire_method%CNFireFluxes(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & - num_actfirec, filter_actfirec, num_actfirep, filter_actfirep, & - dgvs_inst, cnveg_state_inst, & - cnveg_carbonstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & - soilbiogeochem_carbonflux_inst, & - leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp, 1:nlevdecomp_full), & - froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp, 1:nlevdecomp_full), & - croot_prof_patch=soilbiogeochem_state_inst%croot_prof_patch(begp:endp, 1:nlevdecomp_full), & - stem_prof_patch=soilbiogeochem_state_inst%stem_prof_patch(begp:endp, 1:nlevdecomp_full), & - totsomc_col=soilbiogeochem_carbonstate_inst%totsomc_col(begc:endc), & - decomp_cpools_vr_col=soilbiogeochem_carbonstate_inst%decomp_cpools_vr_col(begc:endc,1:nlevdecomp_full,1:ndecomp_pools), & - decomp_npools_vr_col=soilbiogeochem_nitrogenstate_inst%decomp_npools_vr_col(begc:endc,1:nlevdecomp_full,1:ndecomp_pools), & - somc_fire_col=soilbiogeochem_carbonflux_inst%somc_fire_col(begc:endc)) - call t_stopf('CNFire') - - - !-------------------------------------------------------------------------- - ! Update3 - ! The state updates are still called for the matrix solution (use_matrixn - ! and use_soil_matrixcn) but most of the state updates are done after - ! the matrix multiply in VegMatrix and SoilMatrix. - !-------------------------------------------------------------------------- - - call t_startf('CNUpdate3') - if ( use_c13 ) then - call CIsoFlux3(num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_state_inst , soilbiogeochem_carbonstate_inst, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, & - c13_soilbiogeochem_carbonstate_inst, & - isotope='c13') - end if - if ( use_c14 ) then - call CIsoFlux3(num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_state_inst , soilbiogeochem_carbonstate_inst, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, & - c14_soilbiogeochem_carbonstate_inst, & - isotope='c14') - end if + if_bgc_vegp3: if(num_bgc_vegp>0)then + + call t_startf('CNFire') + call cnfire_method%CNFireArea(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + num_exposedvegp, filter_exposedvegp, num_noexposedvegp, filter_noexposedvegp, & + atm2lnd_inst, energyflux_inst, saturated_excess_runoff_inst, waterdiagnosticbulk_inst, wateratm2lndbulk_inst, & + waterstatebulk_inst, soilstate_inst, soil_water_retention_curve, & + cnveg_state_inst, cnveg_carbonstate_inst, & + totlitc_col=soilbiogeochem_carbonstate_inst%totlitc_col(begc:endc), & + decomp_cpools_vr_col=soilbiogeochem_carbonstate_inst%decomp_cpools_vr_col(begc:endc,1:nlevdecomp_full,1:ndecomp_pools), & + t_soi17cm_col=temperature_inst%t_soi17cm_col(begc:endc)) + + call cnfire_method%CNFireFluxes(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + num_actfirec, filter_actfirec, num_actfirep, filter_actfirep, & + dgvs_inst, cnveg_state_inst, & + cnveg_carbonstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & + soilbiogeochem_carbonflux_inst, & + leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp, 1:nlevdecomp_full), & + froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp, 1:nlevdecomp_full), & + croot_prof_patch=soilbiogeochem_state_inst%croot_prof_patch(begp:endp, 1:nlevdecomp_full), & + stem_prof_patch=soilbiogeochem_state_inst%stem_prof_patch(begp:endp, 1:nlevdecomp_full), & + totsomc_col=soilbiogeochem_carbonstate_inst%totsomc_col(begc:endc), & + decomp_cpools_vr_col=soilbiogeochem_carbonstate_inst%decomp_cpools_vr_col(begc:endc,1:nlevdecomp_full,1:ndecomp_pools), & + decomp_npools_vr_col=soilbiogeochem_nitrogenstate_inst%decomp_npools_vr_col(begc:endc,1:nlevdecomp_full,1:ndecomp_pools), & + somc_fire_col=soilbiogeochem_carbonflux_inst%somc_fire_col(begc:endc)) + call t_stopf('CNFire') + + + !-------------------------------------------------------------------------- + ! Update3 + ! The state updates are still called for the matrix solution (use_matrixn + ! and use_soil_matrixcn) but most of the state updates are done after + ! the matrix multiply in VegMatrix and SoilMatrix. + !-------------------------------------------------------------------------- + + call t_startf('CNUpdate3') + if ( use_c13 ) then + call CIsoFlux3(num_bgc_vegp, filter_bgc_vegp, & + soilbiogeochem_state_inst , soilbiogeochem_carbonstate_inst, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, & + c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, & + c13_soilbiogeochem_carbonstate_inst, & + isotope='c13') + end if + if ( use_c14 ) then + call CIsoFlux3(num_bgc_vegp, filter_bgc_vegp, & + soilbiogeochem_state_inst , soilbiogeochem_carbonstate_inst, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, & + c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, & + c14_soilbiogeochem_carbonstate_inst, & + isotope='c14') + end if - call CStateUpdate3( num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, soilbiogeochem_carbonstate_inst, & - soilbiogeochem_carbonflux_inst) + call CStateUpdate3( num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + cnveg_carbonflux_inst, cnveg_carbonstate_inst, soilbiogeochem_carbonstate_inst, & + soilbiogeochem_carbonflux_inst) - if ( use_c13 ) then - call CStateUpdate3( num_soilc, filter_soilc, num_soilp, filter_soilp, & - c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & - c13_soilbiogeochem_carbonflux_inst) - end if + if ( use_c13 ) then + call CStateUpdate3( num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + c13_cnveg_carbonflux_inst, c13_cnveg_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & + c13_soilbiogeochem_carbonflux_inst) + end if - if ( use_c14 ) then - call CStateUpdate3( num_soilc, filter_soilc, num_soilp, filter_soilp, & - c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst, & - c14_soilbiogeochem_carbonflux_inst) + if ( use_c14 ) then + call CStateUpdate3( num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + c14_cnveg_carbonflux_inst, c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst, & + c14_soilbiogeochem_carbonflux_inst) - call C14Decay(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & - c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst, & - c14_cnveg_carbonflux_inst, c14_soilbiogeochem_carbonflux_inst) - end if - call t_stopf('CNUpdate3') + call C14Decay(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + c14_cnveg_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst, & + c14_cnveg_carbonflux_inst, c14_soilbiogeochem_carbonflux_inst) + end if + call t_stopf('CNUpdate3') - if ( use_nguardrail ) then + end if if_bgc_vegp3 + + if ( use_nguardrail .and. num_bgc_vegp>0 ) then call t_startf('CNPrecisionControl') - call CNPrecisionControl(bounds, num_soilp, filter_soilp, & + call CNPrecisionControl(bounds, num_bgc_vegp, filter_bgc_vegp, & cnveg_carbonstate_inst, c13_cnveg_carbonstate_inst, & c14_cnveg_carbonstate_inst, cnveg_nitrogenstate_inst) call t_stopf('CNPrecisionControl') @@ -966,7 +1017,7 @@ end subroutine CNDriverNoLeaching !----------------------------------------------------------------------- subroutine CNDriverLeaching(bounds, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & num_actfirec, filter_actfirec, num_actfirep, filter_actfirep,& waterstatebulk_inst, waterfluxbulk_inst, & soilstate_inst, cnveg_state_inst, & @@ -986,16 +1037,17 @@ subroutine CNDriverLeaching(bounds, & ! !USES: use SoilBiogeochemNLeachingMod, only: SoilBiogeochemNLeaching use CNNStateUpdate3Mod , only: NStateUpdate3 - use clm_time_manager , only : is_first_step_of_this_run_segment,is_beg_curr_year,is_end_curr_year,get_curr_date - use CNSharedParamsMod , only : use_matrixcn + use CNNStateUpdate3Mod , only: NStateUpdateLeaching + use clm_time_manager , only: is_first_step_of_this_run_segment,is_beg_curr_year,is_end_curr_year,get_curr_date + use CNSharedParamsMod , only: use_matrixcn use SoilBiogeochemDecompCascadeConType , only : use_soil_matrixcn ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_vegp ! number of soil patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for soil patches integer , intent(in) :: num_actfirec ! number of soil columns on fire in filter integer , intent(in) :: filter_actfirec(:) ! filter for soil columns on fire integer , intent(in) :: num_actfirep ! number of soil patches on fire in filter @@ -1027,21 +1079,26 @@ subroutine CNDriverLeaching(bounds, & ! Mineral nitrogen dynamics (deposition, fixation, leaching) call t_startf('SoilBiogeochemNLeaching') - call SoilBiogeochemNLeaching(bounds, num_soilc, filter_soilc, & + call SoilBiogeochemNLeaching(bounds, num_bgc_soilc, filter_bgc_soilc, & waterstatebulk_inst, waterfluxbulk_inst, soilbiogeochem_nitrogenstate_inst, & soilbiogeochem_nitrogenflux_inst) - call t_stopf('SoilBiogeochemNLeaching') - - ! Nitrogen state variable update, mortality fluxes. - - call t_startf('NUpdate3') - - call NStateUpdate3(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, & + call NStateUpdateLeaching(num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst) + call t_stopf('SoilBiogeochemNLeaching') - call t_stopf('NUpdate3') + + + + ! Nitrogen state variable update, mortality fluxes. + if(num_bgc_vegp>0)then + call t_startf('NUpdate3') + call NStateUpdate3(num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, & + soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst) + call t_stopf('NUpdate3') + end if + !-------------------------------------------------------------------------- ! Solve the matrix solution and do the state update for matrix solution as ! part of that @@ -1063,7 +1120,7 @@ end subroutine CNDriverLeaching !----------------------------------------------------------------------- subroutine CNDriverSummarizeStates(bounds, num_allc, filter_allc, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & cnveg_carbonstate_inst, c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & cnveg_nitrogenstate_inst, & soilbiogeochem_carbonstate_inst, & @@ -1080,10 +1137,10 @@ subroutine CNDriverSummarizeStates(bounds, num_allc, filter_allc, & type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_allc ! number of columns in allc filter integer , intent(in) :: filter_allc(:) ! filter for all active columns - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_vegp ! number of soil patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for soil patches type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst type(cnveg_carbonstate_type) , intent(inout) :: c13_cnveg_carbonstate_inst type(cnveg_carbonstate_type) , intent(inout) :: c14_cnveg_carbonstate_inst @@ -1104,53 +1161,46 @@ subroutine CNDriverSummarizeStates(bounds, num_allc, filter_allc, & call t_startf('CNsum') ! ---------------------------------------------- - ! soilbiogeochem carbon/nitrogen state summary + ! cnveg carbon/nitrogen state summary ! ---------------------------------------------- + call cnveg_carbonstate_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp) - call soilbiogeochem_carbonstate_inst%summary(bounds, num_allc, filter_allc) if ( use_c13 ) then - call c13_soilbiogeochem_carbonstate_inst%summary(bounds, num_allc, filter_allc) + call c13_cnveg_carbonstate_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp) end if + if ( use_c14 ) then - call c14_soilbiogeochem_carbonstate_inst%summary(bounds, num_allc, filter_allc) + call c14_cnveg_carbonstate_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp) end if - call soilbiogeochem_nitrogenstate_inst%summary(bounds, num_allc, filter_allc) ! ---------------------------------------------- - ! cnveg carbon/nitrogen state summary + ! soilbiogeochem carbon/nitrogen state summary + ! RGK 02-23: soilbiogeochem summary now depends on + ! cnveg summary, swapped call order ! ---------------------------------------------- - call cnveg_carbonstate_inst%Summary(bounds, num_allc, filter_allc, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_cwdc_col=soilbiogeochem_carbonstate_inst%cwdc_col(begc:endc), & - soilbiogeochem_totlitc_col=soilbiogeochem_carbonstate_inst%totlitc_col(begc:endc), & - soilbiogeochem_totmicc_col=soilbiogeochem_carbonstate_inst%totmicc_col(begc:endc), & - soilbiogeochem_totsomc_col=soilbiogeochem_carbonstate_inst%totsomc_col(begc:endc), & - soilbiogeochem_ctrunc_col=soilbiogeochem_carbonstate_inst%ctrunc_col(begc:endc)) - + call soilbiogeochem_carbonstate_inst%summary(bounds, num_allc, filter_allc, & + num_bgc_soilc, filter_bgc_soilc, cnveg_carbonstate_inst) if ( use_c13 ) then - call c13_cnveg_carbonstate_inst%Summary(bounds, num_allc, filter_allc, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_cwdc_col=c13_soilbiogeochem_carbonstate_inst%cwdc_col(begc:endc), & - soilbiogeochem_totlitc_col=c13_soilbiogeochem_carbonstate_inst%totlitc_col(begc:endc), & - soilbiogeochem_totmicc_col=c13_soilbiogeochem_carbonstate_inst%totmicc_col(begc:endc), & - soilbiogeochem_totsomc_col=c13_soilbiogeochem_carbonstate_inst%totsomc_col(begc:endc), & - soilbiogeochem_ctrunc_col=c13_soilbiogeochem_carbonstate_inst%ctrunc_col(begc:endc)) + call c13_soilbiogeochem_carbonstate_inst%summary(bounds, num_allc, filter_allc, & + num_bgc_soilc, filter_bgc_soilc, c13_cnveg_carbonstate_inst) end if - if ( use_c14 ) then - call c14_cnveg_carbonstate_inst%Summary(bounds, num_allc, filter_allc, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_cwdc_col=c14_soilbiogeochem_carbonstate_inst%cwdc_col(begc:endc), & - soilbiogeochem_totlitc_col=c14_soilbiogeochem_carbonstate_inst%totlitc_col(begc:endc), & - soilbiogeochem_totmicc_col=c14_soilbiogeochem_carbonstate_inst%totmicc_col(begc:endc), & - soilbiogeochem_totsomc_col=c14_soilbiogeochem_carbonstate_inst%totsomc_col(begc:endc), & - soilbiogeochem_ctrunc_col=c14_soilbiogeochem_carbonstate_inst%ctrunc_col(begc:endc)) + call c14_soilbiogeochem_carbonstate_inst%summary(bounds, num_allc, filter_allc, & + num_bgc_soilc, filter_bgc_soilc, c14_cnveg_carbonstate_inst) end if + + + ! RGK 02-23: This call will be moved to after cnveg nitr summary when we + ! couple in FATES N + - call cnveg_nitrogenstate_inst%Summary(bounds, num_allc, filter_allc, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_nitrogenstate_inst) + call cnveg_nitrogenstate_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp) + + call soilbiogeochem_nitrogenstate_inst%summary(bounds, num_allc, filter_allc, & + num_bgc_soilc, filter_bgc_soilc, cnveg_nitrogenstate_inst) + call t_stopf('CNsum') @@ -1158,7 +1208,7 @@ end subroutine CNDriverSummarizeStates !----------------------------------------------------------------------- subroutine CNDriverSummarizeFluxes(bounds, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & cnveg_carbonflux_inst, c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & cnveg_nitrogenflux_inst, & c_products_inst, c13_products_inst, c14_products_inst, & @@ -1179,10 +1229,10 @@ subroutine CNDriverSummarizeFluxes(bounds, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_vegp ! number of soil patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for soil patches type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst type(cnveg_carbonflux_type) , intent(inout) :: c13_cnveg_carbonflux_inst type(cnveg_carbonflux_type) , intent(inout) :: c14_cnveg_carbonflux_inst @@ -1217,72 +1267,74 @@ subroutine CNDriverSummarizeFluxes(bounds, & ! soilbiogeochem carbon/nitrogen flux summary ! ---------------------------------------------- - call soilbiogeochem_carbonflux_inst%Summary(bounds, num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + call soilbiogeochem_carbonflux_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & soilbiogeochem_carbonflux_inst%decomp_cascade_ctransfer_col(begc:endc,1:ndecomp_cascade_transitions), & soilbiogeochem_carbonstate_inst%cwdc_col(begc:endc), & soilbiogeochem_nitrogenstate_inst%cwdn_col(begc:endc), & - leafc_to_litter_patch=cnveg_carbonflux_inst%leafc_to_litter_patch(begp:endp), & - frootc_to_litter_patch=cnveg_carbonflux_inst%frootc_to_litter_patch(begp:endp)) + leafc_to_litter_patch=cnveg_carbonflux_inst%leafc_to_litter_patch, & + frootc_to_litter_patch=cnveg_carbonflux_inst%frootc_to_litter_patch) if ( use_c13 ) then - call c13_soilbiogeochem_carbonflux_inst%Summary(bounds, num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + call c13_soilbiogeochem_carbonflux_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & c13_soilbiogeochem_carbonflux_inst%decomp_cascade_ctransfer_col(begc:endc,1:ndecomp_cascade_transitions), & c13_soilbiogeochem_carbonstate_inst%cwdc_col(begc:endc), & soilbiogeochem_nitrogenstate_inst%cwdn_col(begc:endc), & - leafc_to_litter_patch=c13_cnveg_carbonflux_inst%leafc_to_litter_patch(begp:endp), & - frootc_to_litter_patch=c13_cnveg_carbonflux_inst%frootc_to_litter_patch(begp:endp)) + leafc_to_litter_patch=c13_cnveg_carbonflux_inst%leafc_to_litter_patch, & + frootc_to_litter_patch=c13_cnveg_carbonflux_inst%frootc_to_litter_patch) end if if ( use_c14 ) then - call c14_soilbiogeochem_carbonflux_inst%Summary(bounds, num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + call c14_soilbiogeochem_carbonflux_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & c14_soilbiogeochem_carbonflux_inst%decomp_cascade_ctransfer_col(begc:endc,1:ndecomp_cascade_transitions), & c14_soilbiogeochem_carbonstate_inst%cwdc_col(begc:endc), & soilbiogeochem_nitrogenstate_inst%cwdn_col(begc:endc), & - leafc_to_litter_patch=c14_cnveg_carbonflux_inst%leafc_to_litter_patch(begp:endp), & - frootc_to_litter_patch=c14_cnveg_carbonflux_inst%frootc_to_litter_patch(begp:endp)) + leafc_to_litter_patch=c14_cnveg_carbonflux_inst%leafc_to_litter_patch, & + frootc_to_litter_patch=c14_cnveg_carbonflux_inst%frootc_to_litter_patch) end if - call soilbiogeochem_nitrogenflux_inst%Summary(bounds, num_soilc, filter_soilc) + call soilbiogeochem_nitrogenflux_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc) ! ---------------------------------------------- ! cnveg carbon/nitrogen flux summary ! ---------------------------------------------- - call t_startf('CNvegCflux_summary') - call cnveg_carbonflux_inst%Summary(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & - isotope='bulk', & - soilbiogeochem_hr_col=soilbiogeochem_carbonflux_inst%hr_col(begc:endc), & - soilbiogeochem_cwdhr_col=soilbiogeochem_carbonflux_inst%cwdhr_col(begc:endc), & - soilbiogeochem_lithr_col=soilbiogeochem_carbonflux_inst%lithr_col(begc:endc), & - soilbiogeochem_decomp_cascade_ctransfer_col=& - soilbiogeochem_carbonflux_inst%decomp_cascade_ctransfer_col(begc:endc,1:ndecomp_cascade_transitions), & - product_closs_grc=c_products_inst%product_loss_grc(begg:endg)) - - if ( use_c13 ) then - call c13_cnveg_carbonflux_inst%Summary(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & - isotope='c13', & - soilbiogeochem_hr_col=c13_soilbiogeochem_carbonflux_inst%hr_col(begc:endc), & - soilbiogeochem_cwdhr_col=c13_soilbiogeochem_carbonflux_inst%cwdhr_col(begc:endc), & - soilbiogeochem_lithr_col=c13_soilbiogeochem_carbonflux_inst%lithr_col(begc:endc), & - soilbiogeochem_decomp_cascade_ctransfer_col=& - c13_soilbiogeochem_carbonflux_inst%decomp_cascade_ctransfer_col(begc:endc,1:ndecomp_cascade_transitions), & - product_closs_grc=c13_products_inst%product_loss_grc(begg:endg)) - end if - - if ( use_c14 ) then - call c14_cnveg_carbonflux_inst%Summary(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & - isotope='c14', & - soilbiogeochem_hr_col=c14_soilbiogeochem_carbonflux_inst%hr_col(begc:endc), & - soilbiogeochem_cwdhr_col=c14_soilbiogeochem_carbonflux_inst%cwdhr_col(begc:endc), & - soilbiogeochem_lithr_col=c14_soilbiogeochem_carbonflux_inst%lithr_col(begc:endc), & + if_bgc_vegp: if(num_bgc_vegp>0) then + call t_startf('CNvegCflux_summary') + call cnveg_carbonflux_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + isotope='bulk', & + soilbiogeochem_hr_col=soilbiogeochem_carbonflux_inst%hr_col(begc:endc), & + soilbiogeochem_cwdhr_col=soilbiogeochem_carbonflux_inst%cwdhr_col(begc:endc), & + soilbiogeochem_lithr_col=soilbiogeochem_carbonflux_inst%lithr_col(begc:endc), & soilbiogeochem_decomp_cascade_ctransfer_col=& - c14_soilbiogeochem_carbonflux_inst%decomp_cascade_ctransfer_col(begc:endc,1:ndecomp_cascade_transitions), & - product_closs_grc=c14_products_inst%product_loss_grc(begg:endg)) - end if - call t_stopf('CNvegCflux_summary') - - call cnveg_nitrogenflux_inst%Summary(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp) + soilbiogeochem_carbonflux_inst%decomp_cascade_ctransfer_col(begc:endc,1:ndecomp_cascade_transitions), & + product_closs_grc=c_products_inst%product_loss_grc(begg:endg)) + + if ( use_c13 ) then + call c13_cnveg_carbonflux_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + isotope='c13', & + soilbiogeochem_hr_col=c13_soilbiogeochem_carbonflux_inst%hr_col(begc:endc), & + soilbiogeochem_cwdhr_col=c13_soilbiogeochem_carbonflux_inst%cwdhr_col(begc:endc), & + soilbiogeochem_lithr_col=c13_soilbiogeochem_carbonflux_inst%lithr_col(begc:endc), & + soilbiogeochem_decomp_cascade_ctransfer_col=& + c13_soilbiogeochem_carbonflux_inst%decomp_cascade_ctransfer_col(begc:endc,1:ndecomp_cascade_transitions), & + product_closs_grc=c13_products_inst%product_loss_grc(begg:endg)) + end if + + if ( use_c14 ) then + call c14_cnveg_carbonflux_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & + isotope='c14', & + soilbiogeochem_hr_col=c14_soilbiogeochem_carbonflux_inst%hr_col(begc:endc), & + soilbiogeochem_cwdhr_col=c14_soilbiogeochem_carbonflux_inst%cwdhr_col(begc:endc), & + soilbiogeochem_lithr_col=c14_soilbiogeochem_carbonflux_inst%lithr_col(begc:endc), & + soilbiogeochem_decomp_cascade_ctransfer_col=& + c14_soilbiogeochem_carbonflux_inst%decomp_cascade_ctransfer_col(begc:endc,1:ndecomp_cascade_transitions), & + product_closs_grc=c14_products_inst%product_loss_grc(begg:endg)) + end if + call t_stopf('CNvegCflux_summary') + call cnveg_nitrogenflux_inst%Summary(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp) + end if if_bgc_vegp + call t_stopf('CNsum') end subroutine CNDriverSummarizeFluxes diff --git a/src/biogeochem/CNFireEmissionsMod.F90 b/src/biogeochem/CNFireEmissionsMod.F90 index 645f074a7d..5a15e138d5 100644 --- a/src/biogeochem/CNFireEmissionsMod.F90 +++ b/src/biogeochem/CNFireEmissionsMod.F90 @@ -185,7 +185,7 @@ subroutine InitHistory(this, bounds) end subroutine InitHistory !----------------------------------------------------------------------- - subroutine CNFireEmisUpdate(bounds, num_soilp, filter_soilp, cnveg_cf_inst, cnveg_cs_inst, fireemis_inst ) + subroutine CNFireEmisUpdate(bounds, num_bgc_vegp, filter_bgc_vegp, cnveg_cf_inst, cnveg_cs_inst, fireemis_inst ) use CNVegcarbonfluxType, only : cnveg_carbonflux_type use CNVegCarbonStateType, only : cnveg_carbonstate_type @@ -194,8 +194,8 @@ subroutine CNFireEmisUpdate(bounds, num_soilp, filter_soilp, cnveg_cf_inst, cnve !ARGUMENTS: type(bounds_type), intent(in) :: bounds - integer, intent(in) :: num_soilp ! number of soil pfts in filter - integer, intent(in) :: filter_soilp(:) ! filter for soil pfts + integer, intent(in) :: num_bgc_vegp ! number of bgc veg patches + integer, intent(in) :: filter_bgc_vegp(:) ! filter for bgc veg patches type(cnveg_carbonflux_type), intent(in) :: cnveg_cf_inst type(cnveg_carbonstate_type),intent(in) :: cnveg_cs_inst type(fireemis_type), intent(inout) :: fireemis_inst @@ -235,8 +235,8 @@ subroutine CNFireEmisUpdate(bounds, num_soilp, filter_soilp, cnveg_cf_inst, cnve ! Begin loop over points !_______________________________________________________________________________ - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) g = patch%gridcell(p) c = patch%column(p) diff --git a/src/biogeochem/CNGapMortalityMod.F90 b/src/biogeochem/CNGapMortalityMod.F90 index 91c937f655..aa53317fb3 100644 --- a/src/biogeochem/CNGapMortalityMod.F90 +++ b/src/biogeochem/CNGapMortalityMod.F90 @@ -82,7 +82,7 @@ subroutine readParams ( ncid ) end subroutine readParams !----------------------------------------------------------------------- - subroutine CNGapMortality (bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & + subroutine CNGapMortality (bounds, num_soilp, filter_soilp, & dgvs_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst,& cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, canopystate_inst, & leaf_prof_patch, froot_prof_patch, croot_prof_patch, stem_prof_patch) @@ -99,8 +99,6 @@ subroutine CNGapMortality (bounds, num_soilc, filter_soilc, num_soilp, filter_so ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! column filter for soil points integer , intent(in) :: num_soilp ! number of soil patches in filter integer , intent(in) :: filter_soilp(:) ! patch filter for soil points type(dgvs_type) , intent(inout) :: dgvs_inst @@ -306,19 +304,19 @@ subroutine CNGapMortality (bounds, num_soilc, filter_soilc, num_soilp, filter_so ! gather all patch-level litterfall fluxes to the column ! for litter C and N inputs - call CNGap_PatchToColumn(bounds, num_soilc, filter_soilc, & + call CNGap_PatchToColumn(bounds, num_soilp, filter_soilp, & cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & leaf_prof_patch(bounds%begp:bounds%endp, 1:nlevdecomp_full), & froot_prof_patch(bounds%begp:bounds%endp, 1:nlevdecomp_full), & croot_prof_patch(bounds%begp:bounds%endp, 1:nlevdecomp_full), & stem_prof_patch(bounds%begp:bounds%endp, 1:nlevdecomp_full)) - + end associate end subroutine CNGapMortality !----------------------------------------------------------------------- - subroutine CNGap_PatchToColumn (bounds, num_soilc, filter_soilc, & + subroutine CNGap_PatchToColumn (bounds, num_soilp, filter_soilp, & cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & leaf_prof_patch, froot_prof_patch, croot_prof_patch, stem_prof_patch) ! @@ -331,8 +329,8 @@ subroutine CNGap_PatchToColumn (bounds, num_soilc, filter_soilc, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! soil column filter + integer , intent(in) :: num_soilp ! number of soil patches in filter + integer , intent(in) :: filter_soilp(:) ! soil patch filter type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst real(r8) , intent(in) :: leaf_prof_patch(bounds%begp:,1:) @@ -341,7 +339,7 @@ subroutine CNGap_PatchToColumn (bounds, num_soilc, filter_soilc, & real(r8) , intent(in) :: stem_prof_patch(bounds%begp:,1:) ! ! !LOCAL VARIABLES: - integer :: fc,c,pi,p,j,i ! indices + integer :: fp,c,p,j,i ! indices !----------------------------------------------------------------------- SHR_ASSERT_ALL_FL((ubound(leaf_prof_patch) == (/bounds%endp,nlevdecomp_full/)), sourcefile, __LINE__) @@ -408,84 +406,75 @@ subroutine CNGap_PatchToColumn (bounds, num_soilc, filter_soilc, & ) do j = 1,nlevdecomp - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) - - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - - if (patch%active(p)) then - - do i = i_litr_min, i_litr_max - gap_mortality_c_to_litr_c(c,j,i) = & - gap_mortality_c_to_litr_c(c,j,i) + & - ! leaf gap mortality carbon fluxes - m_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & - ! fine root gap mortality carbon fluxes - m_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) - end do - - ! wood gap mortality carbon fluxes - gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & - (m_livestemc_to_litter(p) + m_deadstemc_to_litter(p)) * wtcol(p) * stem_prof(p,j) - gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & - (m_livecrootc_to_litter(p) + m_deadcrootc_to_litter(p)) * wtcol(p) * croot_prof(p,j) - - ! storage gap mortality carbon fluxes - ! Metabolic litter is treated differently than other types - ! of litter, so it gets this additional line after the - ! most recent loop over all litter types - gap_mortality_c_to_litr_c(c,j,i_met_lit) = & - gap_mortality_c_to_litr_c(c,j,i_met_lit) + & - (m_leafc_storage_to_litter(p) + m_gresp_storage_to_litter(p)) * wtcol(p) * leaf_prof(p,j) + & - m_frootc_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - (m_livestemc_storage_to_litter(p) + m_deadstemc_storage_to_litter(p)) * wtcol(p) * stem_prof(p,j) + & - (m_livecrootc_storage_to_litter(p) + m_deadcrootc_storage_to_litter(p)) * wtcol(p) * croot_prof(p,j) + & - - ! transfer gap mortality carbon fluxes - (m_leafc_xfer_to_litter(p) + m_gresp_xfer_to_litter(p)) * wtcol(p) * leaf_prof(p,j) + & - m_frootc_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - (m_livestemc_xfer_to_litter(p) + m_deadstemc_xfer_to_litter(p)) * wtcol(p) * stem_prof(p,j) + & - (m_livecrootc_xfer_to_litter(p) + m_deadcrootc_xfer_to_litter(p)) * wtcol(p) * croot_prof(p,j) - - do i = i_litr_min, i_litr_max - gap_mortality_n_to_litr_n(c,j,i) = & - gap_mortality_n_to_litr_n(c,j,i) + & - ! leaf gap mortality nitrogen fluxes - m_leafn_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & - ! fine root litter nitrogen fluxes - m_frootn_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) - end do - - ! wood gap mortality nitrogen fluxes - gap_mortality_n_to_cwdn(c,j) = gap_mortality_n_to_cwdn(c,j) + & - (m_livestemn_to_litter(p) + m_deadstemn_to_litter(p)) * wtcol(p) * stem_prof(p,j) - gap_mortality_n_to_cwdn(c,j) = gap_mortality_n_to_cwdn(c,j) + & - (m_livecrootn_to_litter(p) + m_deadcrootn_to_litter(p)) * wtcol(p) * croot_prof(p,j) - - ! Metabolic litter is treated differently than other types - ! of litter, so it gets this additional line after the - ! most recent loop over all litter types - gap_mortality_n_to_litr_n(c,j,i_met_lit) = & - gap_mortality_n_to_litr_n(c,j,i_met_lit) + & - ! retranslocated N pool gap mortality fluxes - m_retransn_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - ! storage gap mortality nitrogen fluxes - m_leafn_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - m_frootn_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - (m_livestemn_storage_to_litter(p) + m_deadstemn_storage_to_litter(p)) * wtcol(p) * stem_prof(p,j) + & - (m_livecrootn_storage_to_litter(p) + m_deadcrootn_storage_to_litter(p)) * wtcol(p) * croot_prof(p,j) + & - ! transfer gap mortality nitrogen fluxes - m_leafn_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - m_frootn_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - (m_livestemn_xfer_to_litter(p) + m_deadstemn_xfer_to_litter(p)) * wtcol(p) * stem_prof(p,j) + & - (m_livecrootn_xfer_to_litter(p) + m_deadcrootn_xfer_to_litter(p)) * wtcol(p) * croot_prof(p,j) - - end if - end if + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) + + do i = i_litr_min, i_litr_max + gap_mortality_c_to_litr_c(c,j,i) = & + gap_mortality_c_to_litr_c(c,j,i) + & + ! leaf gap mortality carbon fluxes + m_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & + ! fine root gap mortality carbon fluxes + m_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) + end do + ! wood gap mortality carbon fluxes + gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & + (m_livestemc_to_litter(p) + m_deadstemc_to_litter(p)) * wtcol(p) * stem_prof(p,j) + gap_mortality_c_to_cwdc(c,j) = gap_mortality_c_to_cwdc(c,j) + & + (m_livecrootc_to_litter(p) + m_deadcrootc_to_litter(p)) * wtcol(p) * croot_prof(p,j) + + ! storage gap mortality carbon fluxes + ! Metabolic litter is treated differently than other types + ! of litter, so it gets this additional line after the + ! most recent loop over all litter types + gap_mortality_c_to_litr_c(c,j,i_met_lit) = & + gap_mortality_c_to_litr_c(c,j,i_met_lit) + & + (m_leafc_storage_to_litter(p) + m_gresp_storage_to_litter(p)) * wtcol(p) * leaf_prof(p,j) + & + m_frootc_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + (m_livestemc_storage_to_litter(p) + m_deadstemc_storage_to_litter(p)) * wtcol(p) * stem_prof(p,j) + & + (m_livecrootc_storage_to_litter(p) + m_deadcrootc_storage_to_litter(p)) * wtcol(p) * croot_prof(p,j) + & + + ! transfer gap mortality carbon fluxes + (m_leafc_xfer_to_litter(p) + m_gresp_xfer_to_litter(p)) * wtcol(p) * leaf_prof(p,j) + & + m_frootc_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + (m_livestemc_xfer_to_litter(p) + m_deadstemc_xfer_to_litter(p)) * wtcol(p) * stem_prof(p,j) + & + (m_livecrootc_xfer_to_litter(p) + m_deadcrootc_xfer_to_litter(p)) * wtcol(p) * croot_prof(p,j) + + do i = i_litr_min, i_litr_max + gap_mortality_n_to_litr_n(c,j,i) = & + gap_mortality_n_to_litr_n(c,j,i) + & + ! leaf gap mortality nitrogen fluxes + m_leafn_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & + ! fine root litter nitrogen fluxes + m_frootn_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) end do + + ! wood gap mortality nitrogen fluxes + gap_mortality_n_to_cwdn(c,j) = gap_mortality_n_to_cwdn(c,j) + & + (m_livestemn_to_litter(p) + m_deadstemn_to_litter(p)) * wtcol(p) * stem_prof(p,j) + gap_mortality_n_to_cwdn(c,j) = gap_mortality_n_to_cwdn(c,j) + & + (m_livecrootn_to_litter(p) + m_deadcrootn_to_litter(p)) * wtcol(p) * croot_prof(p,j) + + ! Metabolic litter is treated differently than other types + ! of litter, so it gets this additional line after the + ! most recent loop over all litter types + gap_mortality_n_to_litr_n(c,j,i_met_lit) = & + gap_mortality_n_to_litr_n(c,j,i_met_lit) + & + ! retranslocated N pool gap mortality fluxes + m_retransn_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + ! storage gap mortality nitrogen fluxes + m_leafn_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + m_frootn_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + (m_livestemn_storage_to_litter(p) + m_deadstemn_storage_to_litter(p)) * wtcol(p) * stem_prof(p,j) + & + (m_livecrootn_storage_to_litter(p) + m_deadcrootn_storage_to_litter(p)) * wtcol(p) * croot_prof(p,j) + & + ! transfer gap mortality nitrogen fluxes + m_leafn_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + m_frootn_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + (m_livestemn_xfer_to_litter(p) + m_deadstemn_xfer_to_litter(p)) * wtcol(p) * stem_prof(p,j) + & + (m_livecrootn_xfer_to_litter(p) + m_deadcrootn_xfer_to_litter(p)) * wtcol(p) * croot_prof(p,j) + end do end do diff --git a/src/biogeochem/CNNDynamicsMod.F90 b/src/biogeochem/CNNDynamicsMod.F90 index a658a63768..10c0f5ea38 100644 --- a/src/biogeochem/CNNDynamicsMod.F90 +++ b/src/biogeochem/CNNDynamicsMod.F90 @@ -25,6 +25,7 @@ module CNNDynamicsMod use ColumnType , only : col use PatchType , only : patch use perf_mod , only : t_startf, t_stopf + use CLMFatesInterfaceMod , only : hlm_fates_interface_type ! implicit none private @@ -192,7 +193,8 @@ end subroutine CNFreeLivingFixation !----------------------------------------------------------------------- subroutine CNNFixation(num_soilc, filter_soilc, & - cnveg_carbonflux_inst, soilbiogeochem_nitrogenflux_inst) + cnveg_carbonflux_inst, soilbiogeochem_nitrogenflux_inst, & + clm_fates, clump_index) ! ! !DESCRIPTION: ! On the radiation time step, update the nitrogen fixation rate @@ -209,12 +211,15 @@ subroutine CNNFixation(num_soilc, filter_soilc, & integer , intent(in) :: num_soilc ! number of soil columns in filter integer , intent(in) :: filter_soilc(:) ! filter for soil columns type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst - type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst + type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst + type(hlm_fates_interface_type) , intent(inout) :: clm_fates + integer , intent(in) :: clump_index ! ! !LOCAL VARIABLES: - integer :: c,fc ! indices + integer :: c,fc,s ! indices real(r8) :: t ! temporary real(r8) :: dayspyr ! days per year + real(r8) :: npp ! lag or smoothed net primary productivity (gC/m2/s) !----------------------------------------------------------------------- associate( & @@ -225,16 +230,26 @@ subroutine CNNFixation(num_soilc, filter_soilc, & ) dayspyr = get_curr_days_per_year() - if ( nfix_timeconst > 0._r8 .and. nfix_timeconst < 500._r8 ) then ! use exponential relaxation with time constant nfix_timeconst for NPP - NFIX relation ! Loop through columns do fc = 1,num_soilc c = filter_soilc(fc) - if (col_lag_npp(c) /= spval) then + if(col%is_fates(c))then + s = clm_fates%f2hmap(clump_index)%hsites(c) + ! %ema_npp is Smoothed [gc/m2/yr] + !npp = clm_fates%fates(clump_index)%bc_out(s)%ema_npp/(dayspyr*secspday) + ! FATES N cycling is not yet active, so runs are supplemented anyway + ! this will be added when FATES N cycling is completed. + npp = 0._r8 + else + npp = col_lag_npp(c) + end if + + if (npp /= spval) then ! need to put npp in units of gC/m^2/year here first - t = (1.8_r8 * (1._r8 - exp(-0.003_r8 * col_lag_npp(c)*(secspday * dayspyr))))/(secspday * dayspyr) + t = (1.8_r8 * (1._r8 - exp(-0.003_r8 * npp *(secspday * dayspyr))))/(secspday * dayspyr) nfix_to_sminn(c) = max(0._r8,t) else nfix_to_sminn(c) = 0._r8 @@ -245,7 +260,16 @@ subroutine CNNFixation(num_soilc, filter_soilc, & do fc = 1,num_soilc c = filter_soilc(fc) - t = (1.8_r8 * (1._r8 - exp(-0.003_r8 * cannsum_npp(c))))/(secspday * dayspyr) + if(col%is_fates(c))then + s = clm_fates%f2hmap(clump_index)%hsites(c) + !npp = clm_fates%fates(clump_index)%bc_out(s)%ema_npp + ! See above regarding FATES and N fixation + npp = 0._r8 + else + npp = cannsum_npp(c) + end if + + t = (1.8_r8 * (1._r8 - exp(-0.003_r8 * npp)))/(secspday * dayspyr) nfix_to_sminn(c) = max(0._r8,t) end do endif diff --git a/src/biogeochem/CNNStateUpdate1Mod.F90 b/src/biogeochem/CNNStateUpdate1Mod.F90 index c99729b2ee..5358c46de1 100644 --- a/src/biogeochem/CNNStateUpdate1Mod.F90 +++ b/src/biogeochem/CNNStateUpdate1Mod.F90 @@ -23,7 +23,10 @@ module CNNStateUpdate1Mod use SoilBiogeochemNitrogenFluxType , only : soilbiogeochem_nitrogenflux_type use SoilBiogeochemNitrogenStateType , only : soilbiogeochem_nitrogenstate_type use CropReprPoolsMod , only : nrepr, repr_grain_min, repr_grain_max, repr_structure_min, repr_structure_max - use PatchType , only : patch + use PatchType , only : patch + use CLMFatesInterfaceMod , only : hlm_fates_interface_type + use ColumnType , only : col + ! implicit none private @@ -96,7 +99,9 @@ end subroutine NStateUpdateDynPatch !----------------------------------------------------------------------- subroutine NStateUpdate1(num_soilc, filter_soilc, num_soilp, filter_soilp, & - cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) + cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst, & + clm_fates, clump_index) + use CNSharedParamsMod , only : use_fun ! ! !DESCRIPTION: @@ -111,6 +116,9 @@ subroutine NStateUpdate1(num_soilc, filter_soilc, num_soilp, filter_soilp, & type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst type(cnveg_nitrogenstate_type) , intent(inout) :: cnveg_nitrogenstate_inst type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst + type(hlm_fates_interface_type) , intent(inout) :: clm_fates + integer , intent(in) :: clump_index + ! ! !LOCAL VARIABLES: integer :: c,p,j,l,g,k,i ! indices @@ -134,9 +142,23 @@ subroutine NStateUpdate1(num_soilc, filter_soilc, num_soilp, filter_soilp, & ! soilbiogeochemistry fluxes TODO - this should be moved elsewhere ! plant to litter fluxes - phenology and dynamic landcover fluxes - do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + + fc_loop: do fc = 1,num_soilc + c = filter_soilc(fc) + + fates_if: if( col%is_fates(c) ) then + + ! If this is a fates column, then we ask fates for the + ! litter fluxes, the following routine simply copies + ! prepared litter c flux boundary conditions into + ! cf_soil%decomp_cpools_sourcesink_col + + call clm_fates%UpdateNLitterfluxes(nf_soil,clump_index,c) + + else + + do j = 1, nlevdecomp + ! ! State update without the matrix solution ! @@ -151,19 +173,20 @@ subroutine NStateUpdate1(num_soilc, filter_soilc, num_soilp, filter_soilp, & ! time step, but to be safe, I'm explicitly setting it to zero here. nf_soil%decomp_npools_sourcesink_col(c,j,i_cwd) = 0._r8 - ! - ! For the matrix solution the actual state update comes after the matrix - ! multiply in SoilMatrix, but the matrix needs to be setup with - ! the equivalent of above. Those changes can be here or in the - ! native subroutines dealing with that field - ! + ! + ! For the matrix solution the actual state update comes after the matrix + ! multiply in SoilMatrix, but the matrix needs to be setup with + ! the equivalent of above. Those changes can be here or in the + ! native subroutines dealing with that field + ! else ! Do the above to the matrix solution do i = i_litr_min, i_litr_max end do end if end do - end do + end if fates_if + end do fc_loop do fp = 1,num_soilp p = filter_soilp(fp) diff --git a/src/biogeochem/CNNStateUpdate3Mod.F90 b/src/biogeochem/CNNStateUpdate3Mod.F90 index b5e3f32fec..26902cef22 100644 --- a/src/biogeochem/CNNStateUpdate3Mod.F90 +++ b/src/biogeochem/CNNStateUpdate3Mod.F90 @@ -25,11 +25,63 @@ module CNNStateUpdate3Mod private ! ! !PUBLIC MEMBER FUNCTIONS: - public:: NStateUpdate3 + public :: NStateUpdate3 + public :: NStateUpdateLeaching !----------------------------------------------------------------------- contains + subroutine NStateUpdateLeaching(num_soilc, filter_soilc, & + soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst) + ! + ! !DESCRIPTION: + ! On the radiation time step, update all the prognostic nitrogen state + ! variables affected by the Sminn leaching flux. + ! RGK: This code was separated from gap mortality fluxes to make this + ! compatible with FATES. + ! + ! !ARGUMENTS: + integer , intent(in) :: num_soilc ! number of soil columns in filter + integer , intent(in) :: filter_soilc(:) ! filter for soil columns + type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst + type(soilbiogeochem_nitrogenstate_type) , intent(inout) :: soilbiogeochem_nitrogenstate_inst + + ! !LOCAL VARIABLES: + integer :: c,p,j,l,k ! indices + integer :: fp,fc ! lake filter indices + real(r8):: dt ! radiation time step (seconds) + !----------------------------------------------------------------------- + + associate( & + nf_soil => soilbiogeochem_nitrogenflux_inst , & ! Input + ns_soil => soilbiogeochem_nitrogenstate_inst & ! Output + ) + + ! set time steps + dt = get_step_size_real() + + do j = 1, nlevdecomp + ! column loop + do fc = 1,num_soilc + c = filter_soilc(fc) + + if (.not. use_nitrif_denitrif) then + ! mineral N loss due to leaching + ns_soil%sminn_vr_col(c,j) = ns_soil%sminn_vr_col(c,j) - nf_soil%sminn_leached_vr_col(c,j) * dt + else + ! mineral N loss due to leaching and runoff + ns_soil%smin_no3_vr_col(c,j) = max( ns_soil%smin_no3_vr_col(c,j) - & + ( nf_soil%smin_no3_leached_vr_col(c,j) + nf_soil%smin_no3_runoff_vr_col(c,j) ) * dt, 0._r8) + + ns_soil%sminn_vr_col(c,j) = ns_soil%smin_no3_vr_col(c,j) + ns_soil%smin_nh4_vr_col(c,j) + end if + end do + end do + + end associate + return + end subroutine NStateUpdateLeaching + !----------------------------------------------------------------------- subroutine NStateUpdate3(num_soilc, filter_soilc, num_soilp, filter_soilp, & cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, & @@ -37,7 +89,7 @@ subroutine NStateUpdate3(num_soilc, filter_soilc, num_soilp, filter_soilp, & ! ! !DESCRIPTION: ! On the radiation time step, update all the prognostic nitrogen state - ! variables affected by gap-phase mortality fluxes. Also the Sminn leaching flux. + ! variables affected by gap-phase mortality fluxes. ! NOTE - associate statements have been removed where there are ! no science equations. This increases readability and maintainability. ! @@ -72,20 +124,8 @@ subroutine NStateUpdate3(num_soilc, filter_soilc, num_soilp, filter_soilp, & do fc = 1,num_soilc c = filter_soilc(fc) - if (.not. use_nitrif_denitrif) then - ! mineral N loss due to leaching - ns_soil%sminn_vr_col(c,j) = ns_soil%sminn_vr_col(c,j) - nf_soil%sminn_leached_vr_col(c,j) * dt - else - ! mineral N loss due to leaching and runoff - ns_soil%smin_no3_vr_col(c,j) = max( ns_soil%smin_no3_vr_col(c,j) - & - ( nf_soil%smin_no3_leached_vr_col(c,j) + nf_soil%smin_no3_runoff_vr_col(c,j) ) * dt, 0._r8) - - ns_soil%sminn_vr_col(c,j) = ns_soil%smin_no3_vr_col(c,j) + ns_soil%smin_nh4_vr_col(c,j) - end if - ! column level nitrogen fluxes from fire ! patch-level wood to column-level CWD (uncombusted wood) - ! ! State update without the matrix solution ! diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index ec04fcbf54..7044cdc402 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -135,6 +135,10 @@ module CNPhenologyMod real(r8), private :: initial_seed_at_planting = 3._r8 ! Initial seed at planting + real(r8) :: min_gddmaturity = 1._r8 ! Weird things can happen if gddmaturity is tiny + logical, public :: generate_crop_gdds = .false. ! If true, harvest the day before next sowing + logical, public :: use_mxmat = .true. ! If true, ignore crop maximum growing season length + ! Constants for seasonal decidious leaf onset and offset logical, private :: onset_thresh_depends_on_veg = .false. ! If onset threshold depends on vegetation type integer, public, parameter :: critical_daylight_constant = 1 @@ -145,6 +149,14 @@ module CNPhenologyMod ! For determining leaf offset latitude that's considered high latitude (see Eitel 2019) real(r8), parameter :: critical_offset_high_lat = 65._r8 ! Start of what's considered high latitude (degrees) + real(r8), parameter :: HARVEST_REASON_MATURE = 1._r8 + real(r8), parameter :: HARVEST_REASON_MAXSEASLENGTH = 2._r8 + real(r8), parameter :: HARVEST_REASON_SOWNBADDEC31 = 3._r8 + real(r8), parameter :: HARVEST_REASON_SOWTODAY = 4._r8 + real(r8), parameter :: HARVEST_REASON_SOWTOMORROW = 5._r8 + real(r8), parameter :: HARVEST_REASON_IDOPTOMORROW = 6._r8 + real(r8), parameter :: HARVEST_REASON_VERNFREEZEKILL = 7._r8 + character(len=*), parameter, private :: sourcefile = & __FILE__ !----------------------------------------------------------------------- @@ -176,7 +188,8 @@ subroutine CNPhenologyReadNML( NLFilename ) character(len=*), parameter :: nmlname = 'cnphenology' !----------------------------------------------------------------------- namelist /cnphenology/ initial_seed_at_planting, onset_thresh_depends_on_veg, & - min_critical_dayl_method + min_critical_dayl_method, generate_crop_gdds, & + use_mxmat ! Initialize options to default values, in case they are not specified in ! the namelist @@ -200,6 +213,8 @@ subroutine CNPhenologyReadNML( NLFilename ) call shr_mpi_bcast (initial_seed_at_planting, mpicom) call shr_mpi_bcast (onset_thresh_depends_on_veg, mpicom) call shr_mpi_bcast (min_critical_dayl_method, mpicom) + call shr_mpi_bcast (generate_crop_gdds, mpicom) + call shr_mpi_bcast (use_mxmat, mpicom) if ( min_critical_dayl_method == "DependsOnLat" )then critical_daylight_method = critical_daylight_depends_on_lat @@ -393,7 +408,8 @@ subroutine CNPhenology (bounds, num_soilc, filter_soilc, num_soilp, & cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) call CNOffsetLitterfall(num_soilp, filter_soilp, & - cnveg_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) + cnveg_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & + crop_inst) call CNBackgroundLitterfall(num_soilp, filter_soilp, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) @@ -406,7 +422,7 @@ subroutine CNPhenology (bounds, num_soilc, filter_soilc, num_soilp, & ! gather all patch-level litterfall fluxes to the column for litter C and N inputs - call CNLitterToColumn(bounds, num_soilc, filter_soilc, & + call CNLitterToColumn(bounds, num_soilp, filter_soilp, & cnveg_state_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & leaf_prof_patch(bounds%begp:bounds%endp,1:nlevdecomp_full), & froot_prof_patch(bounds%begp:bounds%endp,1:nlevdecomp_full)) @@ -425,7 +441,7 @@ subroutine CNPhenologyInit(bounds) ! ! !USES: use clm_time_manager, only: get_step_size_real - use clm_varctl , only: use_crop + use clm_varctl , only: use_crop, use_cropcal_rx_sdates use clm_varcon , only: secspday ! ! !ARGUMENTS: @@ -534,7 +550,7 @@ subroutine CNPhenologyClimate (num_soilp, filter_soilp, num_pcropp, filter_pcrop ! ! !LOCAL VARIABLES: integer :: p ! indices - integer :: fp ! lake filter patch index + integer :: fp ! filter patch index real(r8) :: dayspyr ! days per year (days) integer :: kyr ! current year integer :: kmo ! month of year (1, ..., 12) @@ -631,7 +647,7 @@ subroutine CNEvergreenPhenology (num_soilp, filter_soilp , & ! !LOCAL VARIABLES: real(r8):: avg_dayspyr ! Average days per year integer :: p ! indices - integer :: fp ! lake filter patch index + integer :: fp ! filter patch index real(r8):: tranr real(r8):: t1 ! temporary variable @@ -816,7 +832,7 @@ subroutine CNSeasonDecidPhenology (num_soilp, filter_soilp , & ! ! !LOCAL VARIABLES: integer :: g,c,p !indices - integer :: fp !lake filter patch index + integer :: fp !filter patch index real(r8):: ws_flag !winter-summer solstice flag (0 or 1) real(r8):: crit_onset_gdd !critical onset growing degree-day sum real(r8):: crit_daylat !latitudinal light gradient in arctic-boreal @@ -1272,7 +1288,7 @@ subroutine CNStressDecidPhenology (num_soilp, filter_soilp , & ! !LOCAL VARIABLES: real(r8),parameter :: secspqtrday = secspday / 4 ! seconds per quarter day integer :: g,c,p ! indices - integer :: fp ! lake filter patch index + integer :: fp ! filter patch index real(r8):: avg_dayspyr ! average days per year real(r8):: crit_onset_gdd ! degree days for onset trigger real(r8):: soilt ! temperature of top soil layer @@ -1709,6 +1725,8 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & ! !USES: use clm_time_manager , only : get_prev_calday, get_curr_days_per_year, is_beg_curr_year use clm_time_manager , only : get_average_days_per_year + use clm_time_manager , only : get_prev_date + use clm_time_manager , only : is_doy_in_interval use pftconMod , only : ntmp_corn, nswheat, nwwheat, ntmp_soybean use pftconMod , only : nirrig_tmp_corn, nirrig_swheat, nirrig_wwheat, nirrig_tmp_soybean use pftconMod , only : ntrp_corn, nsugarcane, ntrp_soybean, ncotton, nrice @@ -1720,6 +1738,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & use clm_varctl , only : use_fertilizer use clm_varctl , only : use_c13, use_c14 use clm_varcon , only : c13ratio, c14ratio + use clm_varctl , only : use_cropcal_rx_sdates, use_cropcal_rx_cultivar_gdds, use_cropcal_streams ! ! !ARGUMENTS: integer , intent(in) :: num_pcropp ! number of prog crop patches in filter @@ -1743,26 +1762,43 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & integer g ! gridcell indices integer h ! hemisphere indices integer s ! growing season indices + integer k ! grain pool indices integer idpp ! number of days past planting + integer mxmat ! maximum growing season length + integer kyr ! current year + integer kmo ! month of year (1, ..., 12) + integer kda ! day of month (1, ..., 31) + integer mcsec ! seconds of day (0, ..., seconds/day) + real(r8) harvest_reason real(r8) dayspyr ! days per year in this year real(r8) avg_dayspyr ! average number of days per year real(r8) crmcorn ! comparitive relative maturity for corn real(r8) ndays_on ! number of days to fertilize + logical is_in_sowing_window ! is the crop in its sowing window? + logical is_end_sowing_window ! is it the last day of the crop's sowing window? + logical sowing_gdd_requirement_met ! has the gridcell historically been warm enough to support the crop? logical do_plant_normal ! are the normal planting rules defined and satisfied? logical do_plant_lastchance ! if not the above, what about relaxed rules for the last day of the planting window? + logical do_plant_prescribed ! is today the prescribed sowing date? + logical do_plant ! are we planting in this time step for any reason? + logical did_plant ! did we plant the crop in this time step? + logical allow_unprescribed_planting ! should crop be allowed to be planted according to sowing window rules? + logical do_harvest ! Are harvest conditions satisfied? + logical fake_harvest ! Dealing with incorrect Dec. 31 planting + logical did_plant_prescribed_today ! Was the crop sown today? + logical will_plant_prescribed_tomorrow ! Is tomorrow a prescribed sowing day? + logical vernalization_forces_harvest ! Was the crop killed by freezing during vernalization? !------------------------------------------------------------------------ associate( & ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type - leaf_long => pftcon%leaf_long , & ! Input: leaf longevity (yrs) + leaf_long => pftcon%leaf_long , & ! Input: leaf longevity (yrs) leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN) manunitro => pftcon%manunitro , & ! Input: max manure to be applied in total (kgN/m2) - mxmat => pftcon%mxmat , & ! Input: minplanttemp => pftcon%minplanttemp , & ! Input: planttemp => pftcon%planttemp , & ! Input: gddmin => pftcon%gddmin , & ! Input: - hybgdd => pftcon%hybgdd , & ! Input: lfemerg => pftcon%lfemerg , & ! Input: grnfill => pftcon%grnfill , & ! Input: @@ -1772,7 +1808,6 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & a10tmin => temperature_inst%t_a10min_patch , & ! Input: [real(r8) (:) ] 10-day running mean of min 2-m temperature gdd020 => temperature_inst%gdd020_patch , & ! Input: [real(r8) (:) ] 20 yr mean of gdd0 gdd820 => temperature_inst%gdd820_patch , & ! Input: [real(r8) (:) ] 20 yr mean of gdd8 - gdd1020 => temperature_inst%gdd1020_patch , & ! Input: [real(r8) (:) ] 20 yr mean of gdd10 fertnitro => crop_inst%fertnitro_patch , & ! Input: [real(r8) (:) ] fertilizer nitrogen hui => crop_inst%hui_patch , & ! Input: [real(r8) (:) ] crop patch heat unit index (growing degree-days); set to 0 at sowing and accumulated until harvest @@ -1780,12 +1815,14 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & harvdate => crop_inst%harvdate_patch , & ! Output: [integer (:) ] harvest date croplive => crop_inst%croplive_patch , & ! Output: [logical (:) ] Flag, true if planted, not harvested vf => crop_inst%vf_patch , & ! Output: [real(r8) (:) ] vernalization factor + next_rx_sdate => crop_inst%next_rx_sdate_patch , & ! Inout: [integer (:) ] prescribed sowing date of next growing season this year sowing_count => crop_inst%sowing_count , & ! Inout: [integer (:) ] number of sowing events this year for this patch harvest_count => crop_inst%harvest_count , & ! Inout: [integer (:) ] number of harvest events this year for this patch peaklai => cnveg_state_inst%peaklai_patch , & ! Output: [integer (:) ] 1: max allowed lai; 0: not at max tlai => canopystate_inst%tlai_patch , & ! Input: [real(r8) (:) ] one-sided leaf area index, no burying by snow - idop => cnveg_state_inst%idop_patch , & ! Output: [integer (:) ] date of planting + idop => cnveg_state_inst%idop_patch , & ! Output: [integer (:) ] date of planting (day of year) + iyop => cnveg_state_inst%iyop_patch , & ! Output: [integer (:) ] year of planting (day of year) gddmaturity => cnveg_state_inst%gddmaturity_patch , & ! Output: [real(r8) (:) ] gdd needed to harvest huileaf => cnveg_state_inst%huileaf_patch , & ! Output: [real(r8) (:) ] heat unit index needed from planting to leaf emergence huigrain => cnveg_state_inst%huigrain_patch , & ! Output: [real(r8) (:) ] same to reach vegetative maturity @@ -1814,6 +1851,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & dayspyr = get_curr_days_per_year() avg_dayspyr = get_average_days_per_year() jday = get_prev_calday() + call get_prev_date(kyr, kmo, kda, mcsec) if (use_fertilizer) then ndays_on = 20._r8 ! number of days to fertilize @@ -1833,6 +1871,9 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & bgtr(p) = 0._r8 lgsf(p) = 0._r8 + ! Should never be saved as zero, but including this so it's initialized just in case + harvest_reason = 0._r8 + ! --------------------------------- ! from AgroIBIS subroutine planting ! --------------------------------- @@ -1843,28 +1884,97 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & ! Second condition ensures everything is correctly set when resuming from a run with old code ! OR starting a run mid-year without any restart file OR handling a new crop column that just ! came into existence (and not at the year boundary for some reason). - if ( is_beg_curr_year() .or. crop_inst%sdates_thisyr(p,1) == spval ) then + if ( is_beg_curr_year() .or. crop_inst%sdates_thisyr_patch(p,1) == spval ) then sowing_count(p) = 0 harvest_count(p) = 0 do s = 1, mxsowings - crop_inst%sdates_thisyr(p,s) = -1._r8 + crop_inst%sdates_thisyr_patch(p,s) = -1._r8 + crop_inst%sowing_reason_thisyr_patch(p,s) = -1._r8 end do do s = 1, mxharvests - crop_inst%hdates_thisyr(p,s) = -1._r8 + crop_inst%sdates_perharv_patch(p,s) = -1._r8 + crop_inst%syears_perharv_patch(p,s) = -1._r8 + crop_inst%hdates_thisyr_patch(p,s) = -1._r8 + cnveg_state_inst%gddmaturity_thisyr(p,s) = -1._r8 + crop_inst%gddaccum_thisyr_patch(p,s) = -1._r8 + crop_inst%hui_thisyr_patch(p,s) = -1._r8 + crop_inst%sowing_reason_perharv_patch = -1._r8 + crop_inst%harvest_reason_thisyr_patch(p,s) = -1._r8 + do k = repr_grain_min, repr_grain_max + cnveg_carbonflux_inst%repr_grainc_to_food_perharv_patch(p,s,k) = 0._r8 + end do end do + do k = repr_grain_min, repr_grain_max + cnveg_carbonflux_inst%repr_grainc_to_food_thisyr_patch(p,k) = 0._r8 + end do + next_rx_sdate(p) = crop_inst%rx_sdates_thisyr_patch(p,1) + end if + + ! Get next sowing date + if (sowing_count(p) < mxsowings) then + next_rx_sdate(p) = crop_inst%rx_sdates_thisyr_patch(p,sowing_count(p)+1) end if + ! CropType->InitAllocate() initializes next_rx_sdate to -1. It's only changed from that, by cropCalStreamMod->cropcal_interp(), when use_cropcal_rx_sdates is true. So if not using prescribed sowing dates, this boolean will always be false, because jday can never be -1. + do_plant_prescribed = next_rx_sdate(p) == jday .and. sowing_count(p) < mxsowings + ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2022-02-18) ! When resuming from a run with old code, may need to manually set these. ! Will be needed until we can rely on all restart files have been generated ! with CropPhenology() getting the day of the year from the START of the timestep ! (i.e., jday = get_prev_calday()) instead of the END of the timestep (i.e., ! jday = get_calday()). See CTSM issue #1623. + ! Once removed, can also remove the "Instead, always harvest the day before idop" bit. if (croplive(p) .and. idop(p) <= jday .and. sowing_count(p) == 0) then sowing_count(p) = 1 - crop_inst%sdates_thisyr(p,1) = real(idop(p), r8) + crop_inst%sdates_thisyr_patch(p,1) = real(idop(p), r8) end if + ! This is outside the croplive check so that the "harvest if planting conditions were met today" conditional works. + is_in_sowing_window = is_doy_in_interval(minplantjday(ivt(p),h), maxplantjday(ivt(p),h), jday) + is_end_sowing_window = jday == maxplantjday(ivt(p),h) + ! + ! Only allow sowing according to normal "window" rules if not using prescribed + ! sowing dates at all, or if this cell had no values in the prescribed sowing + ! date file. + allow_unprescribed_planting = (.not. use_cropcal_rx_sdates) .or. crop_inst%rx_sdates_thisyr_patch(p,1)<0 + if (sowing_count(p) == mxsowings) then + do_plant_normal = .false. + do_plant_lastchance = .false. + else if (ivt(p) == nwwheat .or. ivt(p) == nirrig_wwheat) then + ! winter temperate cereal : use gdd0 as a limit to plant winter cereal + sowing_gdd_requirement_met = gdd020(p) /= spval .and. gdd020(p) >= gddmin(ivt(p)) + ! Are all the normal requirements for planting met? + do_plant_normal = allow_unprescribed_planting .and. & + a5tmin(p) /= spval .and. & + a5tmin(p) <= minplanttemp(ivt(p)) .and. & + is_in_sowing_window .and. & + sowing_gdd_requirement_met + ! If not, but it's the last day of the planting window, what about relaxed rules? + do_plant_lastchance = allow_unprescribed_planting .and. & + (.not. do_plant_normal) .and. & + is_end_sowing_window .and. & + sowing_gdd_requirement_met + else ! not winter cereal... slevis: added distinction between NH and SH + ! slevis: The idea is that jday will equal idop sooner or later in the year + ! while the gdd part is either true or false for the year. + ! Are all the normal requirements for planting met? + do_plant_normal = allow_unprescribed_planting .and. & + t10(p) /= spval .and. a10tmin(p) /= spval .and. & + t10(p) > planttemp(ivt(p)) .and. & + a10tmin(p) > minplanttemp(ivt(p)) .and. & + is_in_sowing_window .and. & + gdd820(p) /= spval .and. & + gdd820(p) >= gddmin(ivt(p)) + ! If not, but it's the last day of the planting window, what about relaxed rules? + do_plant_lastchance = allow_unprescribed_planting .and. & + (.not. do_plant_normal) .and. & + is_end_sowing_window .and. & + gdd820(p) > 0._r8 .and. & + gdd820(p) /= spval + end if + do_plant = do_plant_prescribed .or. do_plant_normal .or. do_plant_lastchance + did_plant = .false. ! Once outputs can handle >1 planting per year, remove 2nd condition. if ( (.not. croplive(p)) .and. sowing_count(p) == 0 ) then @@ -1884,96 +1994,30 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & ! According to Chris Kucharik, the dataset of ! xinpdate was generated from a previous model run at 0.5 deg resolution - ! winter temperate cereal : use gdd0 as a limit to plant winter cereal - - if (ivt(p) == nwwheat .or. ivt(p) == nirrig_wwheat) then - - ! Are all the normal requirements for planting met? - do_plant_normal = a5tmin(p) /= spval .and. & - a5tmin(p) <= minplanttemp(ivt(p)) .and. & - jday >= minplantjday(ivt(p),h) .and. & - jday <= maxplantjday(ivt(p),h) .and. & - (gdd020(p) /= spval .and. & - gdd020(p) >= gddmin(ivt(p))) - ! If not, but it's the last day of the planting window, what about relaxed rules? - do_plant_lastchance = (.not. do_plant_normal) .and. & - jday == maxplantjday(ivt(p),h) .and. & - gdd020(p) /= spval .and. & - gdd020(p) >= gddmin(ivt(p)) - - if (do_plant_normal .or. do_plant_lastchance) then + if (do_plant) then + if (ivt(p) == nwwheat .or. ivt(p) == nirrig_wwheat) then cumvd(p) = 0._r8 hdidx(p) = 0._r8 vf(p) = 0._r8 - - call PlantCrop(p, leafcn(ivt(p)), jday, crop_inst, cnveg_state_inst, & - cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & - cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & - c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst) - - gddmaturity(p) = hybgdd(ivt(p)) - - else - gddmaturity(p) = 0._r8 end if - else ! not winter cereal... slevis: added distinction between NH and SH - ! slevis: The idea is that jday will equal idop sooner or later in the year - ! while the gdd part is either true or false for the year. - - ! Are all the normal requirements for planting met? - do_plant_normal = t10(p) /= spval .and. a10tmin(p) /= spval .and. & - t10(p) > planttemp(ivt(p)) .and. & - a10tmin(p) > minplanttemp(ivt(p)) .and. & - jday >= minplantjday(ivt(p),h) .and. & - jday <= maxplantjday(ivt(p),h) .and. & - gdd820(p) /= spval .and. & - gdd820(p) >= gddmin(ivt(p)) - ! If not, but it's the last day of the planting window, what about relaxed rules? - do_plant_lastchance = (.not. do_plant_normal) .and. & - jday == maxplantjday(ivt(p),h) .and. & - gdd820(p) > 0._r8 .and. & - gdd820(p) /= spval - - if (do_plant_normal .or. do_plant_lastchance) then - - call PlantCrop(p, leafcn(ivt(p)), jday, crop_inst, cnveg_state_inst, & - cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & - cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & - c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst) - - ! go a specified amount of time before/after - ! climatological date - if (ivt(p) == ntmp_soybean .or. ivt(p) == nirrig_tmp_soybean .or. & - ivt(p) == ntrp_soybean .or. ivt(p) == nirrig_trp_soybean) then - gddmaturity(p) = min(gdd1020(p), hybgdd(ivt(p))) - end if - - if (ivt(p) == ntmp_corn .or. ivt(p) == nirrig_tmp_corn .or. & - ivt(p) == ntrp_corn .or. ivt(p) == nirrig_trp_corn .or. & - ivt(p) == nsugarcane .or. ivt(p) == nirrig_sugarcane .or. & - ivt(p) == nmiscanthus .or. ivt(p) == nirrig_miscanthus .or. & - ivt(p) == nswitchgrass .or. ivt(p) == nirrig_switchgrass) then - gddmaturity(p) = max(950._r8, min(gdd820(p)*0.85_r8, hybgdd(ivt(p)))) - if (do_plant_normal) then - gddmaturity(p) = max(950._r8, min(gddmaturity(p)+150._r8, 1850._r8)) - end if - end if - if (ivt(p) == nswheat .or. ivt(p) == nirrig_swheat .or. & - ivt(p) == ncotton .or. ivt(p) == nirrig_cotton .or. & - ivt(p) == nrice .or. ivt(p) == nirrig_rice) then - gddmaturity(p) = min(gdd020(p), hybgdd(ivt(p))) - end if + call PlantCrop(p, leafcn(ivt(p)), jday, kyr, do_plant_normal, & + do_plant_lastchance, do_plant_prescribed, & + temperature_inst, crop_inst, cnveg_state_inst, & + cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & + cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & + c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst) + did_plant = .true. - else - gddmaturity(p) = 0._r8 - end if - end if ! crop patch distinction + else + gddmaturity(p) = 0._r8 + end if ! crop phenology (gdd thresholds) controlled by gdd needed for ! maturity (physiological) which is based on the average gdd - ! accumulation and hybrids in United States from April 1 - Sept 30 + ! accumulation and hybrids in United States from April 1 - Sept 30, + ! unless using cultivar GDD target inputs ! calculate threshold from phase 1 to phase 2: ! threshold for attaining leaf emergence (based on fraction of @@ -2065,11 +2109,12 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & ! vernalization factor is not 1; ! vf affects the calculation of gddtsoi & hui + vernalization_forces_harvest = .false. if (t_ref2m_min(p) < 1.e30_r8 .and. vf(p) /= 1._r8 .and. & (ivt(p) == nwwheat .or. ivt(p) == nirrig_wwheat)) then call vernalization(p, & canopystate_inst, temperature_inst, waterdiagnosticbulk_inst, cnveg_state_inst, & - crop_inst) + crop_inst, vernalization_forces_harvest) end if ! days past planting may determine harvest @@ -2092,13 +2137,111 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & hui(p) = max(hui(p),huigrain(p)) endif + do_harvest = .false. + fake_harvest = .false. + did_plant_prescribed_today = .false. + if (use_cropcal_rx_sdates .and. sowing_count(p) > 0) then + did_plant_prescribed_today = crop_inst%sdates_thisyr_patch(p,sowing_count(p)) == real(jday, r8) + end if + + ! Optionally ignore maximum growing season length + mxmat = pftcon%mxmat(ivt(p)) + if (.not. use_mxmat) then + mxmat = 999 + end if + + if (jday == 1 .and. croplive(p) .and. idop(p) == 1 .and. sowing_count(p) == 0) then + ! BACKWARDS_COMPATIBILITY(ssr, 2022-02-03): To get rid of crops incorrectly planted in last time step of Dec. 31. That was fixed in commit dadbc62 ("Call CropPhenology regardless of doalb"), but this handles restart files with the old behavior. fake_harvest ensures that outputs aren't polluted. + do_harvest = .true. + fake_harvest = .true. + harvest_reason = HARVEST_REASON_SOWNBADDEC31 + else if (use_cropcal_streams .and. do_plant .and. .not. did_plant) then + ! Today was supposed to be the planting day, but the previous crop still hasn't been harvested. + do_harvest = .true. + harvest_reason = HARVEST_REASON_SOWTODAY + + ! If generate_crop_gdds and this patch has prescribed sowing inputs + else if (generate_crop_gdds .and. crop_inst%rx_sdates_thisyr_patch(p,1) .gt. 0) then + if (next_rx_sdate(p) >= 0) then + ! Harvest the day before the next sowing date this year. + do_harvest = jday == next_rx_sdate(p) - 1 + + ! ... unless that will lead to growing season length 365 (or 366, + ! if last year was a leap year). This would result in idop==jday, + ! which would invoke the "manually setting sowing_count and + ! sdates_thisyr" code. This would lead to crops never getting + ! harvested. Instead, always harvest the day before idop. + if ((.not. do_harvest) .and. & + (idop(p) > 1 .and. jday == idop(p) - 1) .or. & + (idop(p) == 1 .and. jday == dayspyr)) then + do_harvest = .true. + if (do_harvest) then + harvest_reason = HARVEST_REASON_IDOPTOMORROW + end if + else if (do_harvest) then + harvest_reason = HARVEST_REASON_SOWTOMORROW + end if + + else + ! If this patch has already had all its plantings for the year, don't harvest + ! until some time next year. + do_harvest = .false. + + ! ... unless first sowing next year happens Jan. 1. + ! WARNING: This implementation assumes that sowing dates don't change over time! + ! In order to avoid this, you'd have to read this year's AND next year's prescribed + ! sowing dates. + if (crop_inst%rx_sdates_thisyr_patch(p,1) == 1) then + do_harvest = jday == dayspyr + end if + + if (do_harvest) then + harvest_reason = HARVEST_REASON_SOWTOMORROW + end if + + endif + + else if (did_plant_prescribed_today) then + ! Do not harvest on the day this growing season began; + ! would create challenges for postprocessing. + do_harvest = .false. + else if (vernalization_forces_harvest) then + do_harvest = .true. + harvest_reason = HARVEST_REASON_VERNFREEZEKILL + else + ! Original harvest rule + do_harvest = hui(p) >= gddmaturity(p) .or. idpp >= mxmat + + ! Always harvest the day before the next prescribed sowing, if still alive. + ! WARNING: This implementation assumes that sowing dates don't change over time! + ! In order to avoid this, you'd have to read this year's AND next year's prescribed + ! sowing dates. + ! WARNING: This implementation assumes that all patches use prescribed sowing dates. + if (use_cropcal_rx_sdates) then + will_plant_prescribed_tomorrow = (jday == next_rx_sdate(p) - 1) .or. & + (crop_inst%sdates_thisyr_patch(p,1) == 1 .and. & + jday == dayspyr) + else + will_plant_prescribed_tomorrow = .false. + end if + do_harvest = do_harvest .or. will_plant_prescribed_tomorrow + + if (hui(p) >= gddmaturity(p)) then + harvest_reason = HARVEST_REASON_MATURE + else if (idpp >= mxmat) then + harvest_reason = HARVEST_REASON_MAXSEASLENGTH + else if (will_plant_prescribed_tomorrow) then + harvest_reason = HARVEST_REASON_SOWTOMORROW + end if + endif + ! The following conditionals are similar to those in CropPhase. However, they ! differ slightly because here we are potentially setting a new crop phase, ! whereas CropPhase is just designed to get the current, already-determined ! phase. However, despite these differences: if you make changes to the ! following conditionals, you should also check to see if you should make ! similar changes in CropPhase. - if (leafout(p) >= huileaf(p) .and. hui(p) < huigrain(p) .and. idpp < mxmat(ivt(p))) then + if ((.not. do_harvest) .and. leafout(p) >= huileaf(p) .and. hui(p) < huigrain(p) .and. idpp < mxmat) then cphase(p) = cphase_leafemerge if (abs(onset_counter(p)) > 1.e-6_r8) then onset_flag(p) = 1._r8 @@ -2124,10 +2267,23 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & ! the onset_counter would change from dt and you'd need to make ! changes to the offset subroutine below - else if (hui(p) >= gddmaturity(p) .or. idpp >= mxmat(ivt(p))) then - if (harvdate(p) >= NOT_Harvested) harvdate(p) = jday - harvest_count(p) = harvest_count(p) + 1 - crop_inst%hdates_thisyr(p, harvest_count(p)) = real(jday, r8) + else if (do_harvest) then + ! Don't update these if you're just harvesting because of incorrect Dec. + ! 31 planting + if (.not. fake_harvest) then + if (harvdate(p) >= NOT_Harvested) harvdate(p) = jday + harvest_count(p) = harvest_count(p) + 1 + crop_inst%sdates_perharv_patch(p, harvest_count(p)) = real(idop(p), r8) + crop_inst%syears_perharv_patch(p, harvest_count(p)) = real(iyop(p), r8) + crop_inst%hdates_thisyr_patch(p, harvest_count(p)) = real(jday, r8) + cnveg_state_inst%gddmaturity_thisyr(p,harvest_count(p)) = gddmaturity(p) + crop_inst%gddaccum_thisyr_patch(p, harvest_count(p)) = crop_inst%gddaccum_patch(p) + crop_inst%hui_thisyr_patch(p, harvest_count(p)) = hui(p) + crop_inst%sowing_reason_perharv_patch(p, harvest_count(p)) = real(crop_inst%sowing_reason_patch(p), r8) + crop_inst%sowing_reason_patch(p) = -1 + crop_inst%harvest_reason_thisyr_patch(p, harvest_count(p)) = harvest_reason + endif + croplive(p) = .false. ! no re-entry in greater if-block cphase(p) = cphase_harvest if (tlai(p) > 0._r8) then ! plant had emerged before harvest @@ -2142,6 +2298,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & crop_seedc_to_leaf(p) = crop_seedc_to_leaf(p) - leafc_xfer(p)/dt crop_seedn_to_leaf(p) = crop_seedn_to_leaf(p) - leafn_xfer(p)/dt leafc_xfer(p) = 0._r8 + leafn_xfer(p) = leafc_xfer(p) / leafcn(ivt(p)) if (use_c13) then c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = 0._r8 @@ -2325,8 +2482,9 @@ subroutine CropPhenologyInit(bounds) end subroutine CropPhenologyInit !----------------------------------------------------------------------- - subroutine PlantCrop(p, leafcn_in, jday, & - crop_inst, cnveg_state_inst, & + subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, & + do_plant_lastchance, do_plant_prescribed, & + temperature_inst, crop_inst, cnveg_state_inst, & cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst) @@ -2339,12 +2497,25 @@ subroutine PlantCrop(p, leafcn_in, jday, & ! !USES: use clm_varctl , only : use_c13, use_c14 + use clm_varctl , only : use_cropcal_rx_sdates, use_cropcal_rx_cultivar_gdds, use_cropcal_streams use clm_varcon , only : c13ratio, c14ratio + use clm_varpar , only : mxsowings + use pftconMod , only : ntmp_corn, nswheat, nwwheat, ntmp_soybean + use pftconMod , only : nirrig_tmp_corn, nirrig_swheat, nirrig_wwheat, nirrig_tmp_soybean + use pftconMod , only : ntrp_corn, nsugarcane, ntrp_soybean, ncotton, nrice + use pftconMod , only : nirrig_trp_corn, nirrig_sugarcane, nirrig_trp_soybean + use pftconMod , only : nirrig_cotton, nirrig_rice + use pftconMod , only : nmiscanthus, nirrig_miscanthus, nswitchgrass, nirrig_switchgrass ! ! !ARGUMENTS: integer , intent(in) :: p ! PATCH index running over real(r8) , intent(in) :: leafcn_in ! leaf C:N (gC/gN) of this patch's vegetation type (pftcon%leafcn(ivt(p))) integer , intent(in) :: jday ! julian day of the year + integer , intent(in) :: kyr ! current year + logical , intent(in) :: do_plant_normal ! Are all the normal requirements for planting met? + logical , intent(in) :: do_plant_lastchance ! Are the last-chance requirements for planting met? + logical , intent(in) :: do_plant_prescribed ! are we planting because it was prescribed? + type(temperature_type) , intent(in) :: temperature_inst type(crop_type) , intent(inout) :: crop_inst type(cnveg_state_type) , intent(inout) :: cnveg_state_inst type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst @@ -2353,26 +2524,68 @@ subroutine PlantCrop(p, leafcn_in, jday, & type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst type(cnveg_carbonstate_type) , intent(inout) :: c13_cnveg_carbonstate_inst type(cnveg_carbonstate_type) , intent(inout) :: c14_cnveg_carbonstate_inst + ! + ! LOCAL VARAIBLES: + integer s ! growing season index + integer k ! grain pool index + real(r8) gdd_target ! cultivar GDD target this growing season + real(r8) this_sowing_reason ! number representing sowing reason(s) + logical did_rx_gdds ! did this patch use a prescribed harvest requirement? !------------------------------------------------------------------------ associate( & + ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type croplive => crop_inst%croplive_patch , & ! Output: [logical (:) ] Flag, true if planted, not harvested harvdate => crop_inst%harvdate_patch , & ! Output: [integer (:) ] harvest date + next_rx_sdate => crop_inst%next_rx_sdate_patch , & ! Inout: [integer (:) ] prescribed sowing date of next growing season this year sowing_count => crop_inst%sowing_count , & ! Inout: [integer (:) ] number of sowing events this year for this patch - idop => cnveg_state_inst%idop_patch , & ! Output: [integer (:) ] date of planting + sowing_reason => crop_inst%sowing_reason_thisyr_patch , & ! Output: [real(r8) (:) ] reason for each sowing this year for this patch + gddmaturity => cnveg_state_inst%gddmaturity_patch , & ! Output: [real(r8) (:) ] gdd needed to harvest + idop => cnveg_state_inst%idop_patch , & ! Output: [integer (:) ] date of planting + iyop => cnveg_state_inst%iyop_patch , & ! Output: [integer (:) ] year of planting leafc_xfer => cnveg_carbonstate_inst%leafc_xfer_patch , & ! Output: [real(r8) (:) ] (gC/m2) leaf C transfer leafn_xfer => cnveg_nitrogenstate_inst%leafn_xfer_patch , & ! Output: [real(r8) (:) ] (gN/m2) leaf N transfer crop_seedc_to_leaf => cnveg_carbonflux_inst%crop_seedc_to_leaf_patch , & ! Output: [real(r8) (:) ] (gC/m2/s) seed source to leaf - crop_seedn_to_leaf => cnveg_nitrogenflux_inst%crop_seedn_to_leaf_patch & ! Output: [real(r8) (:) ] (gN/m2/s) seed source to leaf + crop_seedn_to_leaf => cnveg_nitrogenflux_inst%crop_seedn_to_leaf_patch, & ! Output: [real(r8) (:) ] (gN/m2/s) seed source to leaf + hybgdd => pftcon%hybgdd , & ! Input: [real(r8) (:) ] + gddmin => pftcon%gddmin , & ! Input: + gdd020 => temperature_inst%gdd020_patch , & ! Input: [real(r8) (:) ] 20 yr mean of gdd0 + gdd820 => temperature_inst%gdd820_patch , & ! Input: [real(r8) (:) ] 20 yr mean of gdd8 + gdd1020 => temperature_inst%gdd1020_patch , & ! Input: [real(r8) (:) ] 20 yr mean of gdd10 + aleafi => cnveg_state_inst%aleafi_patch , & ! Output: [real(r8) (:) ] saved allocation coefficient from phase 2 + astemi => cnveg_state_inst%astemi_patch , & ! Output: [real(r8) (:) ] saved allocation coefficient from phase 2 + aleaf => cnveg_state_inst%aleaf_patch , & ! Output: [real(r8) (:) ] leaf allocation coefficient + astem => cnveg_state_inst%astem_patch , & ! Output: [real(r8) (:) ] stem allocation coefficient + aroot => cnveg_state_inst%aroot_patch , & ! Output: [real(r8) (:) ] root allocation coefficient + arepr => cnveg_state_inst%arepr_patch & ! Output: [real(r8) (:,:) ] reproductive allocation coefficient(s) ) ! impose limit on growing season length needed ! for crop maturity - for cold weather constraints croplive(p) = .true. idop(p) = jday + iyop(p) = kyr harvdate(p) = NOT_Harvested sowing_count(p) = sowing_count(p) + 1 - crop_inst%sdates_thisyr(p,sowing_count(p)) = jday + + if (use_cropcal_rx_sdates .and. sowing_count(p) < mxsowings) then + next_rx_sdate(p) = crop_inst%rx_sdates_thisyr_patch(p, sowing_count(p)+1) + else + next_rx_sdate(p) = -1 + endif + crop_inst%sdates_thisyr_patch(p,sowing_count(p)) = real(jday, r8) + + this_sowing_reason = 0._r8 + if (do_plant_prescribed) then + this_sowing_reason = 10._r8 + end if + if (do_plant_normal) then + this_sowing_reason = this_sowing_reason + 1._r8 + else if (do_plant_lastchance) then + this_sowing_reason = this_sowing_reason + 2._r8 + end if + sowing_reason(p,sowing_count(p)) = this_sowing_reason + crop_inst%sowing_reason_patch(p) = this_sowing_reason leafc_xfer(p) = initial_seed_at_planting leafn_xfer(p) = leafc_xfer(p) / leafcn_in ! with onset @@ -2398,13 +2611,64 @@ subroutine PlantCrop(p, leafcn_in, jday, & endif endif + ! set GDD target + did_rx_gdds = .false. + if (use_cropcal_rx_cultivar_gdds .and. crop_inst%rx_cultivar_gdds_thisyr_patch(p,sowing_count(p)) .ge. 0._r8) then + gddmaturity(p) = crop_inst%rx_cultivar_gdds_thisyr_patch(p,sowing_count(p)) + did_rx_gdds = .true. + else if (ivt(p) == nwwheat .or. ivt(p) == nirrig_wwheat) then + gddmaturity(p) = hybgdd(ivt(p)) + else + if (ivt(p) == ntmp_soybean .or. ivt(p) == nirrig_tmp_soybean .or. & + ivt(p) == ntrp_soybean .or. ivt(p) == nirrig_trp_soybean) then + gddmaturity(p) = min(gdd1020(p), hybgdd(ivt(p))) + end if + if (ivt(p) == ntmp_corn .or. ivt(p) == nirrig_tmp_corn .or. & + ivt(p) == ntrp_corn .or. ivt(p) == nirrig_trp_corn .or. & + ivt(p) == nsugarcane .or. ivt(p) == nirrig_sugarcane .or. & + ivt(p) == nmiscanthus .or. ivt(p) == nirrig_miscanthus .or. & + ivt(p) == nswitchgrass .or. ivt(p) == nirrig_switchgrass) then + gddmaturity(p) = max(950._r8, min(gdd820(p)*0.85_r8, hybgdd(ivt(p)))) + if (do_plant_normal) then + gddmaturity(p) = max(950._r8, min(gddmaturity(p)+150._r8, 1850._r8)) + end if + end if + if (ivt(p) == nswheat .or. ivt(p) == nirrig_swheat .or. & + ivt(p) == ncotton .or. ivt(p) == nirrig_cotton .or. & + ivt(p) == nrice .or. ivt(p) == nirrig_rice) then + gddmaturity(p) = min(gdd020(p), hybgdd(ivt(p))) + end if + + endif + + if (use_cropcal_streams .and. gddmaturity(p) < min_gddmaturity) then + if (did_rx_gdds) then + write(iulog,*) 'Some patch with ivt ',ivt(p),' has rx gddmaturity',gddmaturity(p),'; using min_gddmaturity instead (',min_gddmaturity,')' + endif + gddmaturity(p) = min_gddmaturity + endif + + ! Initialize allocation coefficients. + ! Because crops have no live carbon pools when planted but not emerged, this shouldn't + ! matter unless they skip the vegetative phase (which only happens in very weird run + ! setups). + aleaf(p) = 1._r8 + aleafi(p) = 1._r8 + astem(p) = 0._r8 + astemi(p) = 0._r8 + aroot(p) = 0._r8 + do k = 1, nrepr + arepr(p,k) = 0._r8 + end do + end associate end subroutine PlantCrop !----------------------------------------------------------------------- subroutine vernalization(p, & - canopystate_inst, temperature_inst, waterdiagnosticbulk_inst, cnveg_state_inst, crop_inst) + canopystate_inst, temperature_inst, waterdiagnosticbulk_inst, cnveg_state_inst, crop_inst, & + force_harvest) ! ! !DESCRIPTION: ! @@ -2423,6 +2687,7 @@ subroutine vernalization(p, & type(waterdiagnosticbulk_type) , intent(in) :: waterdiagnosticbulk_inst type(cnveg_state_type) , intent(inout) :: cnveg_state_inst type(crop_type) , intent(inout) :: crop_inst + logical , intent(inout) :: force_harvest ! "harvest" forced if freeze-killed ! ! LOCAL VARAIBLES: real(r8) tcrown ! ? @@ -2442,8 +2707,6 @@ subroutine vernalization(p, & hdidx => cnveg_state_inst%hdidx_patch , & ! Output: [real(r8) (:) ] cold hardening index? cumvd => cnveg_state_inst%cumvd_patch , & ! Output: [real(r8) (:) ] cumulative vernalization d?ependence? - gddmaturity => cnveg_state_inst%gddmaturity_patch , & ! Output: [real(r8) (:) ] gdd needed to harvest - huigrain => cnveg_state_inst%huigrain_patch , & ! Output: [real(r8) (:) ] heat unit index needed to reach vegetative maturity vf => crop_inst%vf_patch & ! Output: [real(r8) (:) ] vernalization factor for cereal ) @@ -2533,9 +2796,14 @@ subroutine vernalization(p, & if (tkil >= tcrown) then if ((0.95_r8 - 0.02_r8 * (tcrown - tkil)**2) >= 0.02_r8) then write (iulog,*) 'crop damaged by cold temperatures at p,c =', p,c - else if (tlai(p) > 0._r8) then ! slevis: kill if past phase1 - gddmaturity(p) = 0._r8 ! by forcing through - huigrain(p) = 0._r8 ! harvest + else if (tlai(p) > 0._r8) then + ! slevis: kill if past phase1 by forcing through harvest + ! srabin: do this with force_harvest instead of setting + ! gddmaturity = huigrain = 0, since gddmaturity==0 can + ! lead to 0/0 when the crop isn't actually harvested based + ! on "maturity." This can occur when generate_crop_gdds + ! is true. + force_harvest = .true. write (iulog,*) '95% of crop killed by cold temperatures at p,c =', p,c end if end if @@ -2565,7 +2833,7 @@ subroutine CNOnsetGrowth (num_soilp, filter_soilp, & ! ! !LOCAL VARIABLES: integer :: p ! indices - integer :: fp ! lake filter patch index + integer :: fp ! filter patch index real(r8):: t1 ! temporary variable !----------------------------------------------------------------------- @@ -2675,7 +2943,8 @@ end subroutine CNOnsetGrowth !----------------------------------------------------------------------- subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & - cnveg_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) + cnveg_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & + crop_inst) ! ! !DESCRIPTION: ! Determines the flux of C and N from displayed pools to litter @@ -2696,10 +2965,11 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & type(cnveg_nitrogenstate_type), intent(in) :: cnveg_nitrogenstate_inst type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst + type(crop_type) , intent(in) :: crop_inst ! ! !LOCAL VARIABLES: - integer :: p, c, k ! indices - integer :: fp ! lake filter patch index + integer :: p, c, k, h ! indices + integer :: fp ! filter patch index real(r8):: t1 ! temporary variable real(r8):: denom ! temporary variable for divisor real(r8) :: ntovr_leaf @@ -2709,6 +2979,7 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & real(r8) :: cropseedn_deficit_remaining ! remaining amount of crop seed N deficit that still needs to be restored (gN/m2) (positive, in contrast to the negative cropseedn_deficit) real(r8) :: cropseedc_deficit_to_restore ! amount of crop seed C deficit that will be restored from this grain pool (gC/m2) real(r8) :: cropseedn_deficit_to_restore ! amount of crop seed N deficit that will be restored from this grain pool (gN/m2) + real(r8) :: repr_grainc_to_food_thispool ! amount added to / subtracted from repr_grainc_to_food for the pool in question (gC/m2/s) !----------------------------------------------------------------------- associate( & @@ -2746,6 +3017,8 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & frootc_to_litter => cnveg_carbonflux_inst%frootc_to_litter_patch , & ! Output: [real(r8) (:) ] fine root C litterfall (gC/m2/s) livestemc_to_litter => cnveg_carbonflux_inst%livestemc_to_litter_patch , & ! Output: [real(r8) (:) ] live stem C litterfall (gC/m2/s) repr_grainc_to_food => cnveg_carbonflux_inst%repr_grainc_to_food_patch , & ! Output: [real(r8) (:,:) ] grain C to food (gC/m2/s) + repr_grainc_to_food_perharv => cnveg_carbonflux_inst%repr_grainc_to_food_perharv_patch, & ! Output: [real(r8) (:,:,:) ] grain C to food per harvest (gC/m2) + repr_grainc_to_food_thisyr => cnveg_carbonflux_inst%repr_grainc_to_food_thisyr_patch, & ! Output: [real(r8) (:,:) ] grain C to food harvested this calendar year (gC/m2) repr_grainc_to_seed => cnveg_carbonflux_inst%repr_grainc_to_seed_patch , & ! Output: [real(r8) (:,:) ] grain C to seed (gC/m2/s) repr_structurec_to_cropprod => cnveg_carbonflux_inst%repr_structurec_to_cropprod_patch, & ! Output: [real(r8) (:,:) ] reproductive structure C to crop product pool (gC/m2/s) repr_structurec_to_litter => cnveg_carbonflux_inst%repr_structurec_to_litter_patch, & ! Output: [real(r8) (:,:) ] reproductive structure C to litter (gC/m2/s) @@ -2797,6 +3070,10 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & ! this assumes that offset_counter == dt for crops ! if this were ever changed, we'd need to add code to the "else" if (ivt(p) >= npcropmin) then + + ! How many harvests have occurred? + h = crop_inst%harvest_count(p) + ! Replenish the seed deficits from grain, if there is enough available ! grain. (If there is not enough available grain, the seed deficits will ! accumulate until there is eventually enough grain to replenish them.) @@ -2820,8 +3097,15 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & repr_grainn_to_seed(p,k) = t1 * cropseedn_deficit_to_restore ! Send the remaining grain to the food product pool + repr_grainc_to_food_thispool = cpool_to_reproductivec(p,k) - repr_grainc_to_seed(p,k) repr_grainc_to_food(p,k) = t1 * reproductivec(p,k) & - + cpool_to_reproductivec(p,k) - repr_grainc_to_seed(p,k) + + repr_grainc_to_food_thispool + if (reproductivec(p,k) + repr_grainc_to_food_thispool * dt > 0._r8) then + repr_grainc_to_food_perharv(p,h,k) = reproductivec(p,k) & + + repr_grainc_to_food_thispool * dt + repr_grainc_to_food_thisyr(p,k) = repr_grainc_to_food_thisyr(p,k) & + + repr_grainc_to_food_perharv(p,h,k) + end if repr_grainn_to_food(p,k) = t1 * reproductiven(p,k) & + npool_to_reproductiven(p,k) - repr_grainn_to_seed(p,k) end do @@ -3032,7 +3316,7 @@ subroutine CNBackgroundLitterfall (num_soilp, filter_soilp, & ! ! !LOCAL VARIABLES: integer :: p ! indices - integer :: fp ! lake filter patch index + integer :: fp ! filter patch index real(r8) :: fr_leafn_to_litter ! fraction of the nitrogen turnover that goes to litter; remaining fraction is retranslocated real(r8) :: ntovr_leaf real(r8) :: denom @@ -3189,7 +3473,7 @@ subroutine CNLivewoodTurnover (num_soilp, filter_soilp, & ! ! !LOCAL VARIABLES: integer :: p ! indices - integer :: fp ! lake filter patch index + integer :: fp ! filter patch index real(r8):: ctovr ! temporary variable for carbon turnover real(r8):: ntovr ! temporary variable for nitrogen turnover !----------------------------------------------------------------------- @@ -3383,7 +3667,7 @@ subroutine CNCropHarvestToProductPools(bounds, num_soilp, filter_soilp, num_soil end subroutine CNCropHarvestToProductPools !----------------------------------------------------------------------- - subroutine CNLitterToColumn (bounds, num_soilc, filter_soilc, & + subroutine CNLitterToColumn (bounds, num_bgc_vegp, filter_bgc_vegp, & cnveg_state_inst,cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & leaf_prof_patch, froot_prof_patch) ! @@ -3392,14 +3676,14 @@ subroutine CNLitterToColumn (bounds, num_soilc, filter_soilc, & ! to the column level and assign them to the three litter pools ! ! !USES: - use clm_varpar , only : max_patch_per_col, nlevdecomp + use clm_varpar , only : nlevdecomp use pftconMod , only : npcropmin use clm_varctl , only : use_grainproduct ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_vegp ! number of bgc veg patches + integer , intent(in) :: filter_bgc_vegp(:) ! filter for bgc veg patches type(cnveg_state_type) , intent(in) :: cnveg_state_inst type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst @@ -3407,7 +3691,7 @@ subroutine CNLitterToColumn (bounds, num_soilc, filter_soilc, & real(r8) , intent(in) :: froot_prof_patch(bounds%begp:,1:) ! ! !LOCAL VARIABLES: - integer :: fc,c,pi,p,k,j,i ! indices + integer :: fp,c,p,k,j,i ! indices !----------------------------------------------------------------------- SHR_ASSERT_ALL_FL((ubound(leaf_prof_patch) == (/bounds%endp,nlevdecomp_full/)), sourcefile, __LINE__) @@ -3437,95 +3721,87 @@ subroutine CNLitterToColumn (bounds, num_soilc, filter_soilc, & frootn_to_litter => cnveg_nitrogenflux_inst%frootn_to_litter_patch , & ! Input: [real(r8) (:) ] fine root N litterfall (gN/m2/s) phenology_n_to_litr_n => cnveg_nitrogenflux_inst%phenology_n_to_litr_n_col & ! Output: [real(r8) (:,:,:) ] N fluxes associated with phenology (litterfall and crop) to litter pools (gN/m3/s) ) - - do j = 1, nlevdecomp - do pi = 1,max_patch_per_col - do fc = 1,num_soilc - c = filter_soilc(fc) - - if ( pi <= col%npatches(c) ) then - p = col%patchi(c) + pi - 1 - if (patch%active(p)) then - - do i = i_litr_min, i_litr_max - ! leaf litter carbon fluxes - phenology_c_to_litr_c(c,j,i) = & - phenology_c_to_litr_c(c,j,i) + & - leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + + do_nlev: do j = 1, nlevdecomp - ! leaf litter nitrogen fluxes - phenology_n_to_litr_n(c,j,i) = & - phenology_n_to_litr_n(c,j,i) + & - leafn_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + do_vegp: do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) + c = patch%column(p) - ! fine root litter carbon fluxes + do_ilit: do i = i_litr_min, i_litr_max + ! leaf litter carbon fluxes + phenology_c_to_litr_c(c,j,i) = & + phenology_c_to_litr_c(c,j,i) + & + leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + + ! leaf litter nitrogen fluxes + phenology_n_to_litr_n(c,j,i) = & + phenology_n_to_litr_n(c,j,i) + & + leafn_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + + ! fine root litter carbon fluxes + phenology_c_to_litr_c(c,j,i) = & + phenology_c_to_litr_c(c,j,i) + & + frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) + + ! fine root litter nitrogen fluxes + phenology_n_to_litr_n(c,j,i) = & + phenology_n_to_litr_n(c,j,i) + & + frootn_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) + end do do_ilit + + ! agroibis puts crop stem litter together with leaf litter + ! so I've used the leaf lf_f* parameters instead of making + ! new ones for now (slevis) + ! also for simplicity I've put "food" into the litter pools + + if (ivt(p) >= npcropmin) then ! add livestemc to litter + do i = i_litr_min, i_litr_max + ! stem litter carbon fluxes + phenology_c_to_litr_c(c,j,i) = & + phenology_c_to_litr_c(c,j,i) + & + livestemc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + + ! stem litter nitrogen fluxes + phenology_n_to_litr_n(c,j,i) = & + phenology_n_to_litr_n(c,j,i) + & + livestemn_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + end do + + if (.not. use_grainproduct) then + do i = i_litr_min, i_litr_max + do k = repr_grain_min, repr_grain_max + ! grain litter carbon fluxes phenology_c_to_litr_c(c,j,i) = & - phenology_c_to_litr_c(c,j,i) + & - frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) + phenology_c_to_litr_c(c,j,i) + & + repr_grainc_to_food(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - ! fine root litter nitrogen fluxes + ! grain litter nitrogen fluxes phenology_n_to_litr_n(c,j,i) = & - phenology_n_to_litr_n(c,j,i) + & - frootn_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) + phenology_n_to_litr_n(c,j,i) + & + repr_grainn_to_food(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) end do - - ! agroibis puts crop stem litter together with leaf litter - ! so I've used the leaf lf_f* parameters instead of making - ! new ones for now (slevis) - ! also for simplicity I've put "food" into the litter pools - - if (ivt(p) >= npcropmin) then ! add livestemc to litter - do i = i_litr_min, i_litr_max - ! stem litter carbon fluxes - phenology_c_to_litr_c(c,j,i) = & - phenology_c_to_litr_c(c,j,i) + & - livestemc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - - ! stem litter nitrogen fluxes - phenology_n_to_litr_n(c,j,i) = & - phenology_n_to_litr_n(c,j,i) + & - livestemn_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - end do - - if (.not. use_grainproduct) then - do i = i_litr_min, i_litr_max - do k = repr_grain_min, repr_grain_max - ! grain litter carbon fluxes - phenology_c_to_litr_c(c,j,i) = & - phenology_c_to_litr_c(c,j,i) + & - repr_grainc_to_food(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - - ! grain litter nitrogen fluxes - phenology_n_to_litr_n(c,j,i) = & - phenology_n_to_litr_n(c,j,i) + & - repr_grainn_to_food(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - end do - end do - end if - - do i = i_litr_min, i_litr_max - do k = repr_structure_min, repr_structure_max - ! reproductive structure litter carbon fluxes - phenology_c_to_litr_c(c,j,i) = & - phenology_c_to_litr_c(c,j,i) + & - repr_structurec_to_litter(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - - ! reproductive structure litter nitrogen fluxes - phenology_n_to_litr_n(c,j,i) = & - phenology_n_to_litr_n(c,j,i) + & - repr_structuren_to_litter(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - end do - end do - end if - end if + end do end if - end do - - end do - end do + do i = i_litr_min, i_litr_max + do k = repr_structure_min, repr_structure_max + ! reproductive structure litter carbon fluxes + phenology_c_to_litr_c(c,j,i) = & + phenology_c_to_litr_c(c,j,i) + & + repr_structurec_to_litter(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + + ! reproductive structure litter nitrogen fluxes + phenology_n_to_litr_n(c,j,i) = & + phenology_n_to_litr_n(c,j,i) + & + repr_structuren_to_litter(p,k) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + end do + end do + end if + end do do_vegp + end do do_nlev - end associate + end associate end subroutine CNLitterToColumn diff --git a/src/biogeochem/CNPrecisionControlMod.F90 b/src/biogeochem/CNPrecisionControlMod.F90 index 8b98f6c3fb..787a5b54d7 100644 --- a/src/biogeochem/CNPrecisionControlMod.F90 +++ b/src/biogeochem/CNPrecisionControlMod.F90 @@ -96,7 +96,7 @@ subroutine CNPrecisionControlReadNML( NLFilename ) end subroutine CNPrecisionControlReadNML !----------------------------------------------------------------------- - subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & + subroutine CNPrecisionControl(bounds, num_bgc_vegp, filter_bgc_vegp, & cnveg_carbonstate_inst, c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & cnveg_nitrogenstate_inst) ! @@ -111,8 +111,8 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds ! bounds - integer , intent(in) :: num_soilp ! number of soil patchs in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_vegp ! number of bgc veg patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for bgc veg patches type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst type(cnveg_carbonstate_type) , intent(inout) :: c13_cnveg_carbonstate_inst type(cnveg_carbonstate_type) , intent(inout) :: c14_cnveg_carbonstate_inst @@ -190,8 +190,8 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & ) ! patch loop - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) ! initialize the patch-level C and N truncation terms pc(p) = 0._r8 @@ -205,7 +205,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & ! the C component, but truncate C, C13, and N components ! leaf C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%leafc_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%leafc_patch(bounds%begp:bounds%endp), & ns%leafn_patch(bounds%begp:bounds%endp), & pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep) @@ -223,7 +223,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & ! leaf storage C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%leafc_storage_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%leafc_storage_patch(bounds%begp:bounds%endp), & ns%leafn_storage_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep) if (use_c13) then @@ -238,7 +238,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! leaf transfer C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%leafc_xfer_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%leafc_xfer_patch(bounds%begp:bounds%endp), & ns%leafn_xfer_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep) if (use_c13) then @@ -256,7 +256,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & ! EBK KO DML: For some reason frootc/frootn can go negative and allowing ! it to be negative is important for C4 crops (otherwise they die) Jun/3/2016 if ( prec_control_for_froot ) then - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%frootc_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%frootc_patch(bounds%begp:bounds%endp), & ns%frootn_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep, allowneg=.true.) if (use_c13) then @@ -272,7 +272,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! froot storage C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%frootc_storage_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%frootc_storage_patch(bounds%begp:bounds%endp), & ns%frootn_storage_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), & __LINE__, num_truncatep, filter_truncatep) if (use_c13) then @@ -287,7 +287,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! froot transfer C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%frootc_xfer_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%frootc_xfer_patch(bounds%begp:bounds%endp), & ns%frootn_xfer_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep) if (use_c13) then @@ -304,7 +304,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & if ( use_crop )then do k = 1, nrepr ! grain C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%reproductivec_patch(bounds%begp:bounds%endp,k), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%reproductivec_patch(bounds%begp:bounds%endp,k), & ns%reproductiven_patch(bounds%begp:bounds%endp,k), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep, croponly=.true. ) if (use_c13) then @@ -319,7 +319,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! grain storage C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, & cs%reproductivec_storage_patch(bounds%begp:bounds%endp,k), & ns%reproductiven_storage_patch(bounds%begp:bounds%endp,k), pc(bounds%begp:), pn(bounds%begp:), & __LINE__, num_truncatep, filter_truncatep, croponly=.true. ) @@ -336,7 +336,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! grain transfer C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, & cs%reproductivec_xfer_patch(bounds%begp:bounds%endp,k), & ns%reproductiven_xfer_patch(bounds%begp:bounds%endp,k), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep, croponly=.true.) @@ -352,7 +352,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if end do ! grain transfer C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%cropseedc_deficit_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%cropseedc_deficit_patch(bounds%begp:bounds%endp), & ns%cropseedn_deficit_patch(bounds%begp:bounds%endp), pc(bounds%begp:), & pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep, & @@ -371,7 +371,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! livestem C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%livestemc_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%livestemc_patch(bounds%begp:bounds%endp), & ns%livestemn_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep) if (use_c13) then @@ -386,7 +386,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! livestem storage C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%livestemc_storage_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%livestemc_storage_patch(bounds%begp:bounds%endp), & ns%livestemn_storage_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), & __LINE__, num_truncatep, filter_truncatep) @@ -401,7 +401,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & __LINE__) end if ! livestem transfer C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%livestemc_xfer_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%livestemc_xfer_patch(bounds%begp:bounds%endp), & ns%livestemn_xfer_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), & __LINE__, num_truncatep, filter_truncatep) if (use_c13) then @@ -416,7 +416,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! deadstem C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%deadstemc_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%deadstemc_patch(bounds%begp:bounds%endp), & ns%deadstemn_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep) if (use_c13) then @@ -430,7 +430,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & __LINE__) end if ! deadstem storage C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%deadstemc_storage_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%deadstemc_storage_patch(bounds%begp:bounds%endp), & ns%deadstemn_storage_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), & __LINE__, num_truncatep, filter_truncatep) if (use_c13) then @@ -445,7 +445,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! deadstem transfer C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%deadstemc_xfer_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%deadstemc_xfer_patch(bounds%begp:bounds%endp), & ns%deadstemn_xfer_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), & __LINE__, num_truncatep, filter_truncatep) if (use_c13) then @@ -460,7 +460,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! livecroot C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%livecrootc_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%livecrootc_patch(bounds%begp:bounds%endp), & ns%livecrootn_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep) if (use_c13) then @@ -475,7 +475,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! livecroot storage C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%livecrootc_storage_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%livecrootc_storage_patch(bounds%begp:bounds%endp), & ns%livecrootn_storage_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), & __LINE__, num_truncatep, filter_truncatep) if (use_c13) then @@ -490,7 +490,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! livecroot transfer C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%livecrootc_xfer_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%livecrootc_xfer_patch(bounds%begp:bounds%endp), & ns%livecrootn_xfer_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), & __LINE__, num_truncatep, filter_truncatep) @@ -506,7 +506,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! deadcroot C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%deadcrootc_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%deadcrootc_patch(bounds%begp:bounds%endp), & ns%deadcrootn_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & num_truncatep, filter_truncatep) if (use_c13) then @@ -521,7 +521,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! deadcroot storage C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%deadcrootc_storage_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%deadcrootc_storage_patch(bounds%begp:bounds%endp), & ns%deadcrootn_storage_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), & __LINE__, num_truncatep, filter_truncatep) if (use_c13) then @@ -536,7 +536,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! deadcroot transfer C and N - call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%deadcrootc_xfer_patch(bounds%begp:bounds%endp), & + call TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%deadcrootc_xfer_patch(bounds%begp:bounds%endp), & ns%deadcrootn_xfer_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), & __LINE__, num_truncatep, filter_truncatep) if (use_c13) then @@ -551,7 +551,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! gresp_storage (C only) - call TruncateCStates( bounds, filter_soilp, num_soilp, cs%gresp_storage_patch(bounds%begp:bounds%endp), & + call TruncateCStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%gresp_storage_patch(bounds%begp:bounds%endp), & pc(bounds%begp:), __LINE__, num_truncatep, filter_truncatep) if (use_c13) then call TruncateAdditional( bounds, num_truncatep, filter_truncatep, & @@ -565,7 +565,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! gresp_xfer(c only) - call TruncateCStates( bounds, filter_soilp, num_soilp, cs%gresp_xfer_patch(bounds%begp:bounds%endp), & + call TruncateCStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%gresp_xfer_patch(bounds%begp:bounds%endp), & pc(bounds%begp:), __LINE__, num_truncatep, filter_truncatep) if (use_c13) then call TruncateAdditional( bounds, num_truncatep, filter_truncatep, & @@ -579,7 +579,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! cpool (C only) - call TruncateCStates( bounds, filter_soilp, num_soilp, cs%cpool_patch(bounds%begp:bounds%endp), & + call TruncateCStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%cpool_patch(bounds%begp:bounds%endp), & pc(bounds%begp:), __LINE__, num_truncatep, filter_truncatep) if (use_c13) then call TruncateAdditional( bounds, num_truncatep, filter_truncatep, & @@ -595,7 +595,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & if ( use_crop )then ! xsmrpool (C only) ! xsmr is a pool to balance the budget and as such can be freely negative - call TruncateCStates( bounds, filter_soilp, num_soilp, cs%xsmrpool_patch(bounds%begp:bounds%endp), & + call TruncateCStates( bounds, filter_bgc_vegp, num_bgc_vegp, cs%xsmrpool_patch(bounds%begp:bounds%endp), & pc(bounds%begp:), __LINE__, num_truncatep, filter_truncatep, & allowneg=.true., croponly=.true. ) if (use_c13) then @@ -612,16 +612,16 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end if ! retransn (N only) - call TruncateNStates( bounds, filter_soilp, num_soilp, ns%retransn_patch(bounds%begp:bounds%endp), pn(bounds%begp:), & + call TruncateNStates( bounds, filter_bgc_vegp, num_bgc_vegp, ns%retransn_patch(bounds%begp:bounds%endp), pn(bounds%begp:), & __LINE__ ) ! npool (N only) - call TruncateNStates( bounds, filter_soilp, num_soilp, ns%npool_patch(bounds%begp:bounds%endp), pn(bounds%begp:), & + call TruncateNStates( bounds, filter_bgc_vegp, num_bgc_vegp, ns%npool_patch(bounds%begp:bounds%endp), pn(bounds%begp:), & __LINE__ ) ! patch loop - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) cs%ctrunc_patch(p) = cs%ctrunc_patch(p) + pc(p) @@ -639,7 +639,7 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & end subroutine CNPrecisionControl - subroutine TruncateCandNStates( bounds, filter_soilp, num_soilp, carbon_patch, nitrogen_patch, pc, pn, lineno, & + subroutine TruncateCandNStates( bounds, filter_bgc_vegp, num_bgc_vegp, carbon_patch, nitrogen_patch, pc, pn, lineno, & num_truncatep, filter_truncatep, croponly, allowneg ) ! ! !DESCRIPTION: @@ -657,8 +657,8 @@ subroutine TruncateCandNStates( bounds, filter_soilp, num_soilp, carbon_patch, n ! !ARGUMENTS: implicit none type(bounds_type) , intent(in) :: bounds ! bounds - integer , intent(in) :: num_soilp ! number of soil patchs in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_vegp ! number of bgc veg patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for bgc veg patches real(r8), intent(inout) :: carbon_patch(bounds%begp:) real(r8), intent(inout) :: nitrogen_patch(bounds%begp:) real(r8), intent(inout) :: pc(bounds%begp:) @@ -688,8 +688,8 @@ subroutine TruncateCandNStates( bounds, filter_soilp, num_soilp, carbon_patch, n end if num_truncatep = 0 - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) if ( .not. lcroponly .or. (patch%itype(p) >= nc3crop) ) then if ( .not. lallowneg .and. ((carbon_patch(p) < cnegcrit) .or. (nitrogen_patch(p) < nnegcrit)) ) then @@ -733,7 +733,7 @@ subroutine TruncateCandNStates( bounds, filter_soilp, num_soilp, carbon_patch, n end do end subroutine TruncateCandNStates - subroutine TruncateCStates( bounds, filter_soilp, num_soilp, carbon_patch, pc, lineno, & + subroutine TruncateCStates( bounds, filter_bgc_vegp, num_bgc_vegp, carbon_patch, pc, lineno, & num_truncatep, filter_truncatep, croponly, allowneg ) ! ! !DESCRIPTION: @@ -751,8 +751,8 @@ subroutine TruncateCStates( bounds, filter_soilp, num_soilp, carbon_patch, pc, l ! !ARGUMENTS: implicit none type(bounds_type), intent(in) :: bounds ! bounds - integer , intent(in) :: num_soilp ! number of soil patchs in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_vegp ! number of bgc veg patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for bgc veg patches real(r8) , intent(inout) :: carbon_patch(bounds%begp:) real(r8) , intent(inout) :: pc(bounds%begp:) integer , intent(in) :: lineno @@ -780,8 +780,8 @@ subroutine TruncateCStates( bounds, filter_soilp, num_soilp, carbon_patch, pc, l end if num_truncatep = 0 - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) if ( .not. lcroponly .or. (patch%itype(p) >= nc3crop) ) then if ( .not. lallowneg .and. (carbon_patch(p) < cnegcrit) ) then @@ -801,7 +801,7 @@ subroutine TruncateCStates( bounds, filter_soilp, num_soilp, carbon_patch, pc, l end do end subroutine TruncateCStates - subroutine TruncateNStates( bounds, filter_soilp, num_soilp, nitrogen_patch, pn, lineno ) + subroutine TruncateNStates( bounds, filter_bgc_vegp, num_bgc_vegp, nitrogen_patch, pn, lineno ) ! ! !DESCRIPTION: ! Truncate Nitrogen states. If a nitrogen state is too small truncate it to @@ -816,8 +816,8 @@ subroutine TruncateNStates( bounds, filter_soilp, num_soilp, nitrogen_patch, pn, ! !ARGUMENTS: implicit none type(bounds_type) , intent(in) :: bounds ! bounds - integer , intent(in) :: num_soilp ! number of soil patchs in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_vegp ! number of bgc veg patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for bgc veg patches real(r8), intent(inout) :: nitrogen_patch(bounds%begp:) real(r8), intent(inout) :: pn(bounds%begp:) integer, intent(in) :: lineno @@ -826,8 +826,8 @@ subroutine TruncateNStates( bounds, filter_soilp, num_soilp, nitrogen_patch, pn, SHR_ASSERT_ALL_FL((ubound(nitrogen_patch) == (/bounds%endp/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(pn) == (/bounds%endp/)), sourcefile, __LINE__) - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) if ( nitrogen_patch(p) < nnegcrit ) then ! write(iulog,*) 'WARNING: Nitrogen patch negative = ', nitrogen_patch ! call endrun(subgrid_index=p, subgrid_level=subgrid_level_patch, & diff --git a/src/biogeochem/CNProductsMod.F90 b/src/biogeochem/CNProductsMod.F90 index d1684e367b..4ef5c7c86f 100644 --- a/src/biogeochem/CNProductsMod.F90 +++ b/src/biogeochem/CNProductsMod.F90 @@ -19,7 +19,9 @@ module CNProductsMod ! ! !PUBLIC TYPES: type, public :: cn_products_type - private + + private ! Default these procedures to private, unless specified otherwise + ! ------------------------------------------------------------------------ ! Public instance variables ! ------------------------------------------------------------------------ @@ -49,9 +51,9 @@ module CNProductsMod real(r8), pointer :: gru_prod100_gain_grc(:) ! (g[C or N]/m2/s) gross unrepresented landcover addition to 100-year wood product pool real(r8), pointer :: gru_woodprod_gain_grc(:) ! (g[C or N]/m2/s) gross unrepresented landcover addition to wood product pools real(r8), pointer :: hrv_deadstem_to_prod10_patch(:) ! (g[C or N]/m2/s) dead stem harvest to 10-year wood product pool - real(r8), pointer :: hrv_deadstem_to_prod10_grc(:) ! (g[C or N]/m2/s) dead stem harvest to 10-year wood product pool + real(r8), pointer,public :: hrv_deadstem_to_prod10_grc(:) ! (g[C or N]/m2/s) dead stem harvest to 10-year wood product pool real(r8), pointer :: hrv_deadstem_to_prod100_patch(:) ! (g[C or N]/m2/s) dead stem harvest to 100-year wood product pool - real(r8), pointer :: hrv_deadstem_to_prod100_grc(:) ! (g[C or N]/m2/s) dead stem harvest to 100-year wood product pool + real(r8), pointer,public :: hrv_deadstem_to_prod100_grc(:) ! (g[C or N]/m2/s) dead stem harvest to 100-year wood product pool real(r8), pointer :: crop_harvest_to_cropprod1_patch(:) ! (g[C or N]/m2/s) crop harvest to 1-year crop product pool real(r8), pointer :: crop_harvest_to_cropprod1_grc(:) ! (g[C or N]/m2/s) crop harvest to 1-year crop product pool @@ -69,12 +71,14 @@ module CNProductsMod procedure, private :: InitHistory procedure, private :: InitCold procedure, public :: Restart - + procedure, public :: SetValues + ! Science routines procedure, public :: UpdateProducts procedure, private :: PartitionWoodFluxes procedure, private :: PartitionCropFluxes - procedure, private :: ComputeSummaryVars + procedure, public :: ComputeProductSummaryVars + procedure, public :: ComputeSummaryVars end type cn_products_type @@ -160,6 +164,29 @@ subroutine InitAllocate(this, bounds) end subroutine InitAllocate + subroutine SetValues(this, bounds, setval) + + ! !ARGUMENTS: + class(cn_products_type), intent(inout) :: this + type(bounds_type), intent(in) :: bounds + real(r8), intent(in) :: setval + + ! This zero's arrays that are incremented on each model time-step + ! the hrv_deadstem arrays use a p2g routine for the use_cn portion + ! but we added this zero'ing here because FATES needs it zero'd + + this%dwt_prod10_gain_grc(bounds%begg:bounds%endg) = setval + this%dwt_prod100_gain_grc(bounds%begg:bounds%endg) = setval + this%dwt_cropprod1_gain_grc(bounds%begg:bounds%endg) = setval + + this%crop_harvest_to_cropprod1_grc(bounds%begg:bounds%endg) = setval + this%hrv_deadstem_to_prod10_grc(bounds%begg:bounds%endg) = setval + this%hrv_deadstem_to_prod100_grc(bounds%begg:bounds%endg) = setval + + return + end subroutine SetValues + + !----------------------------------------------------------------------- subroutine InitHistory(this, bounds) ! !USES: @@ -475,6 +502,7 @@ subroutine UpdateProducts(this, bounds, & ! !DESCRIPTION: ! Update all loss fluxes from wood and crop product pools, and update product pool ! state variables for both loss and gain terms + ! This is only for non-fates patches and columns ! ! !ARGUMENTS: class(cn_products_type) , intent(inout) :: this @@ -484,13 +512,13 @@ subroutine UpdateProducts(this, bounds, & ! dynamic landcover addition to wood product pools (g/m2/s) [patch]; although this is ! a patch-level flux, it is expressed per unit GRIDCELL area - real(r8), intent(in) :: dwt_wood_product_gain_patch( bounds%begp: ) + real(r8), intent(in) :: dwt_wood_product_gain_patch(bounds%begp:) ! gross unrepresented landcover addition to wood product pools (g/m2/s) [patch] real(r8), intent(in) :: gru_wood_product_gain_patch( bounds%begp: ) ! wood harvest addition to wood product pools (g/m2/s) [patch] - real(r8), intent(in) :: wood_harvest_patch( bounds%begp: ) + real(r8), intent(in) :: wood_harvest_patch(bounds%begp:) ! dynamic landcover addition to crop product pools (g/m2/s) [patch]; although this is ! a patch-level flux, it is expressed per unit GRIDCELL area @@ -498,78 +526,30 @@ subroutine UpdateProducts(this, bounds, & ! crop harvest to crop product pool (g/m2/s) [patch] real(r8), intent(in) :: crop_harvest_to_cropprod_patch( bounds%begp: ) - ! - ! !LOCAL VARIABLES: - integer :: g ! indices - real(r8) :: dt ! time step (seconds) - real(r8) :: kprod1 ! decay constant for 1-year product pool - real(r8) :: kprod10 ! decay constant for 10-year product pool - real(r8) :: kprod100 ! decay constant for 100-year product pool - !----------------------------------------------------------------------- + SHR_ASSERT_ALL_FL((ubound(dwt_wood_product_gain_patch) == (/bounds%endp/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(gru_wood_product_gain_patch) == (/bounds%endp/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(wood_harvest_patch) == (/bounds%endp/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(dwt_crop_product_gain_patch) == (/bounds%endp/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(crop_harvest_to_cropprod_patch) == (/bounds%endp/)), sourcefile, __LINE__) - + call this%PartitionWoodFluxes(bounds, & num_soilp, filter_soilp, & dwt_wood_product_gain_patch(bounds%begp:bounds%endp), & gru_wood_product_gain_patch(bounds%begp:bounds%endp), & wood_harvest_patch(bounds%begp:bounds%endp)) - + call this%PartitionCropFluxes(bounds, & num_soilp, filter_soilp, & dwt_crop_product_gain_patch(bounds%begp:bounds%endp), & crop_harvest_to_cropprod_patch(bounds%begp:bounds%endp)) - ! calculate losses from product pools - ! the following (1/s) rate constants result in ~90% loss of initial state over 1, 10 and 100 years, - ! respectively, using a discrete-time fractional decay algorithm. - kprod1 = 7.2e-8_r8 - kprod10 = 7.2e-9_r8 - kprod100 = 7.2e-10_r8 - - do g = bounds%begg, bounds%endg - ! calculate fluxes out of product pools (1/sec) - this%cropprod1_loss_grc(g) = this%cropprod1_grc(g) * kprod1 - this%prod10_loss_grc(g) = this%prod10_grc(g) * kprod10 - this%prod100_loss_grc(g) = this%prod100_grc(g) * kprod100 - end do - - ! set time steps - dt = get_step_size_real() - - ! update product state variables - do g = bounds%begg, bounds%endg - - ! fluxes into wood & crop product pools, from landcover change - this%cropprod1_grc(g) = this%cropprod1_grc(g) + this%dwt_cropprod1_gain_grc(g)*dt - this%prod10_grc(g) = this%prod10_grc(g) + this%dwt_prod10_gain_grc(g)*dt - this%prod100_grc(g) = this%prod100_grc(g) + this%dwt_prod100_gain_grc(g)*dt - - ! fluxes into wood & crop product pools, from gross unrepresented landcover change - this%prod10_grc(g) = this%prod10_grc(g) + this%gru_prod10_gain_grc(g)*dt - this%prod100_grc(g) = this%prod100_grc(g) + this%gru_prod100_gain_grc(g)*dt - - ! fluxes into wood & crop product pools, from harvest - this%cropprod1_grc(g) = this%cropprod1_grc(g) + this%crop_harvest_to_cropprod1_grc(g)*dt - this%prod10_grc(g) = this%prod10_grc(g) + this%hrv_deadstem_to_prod10_grc(g)*dt - this%prod100_grc(g) = this%prod100_grc(g) + this%hrv_deadstem_to_prod100_grc(g)*dt - - ! fluxes out of wood & crop product pools, from decomposition - this%cropprod1_grc(g) = this%cropprod1_grc(g) - this%cropprod1_loss_grc(g)*dt - this%prod10_grc(g) = this%prod10_grc(g) - this%prod10_loss_grc(g)*dt - this%prod100_grc(g) = this%prod100_grc(g) - this%prod100_loss_grc(g)*dt - - end do - - call this%ComputeSummaryVars(bounds) - + return end subroutine UpdateProducts !----------------------------------------------------------------------- + subroutine PartitionWoodFluxes(this, bounds, & num_soilp, filter_soilp, & dwt_wood_product_gain_patch, & @@ -659,7 +639,7 @@ subroutine PartitionWoodFluxes(this, bounds, & this%hrv_deadstem_to_prod100_patch(p) = & wood_harvest_patch(p) * (1.0_r8 - pftcon%pprodharv10(patch%itype(p))) end do - + ! Average harvest fluxes from patch to gridcell call p2g(bounds, & this%hrv_deadstem_to_prod10_patch(bounds%begp:bounds%endp), & @@ -667,24 +647,18 @@ subroutine PartitionWoodFluxes(this, bounds, & p2c_scale_type = 'unity', & c2l_scale_type = 'unity', & l2g_scale_type = 'unity') - + call p2g(bounds, & this%hrv_deadstem_to_prod100_patch(bounds%begp:bounds%endp), & this%hrv_deadstem_to_prod100_grc(bounds%begg:bounds%endg), & p2c_scale_type = 'unity', & c2l_scale_type = 'unity', & l2g_scale_type = 'unity') - - ! Zero the dwt gains - do g = bounds%begg, bounds%endg - this%dwt_prod10_gain_grc(g) = 0._r8 - this%dwt_prod100_gain_grc(g) = 0._r8 - end do - + ! Partition dynamic land cover fluxes to 10 and 100-year product pools. do p = bounds%begp, bounds%endp g = patch%gridcell(p) - + ! Note that pprod10 + pprod100 do NOT sum to 1: some fraction of the dwt changes ! was lost to other fluxes. dwt_wood_product_gain_patch gives the amount that goes ! to all product pools, so we need to determine the fraction of that flux that @@ -702,14 +676,15 @@ subroutine PartitionWoodFluxes(this, bounds, & dwt_wood_product_gain_patch(p) * pprod10_frac this%dwt_prod100_gain_grc(g) = this%dwt_prod100_gain_grc(g) + & dwt_wood_product_gain_patch(p) * pprod100_frac + else if (dwt_wood_product_gain_patch(p) > 0) then call endrun(& msg='ERROR: dwt_wood_product_gain_patch(p) > 0' // & errMsg(sourcefile, __LINE__)) end if - + end do - + end subroutine PartitionWoodFluxes !----------------------------------------------------------------------- @@ -768,10 +743,6 @@ subroutine PartitionCropFluxes(this, bounds, & ! Determine gains from dynamic landcover - do g = bounds%begg, bounds%endg - this%dwt_cropprod1_gain_grc(g) = 0._r8 - end do - do p = bounds%begp, bounds%endp g = patch%gridcell(p) @@ -784,6 +755,61 @@ subroutine PartitionCropFluxes(this, bounds, & end subroutine PartitionCropFluxes + !----------------------------------------------------------------------- + subroutine ComputeProductSummaryVars(this, bounds) + + class(cn_products_type) , intent(inout) :: this + type(bounds_type) , intent(in) :: bounds + + integer :: g ! indices + real(r8) :: dt ! time step (seconds) + real(r8) :: kprod1 ! decay constant for 1-year product pool + real(r8) :: kprod10 ! decay constant for 10-year product pool + real(r8) :: kprod100 ! decay constant for 100-year product pool + + ! calculate losses from product pools + ! the following (1/s) rate constants result in ~90% loss of initial state over 1, 10 and 100 years, + ! respectively, using a discrete-time fractional decay algorithm. + kprod1 = 7.2e-8_r8 + kprod10 = 7.2e-9_r8 + kprod100 = 7.2e-10_r8 + + do g = bounds%begg, bounds%endg + ! calculate fluxes out of product pools (1/sec) + this%cropprod1_loss_grc(g) = this%cropprod1_grc(g) * kprod1 + this%prod10_loss_grc(g) = this%prod10_grc(g) * kprod10 + this%prod100_loss_grc(g) = this%prod100_grc(g) * kprod100 + end do + + ! set time steps + dt = get_step_size_real() + + ! update product state variables + do g = bounds%begg, bounds%endg + + ! fluxes into wood & crop product pools, from landcover change + this%cropprod1_grc(g) = this%cropprod1_grc(g) + this%dwt_cropprod1_gain_grc(g)*dt + this%prod10_grc(g) = this%prod10_grc(g) + this%dwt_prod10_gain_grc(g)*dt + this%prod100_grc(g) = this%prod100_grc(g) + this%dwt_prod100_gain_grc(g)*dt + + ! fluxes into wood & grain product pools, from gross unrepresented landcover change + this%prod10_grc(g) = this%prod10_grc(g) + this%gru_prod10_gain_grc(g)*dt + this%prod100_grc(g) = this%prod100_grc(g) + this%gru_prod100_gain_grc(g)*dt + + ! fluxes into wood & crop product pools, from harvest + this%cropprod1_grc(g) = this%cropprod1_grc(g) + this%crop_harvest_to_cropprod1_grc(g)*dt + this%prod10_grc(g) = this%prod10_grc(g) + this%hrv_deadstem_to_prod10_grc(g)*dt + this%prod100_grc(g) = this%prod100_grc(g) + this%hrv_deadstem_to_prod100_grc(g)*dt + + ! fluxes out of wood & crop product pools, from decomposition + this%cropprod1_grc(g) = this%cropprod1_grc(g) - this%cropprod1_loss_grc(g)*dt + this%prod10_grc(g) = this%prod10_grc(g) - this%prod10_loss_grc(g)*dt + this%prod100_grc(g) = this%prod100_grc(g) - this%prod100_loss_grc(g)*dt + end do + + return + end subroutine ComputeProductSummaryVars + !----------------------------------------------------------------------- subroutine ComputeSummaryVars(this, bounds) @@ -799,10 +825,9 @@ subroutine ComputeSummaryVars(this, bounds) ! ! !LOCAL VARIABLES: integer :: g ! indices - - character(len=*), parameter :: subname = 'ComputeSummaryVars' !----------------------------------------------------------------------- - + character(len=*), parameter :: subname = 'ComputeSummaryVars' + do g = bounds%begg, bounds%endg ! total wood products diff --git a/src/biogeochem/CNVegCarbonFluxType.F90 b/src/biogeochem/CNVegCarbonFluxType.F90 index 7864007faf..e930543e25 100644 --- a/src/biogeochem/CNVegCarbonFluxType.F90 +++ b/src/biogeochem/CNVegCarbonFluxType.F90 @@ -13,6 +13,7 @@ module CNVegCarbonFluxType use clm_varpar , only : ndecomp_cascade_transitions, ndecomp_pools use clm_varpar , only : nvegcpool use clm_varpar , only : nlevdecomp_full, nlevdecomp, i_litr_min, i_litr_max + use clm_varpar , only : mxharvests use clm_varcon , only : spval, dzsoi_decomp use clm_varctl , only : use_cndv, use_c13, use_c14, use_nitrif_denitrif, use_crop use CNSharedParamsMod , only : use_matrixcn @@ -139,6 +140,8 @@ module CNVegCarbonFluxType real(r8), pointer :: frootc_to_litter_patch (:) ! fine root C litterfall (gC/m2/s) real(r8), pointer :: livestemc_to_litter_patch (:) ! live stem C litterfall (gC/m2/s) real(r8), pointer :: repr_grainc_to_food_patch (:,:) ! grain C to food for prognostic crop(gC/m2/s) [patch, repr_grain_min:repr_grain_max] + real(r8), pointer :: repr_grainc_to_food_perharv_patch (:,:,:) ! grain C to food for prognostic crop accumulated by harvest (gC/m2) [patch, harvest, repr_grain_min:repr_grain_max]. Not per-second because this variable represents an accumulation over each growing season, to be instantaneously at the end of each calendar year, to provide output that's easier to work with. + real(r8), pointer :: repr_grainc_to_food_thisyr_patch (:,:) ! grain C to food for prognostic crop accumulated this calendar year (gC/m2) [patch, repr_grain_min:repr_grain_max]. Not per-second because this variable represents an accumulation over an entire calendar year, to be saved instantaneously at the end of each calendar year, to provide output that's easier to work with. real(r8), pointer :: repr_structurec_to_cropprod_patch (:,:) ! reproductive structure C to crop product pool for prognostic crop (gC/m2/s) [patch, repr_structure_min:repr_structure_max] real(r8), pointer :: repr_structurec_to_litter_patch (:,:) ! reproductive structure C to litter for prognostic crop (gC/m2/s) [patch, repr_structure_min:repr_structure_max] @@ -431,21 +434,23 @@ module CNVegCarbonFluxType contains !------------------------------------------------------------------------ - subroutine Init(this, bounds, carbon_type, dribble_crophrv_xsmrpool_2atm) + subroutine Init(this, bounds, carbon_type, dribble_crophrv_xsmrpool_2atm,alloc_full_veg) class(cnveg_carbonflux_type) :: this type(bounds_type), intent(in) :: bounds character(len=3) , intent(in) :: carbon_type ! one of ['c12', c13','c14'] logical , intent(in) :: dribble_crophrv_xsmrpool_2atm + logical , intent(in) :: alloc_full_veg this%dribble_crophrv_xsmrpool_2atm = dribble_crophrv_xsmrpool_2atm - call this%InitAllocate ( bounds, carbon_type) - if(use_matrixcn)then - call this%InitTransfer () + call this%InitAllocate ( bounds, carbon_type,alloc_full_veg) + if(alloc_full_veg)then + if(use_matrixcn)then + call this%InitTransfer () + end if + call this%InitHistory ( bounds, carbon_type ) + call this%InitCold (bounds ) end if - call this%InitHistory ( bounds, carbon_type ) - call this%InitCold (bounds ) - end subroutine Init subroutine InitTransfer (this) @@ -458,12 +463,13 @@ subroutine InitTransfer (this) end subroutine InitTransfer !------------------------------------------------------------------------ - subroutine InitAllocate(this, bounds, carbon_type) + subroutine InitAllocate(this, bounds, carbon_type, alloc_full_veg) ! ! !ARGUMENTS: class (cnveg_carbonflux_type) :: this type(bounds_type), intent(in) :: bounds character(len=*) , intent(in) :: carbon_type ! one of ['c12', c13','c14'] + logical , intent(in) :: alloc_full_veg ! ! !LOCAL VARIABLES: integer :: begp,endp @@ -473,9 +479,15 @@ subroutine InitAllocate(this, bounds, carbon_type) character(len=:), allocatable :: carbon_type_suffix !------------------------------------------------------------------------ - begp = bounds%begp; endp = bounds%endp - begc = bounds%begc; endc = bounds%endc - begg = bounds%begg; endg = bounds%endg + if(alloc_full_veg)then + begp = bounds%begp; endp = bounds%endp + begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg + else + begp = 0; endp = 0 + begc = 0; endc = 0 + begg = 0; endg = 0 + end if allocate(this%m_leafc_to_litter_patch (begp:endp)) ; this%m_leafc_to_litter_patch (:) = nan allocate(this%m_frootc_to_litter_patch (begp:endp)) ; this%m_frootc_to_litter_patch (:) = nan @@ -651,6 +663,8 @@ subroutine InitAllocate(this, bounds, carbon_type) allocate(this%cpool_to_reproductivec_storage_patch(begp:endp, nrepr)); this%cpool_to_reproductivec_storage_patch (:,:) = nan allocate(this%livestemc_to_litter_patch (begp:endp)) ; this%livestemc_to_litter_patch (:) = nan allocate(this%repr_grainc_to_food_patch(begp:endp, repr_grain_min:repr_grain_max)) ; this%repr_grainc_to_food_patch (:,:) = nan + allocate(this%repr_grainc_to_food_perharv_patch(begp:endp, 1:mxharvests, repr_grain_min:repr_grain_max)) ; this%repr_grainc_to_food_perharv_patch (:,:,:) = nan + allocate(this%repr_grainc_to_food_thisyr_patch(begp:endp, repr_grain_min:repr_grain_max)) ; this%repr_grainc_to_food_thisyr_patch (:,:) = nan allocate(this%repr_structurec_to_cropprod_patch(begp:endp, repr_structure_min:repr_structure_max)) this%repr_structurec_to_cropprod_patch(:,:) = nan allocate(this%repr_structurec_to_litter_patch(begp:endp, repr_structure_min:repr_structure_max)) @@ -925,6 +939,33 @@ subroutine InitHistory(this, bounds, carbon_type) ptr_patch=data1dptr) end do + this%repr_grainc_to_food_perharv_patch(begp:endp,:,:) = spval + do k = repr_grain_min, repr_grain_max + data2dptr => this%repr_grainc_to_food_perharv_patch(:,:,k) + call hist_addfld2d ( & + ! e.g., GRAINC_TO_FOOD_PERHARV + fname=get_repr_hist_fname(k)//'C_TO_FOOD_PERHARV', & + units='gC/m^2', & + type2d='mxharvests', & + avgflag='I', & + long_name=get_repr_longname(k)//' C to food per harvest; should only be output annually', & + ptr_patch=data2dptr, & + default='inactive') + end do + + this%repr_grainc_to_food_thisyr_patch(begp:endp,:) = spval + do k = repr_grain_min, repr_grain_max + data1dptr => this%repr_grainc_to_food_thisyr_patch(:,k) + call hist_addfld1d ( & + ! e.g., GRAINC_TO_FOOD_ANN + fname=get_repr_hist_fname(k)//'C_TO_FOOD_ANN', & + units='gC/m^2', & + avgflag='I', & + long_name=get_repr_longname(k)//' C to food harvested per calendar year; should only be output annually', & + ptr_patch=data1dptr, & + default='inactive') + end do + this%leafc_to_biofuelc_patch(begp:endp) = spval call hist_addfld1d (fname='LEAFC_TO_BIOFUELC', units='gC/m^2/s', & avgflag='A', long_name='leaf C to biofuel C', & @@ -2926,7 +2967,7 @@ subroutine InitHistory(this, bounds, carbon_type) do k = 1, ndecomp_pools if ( decomp_cascade_con%is_litter(k) .or. decomp_cascade_con%is_cwd(k) ) then data1dptr => this%m_decomp_cpools_to_fire_col(:,k) - fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'C_TO_FIRE' + fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'_C_TO_FIRE' longname = trim(decomp_cascade_con%decomp_pool_name_long(k))//' C fire loss' call hist_addfld1d (fname=fieldname, units='gC/m^2/s', & avgflag='A', long_name=longname, & @@ -2934,7 +2975,7 @@ subroutine InitHistory(this, bounds, carbon_type) if ( nlevdecomp_full > 1 ) then data2dptr => this%m_decomp_cpools_to_fire_vr_col(:,:,k) - fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'C_TO_FIRE'//trim(vr_suffix) + fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'_C_TO_FIRE'//trim(vr_suffix) longname = trim(decomp_cascade_con%decomp_pool_name_long(k))//' C fire loss' call hist_addfld_decomp (fname=fieldname, units='gC/m^3/s', type2d='levdcmp', & avgflag='A', long_name=longname, & @@ -3135,7 +3176,7 @@ subroutine InitHistory(this, bounds, carbon_type) do k = 1, ndecomp_pools if ( decomp_cascade_con%is_litter(k) .or. decomp_cascade_con%is_cwd(k) ) then data1dptr => this%m_decomp_cpools_to_fire_col(:,k) - fieldname = 'C13_M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'C_TO_FIRE' + fieldname = 'C13_M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'_C_TO_FIRE' longname = 'C13 '//trim(decomp_cascade_con%decomp_pool_name_long(k))//' C fire loss' call hist_addfld1d (fname=fieldname, units='gC13/m^2', & avgflag='A', long_name=longname, & @@ -3143,7 +3184,7 @@ subroutine InitHistory(this, bounds, carbon_type) if ( nlevdecomp_full > 1 ) then data2dptr => this%m_decomp_cpools_to_fire_vr_col(:,:,k) - fieldname = 'C13_M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'C_TO_FIRE'//trim(vr_suffix) + fieldname = 'C13_M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'_C_TO_FIRE'//trim(vr_suffix) longname = 'C13 '//trim(decomp_cascade_con%decomp_pool_name_long(k))//' C fire loss' call hist_addfld_decomp (fname=fieldname, units='gC13/m^3', type2d='levdcmp', & avgflag='A', long_name=longname, & @@ -3295,7 +3336,7 @@ subroutine InitHistory(this, bounds, carbon_type) do k = 1, ndecomp_pools if ( decomp_cascade_con%is_litter(k) .or. decomp_cascade_con%is_cwd(k) ) then data1dptr => this%m_decomp_cpools_to_fire_col(:,k) - fieldname = 'C14_M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'C_TO_FIRE' + fieldname = 'C14_M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'_C_TO_FIRE' longname = 'C14 '//trim(decomp_cascade_con%decomp_pool_name_long(k))//' C fire loss' call hist_addfld1d (fname=fieldname, units='gC14/m^2', & avgflag='A', long_name=longname, & @@ -3303,7 +3344,7 @@ subroutine InitHistory(this, bounds, carbon_type) if ( nlevdecomp_full > 1 ) then data2dptr => this%m_decomp_cpools_to_fire_vr_col(:,:,k) - fieldname = 'C14_M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'C_TO_FIRE'//trim(vr_suffix) + fieldname = 'C14_M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'_C_TO_FIRE'//trim(vr_suffix) longname = 'C14 '//trim(decomp_cascade_con%decomp_pool_name_long(k))//' C fire loss' call hist_addfld_decomp (fname=fieldname, units='gC14/m^3', type2d='levdcmp', & avgflag='A', long_name=longname, & @@ -3625,6 +3666,7 @@ subroutine RestartBulkOnly ( this, bounds, ncid, flag ) logical :: readvar ! determine if variable is on initial file character(len=256) :: varname real(r8), pointer :: data1dptr(:) ! temp. pointer for slicing larger arrays + real(r8), pointer :: data2dptr(:,:) ! temp. pointer for slicing larger arrays !------------------------------------------------------------------------ if (use_crop) then @@ -3657,6 +3699,38 @@ subroutine RestartBulkOnly ( this, bounds, ncid, flag ) units='gC/m2/s', & interpinic_flag='interp', readvar=readvar, data=data1dptr) end do + + ! Read or write variable(s) with mxharvests dimension + ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2022-06-10) See note in CallRestartvarDimOK() + if (CallRestartvarDimOK(ncid, flag, 'mxharvests')) then + do k = repr_grain_min, repr_grain_max + data2dptr => this%repr_grainc_to_food_perharv_patch(:,:,k) + ! e.g., grainc_to_food_perharv + varname = get_repr_rest_fname(k)//'c_to_food_perharv' + call restartvar(ncid=ncid, flag=flag, varname=varname, & + xtype=ncd_double, & + dim1name='pft', & + dim2name='mxharvests', & + switchdim=.true., & + long_name=get_repr_longname(k)//' C to food per harvest; should only be output annually', & + units='gC/m2', & + readvar=readvar, & + scale_by_thickness=.false., & + interpinic_flag='interp', data=data2dptr) + end do + end if + + do k = repr_grain_min, repr_grain_max + data1dptr => this%repr_grainc_to_food_thisyr_patch(:,k) + ! e.g., grainc_to_food_thisyr + varname = get_repr_rest_fname(k)//'c_to_food_thisyr' + call restartvar(ncid=ncid, flag=flag, varname=varname, & + xtype=ncd_double, & + dim1name='pft', & + long_name=get_repr_longname(k)//' C to food per calendar year; should only be output annually', & + units='gC/m2', & + interpinic_flag='interp', readvar=readvar, data=data1dptr) + end do do k = 1, nrepr data1dptr => this%cpool_to_reproductivec_patch(:,k) diff --git a/src/biogeochem/CNVegCarbonStateType.F90 b/src/biogeochem/CNVegCarbonStateType.F90 index 610689fdb6..7515051d38 100644 --- a/src/biogeochem/CNVegCarbonStateType.F90 +++ b/src/biogeochem/CNVegCarbonStateType.F90 @@ -68,7 +68,6 @@ module CNVegCarbonStateType real(r8), pointer :: ctrunc_patch (:) ! (gC/m2) patch-level sink for C truncation real(r8), pointer :: woodc_patch (:) ! (gC/m2) wood C real(r8), pointer :: leafcmax_patch (:) ! (gC/m2) ann max leaf C - real(r8), pointer :: totc_patch (:) ! (gC/m2) total patch-level carbon, including cpool real(r8), pointer :: rootc_col (:) ! (gC/m2) root carbon at column level (fire) real(r8), pointer :: leafc_col (:) ! (gC/m2) column-level leafc (fire) real(r8), pointer :: deadstemc_col (:) ! (gC/m2) column-level deadstemc (fire) @@ -82,21 +81,21 @@ module CNVegCarbonStateType ! summary (diagnostic) state variables, not involved in mass balance real(r8), pointer :: dispvegc_patch (:) ! (gC/m2) displayed veg carbon, excluding storage and cpool real(r8), pointer :: storvegc_patch (:) ! (gC/m2) stored vegetation carbon, excluding cpool + + logical, private :: dribble_crophrv_xsmrpool_2atm ! Flag to indicate if should harvest xsmrpool to the atmosphere + ! it originates and is defined in CNVegetationFacade.F90 + + ! Total C pools + real(r8), pointer :: totc_patch (:) ! (gC/m2) total patch-level carbon, including cpool real(r8), pointer :: totvegc_patch (:) ! (gC/m2) total vegetation carbon, excluding cpool - real(r8), pointer :: totvegc_col (:) ! (gC/m2) total vegetation carbon, excluding cpool averaged to column (p2c) - - ! Total C pools + real(r8), pointer :: totvegc_col (:) ! (gC/m2) total vegetation carbon, excluding cpool averaged to column (p2c) real(r8), pointer :: totc_p2c_col (:) ! (gC/m2) totc_patch averaged to col - real(r8), pointer :: totc_col (:) ! (gC/m2) total column carbon, incl veg and cpool - real(r8), pointer :: totecosysc_col (:) ! (gC/m2) total ecosystem carbon, incl veg but excl cpool - real(r8), pointer :: totc_grc (:) ! (gC/m2) total gridcell carbon - - logical, private :: dribble_crophrv_xsmrpool_2atm + contains procedure , public :: Init procedure , public :: SetValues - procedure , public :: ZeroDWT + procedure , public :: ZeroDwt procedure , public :: Restart procedure , public :: Summary => Summary_carbonstate procedure , public :: DynamicPatchAdjustments ! adjust state variables when patch areas change @@ -127,7 +126,7 @@ module CNVegCarbonStateType !------------------------------------------------------------------------ subroutine Init(this, bounds, carbon_type, ratio, NLFilename, & - dribble_crophrv_xsmrpool_2atm, c12_cnveg_carbonstate_inst) + dribble_crophrv_xsmrpool_2atm, alloc_full_veg, c12_cnveg_carbonstate_inst) class(cnveg_carbonstate_type) :: this type(bounds_type) , intent(in) :: bounds @@ -135,6 +134,7 @@ subroutine Init(this, bounds, carbon_type, ratio, NLFilename, & character(len=*) , intent(in) :: carbon_type ! Carbon isotope type C12, C13 or C1 character(len=*) , intent(in) :: NLFilename ! Namelist filename logical , intent(in) :: dribble_crophrv_xsmrpool_2atm + logical , intent(in) :: alloc_full_veg ! total number of bgc patches (non-fates) type(cnveg_carbonstate_type) , intent(in), optional :: c12_cnveg_carbonstate_inst ! cnveg_carbonstate for C12 (if C13 or C14) !----------------------------------------------------------------------- @@ -142,15 +142,17 @@ subroutine Init(this, bounds, carbon_type, ratio, NLFilename, & this%dribble_crophrv_xsmrpool_2atm = dribble_crophrv_xsmrpool_2atm - call this%InitAllocate ( bounds) - call this%InitReadNML ( NLFilename ) - call this%InitHistory ( bounds, carbon_type) - if (present(c12_cnveg_carbonstate_inst)) then - call this%InitCold ( bounds, ratio, carbon_type, c12_cnveg_carbonstate_inst ) - else - call this%InitCold ( bounds, ratio, carbon_type ) + call this%InitAllocate ( bounds, alloc_full_veg) + if(alloc_full_veg)then + call this%InitReadNML ( NLFilename ) + call this%InitHistory ( bounds, carbon_type) + if (present(c12_cnveg_carbonstate_inst)) then + call this%InitCold ( bounds, ratio, carbon_type, c12_cnveg_carbonstate_inst ) + else + call this%InitCold ( bounds, ratio, carbon_type ) + end if end if - + end subroutine Init !------------------------------------------------------------------------ @@ -214,21 +216,28 @@ subroutine InitReadNML(this, NLFilename) end subroutine InitReadNML !------------------------------------------------------------------------ - subroutine InitAllocate(this, bounds) + subroutine InitAllocate(this, bounds, alloc_full_veg) ! ! !ARGUMENTS: class (cnveg_carbonstate_type) :: this - type(bounds_type), intent(in) :: bounds + type(bounds_type), intent(in) :: bounds + logical,intent(in) :: alloc_full_veg ! Total number of bgc patches on the proc (non_fates) ! ! !LOCAL VARIABLES: integer :: begp,endp integer :: begc,endc integer :: begg,endg !------------------------------------------------------------------------ - - begp = bounds%begp; endp = bounds%endp - begc = bounds%begc; endc = bounds%endc - begg = bounds%begg; endg = bounds%endg + + if(alloc_full_veg)then + begp = bounds%begp; endp = bounds%endp + begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg + else + begp = 0;endp=0 + begc = 0;endc=0 + begg = 0;endg=0 + end if allocate(this%leafc_patch (begp:endp)) ; this%leafc_patch (:) = nan allocate(this%leafc_storage_patch (begp:endp)) ; this%leafc_storage_patch (:) = nan @@ -277,9 +286,6 @@ subroutine InitAllocate(this, bounds) allocate(this%totvegc_col (begc:endc)) ; this%totvegc_col (:) = nan allocate(this%totc_p2c_col (begc:endc)) ; this%totc_p2c_col (:) = nan - allocate(this%totc_col (begc:endc)) ; this%totc_col (:) = nan - allocate(this%totecosysc_col (begc:endc)) ; this%totecosysc_col (:) = nan - allocate(this%totc_grc (begg:endg)) ; this%totc_grc (:) = nan ! Matrix solution variables if(use_matrixcn)then @@ -509,16 +515,6 @@ subroutine InitHistory(this, bounds, carbon_type) avgflag='A', long_name='fuel load', & ptr_col=this%fuelc_col) - this%totc_col(begc:endc) = spval - call hist_addfld1d (fname='TOTCOLC', units='gC/m^2', & - avgflag='A', long_name='total column carbon, incl veg and cpool but excl product pools', & - ptr_col=this%totc_col) - - this%totecosysc_col(begc:endc) = spval - call hist_addfld1d (fname='TOTECOSYSC', units='gC/m^2', & - avgflag='A', long_name='total ecosystem carbon, incl veg but excl cpool and product pools', & - ptr_col=this%totecosysc_col) - ! Matrix solution history variables if ( use_matrixcn )then end if @@ -675,16 +671,6 @@ subroutine InitHistory(this, bounds, carbon_type) avgflag='A', long_name='C13 pool for seeding new PFTs via dynamic landcover', & ptr_gcell=this%seedc_grc, default='inactive') - this%totc_col(begc:endc) = spval - call hist_addfld1d (fname='C13_TOTCOLC', units='gC13/m^2', & - avgflag='A', long_name='C13 total column carbon, incl veg and cpool but excl product pools', & - ptr_col=this%totc_col, default='inactive') - - this%totecosysc_col(begc:endc) = spval - call hist_addfld1d (fname='C13_TOTECOSYSC', units='gC13/m^2', & - avgflag='A', long_name='C13 total ecosystem carbon, incl veg but excl cpool and product pools', & - ptr_col=this%totecosysc_col) - if (use_crop) then this%reproductivec_patch(begp:endp,:) = spval do k = 1, nrepr @@ -866,16 +852,6 @@ subroutine InitHistory(this, bounds, carbon_type) avgflag='A', long_name='C14 pool for seeding new PFTs via dynamic landcover', & ptr_gcell=this%seedc_grc, default='inactive') - this%totc_col(begc:endc) = spval - call hist_addfld1d (fname='C14_TOTCOLC', units='gC14/m^2', & - avgflag='A', long_name='C14 total column carbon, incl veg and cpool but excl product pools', & - ptr_col=this%totc_col, default='inactive') - - this%totecosysc_col(begc:endc) = spval - call hist_addfld1d (fname='C14_TOTECOSYSC', units='gC14/m^2', & - avgflag='A', long_name='C14 total ecosystem carbon, incl veg but excl cpool and product pools', & - ptr_col=this%totecosysc_col) - if (use_crop) then this%reproductivec_patch(begp:endp,:) = spval do k = 1, nrepr @@ -1099,16 +1075,14 @@ subroutine InitCold(this, bounds, ratio, carbon_type, c12_cnveg_carbonstate_inst ! this%totgrainc_col(c) = 0._r8 ! total carbon pools - this%totecosysc_col(c) = 0._r8 this%totc_p2c_col(c) = 0._r8 - this%totc_col(c) = 0._r8 + end if end do do g = bounds%begg, bounds%endg this%seedc_grc(g) = 0._r8 - this%totc_grc(g) = 0._r8 end do ! initialize fields for special filters @@ -2596,8 +2570,6 @@ subroutine SetValues ( this, & this%fuelc_crop_col(i) = value_column this%totvegc_col(i) = value_column this%totc_p2c_col(i) = value_column - this%totc_col(i) = value_column - this%totecosysc_col(i) = value_column end do end subroutine SetValues @@ -2625,11 +2597,8 @@ subroutine ZeroDwt( this, bounds ) end subroutine ZeroDwt !----------------------------------------------------------------------- - subroutine Summary_carbonstate(this, bounds, num_allc, filter_allc, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_cwdc_col, soilbiogeochem_totlitc_col, & - soilbiogeochem_totmicc_col, soilbiogeochem_totsomc_col, & - soilbiogeochem_ctrunc_col) + subroutine Summary_carbonstate(this, bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp) + ! ! !USES: use subgridAveMod, only : p2c @@ -2642,33 +2611,20 @@ subroutine Summary_carbonstate(this, bounds, num_allc, filter_allc, & ! !ARGUMENTS: class(cnveg_carbonstate_type) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_allc ! number of columns in allc filter - integer , intent(in) :: filter_allc(:) ! filter for all active columns - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches - real(r8) , intent(in) :: soilbiogeochem_cwdc_col(bounds%begc:) - real(r8) , intent(in) :: soilbiogeochem_totmicc_col(bounds%begc:) - real(r8) , intent(in) :: soilbiogeochem_totlitc_col(bounds%begc:) - real(r8) , intent(in) :: soilbiogeochem_totsomc_col(bounds%begc:) - real(r8) , intent(in) :: soilbiogeochem_ctrunc_col(bounds%begc:) + integer , intent(in) :: num_bgc_soilc ! number of bgc soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for bgc soil columns + integer , intent(in) :: num_bgc_vegp ! number of soil patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for soil patches + ! ! !LOCAL VARIABLES: integer :: c,p,j,k,l ! indices integer :: fp,fc ! lake filter indices !----------------------------------------------------------------------- - SHR_ASSERT_ALL_FL((ubound(soilbiogeochem_cwdc_col) == (/bounds%endc/)), sourcefile, __LINE__) - SHR_ASSERT_ALL_FL((ubound(soilbiogeochem_totmicc_col) == (/bounds%endc/)), sourcefile, __LINE__) - SHR_ASSERT_ALL_FL((ubound(soilbiogeochem_totlitc_col) == (/bounds%endc/)), sourcefile, __LINE__) - SHR_ASSERT_ALL_FL((ubound(soilbiogeochem_totsomc_col) == (/bounds%endc/)), sourcefile, __LINE__) - SHR_ASSERT_ALL_FL((ubound(soilbiogeochem_ctrunc_col) == (/bounds%endc/)), sourcefile, __LINE__) - ! calculate patch -level summary of carbon state - - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) ! displayed vegetation carbon, excluding storage and cpool (DISPVEGC) this%dispvegc_patch(p) = & @@ -2738,36 +2694,16 @@ subroutine Summary_carbonstate(this, bounds, num_allc, filter_allc, & ! -------------------------------------------- ! column level summary ! -------------------------------------------- - - call p2c(bounds, num_soilc, filter_soilc, & - this%totvegc_patch(bounds%begp:bounds%endp), & - this%totvegc_col(bounds%begc:bounds%endc)) - - call p2c(bounds, num_soilc, filter_soilc, & - this%totc_patch(bounds%begp:bounds%endp), & - this%totc_p2c_col(bounds%begc:bounds%endc)) - - do fc = 1,num_allc - c = filter_allc(fc) - - ! total ecosystem carbon, including veg but excluding cpool (TOTECOSYSC) - this%totecosysc_col(c) = & - soilbiogeochem_cwdc_col(c) + & - soilbiogeochem_totmicc_col(c) + & - soilbiogeochem_totlitc_col(c) + & - soilbiogeochem_totsomc_col(c) + & - this%totvegc_col(c) - - ! total column carbon, including veg and cpool (TOTCOLC) - this%totc_col(c) = this%totc_p2c_col(c) + & - soilbiogeochem_cwdc_col(c) + & - soilbiogeochem_totmicc_col(c) + & - soilbiogeochem_totlitc_col(c) + & - soilbiogeochem_totsomc_col(c) + & - soilbiogeochem_ctrunc_col(c) - - end do - + if(num_bgc_vegp>0)then + call p2c(bounds, num_bgc_soilc, filter_bgc_soilc, & + this%totvegc_patch(bounds%begp:bounds%endp), & + this%totvegc_col(bounds%begc:bounds%endc)) + + call p2c(bounds, num_bgc_soilc, filter_bgc_soilc, & + this%totc_patch(bounds%begp:bounds%endp), & + this%totc_p2c_col(bounds%begc:bounds%endc)) + end if + end subroutine Summary_carbonstate !----------------------------------------------------------------------- diff --git a/src/biogeochem/CNVegNitrogenFluxType.F90 b/src/biogeochem/CNVegNitrogenFluxType.F90 index ce164b4c37..3217511c14 100644 --- a/src/biogeochem/CNVegNitrogenFluxType.F90 +++ b/src/biogeochem/CNVegNitrogenFluxType.F90 @@ -292,18 +292,21 @@ module CNVegNitrogenFluxType contains !------------------------------------------------------------------------ - subroutine Init(this, bounds) + subroutine Init(this, bounds, alloc_full_veg) class(cnveg_nitrogenflux_type) :: this - type(bounds_type), intent(in) :: bounds + type(bounds_type), intent(in) :: bounds + logical,intent(in) :: alloc_full_veg - call this%InitAllocate (bounds) - if(use_matrixcn)then - call this%InitTransfer () + call this%InitAllocate (bounds,alloc_full_veg) + if(alloc_full_veg)then + if(use_matrixcn)then + call this%InitTransfer () + end if + call this%InitHistory (bounds) + call this%InitCold (bounds) end if - call this%InitHistory (bounds) - call this%InitCold (bounds) - + end subroutine Init subroutine InitTransfer (this) @@ -323,14 +326,15 @@ subroutine InitTransfer (this) end subroutine InitTransfer !------------------------------------------------------------------------ - subroutine InitAllocate(this, bounds) + subroutine InitAllocate(this, bounds, alloc_full_veg) ! ! !DESCRIPTION: ! Initialize patch nitrogen flux ! ! !ARGUMENTS: class (cnveg_nitrogenflux_type) :: this - type(bounds_type) , intent(in) :: bounds + type(bounds_type) , intent(in) :: bounds + logical,intent(in) :: alloc_full_veg ! ! !LOCAL VARIABLES: integer :: begp,endp @@ -338,10 +342,16 @@ subroutine InitAllocate(this, bounds) integer :: begg,endg !------------------------------------------------------------------------ - begp = bounds%begp; endp = bounds%endp - begc = bounds%begc; endc = bounds%endc - begg = bounds%begg; endg = bounds%endg - + if(alloc_full_veg)then + begp = bounds%begp; endp = bounds%endp + begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg + else + begp = 0; endp = 0 + begc = 0; endc = 0 + begg = 0; endg = 0 + end if + allocate(this%m_leafn_to_litter_patch (begp:endp)) ; this%m_leafn_to_litter_patch (:) = nan allocate(this%m_frootn_to_litter_patch (begp:endp)) ; this%m_frootn_to_litter_patch (:) = nan allocate(this%m_leafn_storage_to_litter_patch (begp:endp)) ; this%m_leafn_storage_to_litter_patch (:) = nan @@ -1048,7 +1058,7 @@ subroutine InitHistory(this, bounds) if ( decomp_cascade_con%is_litter(k) .or. decomp_cascade_con%is_cwd(k) ) then this%m_decomp_npools_to_fire_col(begc:endc,k) = spval data1dptr => this%m_decomp_npools_to_fire_col(:,k) - fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'N_TO_FIRE' + fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'_N_TO_FIRE' longname = trim(decomp_cascade_con%decomp_pool_name_long(k))//' N fire loss' call hist_addfld1d (fname=fieldname, units='gN/m^2', & avgflag='A', long_name=longname, & @@ -1057,7 +1067,7 @@ subroutine InitHistory(this, bounds) if ( nlevdecomp_full > 1 ) then this%m_decomp_npools_to_fire_vr_col(begc:endc,:,k) = spval data2dptr => this%m_decomp_npools_to_fire_vr_col(:,:,k) - fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'N_TO_FIRE'//trim(vr_suffix) + fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'_N_TO_FIRE'//trim(vr_suffix) longname = trim(decomp_cascade_con%decomp_pool_name_long(k))//' N fire loss' call hist_addfld_decomp (fname=fieldname, units='gN/m^3', type2d='levdcmp', & avgflag='A', long_name=longname, & diff --git a/src/biogeochem/CNVegNitrogenStateType.F90 b/src/biogeochem/CNVegNitrogenStateType.F90 index f09311e518..42bc47e102 100644 --- a/src/biogeochem/CNVegNitrogenStateType.F90 +++ b/src/biogeochem/CNVegNitrogenStateType.F90 @@ -69,9 +69,7 @@ module CNVegNitrogenStateType real(r8), pointer :: totvegn_col (:) ! (gN/m2) total vegetation nitrogen (p2c) real(r8), pointer :: totn_patch (:) ! (gN/m2) total patch-level nitrogen real(r8), pointer :: totn_p2c_col (:) ! (gN/m2) totn_patch averaged to col - real(r8), pointer :: totn_col (:) ! (gN/m2) total column nitrogen, incl veg - real(r8), pointer :: totecosysn_col (:) ! (gN/m2) total ecosystem nitrogen, incl veg - real(r8), pointer :: totn_grc (:) ! (gN/m2) total gridcell nitrogen + ! acc spinup for matrix solution @@ -98,40 +96,49 @@ module CNVegNitrogenStateType !------------------------------------------------------------------------ subroutine Init(this, bounds, & - leafc_patch, leafc_storage_patch, frootc_patch, frootc_storage_patch, deadstemc_patch) + leafc_patch, leafc_storage_patch, frootc_patch, frootc_storage_patch, & + deadstemc_patch, alloc_full_veg) class(cnveg_nitrogenstate_type) :: this type(bounds_type) , intent(in) :: bounds - real(r8) , intent(in) :: leafc_patch (bounds%begp:) - real(r8) , intent(in) :: leafc_storage_patch (bounds%begp:) - real(r8) , intent(in) :: frootc_patch (bounds%begp:) - real(r8) , intent(in) :: frootc_storage_patch (bounds%begp:) - real(r8) , intent(in) :: deadstemc_patch (bounds%begp:) - - call this%InitAllocate (bounds ) - call this%InitHistory (bounds) - call this%InitCold ( bounds, & - leafc_patch, leafc_storage_patch, frootc_patch, frootc_storage_patch, deadstemc_patch) - + real(r8) , intent(in) :: leafc_patch (:) !(begp:) + real(r8) , intent(in) :: leafc_storage_patch (:) !(begp:) + real(r8) , intent(in) :: frootc_patch (:) !(begp:) + real(r8) , intent(in) :: frootc_storage_patch(:) !(begp:) + real(r8) , intent(in) :: deadstemc_patch (:) !(begp:) + logical , intent(in) :: alloc_full_veg + + call this%InitAllocate (bounds, alloc_full_veg) + if(alloc_full_veg) then + call this%InitHistory (bounds) + call this%InitCold ( bounds, & + leafc_patch, leafc_storage_patch, frootc_patch, frootc_storage_patch, deadstemc_patch) + end if end subroutine Init !------------------------------------------------------------------------ - subroutine InitAllocate(this, bounds) + subroutine InitAllocate(this, bounds, alloc_full_veg) ! ! !ARGUMENTS: class (cnveg_nitrogenstate_type) :: this - type(bounds_type) , intent(in) :: bounds + type(bounds_type) , intent(in) :: bounds + logical,intent(in) :: alloc_full_veg ! ! !LOCAL VARIABLES: integer :: begp,endp integer :: begc,endc integer :: begg,endg !------------------------------------------------------------------------ - - begp = bounds%begp; endp = bounds%endp - begc = bounds%begc; endc = bounds%endc - begg = bounds%begg; endg = bounds%endg - + if(alloc_full_veg) then + begp = bounds%begp; endp = bounds%endp + begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg + else + begp = 0; endp = 0 + begc = 0; endc = 0 + begg = 0; endg = 0 + end if + allocate(this%reproductiven_patch (begp:endp, nrepr)) ; this%reproductiven_patch (:,:) = nan allocate(this%reproductiven_storage_patch (begp:endp, nrepr)) ; this%reproductiven_storage_patch (:,:) = nan allocate(this%reproductiven_xfer_patch (begp:endp, nrepr)) ; this%reproductiven_xfer_patch (:,:) = nan @@ -167,9 +174,7 @@ subroutine InitAllocate(this, bounds) allocate(this%seedn_grc (begg:endg)) ; this%seedn_grc (:) = nan allocate(this%totvegn_col (begc:endc)) ; this%totvegn_col (:) = nan allocate(this%totn_p2c_col (begc:endc)) ; this%totn_p2c_col (:) = nan - allocate(this%totn_col (begc:endc)) ; this%totn_col (:) = nan - allocate(this%totecosysn_col (begc:endc)) ; this%totecosysn_col (:) = nan - allocate(this%totn_grc (begg:endg)) ; this%totn_grc (:) = nan + ! Matrix solution allocations if ( use_matrixcn )then @@ -376,15 +381,7 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='pool for seeding new PFTs via dynamic landcover', & ptr_gcell=this%seedn_grc) - this%totecosysn_col(begc:endc) = spval - call hist_addfld1d (fname='TOTECOSYSN', units='gN/m^2', & - avgflag='A', long_name='total ecosystem N, excluding product pools', & - ptr_col=this%totecosysn_col) - this%totn_col(begc:endc) = spval - call hist_addfld1d (fname='TOTCOLN', units='gN/m^2', & - avgflag='A', long_name='total column-level N, excluding product pools', & - ptr_col=this%totn_col) end subroutine InitHistory @@ -558,16 +555,13 @@ subroutine InitCold(this, bounds, & l = col%landunit(c) if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then ! total nitrogen pools - this%totecosysn_col(c) = 0._r8 this%totn_p2c_col(c) = 0._r8 - this%totn_col(c) = 0._r8 end if end do do g = bounds%begg, bounds%endg this%seedn_grc(g) = 0._r8 - this%totn_grc(g) = 0._r8 end do ! now loop through special filters and explicitly set the variables that @@ -1024,11 +1018,8 @@ subroutine SetValues ( this, & do fi = 1,num_column i = filter_column(fi) - - this%totecosysn_col(i) = value_column this%totvegn_col(i) = value_column this%totn_p2c_col(i) = value_column - this%totn_col(i) = value_column end do end subroutine SetValues @@ -1057,24 +1048,20 @@ subroutine ZeroDwt( this, bounds ) end subroutine ZeroDwt !----------------------------------------------------------------------- - subroutine Summary_nitrogenstate(this, bounds, num_allc, filter_allc, & - num_soilc, filter_soilc, num_soilp, filter_soilp,& - soilbiogeochem_nitrogenstate_inst) + subroutine Summary_nitrogenstate(this, bounds, num_soilc, filter_soilc, num_soilp, filter_soilp) ! ! !USES: use subgridAveMod, only : p2c - use SoilBiogeochemNitrogenStateType, only : soilbiogeochem_nitrogenstate_type + ! ! !ARGUMENTS: class(cnveg_nitrogenstate_type) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_allc ! number of columns in allc filter - integer , intent(in) :: filter_allc(:) ! filter for all active columns integer , intent(in) :: num_soilc ! number of soil columns in filter integer , intent(in) :: filter_soilc(:) ! filter for soil columns integer , intent(in) :: num_soilp ! number of soil patches in filter integer , intent(in) :: filter_soilp(:) ! filter for soil patches - type(soilbiogeochem_nitrogenstate_type) , intent(in) :: soilbiogeochem_nitrogenstate_inst + ! ! !LOCAL VARIABLES: integer :: c,p,j,k,l ! indices @@ -1148,38 +1135,15 @@ subroutine Summary_nitrogenstate(this, bounds, num_allc, filter_allc, & ! -------------------------------------------- ! column level summary ! -------------------------------------------- - - call p2c(bounds, num_soilc, filter_soilc, & - this%totvegn_patch(bounds%begp:bounds%endp), & - this%totvegn_col(bounds%begc:bounds%endc)) - - call p2c(bounds, num_soilc, filter_soilc, & - this%totn_patch(bounds%begp:bounds%endp), & - this%totn_p2c_col(bounds%begc:bounds%endc)) - - do fc = 1,num_allc - c = filter_allc(fc) - - ! total ecosystem nitrogen, including veg (TOTECOSYSN) - this%totecosysn_col(c) = & - soilbiogeochem_nitrogenstate_inst%cwdn_col(c) + & - soilbiogeochem_nitrogenstate_inst%totlitn_col(c) + & - soilbiogeochem_nitrogenstate_inst%totmicn_col(c) + & - soilbiogeochem_nitrogenstate_inst%totsomn_col(c) + & - soilbiogeochem_nitrogenstate_inst%sminn_col(c) + & - this%totvegn_col(c) - - ! total column nitrogen, including patch (TOTCOLN) - - this%totn_col(c) = this%totn_p2c_col(c) + & - soilbiogeochem_nitrogenstate_inst%cwdn_col(c) + & - soilbiogeochem_nitrogenstate_inst%totlitn_col(c) + & - soilbiogeochem_nitrogenstate_inst%totmicn_col(c) + & - soilbiogeochem_nitrogenstate_inst%totsomn_col(c) + & - soilbiogeochem_nitrogenstate_inst%sminn_col(c) + & - soilbiogeochem_nitrogenstate_inst%ntrunc_col(c) - - end do + if(num_soilp>0)then + call p2c(bounds, num_soilc, filter_soilc, & + this%totvegn_patch(bounds%begp:bounds%endp), & + this%totvegn_col(bounds%begc:bounds%endc)) + + call p2c(bounds, num_soilc, filter_soilc, & + this%totn_patch(bounds%begp:bounds%endp), & + this%totn_p2c_col(bounds%begc:bounds%endc)) + end if end subroutine Summary_nitrogenstate diff --git a/src/biogeochem/CNVegStateType.F90 b/src/biogeochem/CNVegStateType.F90 index e30bb9c7e7..c286c0344f 100644 --- a/src/biogeochem/CNVegStateType.F90 +++ b/src/biogeochem/CNVegStateType.F90 @@ -35,6 +35,7 @@ module CNVegStateType real(r8) , pointer :: hdidx_patch (:) ! patch cold hardening index? real(r8) , pointer :: cumvd_patch (:) ! patch cumulative vernalization d?ependence? real(r8) , pointer :: gddmaturity_patch (:) ! patch growing degree days (gdd) needed to harvest (ddays) + real(r8) , pointer :: gddmaturity_thisyr (:,:) ! all at-harvest values of the above for this patch this year (ddays) [patch, mxharvests] real(r8) , pointer :: huileaf_patch (:) ! patch heat unit index needed from planting to leaf emergence real(r8) , pointer :: huigrain_patch (:) ! patch heat unit index needed to reach vegetative maturity real(r8) , pointer :: aleafi_patch (:) ! patch saved leaf allocation coefficient from phase 2 @@ -55,7 +56,8 @@ module CNVegStateType real(r8) , pointer :: htmx_patch (:) ! patch max hgt attained by a crop during yr (m) integer , pointer :: peaklai_patch (:) ! patch 1: max allowed lai; 0: not at max - integer , pointer :: idop_patch (:) ! patch date of planting + integer , pointer :: idop_patch (:) ! patch date of planting (day of year) + integer , pointer :: iyop_patch (:) ! patch year of planting real(r8) , pointer :: lgdp_col (:) ! col gdp limitation factor for fire occurrence (0-1) real(r8) , pointer :: lgdp1_col (:) ! col gdp limitation factor for fire spreading (0-1) @@ -128,31 +130,36 @@ module CNVegStateType contains !------------------------------------------------------------------------ - subroutine Init(this, bounds) + subroutine Init(this, bounds, alloc_full_veg) class(cnveg_state_type) :: this type(bounds_type), intent(in) :: bounds + logical,intent(in) :: alloc_full_veg ! Total number of bgc patches on proc (non-fates) - call this%InitAllocate ( bounds ) + call this%InitAllocate ( bounds, alloc_full_veg) if (use_cn) then call this%InitHistory ( bounds ) end if - call this%InitCold ( bounds ) - + if(alloc_full_veg) then !This is true if not use_fates_bgc + call this%InitCold ( bounds ) + end if + end subroutine Init !------------------------------------------------------------------------ - subroutine InitAllocate(this, bounds) + subroutine InitAllocate(this, bounds, alloc_full_veg) ! ! !DESCRIPTION: ! Initialize module data structure ! ! !USES: use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) + use clm_varpar, only : mxsowings, mxharvests ! ! !ARGUMENTS: class(cnveg_state_type) :: this type(bounds_type), intent(in) :: bounds + logical, intent(in) :: alloc_full_veg ! Total number of bgc patches on proc (non-fates) ! ! !LOCAL VARIABLES: integer :: begp, endp @@ -160,9 +167,15 @@ subroutine InitAllocate(this, bounds) logical :: allows_non_annual_delta !------------------------------------------------------------------------ - begp = bounds%begp; endp= bounds%endp - begc = bounds%begc; endc= bounds%endc - + if(alloc_full_veg)then + begp = bounds%begp; endp= bounds%endp + begc = bounds%begc; endc= bounds%endc + else + begp = 0;endp = 0 + begc = 0;endc = 0 + end if + + ! Note that we set allows_non_annual_delta to false because we expect land cover ! change to be applied entirely at the start of the year. Currently the fire code ! appears to assume that the land cover change rate is constant throughout the year, @@ -207,6 +220,7 @@ subroutine InitAllocate(this, bounds) allocate(this%hdidx_patch (begp:endp)) ; this%hdidx_patch (:) = nan allocate(this%cumvd_patch (begp:endp)) ; this%cumvd_patch (:) = nan allocate(this%gddmaturity_patch (begp:endp)) ; this%gddmaturity_patch (:) = spval + allocate(this%gddmaturity_thisyr (begp:endp,1:mxharvests)) ; this%gddmaturity_thisyr (:,:) = spval allocate(this%huileaf_patch (begp:endp)) ; this%huileaf_patch (:) = nan allocate(this%huigrain_patch (begp:endp)) ; this%huigrain_patch (:) = 0.0_r8 allocate(this%aleafi_patch (begp:endp)) ; this%aleafi_patch (:) = nan @@ -228,6 +242,7 @@ subroutine InitAllocate(this, bounds) allocate(this%peaklai_patch (begp:endp)) ; this%peaklai_patch (:) = 0 allocate(this%idop_patch (begp:endp)) ; this%idop_patch (:) = huge(1) + allocate(this%iyop_patch (begp:endp)) ; this%iyop_patch (:) = ispval allocate(this%lgdp_col (begc:endc)) ; allocate(this%lgdp1_col (begc:endc)) ; @@ -309,10 +324,18 @@ subroutine InitHistory(this, bounds) begc = bounds%begc; endc= bounds%endc if ( use_crop) then + ! Daily this%gddmaturity_patch(begp:endp) = spval call hist_addfld1d (fname='GDDHARV', units='ddays', & avgflag='A', long_name='Growing degree days (gdd) needed to harvest', & ptr_patch=this%gddmaturity_patch, default='inactive') + + ! Per harvest + this%gddmaturity_thisyr(begp:endp,:) = spval + call hist_addfld2d (fname='GDDHARV_PERHARV', units='ddays', type2d='mxharvests', & + avgflag='I', long_name='Growing degree days (gdd) needed to harvest; should only be output annually', & + ptr_patch=this%gddmaturity_thisyr, default='inactive') + end if this%lfc2_col(begc:endc) = spval @@ -482,7 +505,7 @@ subroutine InitHistory(this, bounds) end subroutine InitHistory !----------------------------------------------------------------------- - subroutine initCold(this, bounds) + subroutine InitCold(this, bounds) ! ! !USES: ! @@ -602,7 +625,7 @@ subroutine initCold(this, bounds) this%lfc2_col(c) = 0._r8 end do - end subroutine initCold + end subroutine InitCold !------------------------------------------------------------------------ subroutine Restart(this, bounds, ncid, flag, cnveg_carbonstate, & @@ -842,6 +865,16 @@ subroutine Restart(this, bounds, ncid, flag, cnveg_carbonstate, & call restartvar(ncid=ncid, flag=flag, varname='grain_flag', xtype=ncd_double, & dim1name='pft', long_name='', units='', & interpinic_flag='interp', readvar=readvar, data=this%grain_flag_patch) + + ! Read or write variable(s) with mxharvests dimension + ! BACKWARDS_COMPATIBILITY(ssr, 2022-03-31) See note in CallRestartvarDimOK() + if (CallRestartvarDimOK(ncid, flag, 'mxharvests')) then + call restartvar(ncid=ncid, flag=flag, varname='gddmaturity_thisyr', xtype=ncd_double, & + dim1name='pft', dim2name='mxharvests', switchdim=.true., & + long_name='crop harvest dates for this patch this year', units='day of year', & + scale_by_thickness=.false., & + interpinic_flag='interp', readvar=readvar, data=this%gddmaturity_thisyr) + end if end if if ( flag == 'read' .and. num_reseed_patch > 0 )then if ( masterproc ) write(iulog, *) 'Reseed dead plants for CNVegState' diff --git a/src/biogeochem/CNVegStructUpdateMod.F90 b/src/biogeochem/CNVegStructUpdateMod.F90 index 01209c678f..2e8ed8539b 100644 --- a/src/biogeochem/CNVegStructUpdateMod.F90 +++ b/src/biogeochem/CNVegStructUpdateMod.F90 @@ -143,7 +143,7 @@ subroutine CNVegStructUpdate(bounds,num_soilp, filter_soilp, & dt = real( get_rad_step_size(), r8 ) ! patch loop - do fp = 1,num_soilp + do_patch:do fp = 1,num_soilp p = filter_soilp(fp) c = patch%column(p) g = patch%gridcell(p) @@ -317,7 +317,7 @@ subroutine CNVegStructUpdate(bounds,num_soilp, filter_soilp, & frac_veg_nosno_alb(p) = 0 end if - end do + end do do_patch end associate diff --git a/src/biogeochem/CNVegetationFacade.F90 b/src/biogeochem/CNVegetationFacade.F90 index cc625e2a36..61e2e9cf91 100644 --- a/src/biogeochem/CNVegetationFacade.F90 +++ b/src/biogeochem/CNVegetationFacade.F90 @@ -44,7 +44,7 @@ module CNVegetationFacade use shr_log_mod , only : errMsg => shr_log_errMsg use perf_mod , only : t_startf, t_stopf use decompMod , only : bounds_type - use clm_varctl , only : iulog, use_cn, use_cndv, use_c13, use_c14 + use clm_varctl , only : iulog, use_cn, use_cndv, use_c13, use_c14, use_fates_bgc use abortutils , only : endrun use spmdMod , only : masterproc use clm_time_manager , only : get_curr_date, get_ref_date @@ -206,6 +206,8 @@ subroutine Init(this, bounds, NLFilename, nskip_steps, params_ncid) use CNFireFactoryMod , only : create_cnfire_method use clm_varcon , only : c13ratio, c14ratio use ncdio_pio , only : file_desc_t + use filterMod , only : filter + use decompMod , only : get_proc_clumps ! ! !ARGUMENTS: class(cn_vegetation_type), intent(inout) :: this @@ -215,16 +217,30 @@ subroutine Init(this, bounds, NLFilename, nskip_steps, params_ncid) type(file_desc_t), intent(inout) :: params_ncid ! NetCDF handle to parameter file ! ! !LOCAL VARIABLES: - integer :: begp, endp + integer :: begp, endp, ci + integer :: nclumps ! number of clumps on the proc + logical :: alloc_full_veg ! Signal to allocate vegetation data fully or trivialy + character(len=*), parameter :: subname = 'Init' !----------------------------------------------------------------------- - begp = bounds%begp - endp = bounds%endp - ! Note - always initialize the memory for cnveg_state_inst (used in biogeophys/) - call this%cnveg_state_inst%Init(bounds) + ! - Even if FATES is the only vegetation option, we still allocate + ! - a single value for both column and patch, using index 0 only + ! - that is why we pass the number of bgc veg patches here + + if(use_fates_bgc)then + alloc_full_veg=.false. + begp = 0 + endp = 0 + else + alloc_full_veg=.true. + begp = bounds%begp + endp = bounds%endp + end if + + call this%cnveg_state_inst%Init(bounds,alloc_full_veg) skip_steps = nskip_steps @@ -232,34 +248,43 @@ subroutine Init(this, bounds, NLFilename, nskip_steps, params_ncid) ! Read in the general CN namelist call this%CNReadNML( NLFilename ) ! MUST be called first as passes down control information to others + end if + if(use_cn.or.use_fates_bgc)then call this%cnveg_carbonstate_inst%Init(bounds, carbon_type='c12', ratio=1._r8, & - NLFilename=NLFilename, dribble_crophrv_xsmrpool_2atm=this%dribble_crophrv_xsmrpool_2atm ) + NLFilename=NLFilename, dribble_crophrv_xsmrpool_2atm=this%dribble_crophrv_xsmrpool_2atm, & + alloc_full_veg=alloc_full_veg) + if (use_c13) then call this%c13_cnveg_carbonstate_inst%Init(bounds, carbon_type='c13', ratio=c13ratio, & NLFilename=NLFilename, dribble_crophrv_xsmrpool_2atm=this%dribble_crophrv_xsmrpool_2atm, & - c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) + alloc_full_veg=alloc_full_veg, c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) end if if (use_c14) then call this%c14_cnveg_carbonstate_inst%Init(bounds, carbon_type='c14', ratio=c14ratio, & NLFilename=NLFilename, dribble_crophrv_xsmrpool_2atm=this%dribble_crophrv_xsmrpool_2atm, & - c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) + alloc_full_veg=alloc_full_veg,c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) end if - call this%cnveg_carbonflux_inst%Init(bounds, carbon_type='c12', dribble_crophrv_xsmrpool_2atm=this%dribble_crophrv_xsmrpool_2atm ) + + call this%cnveg_carbonflux_inst%Init(bounds, carbon_type='c12', & + dribble_crophrv_xsmrpool_2atm=this%dribble_crophrv_xsmrpool_2atm, alloc_full_veg=alloc_full_veg ) if (use_c13) then - call this%c13_cnveg_carbonflux_inst%Init(bounds, carbon_type='c13', dribble_crophrv_xsmrpool_2atm=this%dribble_crophrv_xsmrpool_2atm) + call this%c13_cnveg_carbonflux_inst%Init(bounds, carbon_type='c13', & + dribble_crophrv_xsmrpool_2atm=this%dribble_crophrv_xsmrpool_2atm,alloc_full_veg=alloc_full_veg) end if if (use_c14) then - call this%c14_cnveg_carbonflux_inst%Init(bounds, carbon_type='c14', dribble_crophrv_xsmrpool_2atm=this%dribble_crophrv_xsmrpool_2atm) + call this%c14_cnveg_carbonflux_inst%Init(bounds, carbon_type='c14', & + dribble_crophrv_xsmrpool_2atm=this%dribble_crophrv_xsmrpool_2atm,alloc_full_veg=alloc_full_veg) end if call this%cnveg_nitrogenstate_inst%Init(bounds, & this%cnveg_carbonstate_inst%leafc_patch(begp:endp), & this%cnveg_carbonstate_inst%leafc_storage_patch(begp:endp), & this%cnveg_carbonstate_inst%frootc_patch(begp:endp), & this%cnveg_carbonstate_inst%frootc_storage_patch(begp:endp), & - this%cnveg_carbonstate_inst%deadstemc_patch(begp:endp) ) - call this%cnveg_nitrogenflux_inst%Init(bounds) - + this%cnveg_carbonstate_inst%deadstemc_patch(begp:endp), & + alloc_full_veg=alloc_full_veg) + call this%cnveg_nitrogenflux_inst%Init(bounds,alloc_full_veg=alloc_full_veg) + call this%c_products_inst%Init(bounds, species_non_isotope_type('C')) if (use_c13) then call this%c13_products_inst%Init(bounds, species_isotope_type('C', '13')) @@ -268,15 +293,17 @@ subroutine Init(this, bounds, NLFilename, nskip_steps, params_ncid) call this%c14_products_inst%Init(bounds, species_isotope_type('C', '14')) end if call this%n_products_inst%Init(bounds, species_non_isotope_type('N')) - + call this%cn_balance_inst%Init(bounds) - + end if + + if(use_cn)then ! Initialize the memory for the dgvs_inst data structure regardless of whether ! use_cndv is true so that it can be used in associate statements (nag compiler ! complains otherwise) call this%dgvs_inst%Init(bounds) end if - + call create_cnfire_method(NLFilename, this%cnfire_method) call this%cnfire_method%CNFireReadParams( params_ncid ) @@ -502,6 +529,10 @@ subroutine Restart(this, bounds, ncid, flag) cnveg_nitrogenstate=this%cnveg_nitrogenstate_inst, & filter_reseed_patch=reseed_patch, num_reseed_patch=num_reseed_patch) + end if + + if (use_cn .or. use_fates_bgc) then + call this%c_products_inst%restart(bounds, ncid, flag) if (use_c13) then call this%c13_products_inst%restart(bounds, ncid, flag, & @@ -514,9 +545,8 @@ subroutine Restart(this, bounds, ncid, flag) template_multiplier = c14ratio) end if call this%n_products_inst%restart(bounds, ncid, flag) - end if - + if (use_cndv) then call this%dgvs_inst%Restart(bounds, ncid, flag=flag) end if @@ -554,7 +584,7 @@ end subroutine Init2 !----------------------------------------------------------------------- - subroutine InitEachTimeStep(this, bounds, num_soilc, filter_soilc) + subroutine InitEachTimeStep(this, bounds, num_bgc_soilc, filter_bgc_soilc) ! ! !DESCRIPTION: ! Do initializations that need to be done at the start of every time step @@ -568,8 +598,8 @@ subroutine InitEachTimeStep(this, bounds, num_soilc, filter_soilc) ! !ARGUMENTS: class(cn_vegetation_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns ! ! !LOCAL VARIABLES: @@ -763,7 +793,7 @@ end subroutine DynamicAreaConservation !----------------------------------------------------------------------- subroutine InitColumnBalance(this, bounds, num_allc, filter_allc, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & soilbiogeochem_carbonstate_inst, & c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonstate_inst, & @@ -782,10 +812,10 @@ subroutine InitColumnBalance(this, bounds, num_allc, filter_allc, & type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_allc ! number of columns in allc filter integer , intent(in) :: filter_allc(:) ! filter for all active columns - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of bgc soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for bgc soil columns + integer , intent(in) :: num_bgc_vegp ! number of bgc vegetation patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for bgc vegetation patches type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst type(soilbiogeochem_carbonstate_type) , intent(inout) :: c13_soilbiogeochem_carbonstate_inst type(soilbiogeochem_carbonstate_type) , intent(inout) :: c14_soilbiogeochem_carbonstate_inst @@ -798,8 +828,8 @@ subroutine InitColumnBalance(this, bounds, num_allc, filter_allc, & call CNDriverSummarizeStates(bounds, & num_allc, filter_allc, & - num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & this%cnveg_carbonstate_inst, & this%c13_cnveg_carbonstate_inst, & this%c14_cnveg_carbonstate_inst, & @@ -810,15 +840,15 @@ subroutine InitColumnBalance(this, bounds, num_allc, filter_allc, & soilbiogeochem_nitrogenstate_inst) call this%cn_balance_inst%BeginCNColumnBalance( & - bounds, num_soilc, filter_soilc, & - this%cnveg_carbonstate_inst, this%cnveg_nitrogenstate_inst) + bounds, num_bgc_soilc, filter_bgc_soilc, & + soilbiogeochem_carbonstate_inst,soilbiogeochem_nitrogenstate_inst) end subroutine InitColumnBalance !----------------------------------------------------------------------- subroutine InitGridcellBalance(this, bounds, num_allc, filter_allc, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, & soilbiogeochem_carbonstate_inst, & c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonstate_inst, & @@ -838,10 +868,10 @@ subroutine InitGridcellBalance(this, bounds, num_allc, filter_allc, & type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_allc ! number of columns in allc filter integer , intent(in) :: filter_allc(:) ! filter for all active columns - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of bgc soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for bgc soil columns + integer , intent(in) :: num_bgc_vegp ! number of bgc vegetation patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for bgc vegetation patches type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst type(soilbiogeochem_carbonstate_type) , intent(inout) :: c13_soilbiogeochem_carbonstate_inst type(soilbiogeochem_carbonstate_type) , intent(inout) :: c14_soilbiogeochem_carbonstate_inst @@ -852,10 +882,11 @@ subroutine InitGridcellBalance(this, bounds, num_allc, filter_allc, & character(len=*), parameter :: subname = 'InitGridcellBalance' !----------------------------------------------------------------------- + call CNDriverSummarizeStates(bounds, & num_allc, filter_allc, & - num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & this%cnveg_carbonstate_inst, & this%c13_cnveg_carbonstate_inst, & this%c14_cnveg_carbonstate_inst, & @@ -867,20 +898,22 @@ subroutine InitGridcellBalance(this, bounds, num_allc, filter_allc, & ! total gridcell carbon (TOTGRIDCELLC) call c2g( bounds = bounds, & - carr = this%cnveg_carbonstate_inst%totc_col(bounds%begc:bounds%endc), & - garr = this%cnveg_carbonstate_inst%totc_grc(bounds%begg:bounds%endg), & + carr = soilbiogeochem_carbonstate_inst%totc_col(bounds%begc:bounds%endc), & + garr = soilbiogeochem_carbonstate_inst%totc_grc(bounds%begg:bounds%endg), & c2l_scale_type = 'unity', & l2g_scale_type = 'unity') + ! total gridcell nitrogen (TOTGRIDCELLN) call c2g( bounds = bounds, & - carr = this%cnveg_nitrogenstate_inst%totn_col(bounds%begc:bounds%endc), & - garr = this%cnveg_nitrogenstate_inst%totn_grc(bounds%begg:bounds%endg), & + carr = soilbiogeochem_nitrogenstate_inst%totn_col(bounds%begc:bounds%endc), & + garr = soilbiogeochem_nitrogenstate_inst%totn_grc(bounds%begg:bounds%endg), & c2l_scale_type = 'unity', & l2g_scale_type = 'unity') call this%cn_balance_inst%BeginCNGridcellBalance( bounds, & this%cnveg_carbonflux_inst, & - this%cnveg_carbonstate_inst, this%cnveg_nitrogenstate_inst, & + soilbiogeochem_carbonstate_inst, & + soilbiogeochem_nitrogenstate_inst, & this%c_products_inst, this%n_products_inst) end subroutine InitGridcellBalance @@ -888,8 +921,8 @@ end subroutine InitGridcellBalance !----------------------------------------------------------------------- subroutine EcosystemDynamicsPreDrainage(this, bounds, & - num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & num_actfirec, filter_actfirec, & num_actfirep, filter_actfirep, & num_pcropp, filter_pcropp, & @@ -909,9 +942,10 @@ subroutine EcosystemDynamicsPreDrainage(this, bounds, & nutrient_competition_method, fireemis_inst) ! ! !DESCRIPTION: - ! Do the main science for CN vegetation that needs to be done before hydrology-drainage + ! Do the main science for biogeochemistry that needs to be done before hydrology-drainage ! - ! Should only be called if use_cn is true + ! Can be called for either use_cn or use_fates_bgc. + ! Will skip most vegetation patch calls for the latter ! ! !USES: @@ -919,10 +953,10 @@ subroutine EcosystemDynamicsPreDrainage(this, bounds, & ! !ARGUMENTS: class(cn_vegetation_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of bgc soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for bgc soil columns + integer , intent(in) :: num_bgc_vegp ! number of bgc veg patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for bgc veg patches integer , intent(out) :: num_actfirec ! number of soil columns on fire in filter integer , intent(out) :: filter_actfirec(:)! filter for soil columns on fire integer , intent(out) :: num_actfirep ! number of soil patches on fire in filter @@ -971,8 +1005,8 @@ subroutine EcosystemDynamicsPreDrainage(this, bounds, & call crop_inst%CropIncrementYear(num_pcropp, filter_pcropp) call CNDriverNoLeaching(bounds, & - num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & num_pcropp, filter_pcropp, & num_soilnopcropp, filter_soilnopcropp, & num_actfirec, filter_actfirec, & @@ -999,19 +1033,19 @@ subroutine EcosystemDynamicsPreDrainage(this, bounds, & nutrient_competition_method, this%cnfire_method, this%dribble_crophrv_xsmrpool_2atm) ! fire carbon emissions - call CNFireEmisUpdate(bounds, num_soilp, filter_soilp, & + call CNFireEmisUpdate(bounds, num_bgc_vegp, filter_bgc_vegp, & this%cnveg_carbonflux_inst, this%cnveg_carbonstate_inst, fireemis_inst ) call CNAnnualUpdate(bounds, & - num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & this%cnveg_state_inst, this%cnveg_carbonflux_inst) end subroutine EcosystemDynamicsPreDrainage !----------------------------------------------------------------------- subroutine EcosystemDynamicsPostDrainage(this, bounds, num_allc, filter_allc, & - num_soilc, filter_soilc, num_soilp, filter_soilp, num_actfirec, filter_actfirec, num_actfirep, filter_actfirep,& + num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, num_actfirec, filter_actfirec, num_actfirep, filter_actfirep,& doalb, crop_inst, soilstate_inst, soilbiogeochem_state_inst, & waterstatebulk_inst, waterdiagnosticbulk_inst, waterfluxbulk_inst, frictionvel_inst, canopystate_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & @@ -1022,7 +1056,7 @@ subroutine EcosystemDynamicsPostDrainage(this, bounds, num_allc, filter_allc, & ! !DESCRIPTION: ! Do the main science for CN vegetation that needs to be done after hydrology-drainage ! - ! Should only be called if use_cn is true + ! Should only be called if use_cn is true or use_fates_bgc is true ! ! !USES: ! @@ -1031,10 +1065,10 @@ subroutine EcosystemDynamicsPostDrainage(this, bounds, num_allc, filter_allc, & type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_allc ! number of columns in allc filter integer , intent(in) :: filter_allc(:) ! filter for all active columns - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of bgc soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for bgc soil columns + integer , intent(in) :: num_bgc_vegp ! number of bgc veg patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for bgc veg patches integer , intent(in) :: num_actfirec ! number of soil columns on fire in filter integer , intent(in) :: filter_actfirec(:) ! filter for soil columns on fire integer , intent(in) :: num_actfirep ! number of soil patches on fire in filter @@ -1066,8 +1100,8 @@ subroutine EcosystemDynamicsPostDrainage(this, bounds, num_allc, filter_allc, & ! and total soil water outflow. call CNDriverLeaching(bounds, & - num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & num_actfirec, filter_actfirec, & num_actfirep, filter_actfirep, & waterstatebulk_inst, waterfluxbulk_inst, soilstate_inst, this%cnveg_state_inst, & @@ -1082,24 +1116,26 @@ subroutine EcosystemDynamicsPostDrainage(this, bounds, num_allc, filter_allc, & ! Set controls on very low values in critical state variables - call t_startf('CNPrecisionControl') - call CNPrecisionControl(bounds, num_soilp, filter_soilp, & - this%cnveg_carbonstate_inst, this%c13_cnveg_carbonstate_inst, & - this%c14_cnveg_carbonstate_inst, this%cnveg_nitrogenstate_inst) - call t_stopf('CNPrecisionControl') - + if(num_bgc_vegp>0)then + call t_startf('CNPrecisionControl') + call CNPrecisionControl(bounds, num_bgc_vegp, filter_bgc_vegp, & + this%cnveg_carbonstate_inst, this%c13_cnveg_carbonstate_inst, & + this%c14_cnveg_carbonstate_inst, this%cnveg_nitrogenstate_inst) + call t_stopf('CNPrecisionControl') + end if + call t_startf('SoilBiogeochemPrecisionControl') - call SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & + call SoilBiogeochemPrecisionControl(num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonstate_inst,soilbiogeochem_nitrogenstate_inst) call t_stopf('SoilBiogeochemPrecisionControl') ! Call to all CN summary routines - call CNDriverSummarizeStates(bounds, & + call CNDriverSummarizeStates(bounds, & num_allc, filter_allc, & - num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & this%cnveg_carbonstate_inst, & this%c13_cnveg_carbonstate_inst, & this%c14_cnveg_carbonstate_inst, & @@ -1109,9 +1145,9 @@ subroutine EcosystemDynamicsPostDrainage(this, bounds, num_allc, filter_allc, & c14_soilbiogeochem_carbonstate_inst, & soilbiogeochem_nitrogenstate_inst) - call CNDriverSummarizeFluxes(bounds, & - num_soilc, filter_soilc, & - num_soilp, filter_soilp, & + call CNDriverSummarizeFluxes(bounds, & + num_bgc_soilc, filter_bgc_soilc, & + num_bgc_vegp, filter_bgc_vegp, & this%cnveg_carbonflux_inst, & this%c13_cnveg_carbonflux_inst, & this%c14_cnveg_carbonflux_inst, & @@ -1128,24 +1164,27 @@ subroutine EcosystemDynamicsPostDrainage(this, bounds, num_allc, filter_allc, & ! On the radiation time step, use C state variables to calculate ! vegetation structure (LAI, SAI, height) - - if (doalb) then - call CNVegStructUpdate(bounds,num_soilp, filter_soilp, & - waterdiagnosticbulk_inst, frictionvel_inst, this%dgvs_inst, this%cnveg_state_inst, & - crop_inst, this%cnveg_carbonstate_inst, canopystate_inst) + if(num_bgc_vegp>0)then + if (doalb) then + call CNVegStructUpdate(bounds,num_bgc_vegp, filter_bgc_vegp, & + waterdiagnosticbulk_inst, frictionvel_inst, this%dgvs_inst, this%cnveg_state_inst, & + crop_inst, this%cnveg_carbonstate_inst, canopystate_inst) + end if end if - + end subroutine EcosystemDynamicsPostDrainage !----------------------------------------------------------------------- - subroutine BalanceCheck(this, bounds, num_soilc, filter_soilc, & + subroutine BalanceCheck(this, bounds, num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenflux_inst, & - atm2lnd_inst) + soilbiogeochem_carbonstate_inst, soilbiogeochem_nitrogenstate_inst, & + atm2lnd_inst, clm_fates) + ! ! !DESCRIPTION: ! Check the carbon and nitrogen balance ! - ! Should only be called if use_cn is true + ! Should only be called if use_cn is true or use_fates_bgc is true ! ! !USES: use clm_time_manager , only : get_nstep_since_startup_or_lastDA_restart_or_pause @@ -1153,11 +1192,14 @@ subroutine BalanceCheck(this, bounds, num_soilc, filter_soilc, & ! !ARGUMENTS: class(cn_vegetation_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst + type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst + type(soilbiogeochem_nitrogenstate_type) , intent(inout) :: soilbiogeochem_nitrogenstate_inst type(atm2lnd_type) , intent(in) :: atm2lnd_inst + type(hlm_fates_interface_type) , intent(inout) :: clm_fates ! ! !LOCAL VARIABLES: integer :: DA_nstep ! time step number @@ -1175,19 +1217,23 @@ subroutine BalanceCheck(this, bounds, num_soilc, filter_soilc, & else call this%cn_balance_inst%CBalanceCheck( & - bounds, num_soilc, filter_soilc, & + bounds, num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_carbonflux_inst, & + soilbiogeochem_carbonstate_inst, & this%cnveg_carbonflux_inst, & this%cnveg_carbonstate_inst, & - this%c_products_inst) + this%c_products_inst, & + clm_fates) call this%cn_balance_inst%NBalanceCheck( & - bounds, num_soilc, filter_soilc, & + bounds, num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_nitrogenflux_inst, & + soilbiogeochem_nitrogenstate_inst, & this%cnveg_nitrogenflux_inst, & this%cnveg_nitrogenstate_inst, & this%n_products_inst, & - atm2lnd_inst) + atm2lnd_inst, & + clm_fates) end if diff --git a/src/biogeochem/CropType.F90 b/src/biogeochem/CropType.F90 index 6ceeccf7e3..f84c4c1821 100644 --- a/src/biogeochem/CropType.F90 +++ b/src/biogeochem/CropType.F90 @@ -42,12 +42,23 @@ module CropType real(r8), pointer :: gddtsoi_patch (:) ! patch growing degree-days from planting (top two soil layers) (ddays) real(r8), pointer :: vf_patch (:) ! patch vernalization factor for cereal real(r8), pointer :: cphase_patch (:) ! phenology phase (see cphase_* constants above for possible values) + integer , pointer :: sowing_reason_patch (:) ! reason for most recent sowing of this patch real(r8), pointer :: latbaset_patch (:) ! Latitude vary baset for hui (degree C) character(len=20) :: baset_mapping real(r8) :: baset_latvary_intercept real(r8) :: baset_latvary_slope - real(r8), pointer :: sdates_thisyr (:,:) ! all actual sowing dates for this patch this year - real(r8), pointer :: hdates_thisyr (:,:) ! all actual harvest dates for this patch this year + integer , pointer :: next_rx_sdate_patch (:) ! prescribed sowing date for the next growing season this year + integer , pointer :: rx_sdates_thisyr_patch (:,:) ! all prescribed sowing dates for this patch this year (day of year) [patch, mxsowings] + real(r8), pointer :: rx_cultivar_gdds_thisyr_patch (:,:) ! all cultivar GDD targets for this patch this year (ddays) [patch, mxsowings] + real(r8), pointer :: sdates_thisyr_patch (:,:) ! all actual sowing dates for this patch this year (day of year) [patch, mxsowings] + real(r8), pointer :: sdates_perharv_patch (:,:) ! all actual sowing dates for crops *harvested* this year (day of year) [patch, mxharvests] + real(r8), pointer :: syears_perharv_patch (:,:) ! all actual sowing years for crops *harvested* this year (day of year) [patch, mxharvests] + real(r8), pointer :: hdates_thisyr_patch (:,:) ! all actual harvest dates for this patch this year (day of year) [patch, mxharvests] + real(r8), pointer :: gddaccum_thisyr_patch (:,:) ! accumulated GDD at harvest for this patch this year (ddays) [patch, mxharvests] + real(r8), pointer :: hui_thisyr_patch (:,:) ! accumulated heat unit index at harvest for this patch this year (ddays) [patch, mxharvests] + real(r8), pointer :: sowing_reason_thisyr_patch (:,:) ! reason for each sowing for this patch this year [patch, mxsowings] + real(r8), pointer :: sowing_reason_perharv_patch (:,:) ! reason for each sowing of crops *harvested* this year [patch, mxharvests] + real(r8), pointer :: harvest_reason_thisyr_patch (:,:) ! reason for each harvest for this patch this year [patch, mxharvests] integer , pointer :: sowing_count (:) ! number of sowing events this year for this patch integer , pointer :: harvest_count (:) ! number of sowing events this year for this patch ! gddaccum tracks the actual growing degree-days accumulated over the growing season. @@ -62,7 +73,7 @@ module CropType procedure, public :: InitAccBuffer procedure, public :: InitAccVars procedure, public :: Restart - procedure, public :: ReadNML ! Read in the crop namelist + procedure, public :: ReadNML ! Read in the crop_inparm namelist ! NOTE(wjs, 2014-09-29) need to rename this from UpdateAccVars to CropUpdateAccVars ! to prevent cryptic error messages with pgi (v. 13.9 on yellowstone) @@ -132,12 +143,12 @@ subroutine ReadNML(this, NLFilename ) integer :: unitn ! unit for namelist file character(len=*), parameter :: subname = 'Crop::ReadNML' - character(len=*), parameter :: nmlname = 'crop' + character(len=*), parameter :: nmlname = 'crop_inparm' !----------------------------------------------------------------------- character(len=20) :: baset_mapping real(r8) :: baset_latvary_intercept real(r8) :: baset_latvary_slope - namelist /crop/ baset_mapping, baset_latvary_intercept, baset_latvary_slope + namelist /crop_inparm/ baset_mapping, baset_latvary_intercept, baset_latvary_slope ! Initialize options to default values, in case they are not specified in ! the namelist @@ -151,7 +162,7 @@ subroutine ReadNML(this, NLFilename ) call opnfil (NLFilename, unitn, 'F') call shr_nl_find_group_name(unitn, nmlname, status=ierr) if (ierr == 0) then - read(unitn, nml=crop, iostat=ierr) + read(unitn, nml=crop_inparm, iostat=ierr) if (ierr /= 0) then call endrun(msg="ERROR reading "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) end if @@ -179,7 +190,7 @@ subroutine ReadNML(this, NLFilename ) if (masterproc) then write(iulog,*) ' ' write(iulog,*) nmlname//' settings:' - write(iulog,nml=crop) + write(iulog,nml=crop_inparm) write(iulog,*) ' ' end if @@ -214,12 +225,26 @@ subroutine InitAllocate(this, bounds) allocate(this%gddtsoi_patch (begp:endp)) ; this%gddtsoi_patch (:) = spval allocate(this%vf_patch (begp:endp)) ; this%vf_patch (:) = 0.0_r8 allocate(this%cphase_patch (begp:endp)) ; this%cphase_patch (:) = cphase_not_planted + allocate(this%sowing_reason_patch (begp:endp)) ; this%sowing_reason_patch (:) = -1 allocate(this%latbaset_patch (begp:endp)) ; this%latbaset_patch (:) = spval - allocate(this%sdates_thisyr(begp:endp,1:mxsowings)) ; this%sdates_thisyr(:,:) = spval - allocate(this%hdates_thisyr(begp:endp,1:mxharvests)) ; this%hdates_thisyr(:,:) = spval + allocate(this%next_rx_sdate_patch(begp:endp)) ; this%next_rx_sdate_patch(:) = -1 + allocate(this%rx_sdates_thisyr_patch(begp:endp,1:mxsowings)) ; this%rx_sdates_thisyr_patch(:,:) = -1 + allocate(this%rx_cultivar_gdds_thisyr_patch(begp:endp,1:mxsowings)) ; this%rx_cultivar_gdds_thisyr_patch(:,:) = spval + allocate(this%sdates_thisyr_patch(begp:endp,1:mxsowings)) ; this%sdates_thisyr_patch(:,:) = spval + allocate(this%sdates_perharv_patch(begp:endp,1:mxharvests)) ; this%sdates_perharv_patch(:,:) = spval + allocate(this%syears_perharv_patch(begp:endp,1:mxharvests)) ; this%syears_perharv_patch(:,:) = spval + allocate(this%hdates_thisyr_patch(begp:endp,1:mxharvests)) ; this%hdates_thisyr_patch(:,:) = spval + allocate(this%gddaccum_thisyr_patch(begp:endp,1:mxharvests)) ; this%gddaccum_thisyr_patch(:,:) = spval + allocate(this%hui_thisyr_patch(begp:endp,1:mxharvests)) ; this%hui_thisyr_patch(:,:) = spval + allocate(this%sowing_reason_thisyr_patch(begp:endp,1:mxsowings)) ; this%sowing_reason_thisyr_patch(:,:) = spval + allocate(this%sowing_reason_perharv_patch(begp:endp,1:mxharvests)) ; this%sowing_reason_perharv_patch(:,:) = spval + allocate(this%harvest_reason_thisyr_patch(begp:endp,1:mxharvests)) ; this%harvest_reason_thisyr_patch(:,:) = spval allocate(this%sowing_count(begp:endp)) ; this%sowing_count(:) = 0 allocate(this%harvest_count(begp:endp)) ; this%harvest_count(:) = 0 + this%rx_sdates_thisyr_patch(:,:) = -1 + this%rx_cultivar_gdds_thisyr_patch(:,:) = spval + end subroutine InitAllocate !----------------------------------------------------------------------- @@ -272,15 +297,50 @@ subroutine InitHistory(this, bounds) ptr_patch=this%latbaset_patch, default='inactive') end if - this%sdates_thisyr(begp:endp,:) = spval + this%sdates_thisyr_patch(begp:endp,:) = spval call hist_addfld2d (fname='SDATES', units='day of year', type2d='mxsowings', & avgflag='I', long_name='actual crop sowing dates; should only be output annually', & - ptr_patch=this%sdates_thisyr, default='inactive') + ptr_patch=this%sdates_thisyr_patch, default='inactive') + + this%sdates_perharv_patch(begp:endp,:) = spval + call hist_addfld2d (fname='SDATES_PERHARV', units='day of year', type2d='mxharvests', & + avgflag='I', long_name='actual sowing dates for crops harvested this year; should only be output annually', & + ptr_patch=this%sdates_perharv_patch, default='inactive') - this%hdates_thisyr(begp:endp,:) = spval + this%syears_perharv_patch(begp:endp,:) = spval + call hist_addfld2d (fname='SYEARS_PERHARV', units='year', type2d='mxharvests', & + avgflag='I', long_name='actual sowing years for crops harvested this year; should only be output annually', & + ptr_patch=this%syears_perharv_patch, default='inactive') + + this%hdates_thisyr_patch(begp:endp,:) = spval call hist_addfld2d (fname='HDATES', units='day of year', type2d='mxharvests', & avgflag='I', long_name='actual crop harvest dates; should only be output annually', & - ptr_patch=this%hdates_thisyr, default='inactive') + ptr_patch=this%hdates_thisyr_patch, default='inactive') + + this%gddaccum_thisyr_patch(begp:endp,:) = spval + call hist_addfld2d (fname='GDDACCUM_PERHARV', units='ddays', type2d='mxharvests', & + avgflag='I', long_name='At-harvest accumulated growing degree days past planting date for crop; should only be output annually', & + ptr_patch=this%gddaccum_thisyr_patch, default='inactive') + + this%hui_thisyr_patch(begp:endp,:) = spval + call hist_addfld2d (fname='HUI_PERHARV', units='ddays', type2d='mxharvests', & + avgflag='I', long_name='At-harvest accumulated heat unit index for crop; should only be output annually', & + ptr_patch=this%hui_thisyr_patch, default='inactive') + + this%sowing_reason_thisyr_patch(begp:endp,:) = spval + call hist_addfld2d (fname='SOWING_REASON', units='unitless', type2d='mxsowings', & + avgflag='I', long_name='Reason for each crop sowing; should only be output annually', & + ptr_patch=this%sowing_reason_thisyr_patch, default='inactive') + + this%sowing_reason_perharv_patch(begp:endp,:) = spval + call hist_addfld2d (fname='SOWING_REASON_PERHARV', units='unitless', type2d='mxharvests', & + avgflag='I', long_name='Reason for sowing of each crop harvested this year; should only be output annually', & + ptr_patch=this%sowing_reason_perharv_patch, default='inactive') + + this%harvest_reason_thisyr_patch(begp:endp,:) = spval + call hist_addfld2d (fname='HARVEST_REASON_PERHARV', units='1 = mature; 2 = max season length; 3 = incorrect Dec. 31 sowing; 4 = sowing today; 5 = sowing tomorrow; 6 = tomorrow == idop; 7 = killed by cold temperature during vernalization', type2d='mxharvests', & + avgflag='I', long_name='Reason for each crop harvest; should only be output annually', & + ptr_patch=this%harvest_reason_thisyr_patch, default='inactive') end subroutine InitHistory @@ -438,40 +498,7 @@ subroutine InitAccVars(this, bounds) end subroutine InitAccVars !----------------------------------------------------------------------- - logical function CallRestartvarDimOK (ncid, flag, dimname) - ! - ! !DESCRIPTION: - ! Answer whether to call restartvar(), if necessary checking whether - ! a dimension exists in the restart file - ! - ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2022-02-02) - ! Used in Restart(). Even though restartvar() can safely be called for a - ! non-existent variable, it gives an error for a non-existent dimension, so - ! check whether the dimension exists before trying to read. The need for this - ! function arose because we recently added the mxsowings and mxharvests - ! dimensions to the restart file. - ! - ! !USES: - use ncdio_pio - ! - ! !ARGUMENTS: - type(file_desc_t), intent(inout) :: ncid - character(len=*) , intent(in) :: flag - character(len=*) , intent(in) :: dimname - ! - ! !LOCAL VARIABLES: - !----------------------------------------------------------------------- - - if (flag == 'read') then - call check_dim(ncid, dimname, dimexist=CallRestartvarDimOK) - else - CallRestartvarDimOK = .true. - end if - - end function CallRestartvarDimOK - - !----------------------------------------------------------------------- - subroutine Restart(this, bounds, ncid, flag) + subroutine Restart(this, bounds, ncid, cnveg_state_inst, flag) ! ! !USES: use restUtilMod @@ -479,11 +506,15 @@ subroutine Restart(this, bounds, ncid, flag) use PatchType, only : patch use pftconMod, only : npcropmin, npcropmax use clm_varpar, only : mxsowings, mxharvests + ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2023-01-09) + use CNVegstateType, only : cnveg_state_type + use clm_time_manager , only : get_curr_calday, get_curr_date ! ! !ARGUMENTS: class(crop_type), intent(inout) :: this type(bounds_type), intent(in) :: bounds type(file_desc_t), intent(inout) :: ncid + type(cnveg_state_type) , intent(inout) :: cnveg_state_inst ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2023-01-09) character(len=*) , intent(in) :: flag ! ! !LOCAL VARIABLES: @@ -492,6 +523,14 @@ subroutine Restart(this, bounds, ncid, flag) integer :: p logical :: readvar ! determine if variable is on initial file integer :: seasons_found, seasons_loopvar ! getting number of sowings/harvests in patch + ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2023-01-09) + integer jday ! julian day of the year + integer kyr ! current year + integer kmo ! month of year (1, ..., 12) + integer kda ! day of month (1, ..., 31) + integer mcsec ! seconds of day (0, ..., seconds/day) + ! BACKWARDS_COMPATIBILITY(ssr, 2023-01-13) + logical read_hdates_thisyr_patch character(len=*), parameter :: subname = 'Restart' !----------------------------------------------------------------------- @@ -565,20 +604,25 @@ subroutine Restart(this, bounds, ncid, flag) ! the crop phases end if + call restartvar(ncid=ncid, flag=flag, varname='sowing_reason_patch',xtype=ncd_int, & + dim1name='pft', long_name='sowing reason for this patch', & + units='none', & + interpinic_flag='interp', readvar=readvar, data=this%sowing_reason_patch) + ! Read or write variable(s) with mxsowings dimension ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2022-02-02) See note in CallRestartvarDimOK() if (CallRestartvarDimOK(ncid, flag, 'mxsowings')) then - call restartvar(ncid=ncid, flag=flag, varname='sdates_thisyr', xtype=ncd_double, & + call restartvar(ncid=ncid, flag=flag, varname='sdates_thisyr_patch', xtype=ncd_double, & dim1name='pft', dim2name='mxsowings', switchdim=.true., & long_name='crop sowing dates for this patch this year', units='day of year', & scale_by_thickness=.false., & - interpinic_flag='interp', readvar=readvar, data=this%sdates_thisyr) + interpinic_flag='interp', readvar=readvar, data=this%sdates_thisyr_patch) ! Fill variable(s) derived from read-in variable(s) if (flag == 'read' .and. readvar) then do p = bounds%begp,bounds%endp seasons_found = 0 do seasons_loopvar = 1,mxsowings - if (this%sdates_thisyr(p,seasons_loopvar) >= 1 .and. this%sdates_thisyr(p,seasons_loopvar) <= 366) then + if (this%sdates_thisyr_patch(p,seasons_loopvar) >= 1 .and. this%sdates_thisyr_patch(p,seasons_loopvar) <= 366) then seasons_found = seasons_loopvar else exit @@ -592,26 +636,89 @@ subroutine Restart(this, bounds, ncid, flag) ! Read or write variable(s) with mxharvests dimension ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2022-02-02) See note in CallRestartvarDimOK() if (CallRestartvarDimOK(ncid, flag, 'mxharvests')) then - call restartvar(ncid=ncid, flag=flag, varname='hdates_thisyr', xtype=ncd_double, & + call restartvar(ncid=ncid, flag=flag, varname='sdates_perharv_patch', xtype=ncd_double, & + dim1name='pft', dim2name='mxharvests', switchdim=.true., & + long_name='sowing dates for crops harvested in this patch this year', units='day of year', & + scale_by_thickness=.false., & + interpinic_flag='interp', readvar=readvar, data=this%sdates_perharv_patch) + call restartvar(ncid=ncid, flag=flag, varname='syears_perharv_patch', xtype=ncd_double, & + dim1name='pft', dim2name='mxharvests', switchdim=.true., & + long_name='sowing years for crops harvested in this patch this year', units='year', & + scale_by_thickness=.false., & + interpinic_flag='interp', readvar=readvar, data=this%syears_perharv_patch) + call restartvar(ncid=ncid, flag=flag, varname='hdates_thisyr_patch', xtype=ncd_double, & dim1name='pft', dim2name='mxharvests', switchdim=.true., & long_name='crop harvest dates for this patch this year', units='day of year', & scale_by_thickness=.false., & - interpinic_flag='interp', readvar=readvar, data=this%hdates_thisyr) + interpinic_flag='interp', readvar=read_hdates_thisyr_patch, data=this%hdates_thisyr_patch) + call restartvar(ncid=ncid, flag=flag, varname='gddaccum_thisyr_patch', xtype=ncd_double, & + dim1name='pft', dim2name='mxharvests', switchdim=.true., & + long_name='accumulated GDD at harvest for this patch this year', units='ddays', & + scale_by_thickness=.false., & + interpinic_flag='interp', readvar=readvar, data=this%gddaccum_thisyr_patch) + call restartvar(ncid=ncid, flag=flag, varname='hui_thisyr_patch', xtype=ncd_double, & + dim1name='pft', dim2name='mxharvests', switchdim=.true., & + long_name='accumulated heat unit index at harvest for this patch this year', units='ddays', & + scale_by_thickness=.false., & + interpinic_flag='interp', readvar=readvar, data=this%hui_thisyr_patch) + call restartvar(ncid=ncid, flag=flag, varname='sowing_reason_thisyr_patch', xtype=ncd_double, & + dim1name='pft', dim2name='mxsowings', switchdim=.true., & + long_name='reason for each sowing for this patch this year', units='unitless', & + scale_by_thickness=.false., & + interpinic_flag='interp', readvar=readvar, data=this%sowing_reason_thisyr_patch) + call restartvar(ncid=ncid, flag=flag, varname='sowing_reason_perharv_patch', xtype=ncd_double, & + dim1name='pft', dim2name='mxharvests', switchdim=.true., & + long_name='reason for sowing of each crop harvested this year', units='unitless', & + scale_by_thickness=.false., & + interpinic_flag='interp', readvar=readvar, data=this%sowing_reason_perharv_patch) + call restartvar(ncid=ncid, flag=flag, varname='harvest_reason_thisyr_patch', xtype=ncd_double, & + dim1name='pft', dim2name='mxharvests', switchdim=.true., & + long_name='reason for each harvest for this patch this year', units='unitless', & + scale_by_thickness=.false., & + interpinic_flag='interp', readvar=readvar, data=this%harvest_reason_thisyr_patch) + ! Fill variable(s) derived from read-in variable(s) - if (flag == 'read' .and. readvar) then + if (flag == 'read') then + jday = get_curr_calday() + call get_curr_date(kyr, kmo, kda, mcsec) do p = bounds%begp,bounds%endp - seasons_found = 0 - do seasons_loopvar = 1,mxharvests - if (this%hdates_thisyr(p,seasons_loopvar) >= 1 .and. this%hdates_thisyr(p,seasons_loopvar) <= 366) then - seasons_found = seasons_loopvar - else - exit - end if - end do ! loop through possible harvests - this%harvest_count(p) = seasons_found + + ! Harvest count + if (read_hdates_thisyr_patch) then + seasons_found = 0 + do seasons_loopvar = 1,mxharvests + if (this%hdates_thisyr_patch(p,seasons_loopvar) >= 1 .and. this%hdates_thisyr_patch(p,seasons_loopvar) <= 366) then + seasons_found = seasons_loopvar + else + exit + end if + end do ! loop through possible harvests + this%harvest_count(p) = seasons_found + end if + + ! Year of planting + ! Calculating this here instead of saving in restart file to allow for + ! sensible iyop values in startup/hybrid runs. + ! * Assumes no growing season is longer than 364 days (or 365 days if + ! spanning a leap day). + if (cnveg_state_inst%idop_patch(p) <= jday) then + cnveg_state_inst%iyop_patch(p) = kyr + else + cnveg_state_inst%iyop_patch(p) = kyr - 1 + end if end do ! loop through patches end if end if + + ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2023-01-09) + if (flag == 'read') then + do p = bounds%begp,bounds%endp + ! Will be needed until we can rely on all restart files including sowing_reason_patch. + if (this%croplive_patch(p) .and. this%sowing_reason_patch(p) < 0) then + this%sowing_reason_patch(p) = 0 + end if + end do ! loop through patches + end if end if end subroutine Restart diff --git a/src/biogeochem/EDBGCDynMod.F90 b/src/biogeochem/EDBGCDynMod.F90 deleted file mode 100644 index eb13932d13..0000000000 --- a/src/biogeochem/EDBGCDynMod.F90 +++ /dev/null @@ -1,370 +0,0 @@ -module EDBGCDynMod - -! This module creates a pathway to call the belowground biogeochemistry code as driven by the fates vegetation model -! but bypassing the aboveground CN vegetation code. It is modeled after the CNDriverMod in its call sequence and -! functionality. - - use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varctl , only : use_c13, use_c14, use_fates - use decompMod , only : bounds_type - use perf_mod , only : t_startf, t_stopf - use shr_log_mod , only : errMsg => shr_log_errMsg - use abortutils , only : endrun - use SoilBiogeochemDecompCascadeConType , only : no_soil_decomp, mimics_decomp, century_decomp, decomp_method - use CNVegCarbonStateType , only : cnveg_carbonstate_type - use CNVegCarbonFluxType , only : cnveg_carbonflux_type - use SoilBiogeochemStateType , only : soilbiogeochem_state_type - use SoilBiogeochemCarbonStateType , only : soilbiogeochem_carbonstate_type - use SoilBiogeochemCarbonFluxType , only : soilbiogeochem_carbonflux_type - use SoilBiogeochemNitrogenStateType , only : soilbiogeochem_nitrogenstate_type - use SoilBiogeochemNitrogenFluxType , only : soilbiogeochem_nitrogenflux_type - use CanopyStateType , only : canopystate_type - use SoilStateType , only : soilstate_type - use SoilHydrologyType , only : soilhydrology_type - use TemperatureType , only : temperature_type - use WaterFluxBulkType , only : waterfluxbulk_type - use ActiveLayerMod , only : active_layer_type - use atm2lndType , only : atm2lnd_type - use SoilStateType , only : soilstate_type - use ch4Mod , only : ch4_type - use CLMFatesInterfaceMod , only : hlm_fates_interface_type - - implicit none - - ! public :: EDBGCDynInit ! BGC dynamics: initialization - public :: EDBGCDyn ! BGC Dynamics - public :: EDBGCDynSummary ! BGC dynamics: summary - - character(len=*), parameter, private :: sourcefile = & - __FILE__ - -contains - - - !----------------------------------------------------------------------- - subroutine EDBGCDyn(bounds, & - num_soilc, filter_soilc, num_soilp, filter_soilp, num_pcropp, filter_pcropp, doalb, & - cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & - soilbiogeochem_state_inst, clm_fates, & - soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst, & - c13_soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonflux_inst, & - c14_soilbiogeochem_carbonstate_inst, c14_soilbiogeochem_carbonflux_inst, & - active_layer_inst, atm2lnd_inst, waterfluxbulk_inst, & - canopystate_inst, soilstate_inst, temperature_inst, crop_inst, ch4_inst) - ! - ! !DESCRIPTION: - - ! - ! !USES: - use clm_varpar , only: nlevgrnd, nlevdecomp_full - use clm_varpar , only: nlevdecomp, ndecomp_cascade_transitions, ndecomp_pools - use subgridAveMod , only: p2c - use CropType , only: crop_type - use CNNDynamicsMod , only: CNNDeposition,CNNFixation, CNNFert, CNSoyfix - use CNMRespMod , only: CNMResp - use CNPhenologyMod , only: CNPhenology - use CNGRespMod , only: CNGResp - use CNCIsoFluxMod , only: CIsoFlux1, CIsoFlux2, CIsoFlux2h, CIsoFlux3 - use CNC14DecayMod , only: C14Decay - use CNCStateUpdate1Mod , only: CStateUpdate1,CStateUpdate0 - use CNCStateUpdate2Mod , only: CStateUpdate2, CStateUpdate2h - use CNCStateUpdate3Mod , only: CStateUpdate3 - use CNNStateUpdate1Mod , only: NStateUpdate1 - use CNNStateUpdate2Mod , only: NStateUpdate2, NStateUpdate2h - use CNGapMortalityMod , only: CNGapMortality - use SoilBiogeochemDecompCascadeMIMICSMod, only: decomp_rates_mimics - use SoilBiogeochemDecompCascadeBGCMod , only: decomp_rate_constants_bgc - use SoilBiogeochemDecompMod , only: SoilBiogeochemDecomp - use SoilBiogeochemLittVertTranspMod , only: SoilBiogeochemLittVertTransp - use SoilBiogeochemPotentialMod , only: SoilBiogeochemPotential - use SoilBiogeochemVerticalProfileMod , only: SoilBiogeochemVerticalProfile - use SoilBiogeochemNitrifDenitrifMod , only: SoilBiogeochemNitrifDenitrif - use SoilBiogeochemNStateUpdate1Mod , only: SoilBiogeochemNStateUpdate1 - ! - ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches - integer , intent(in) :: num_pcropp ! number of prog. crop patches in filter - integer , intent(in) :: filter_pcropp(:) ! filter for prognostic crop patches - logical , intent(in) :: doalb ! true = surface albedo calculation time step - type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst - type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst - type(soilbiogeochem_state_type) , intent(inout) :: soilbiogeochem_state_inst - type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst - type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst - type(soilbiogeochem_carbonflux_type) , intent(inout) :: c13_soilbiogeochem_carbonflux_inst - type(soilbiogeochem_carbonstate_type) , intent(inout) :: c13_soilbiogeochem_carbonstate_inst - type(soilbiogeochem_carbonflux_type) , intent(inout) :: c14_soilbiogeochem_carbonflux_inst - type(soilbiogeochem_carbonstate_type) , intent(inout) :: c14_soilbiogeochem_carbonstate_inst - type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst - type(soilbiogeochem_nitrogenstate_type) , intent(inout) :: soilbiogeochem_nitrogenstate_inst - type(active_layer_type) , intent(in) :: active_layer_inst - type(atm2lnd_type) , intent(in) :: atm2lnd_inst - type(waterfluxbulk_type) , intent(in) :: waterfluxbulk_inst - type(canopystate_type) , intent(in) :: canopystate_inst - type(soilstate_type) , intent(in) :: soilstate_inst - type(temperature_type) , intent(inout) :: temperature_inst - type(crop_type) , intent(in) :: crop_inst - type(ch4_type) , intent(in) :: ch4_inst - type(hlm_fates_interface_type) , intent(inout) :: clm_fates - ! - ! !LOCAL VARIABLES: - real(r8):: cn_decomp_pools(bounds%begc:bounds%endc,1:nlevdecomp,1:ndecomp_pools) - real(r8):: p_decomp_cpool_loss(bounds%begc:bounds%endc,1:nlevdecomp,1:ndecomp_cascade_transitions) !potential C loss from one pool to another - real(r8):: pmnf_decomp_cascade(bounds%begc:bounds%endc,1:nlevdecomp,1:ndecomp_cascade_transitions) !potential mineral N flux, from one pool to another - real(r8):: p_decomp_npool_to_din(bounds%begc:bounds%endc,1:nlevdecomp,1:ndecomp_cascade_transitions) ! potential flux to dissolved inorganic N - real(r8):: p_decomp_cn_gain(bounds%begc:bounds%endc,1:nlevdecomp,1:ndecomp_pools) ! C:N ratio of the flux gained by the receiver pool - integer :: begc,endc - !----------------------------------------------------------------------- - - begc = bounds%begc; endc = bounds%endc - - associate( & - laisun => canopystate_inst%laisun_patch , & ! Input: [real(r8) (:) ] sunlit projected leaf area index - laisha => canopystate_inst%laisha_patch , & ! Input: [real(r8) (:) ] shaded projected leaf area index - frac_veg_nosno => canopystate_inst%frac_veg_nosno_patch , & ! Input: [integer (:) ] fraction of vegetation not covered by snow (0 OR 1) [-] - frac_veg_nosno_alb => canopystate_inst%frac_veg_nosno_alb_patch , & ! Output: [integer (:) ] frac of vegetation not covered by snow [-] - tlai => canopystate_inst%tlai_patch , & ! Input: [real(r8) (:) ] one-sided leaf area index, no burying by snow - tsai => canopystate_inst%tsai_patch , & ! Input: [real(r8) (:) ] one-sided stem area index, no burying by snow - elai => canopystate_inst%elai_patch , & ! Output: [real(r8) (:) ] one-sided leaf area index with burying by snow - esai => canopystate_inst%esai_patch , & ! Output: [real(r8) (:) ] one-sided stem area index with burying by snow - htop => canopystate_inst%htop_patch , & ! Output: [real(r8) (:) ] canopy top (m) - hbot => canopystate_inst%hbot_patch & ! Output: [real(r8) (:) ] canopy bottom (m) - ) - - ! -------------------------------------------------- - ! zero the column-level C and N fluxes - ! -------------------------------------------------- - - if ( decomp_method /= no_soil_decomp )then - call t_startf('SoilBGCZero') - - call soilbiogeochem_carbonflux_inst%SetValues( & - num_soilc, filter_soilc, 0._r8) - if ( use_c13 ) then - call c13_soilbiogeochem_carbonflux_inst%SetValues( & - num_soilc, filter_soilc, 0._r8) - end if - if ( use_c14 ) then - call c14_soilbiogeochem_carbonflux_inst%SetValues( & - num_soilc, filter_soilc, 0._r8) - end if - - call t_stopf('SoilBGCZero') - end if - - ! -------------------------------------------------- - ! Nitrogen Deposition, Fixation and Respiration - ! -------------------------------------------------- - - ! call t_startf('CNDeposition') - ! call CNNDeposition(bounds, & - ! atm2lnd_inst, soilbiogeochem_nitrogenflux_inst) - ! call t_stopf('CNDeposition') - - - ! if (crop_prog) then - ! call CNNFert(bounds, num_soilc,filter_soilc, & - ! cnveg_nitrogenflux_inst, soilbiogeochem_nitrogenflux_inst) - - ! call CNSoyfix (bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & - ! waterstate_inst, crop_inst, cnveg_state_inst, cnveg_nitrogenflux_inst , & - ! soilbiogeochem_state_inst, soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) - ! end if - - !-------------------------------------------- - ! Soil Biogeochemistry - !-------------------------------------------- - - if (decomp_method == century_decomp) then - call decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & - soilstate_inst, temperature_inst, ch4_inst, soilbiogeochem_carbonflux_inst) - else if (decomp_method == mimics_decomp) then - call decomp_rates_mimics(bounds, num_soilc, filter_soilc, & - num_soilp, filter_soilp, clm_fates, & - soilstate_inst, temperature_inst, cnveg_carbonflux_inst, ch4_inst, & - soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst) - end if - - if ( decomp_method /= no_soil_decomp )then - ! calculate potential decomp rates and total immobilization demand (previously inlined in CNDecompAlloc) - call SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & - soilbiogeochem_state_inst, soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst, & - soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst, & - cn_decomp_pools=cn_decomp_pools(begc:endc,1:nlevdecomp,1:ndecomp_pools), & - p_decomp_cpool_loss=p_decomp_cpool_loss(begc:endc,1:nlevdecomp,1:ndecomp_cascade_transitions), & - p_decomp_cn_gain=p_decomp_cn_gain(begc:endc,1:nlevdecomp,1:ndecomp_pools), & - pmnf_decomp_cascade=pmnf_decomp_cascade(begc:endc,1:nlevdecomp,1:ndecomp_cascade_transitions), & - p_decomp_npool_to_din=p_decomp_npool_to_din(begc:endc,1:nlevdecomp,1:ndecomp_cascade_transitions)) - end if - - !-------------------------------------------- - ! Resolve the competition between plants and soil heterotrophs - ! for available soil mineral N resource - !-------------------------------------------- - ! will add this back in when integrtating hte nutirent cycles - - - !-------------------------------------------- - ! Calculate litter and soil decomposition rate - !-------------------------------------------- - - ! Calculation of actual immobilization and decomp rates, following - ! resolution of plant/heterotroph competition for mineral N (previously inlined in CNDecompAllocation in CNDecompMod) - - if ( decomp_method /= no_soil_decomp )then - call t_startf('SoilBiogeochemDecomp') - - call SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, & - soilbiogeochem_state_inst, soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst, & - soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst, & - cn_decomp_pools=cn_decomp_pools(begc:endc,1:nlevdecomp,1:ndecomp_pools), & - p_decomp_cpool_loss=p_decomp_cpool_loss(begc:endc,1:nlevdecomp,1:ndecomp_cascade_transitions), & - pmnf_decomp_cascade=pmnf_decomp_cascade(begc:endc,1:nlevdecomp,1:ndecomp_cascade_transitions), & - p_decomp_npool_to_din=p_decomp_npool_to_din(begc:endc,1:nlevdecomp,1:ndecomp_cascade_transitions)) - - call t_stopf('SoilBiogeochemDecomp') - - - !-------------------------------------------- - ! Update1 - !-------------------------------------------- - - call t_startf('BNGCUpdate1') - - - ! Update all prognostic carbon state variables (except for gap-phase mortality and fire fluxes) - call CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & - crop_inst, cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - soilbiogeochem_carbonflux_inst, dribble_crophrv_xsmrpool_2atm=.False.) - - call t_stopf('BNGCUpdate1') - - !-------------------------------------------- - ! Calculate vertical mixing of soil and litter pools - !-------------------------------------------- - - call t_startf('SoilBiogeochemLittVertTransp') - - call SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & - active_layer_inst, soilbiogeochem_state_inst, & - soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst, & - c13_soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonflux_inst, & - c14_soilbiogeochem_carbonstate_inst, c14_soilbiogeochem_carbonflux_inst, & - soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) - - call t_stopf('SoilBiogeochemLittVertTransp') - end if - - ! Wood product fluxes will eventually be added to FATES-CLM. However - ! it is likely this will be implemented during or after we break away from - ! using this module. This module and the current coupling stategy bypasses - ! a number of processes in CLM, which includes the wood product modules. - ! Therefore the following call is a placeholder so that the wood-product - ! wrapper code can be copied from here and applied at the right place when the time comes. - ! RGK 06-2022 - - !call FatesWrapWoodProducts(bounds, num_soilc, filter_soilc,c_products_inst) - !call t_startf('CNWoodProducts') - !call c_products_inst%UpdateProducts(bounds, & - ! num_soilp, filter_soilp, & - ! dwt_wood_product_gain_patch = cnveg_carbonflux_inst%dwt_wood_productc_gain_patch(begp:endp), & - ! wood_harvest_patch = cnveg_carbonflux_inst%wood_harvestc_patch(begp:endp), & - ! dwt_crop_product_gain_patch = cnveg_carbonflux_inst%dwt_crop_productc_gain_patch(begp:endp), & - ! crop_harvest_to_cropprod_patch = cnveg_carbonflux_inst%crop_harvestc_to_cropprodc_patch(begp:endp)) - !call t_stopf('CNWoodProducts') - - - end associate - - end subroutine EDBGCDyn - - - !----------------------------------------------------------------------- - subroutine EDBGCDynSummary(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & - soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & - c13_soilbiogeochem_carbonflux_inst, c13_soilbiogeochem_carbonstate_inst, & - c14_soilbiogeochem_carbonflux_inst, c14_soilbiogeochem_carbonstate_inst, & - soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst, & - nc) - ! - ! !DESCRIPTION: - ! Call to all CN and SoilBiogeochem summary routines - ! also aggregate production and decomposition fluxes to whole-ecosystem balance fluxes - ! - ! !USES: - use clm_varpar , only: ndecomp_cascade_transitions - use CNPrecisionControlMod , only: CNPrecisionControl - use SoilBiogeochemPrecisionControlMod , only: SoilBiogeochemPrecisionControl - ! - ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches - type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst - type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst - type(soilbiogeochem_carbonflux_type) , intent(inout) :: c13_soilbiogeochem_carbonflux_inst - type(soilbiogeochem_carbonstate_type) , intent(inout) :: c13_soilbiogeochem_carbonstate_inst - type(soilbiogeochem_carbonflux_type) , intent(inout) :: c14_soilbiogeochem_carbonflux_inst - type(soilbiogeochem_carbonstate_type) , intent(inout) :: c14_soilbiogeochem_carbonstate_inst - type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst - type(soilbiogeochem_nitrogenstate_type) , intent(inout) :: soilbiogeochem_nitrogenstate_inst - integer , intent(in) :: nc ! thread index - ! - ! !LOCAL VARIABLES: - integer :: begc,endc - !----------------------------------------------------------------------- - - begc = bounds%begc; endc= bounds%endc - - ! Call to all summary routines - - call t_startf('BGCsum') - - ! Set controls on very low values in critical state variables - - call SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & - soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & - c14_soilbiogeochem_carbonstate_inst,soilbiogeochem_nitrogenstate_inst) - - ! Note - all summary updates to cnveg_carbonstate_inst and cnveg_carbonflux_inst are done in - ! soilbiogeochem_carbonstate_inst%summary and CNVeg_carbonstate_inst%summary - - ! ---------------------------------------------- - ! soilbiogeochem carbon/nitrogen state summary - ! ---------------------------------------------- - - call soilbiogeochem_carbonstate_inst%summary(bounds, num_soilc, filter_soilc) - if ( use_c13 ) then - call c13_soilbiogeochem_carbonstate_inst%summary(bounds, num_soilc, filter_soilc) - end if - if ( use_c14 ) then - call c14_soilbiogeochem_carbonstate_inst%summary(bounds, num_soilc, filter_soilc) - end if - ! call soilbiogeochem_nitrogenstate_inst%summary(bounds, num_soilc, filter_soilc) - - ! ---------------------------------------------- - ! soilbiogeochem carbon/nitrogen flux summary - ! ---------------------------------------------- - - call soilbiogeochem_carbonflux_inst%Summary(bounds, num_soilc, filter_soilc) - if ( use_c13 ) then - call c13_soilbiogeochem_carbonflux_inst%Summary(bounds, num_soilc, filter_soilc) - end if - if ( use_c14 ) then - call c14_soilbiogeochem_carbonflux_inst%Summary(bounds, num_soilc, filter_soilc) - end if - ! call soilbiogeochem_nitrogenflux_inst%Summary(bounds, num_soilc, filter_soilc) - - - call t_stopf('BGCsum') - - end subroutine EDBGCDynSummary - -end module EDBGCDynMod diff --git a/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 b/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 index e7c16f15c7..6f8632658d 100644 --- a/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 +++ b/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 @@ -1365,7 +1365,6 @@ subroutine calc_plant_nitrogen_demand(this, bounds, & frootn => cnveg_nitrogenstate_inst%frootn_patch , & ! Input: [real(r8) (:) ] (gN/m2) fine root N livestemn_to_retransn => cnveg_nitrogenflux_inst%livestemn_to_retransn_patch,& ! Output: [real(r8) (:) ] sminn_vr => soilbiogeochem_nitrogenstate_inst%sminn_vr_col , & ! Input: [real(r8) (:,:) ] (gN/m3) soil mineral N - btran => energyflux_inst%btran_patch , & ! Input: [real(r8) (:) ] transpiration wetness factor (0 to 1) t_scalar => soilbiogeochem_carbonflux_inst%t_scalar_col & ! Input: [real(r8) (:,:) ] soil temperature scalar for decomp ) diff --git a/src/biogeochem/ch4Mod.F90 b/src/biogeochem/ch4Mod.F90 index afb8af351b..f199e7913f 100644 --- a/src/biogeochem/ch4Mod.F90 +++ b/src/biogeochem/ch4Mod.F90 @@ -17,7 +17,7 @@ module ch4Mod use clm_varcon , only : catomw, s_con, d_con_w, d_con_g, c_h_inv, kh_theta, kh_tbase use landunit_varcon , only : istsoil, istcrop, istdlak use clm_time_manager , only : get_step_size_real, get_nstep - use clm_varctl , only : iulog, use_cn, use_nitrif_denitrif, use_lch4, use_cn, use_fates + use clm_varctl , only : iulog, use_cn, use_nitrif_denitrif, use_lch4, use_fates_bgc use abortutils , only : endrun use decompMod , only : bounds_type, subgrid_level_gridcell, subgrid_level_column use atm2lndType , only : atm2lnd_type @@ -2521,7 +2521,7 @@ subroutine ch4_prod (bounds, num_methc, filter_methc, num_methp, & end if end do - if(use_fates) then + if(use_fates_bgc) then nc = bounds%clump_index do s = 1,clm_fates%fates(nc)%nsites c = clm_fates%f2hmap(nc)%fcolumn(s) @@ -2544,7 +2544,7 @@ subroutine ch4_prod (bounds, num_methc, filter_methc, num_methp, & if (.not. lake) then - if (use_cn .or. use_fates) then + if (use_cn .or. use_fates_bgc) then ! Use soil heterotrophic respiration (based on Wania) base_decomp = (somhr(c)+lithr(c)) / catomw ! Convert from gC to molC @@ -2567,7 +2567,7 @@ subroutine ch4_prod (bounds, num_methc, filter_methc, num_methp, & else call endrun(msg=' ERROR: No source for decomp rate in CH4Prod.'//& ' CH4 model currently requires CN or FATES.'//errMsg(sourcefile, __LINE__)) - end if ! use_cn + end if ! use_cn or use_fates_bgc ! For sensitivity studies base_decomp = base_decomp * cnscalefactor diff --git a/src/biogeophys/BareGroundFluxesMod.F90 b/src/biogeophys/BareGroundFluxesMod.F90 index e68e56841e..645b908157 100644 --- a/src/biogeophys/BareGroundFluxesMod.F90 +++ b/src/biogeophys/BareGroundFluxesMod.F90 @@ -82,7 +82,8 @@ subroutine BareGroundFluxes(bounds, num_noexposedvegp, filter_noexposedvegp, & use shr_const_mod , only : SHR_CONST_RGAS use clm_varpar , only : nlevgrnd use clm_varcon , only : cpair, vkc, grav, denice, denh2o - use clm_varctl , only : use_lch4 + use clm_varcon , only : beta_param, nu_param, meier_param3 + use clm_varctl , only : use_lch4, z0param_method use landunit_varcon , only : istsoil, istcrop use QSatMod , only : QSat use SurfaceResistanceMod , only : do_soilevap_beta,do_soil_resistance_sl14 @@ -90,6 +91,8 @@ subroutine BareGroundFluxes(bounds, num_noexposedvegp, filter_noexposedvegp, & Wet_Bulb, Wet_BulbS, HeatIndex, AppTemp, & swbgt, hmdex, dis_coi, dis_coiS, THIndex, & SwampCoolEff, KtoC, VaporPres + use CanopyStateType , only : canopystate_type + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -138,9 +141,6 @@ subroutine BareGroundFluxes(bounds, num_noexposedvegp, filter_noexposedvegp, & real(r8) :: raih ! temporary variable [kg/m2/s] real(r8) :: raiw ! temporary variable [kg/m2/s] real(r8) :: fm(bounds%begp:bounds%endp) ! needed for BGC only to diagnose 10m wind speed - real(r8) :: z0mg_patch(bounds%begp:bounds%endp) - real(r8) :: z0hg_patch(bounds%begp:bounds%endp) - real(r8) :: z0qg_patch(bounds%begp:bounds%endp) real(r8) :: e_ref2m ! 2 m height surface saturated vapor pressure [Pa] real(r8) :: qsat_ref2m ! 2 m height surface saturated specific humidity [kg/kg] real(r8) :: www ! surface soil wetness [-] @@ -235,16 +235,22 @@ subroutine BareGroundFluxes(bounds, num_noexposedvegp, filter_noexposedvegp, & rh_ref2m_r => waterdiagnosticbulk_inst%rh_ref2m_r_patch , & ! Output: [real(r8) (:) ] Rural 2 m height surface relative humidity (%) rh_ref2m => waterdiagnosticbulk_inst%rh_ref2m_patch , & ! Output: [real(r8) (:) ] 2 m height surface relative humidity (%) - forc_hgt_u_patch => frictionvel_inst%forc_hgt_u_patch , & ! Input: - displa => canopystate_inst%displa_patch , & ! Input: [real(r8) (:) ] displacement height (m) + forc_hgt_u_patch => frictionvel_inst%forc_hgt_u_patch , & ! Output: [real(r8) (:) ] observational height of wind at patch level [m] + forc_hgt_t_patch => frictionvel_inst%forc_hgt_t_patch , & ! Output: [real(r8) (:) ] observational height of temperature at patch level [m] + forc_hgt_q_patch => frictionvel_inst%forc_hgt_q_patch , & ! Output: [real(r8) (:) ] observational height of specific humidity at patch level [m] u10_clm => frictionvel_inst%u10_clm_patch , & ! Input: [real(r8) (:) ] 10 m height winds (m/s) zetamax => frictionvel_inst%zetamaxstable , & ! Input: [real(r8) ] max zeta value under stable conditions + zeta => frictionvel_inst%zeta_patch , & ! Output: [real(r8) (:) ] dimensionless stability parameter z0mg_col => frictionvel_inst%z0mg_col , & ! Output: [real(r8) (:) ] roughness length, momentum [m] z0hg_col => frictionvel_inst%z0hg_col , & ! Output: [real(r8) (:) ] roughness length, sensible heat [m] z0qg_col => frictionvel_inst%z0qg_col , & ! Output: [real(r8) (:) ] roughness length, latent heat [m] - z0mv => frictionvel_inst%z0mv_patch , & ! Output: [real(r8) (:) ] roughness length over vegetation, momentum [m] - z0hv => frictionvel_inst%z0hv_patch , & ! Output: [real(r8) (:) ] roughness length over vegetation, sensible heat [m] - z0qv => frictionvel_inst%z0qv_patch , & ! Output: [real(r8) (:) ] roughness length over vegetation, latent heat [m] + z0mg_patch => frictionvel_inst%z0mg_patch , & ! Output: [real(r8) (:) ] patch roughness length, momentum [m] + z0hg_patch => frictionvel_inst%z0hg_patch , & ! Output: [real(r8) (:) ] patch roughness length, sensible heat [m] + z0qg_patch => frictionvel_inst%z0qg_patch , & ! Output: [real(r8) (:) ] patch roughness length, latent heat [m] + z0mv => frictionvel_inst%z0mv_patch , & ! Output: [real(r8) (:) ] roughness length over vegetation, momentum [m] + z0hv => frictionvel_inst%z0hv_patch , & ! Output: [real(r8) (:) ] roughness length over vegetation, sensible heat [m] + z0qv => frictionvel_inst%z0qv_patch , & ! Output: [real(r8) (:) ] roughness length over vegetation, latent heat [m] + kbm1 => frictionvel_inst%kbm1_patch , & ! Output: [real(r8) (:) ] natural logarithm of z0mg_p/z0hg_p [-] ram1 => frictionvel_inst%ram1_patch , & ! Output: [real(r8) (:) ] aerodynamical resistance (s/m) num_iter => frictionvel_inst%num_iter_patch , & ! Output: [real(r8) (:) ] number of iterations htvp => energyflux_inst%htvp_col , & ! Input: [real(r8) (:) ] latent heat of evaporation (/sublimation) [J/kg] @@ -259,6 +265,8 @@ subroutine BareGroundFluxes(bounds, num_noexposedvegp, filter_noexposedvegp, & rssun => photosyns_inst%rssun_patch , & ! Output: [real(r8) (:) ] leaf sunlit stomatal resistance (s/m) (output from Photosynthesis) rssha => photosyns_inst%rssha_patch , & ! Output: [real(r8) (:) ] leaf shaded stomatal resistance (s/m) (output from Photosynthesis) + displa => canopystate_inst%displa_patch , & ! Output: [real(r8) (:) ] displacement height (m) + begp => bounds%begp , & endp => bounds%endp & ) @@ -298,6 +306,10 @@ subroutine BareGroundFluxes(bounds, num_noexposedvegp, filter_noexposedvegp, & ulrad(p) = 0._r8 dhsdt_canopy(p) = 0._r8 eflx_sh_stem(p) = 0._r8 + z0mv(p) = 0._r8 + z0hv(p) = 0._r8 + z0qv(p) = 0._r8 + ur(p) = max(params_inst%wind_min,sqrt(forc_u(g)*forc_u(g)+forc_v(g)*forc_v(g))) dth(p) = thm(p)-t_grnd(c) @@ -337,20 +349,39 @@ subroutine BareGroundFluxes(bounds, num_noexposedvegp, filter_noexposedvegp, & tstar = temp1(p)*dth(p) qstar = temp2(p)*dqh(p) - z0hg_patch(p) = z0mg_patch(p) / exp(params_inst%a_coef * (ustar(p) * z0mg_patch(p) / 1.5e-5_r8)**params_inst%a_exp) + + select case (z0param_method) + case ('ZengWang2007') + z0hg_patch(p) = z0mg_patch(p) / exp(params_inst%a_coef * (ustar(p) * z0mg_patch(p) / nu_param)**params_inst%a_exp) + case ('Meier2022') + + ! After Yang et al. (2008) + ! (...)**0.5 = sqrt(...) and (...)**0.25 = sqrt(sqrt(...)) + ! likely more efficient to calculate as exponents + z0hg_patch(p) = meier_param3 * nu_param / ustar(p) * exp( -beta_param * ustar(p)**(0.5_r8) * (abs(tstar))**(0.25_r8)) + + end select + z0qg_patch(p) = z0hg_patch(p) + ! Update the forcing heights for new roughness lengths + ! TODO(KWO, 2022-03-15) Only for Meier2022 for now to maintain bfb with ZengWang2007 + if (z0param_method == 'Meier2022') then + forc_hgt_u_patch(p) = forc_hgt_u_patch(g) + z0mg_patch(p) + displa(p) + forc_hgt_t_patch(p) = forc_hgt_t_patch(g) + z0hg_patch(p) + displa(p) + forc_hgt_q_patch(p) = forc_hgt_q_patch(g) + z0qg_patch(p) + displa(p) + end if thvstar = tstar*(1._r8+0.61_r8*forc_q(c)) + 0.61_r8*forc_th(c)*qstar - zeta = zldis(p)*vkc*grav*thvstar/(ustar(p)**2*thv(c)) + zeta(p) = zldis(p)*vkc*grav*thvstar/(ustar(p)**2*thv(c)) - if (zeta >= 0._r8) then !stable - zeta = min(zetamax,max(zeta,0.01_r8)) + if (zeta(p) >= 0._r8) then !stable + zeta(p) = min(zetamax,max(zeta(p),0.01_r8)) um(p) = max(ur(p),0.1_r8) else !unstable - zeta = max(-100._r8,min(zeta,-0.01_r8)) + zeta(p) = max(-100._r8,min(zeta(p),-0.01_r8)) wc = beta(c)*(-grav*ustar(p)*thvstar*zii(c)/thv(c))**0.333_r8 um(p) = sqrt(ur(p)*ur(p) + wc*wc) end if - obu(p) = zldis(p)/zeta + obu(p) = zldis(p)/zeta(p) num_iter(p) = iter end do @@ -441,6 +472,8 @@ subroutine BareGroundFluxes(bounds, num_noexposedvegp, filter_noexposedvegp, & t_ref2m_r(p) = t_ref2m(p) end if + kbm1(p) = log(z0mg_patch(p) / z0hg_patch(p)) + ! Copy local patch ground roughness back to column arrays for history output which ! uses the column arrays. z0mg is unchanged so only need to copy z0hg and z0qg diff --git a/src/biogeophys/BiogeophysPreFluxCalcsMod.F90 b/src/biogeophys/BiogeophysPreFluxCalcsMod.F90 index 2aa56de927..11842560ee 100644 --- a/src/biogeophys/BiogeophysPreFluxCalcsMod.F90 +++ b/src/biogeophys/BiogeophysPreFluxCalcsMod.F90 @@ -10,14 +10,15 @@ module BiogeophysPreFluxCalcsMod #include "shr_assert.h" use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg + use abortutils , only : endrun use decompMod , only : bounds_type use PatchType , only : patch use ColumnType , only : col use LandunitType , only : lun use clm_varcon , only : spval use clm_varpar , only : nlevgrnd, nlevsno, nlevurb, nlevmaxurbgrnd - use clm_varctl , only : use_fates - use pftconMod , only : pftcon + use clm_varctl , only : use_fates, z0param_method, iulog + use pftconMod , only : pftcon, noveg use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use landunit_varcon , only : istsoil, istcrop, istice use clm_varcon , only : hvap, hsub @@ -32,6 +33,8 @@ module BiogeophysPreFluxCalcsMod use WaterDiagnosticBulkType , only : waterdiagnosticbulk_type use WaterStateBulkType , only : waterstatebulk_type use SurfaceResistanceMod , only : calc_soilevap_resis + use WaterFluxBulkType , only : waterfluxbulk_type + ! ! !PUBLIC TYPES: implicit none @@ -57,7 +60,7 @@ subroutine BiogeophysPreFluxCalcs(bounds, & num_urbanc, filter_urbanc, & clm_fates, atm2lnd_inst, canopystate_inst, energyflux_inst, frictionvel_inst, & soilstate_inst, temperature_inst, & - wateratm2lndbulk_inst, waterdiagnosticbulk_inst, waterstatebulk_inst) + wateratm2lndbulk_inst, waterdiagnosticbulk_inst, waterstatebulk_inst, waterfluxbulk_inst) ! ! !DESCRIPTION: ! Do various calculations that need to happen before the main biogeophysics flux calculations @@ -80,6 +83,7 @@ subroutine BiogeophysPreFluxCalcs(bounds, & type(wateratm2lndbulk_type) , intent(in) :: wateratm2lndbulk_inst type(waterdiagnosticbulk_type) , intent(in) :: waterdiagnosticbulk_inst type(waterstatebulk_type) , intent(in) :: waterstatebulk_inst + type(waterfluxbulk_type) , intent(in) :: waterfluxbulk_inst ! ! !LOCAL VARIABLES: integer :: fp, p @@ -93,7 +97,8 @@ subroutine BiogeophysPreFluxCalcs(bounds, & call frictionvel_inst%SetRoughnessLengthsAndForcHeightsNonLake(bounds, & num_nolakec, filter_nolakec, & num_nolakep, filter_nolakep, & - atm2lnd_inst, waterdiagnosticbulk_inst, canopystate_inst) + atm2lnd_inst, waterdiagnosticbulk_inst, canopystate_inst, & + waterfluxbulk_inst) call CalcInitialTemperatureAndEnergyVars(bounds, & num_nolakec, filter_nolakec, & @@ -120,6 +125,11 @@ subroutine SetZ0mDisp(bounds, num_nolakep, filter_nolakep, & ! !DESCRIPTION: ! Set z0m and displa ! + ! !USES: + use clm_time_manager, only : is_first_step, get_nstep, is_beg_curr_year + use clm_varcon , only : cd1_param + use decompMod , only : subgrid_level_patch + use BalanceCheckMod , only : GetBalanceCheckSkipSteps ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_nolakep ! number of column non-lake points in patch filter @@ -131,6 +141,8 @@ subroutine SetZ0mDisp(bounds, num_nolakep, filter_nolakep, & integer :: fp, p character(len=*), parameter :: subname = 'SetZ0mDisp' + real(r8) :: U_ustar ! wind at canopy height divided by friction velocity (unitless) + !----------------------------------------------------------------------- associate( & @@ -154,8 +166,51 @@ subroutine SetZ0mDisp(bounds, num_nolakep, filter_nolakep, & p = filter_nolakep(fp) if( .not.(patch%is_fates(p))) then - z0m(p) = pftcon%z0mr(patch%itype(p)) * htop(p) - displa(p) = pftcon%displar(patch%itype(p)) * htop(p) + select case (z0param_method) + case ('ZengWang2007') + + z0m(p) = pftcon%z0mr(patch%itype(p)) * htop(p) + displa(p) = pftcon%displar(patch%itype(p)) * htop(p) + + case ('Meier2022') + + ! Don't set on first few steps of a simulation, since htop isn't set yet, need to wait until after first do_alb time + if ( is_first_step() .or. get_nstep() <= GetBalanceCheckSkipSteps()-1 ) then + z0m(p) = 0._r8 + displa(p) = 0._r8 + cycle + ! If a crop type and it's the start of the year, htop gets reset to + ! zero... + else if ( is_beg_curr_year() .and. pftcon%crop(patch%itype(p)) /= 0.0_r8 )then + z0m(p) = 0._r8 + displa(p) = 0._r8 + end if + + if (patch%itype(p) == noveg) then + z0m(p) = 0._r8 + displa(p) = 0._r8 + + else + ! Compute as if elai+esai = LAImax in CanopyFluxes + displa(p) = htop(p) * (1._r8 - (1._r8 - exp(-(cd1_param * (pftcon%z0v_LAImax(patch%itype(p))))**0.5_r8)) & + / (cd1_param*(pftcon%z0v_LAImax(patch%itype(p)) ))**0.5_r8) + + U_ustar = 4._r8 * (pftcon%z0v_Cs(patch%itype(p)) + pftcon%z0v_Cr(patch%itype(p)) * (pftcon%z0v_LAImax(patch%itype(p))) & + / 2._r8)**(-0.5_r8) / (pftcon%z0v_LAImax(patch%itype(p))) / pftcon%z0v_c(patch%itype(p)) + + if ( htop(p) <= 1.e-10_r8 )then + write(iulog,*) ' nstep = ', get_nstep(), ' htop = ', htop(p) + call endrun(subgrid_index=p, subgrid_level=subgrid_level_patch, msg=errMsg(sourcefile, __LINE__)) + else + z0m(p) = htop(p) * (1._r8 - displa(p) / htop(p)) * exp(-0.4_r8 * U_ustar + & + log(pftcon%z0v_cw(patch%itype(p))) - 1._r8 + pftcon%z0v_cw(patch%itype(p))**(-1._r8)) + end if + + end if + + + end select + end if end do diff --git a/src/biogeophys/CanopyFluxesMod.F90 b/src/biogeophys/CanopyFluxesMod.F90 index 038f8ea636..ae0832a2b2 100644 --- a/src/biogeophys/CanopyFluxesMod.F90 +++ b/src/biogeophys/CanopyFluxesMod.F90 @@ -14,7 +14,7 @@ module CanopyFluxesMod use shr_log_mod , only : errMsg => shr_log_errMsg use abortutils , only : endrun use clm_varctl , only : iulog, use_cn, use_lch4, use_c13, use_c14, use_cndv, use_fates, & - use_luna, use_hydrstress, use_biomass_heat_storage + use_luna, use_hydrstress, use_biomass_heat_storage, z0param_method use clm_varpar , only : nlevgrnd, nlevsno, nlevcan, mxpft use pftconMod , only : pftcon use decompMod , only : bounds_type, subgrid_level_patch @@ -47,6 +47,7 @@ module CanopyFluxesMod use EDTypesMod , only : ed_site_type use SoilWaterRetentionCurveMod, only : soil_water_retention_curve_type use LunaMod , only : Update_Photosynthesis_Capacity, Acc24_Climate_LUNA,Acc240_Climate_LUNA,Clear24_Climate_LUNA + use NumericsMod , only : truncate_small_values ! ! !PUBLIC TYPES: implicit none @@ -114,6 +115,7 @@ subroutine CanopyFluxesReadNML(NLFilename) namelist /canopyfluxes_inparm/ use_biomass_heat_storage namelist /canopyfluxes_inparm/ itmax_canopy_fluxes + ! Initialize options to default values, in case they are not specified in ! the namelist @@ -228,6 +230,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, use clm_varcon , only : denh2o, tfrz, tlsai_crit, alpha_aero use clm_varcon , only : c14ratio, spval use clm_varcon , only : c_water, c_dry_biomass, c_to_b + use clm_varcon , only : nu_param, cd1_param use perf_mod , only : t_startf, t_stopf use QSatMod , only : QSat use CLMFatesInterfaceMod, only : hlm_fates_interface_type @@ -237,6 +240,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, SwampCoolEff, KtoC, VaporPres use SoilWaterRetentionCurveMod, only : soil_water_retention_curve_type use LunaMod , only : is_time_to_run_LUNA + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -378,6 +382,9 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, integer :: index ! patch index for error real(r8) :: egvf ! effective green vegetation fraction real(r8) :: lt ! elai+esai + real(r8) :: U_ustar ! wind at canopy height divided by friction velocity (unitless) + real(r8) :: U_ustar_ini ! initial guess of wind at canopy height divided by friction velocity (unitless) + real(r8) :: U_ustar_prev ! wind at canopy height divided by friction velocity from the previous iteration (unitless) real(r8) :: ri ! stability parameter for under canopy air (unitless) real(r8) :: csoilb ! turbulent transfer coefficient over bare soil (unitless) real(r8) :: ricsoilc ! modified transfer coefficient under dense canopy (unitless) @@ -416,6 +423,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, real(r8) :: uuc(bounds%begp:bounds%endp) ! undercanopy windspeed real(r8) :: carea_stem ! cross-sectional area of stem real(r8) :: dlrad_leaf ! Downward longwave radition from leaf + real(r8) :: snocan_baseline(bounds%begp:bounds%endp) ! baseline of snocan for use in truncate_small_values ! Indices for raw and rah integer, parameter :: above_canopy = 1 ! Above canopy @@ -449,9 +457,17 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, slatop => pftcon%slatop , & ! SLA at top of canopy [m^2/gC] fbw => pftcon%fbw , & ! Input: fraction of biomass that is water nstem => pftcon%nstem , & ! Input: stem number density (#ind/m2) + woody => pftcon%woody , & ! Input: woody flag rstem_per_dbh => pftcon%rstem_per_dbh , & ! Input: stem resistance per stem diameter (s/m**2) wood_density => pftcon%wood_density , & ! Input: dry wood density (kg/m3) + z0v_Cr => pftcon%z0v_Cr , & ! Input: roughness-element drag coefficient for Raupach92 parameterization (-) + z0v_Cs => pftcon%z0v_Cs , & ! Input: substrate-element drag coefficient for Raupach92 parameterization (-) + z0v_c => pftcon%z0v_c , & ! Input: c parameter for Raupach92 parameterization (-) + z0v_cw => pftcon%z0v_cw , & ! Input: roughness sublayer depth coefficient for Raupach92 parameterization (-) + z0v_LAIoff => pftcon%z0v_LAIoff , & ! Input: leaf area index offset for Raupach92 parameterization (-) + z0v_LAImax => pftcon%z0v_LAImax , & ! Input: onset of over-sheltering for Raupach92 parameterization (-) + forc_lwrad => atm2lnd_inst%forc_lwrad_downscaled_col , & ! Input: [real(r8) (:) ] downward infrared (longwave) radiation (W/m**2) forc_q => wateratm2lndbulk_inst%forc_q_downscaled_col , & ! Input: [real(r8) (:) ] atmospheric specific humidity (kg/kg) forc_pbot => atm2lnd_inst%forc_pbot_downscaled_col , & ! Input: [real(r8) (:) ] atmospheric pressure (Pa) @@ -516,7 +532,12 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, soilbeta => soilstate_inst%soilbeta_col , & ! Input: [real(r8) (:) ] soil wetness relative to field capacity u10_clm => frictionvel_inst%u10_clm_patch , & ! Input: [real(r8) (:) ] 10 m height winds (m/s) - forc_hgt_u_patch => frictionvel_inst%forc_hgt_u_patch , & ! Input: [real(r8) (:) ] observational height of wind at patch level [m] + forc_hgt_t => atm2lnd_inst%forc_hgt_t_grc , & ! Input: [real(r8) (:) ] observational height of temperature [m] + forc_hgt_u => atm2lnd_inst%forc_hgt_u_grc , & ! Input: [real(r8) (:) ] observational height of wind [m] + forc_hgt_q => atm2lnd_inst%forc_hgt_q_grc , & ! Input: [real(r8) (:) ] observational height of specific humidity [m] + forc_hgt_t_patch => frictionvel_inst%forc_hgt_t_patch , & ! Output: [real(r8) (:) ] observational height of temperature at patch level [m] + forc_hgt_q_patch => frictionvel_inst%forc_hgt_q_patch , & ! Output: [real(r8) (:) ] observational height of specific humidity at patch level [m] + forc_hgt_u_patch => frictionvel_inst%forc_hgt_u_patch , & ! Output: [real(r8) (:) ] observational height of wind at patch level [m] z0mg => frictionvel_inst%z0mg_col , & ! Input: [real(r8) (:) ] roughness length of ground, momentum [m] zetamax => frictionvel_inst%zetamaxstable , & ! Input: [real(r8) ] max zeta value under stable conditions ram1 => frictionvel_inst%ram1_patch , & ! Output: [real(r8) (:) ] aerodynamical resistance (s/m) @@ -865,13 +886,54 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, do f = 1, fn p = filterp(f) c = patch%column(p) + g = patch%gridcell(p) + + select case (z0param_method) + case ('ZengWang2007') + lt = min(elai(p)+esai(p), tlsai_crit) + egvf =(1._r8 - alpha_aero * exp(-lt)) / (1._r8 - alpha_aero * exp(-tlsai_crit)) + displa(p) = egvf * displa(p) + z0mv(p) = exp(egvf * log(z0mv(p)) + (1._r8 - egvf) * log(z0mg(c))) + + case ('Meier2022') + lt = max(1.e-5_r8, elai(p) + esai(p)) + displa(p) = htop(p) * (1._r8 - (1._r8 - exp(-(cd1_param * lt)**0.5_r8)) / (cd1_param*lt)**0.5_r8) + + lt = min(lt,z0v_LAImax(patch%itype(p))) + delt = 2._r8 + ! Reminder that (...)**(-0.5) = 1 / sqrt(...) + U_ustar_ini = (z0v_Cs(patch%itype(p)) + z0v_Cr(patch%itype(p)) * lt * 0.5_r8)**(-0.5_r8) & + *z0v_c(patch%itype(p)) * lt * 0.25_r8 + U_ustar = U_ustar_ini + + do while (delt > 1.e-4_r8) + U_ustar_prev = U_ustar + U_ustar = U_ustar_ini * exp(U_ustar_prev) + delt = abs(U_ustar - U_ustar_prev) + end do + + U_ustar = 4._r8 * U_ustar / lt / z0v_c(patch%itype(p)) + + z0mv(p) = htop(p) * (1._r8 - displa(p) / htop(p)) * exp(-vkc * U_ustar + & + log(z0v_cw(patch%itype(p))) - 1._r8 + z0v_cw(patch%itype(p))**(-1._r8)) + + + case default + write(iulog,*) 'ERROR: unknown z0para_method: ', z0param_method + call endrun(msg = 'unknown z0param_method', additional_msg = errMsg(sourcefile, __LINE__)) + end select + + z0hv(p) = z0mv(p) + z0qv(p) = z0mv(p) + + ! Update the forcing heights + ! TODO(KWO, 2022-03-15) Only for Meier2022 for now to maintain bfb with ZengWang2007 + if (z0param_method == 'Meier2022') then + forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mv(p) + displa(p) + forc_hgt_t_patch(p) = forc_hgt_t(g) + z0hv(p) + displa(p) + forc_hgt_q_patch(p) = forc_hgt_q(g) + z0qv(p) + displa(p) + end if - lt = min(elai(p)+esai(p), tlsai_crit) - egvf =(1._r8 - alpha_aero * exp(-lt)) / (1._r8 - alpha_aero * exp(-tlsai_crit)) - displa(p) = egvf * displa(p) - z0mv(p) = exp(egvf * log(z0mv(p)) + (1._r8 - egvf) * log(z0mg(c))) - z0hv(p) = z0mv(p) - z0qv(p) = z0mv(p) end do found = .false. @@ -1007,7 +1069,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, ! changed by K.Sakaguchi from here ! transfer coefficient over bare soil is changed to a local variable ! just for readability of the code (from line 680) - csoilb = vkc / (params_inst%a_coef * (z0mg(c) * uaf(p) / 1.5e-5_r8)**params_inst%a_exp) + csoilb = vkc / (params_inst%a_coef * (z0mg(c) * uaf(p) / nu_param)**params_inst%a_exp) !compute the stability parameter for ricsoilc ("S" in Sakaguchi&Zeng,2008) @@ -1333,7 +1395,25 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, um(p) = max(ur(p),0.1_r8) else !unstable zeta(p) = max(-100._r8,min(zeta(p),-0.01_r8)) - wc = beta*(-grav*ustar(p)*thvstar*zii/thv(c))**0.333_r8 + if ( ustar(p)*thvstar > 0.0d00 )then + write(iulog,*) 'ustar*thvstar is positive and has to be negative' + write(iulog,*) 'p = ', p + write(iulog,*) '-grav*ustar(p)*thvstar*zii/thv(c) = ', -grav*ustar(p)*thvstar*zii/thv(c) + write(iulog,*) 'ustar = ', ustar(p) + write(iulog,*) 'thvstar = ', thvstar + write(iulog,*) 'thv = ', thv(c) + write(iulog,*) 'displa= ', displa(p) + write(iulog,*) 'z0mg= ', z0mg(c) + write(iulog,*) 'zeta= ', zeta(p) + write(iulog,*) 'temp1= ', temp1(p) + write(iulog,*) 'dth= ', dth(p) + write(iulog,*) 'rah(above)= ', rah(p,above_canopy) + write(iulog,*) 'rah(below)= ', rah(p,below_canopy) + !call endrun(decomp_index=p, clmlevel=namep, msg=errmsg(sourcefile, __LINE__)) + wc = 0.0_r8 + else + wc = beta*(-grav*ustar(p)*thvstar*zii/thv(c))**0.333_r8 + end if um(p) = sqrt(ur(p)*ur(p)+wc*wc) end if obu(p) = zldis(p)/zeta(p) @@ -1400,8 +1480,9 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, dt_stem(p) = 0._r8 endif + dhsdt_canopy(p) = dt_stem(p)*cp_stem(p)/dtime & - +(t_veg(p)-tl_ini(p))*cp_leaf(p)/dtime + + (t_veg(p)-tl_ini(p))*cp_leaf(p)/dtime t_stem(p) = t_stem(p) + dt_stem(p) else @@ -1520,6 +1601,9 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, cgrndl(p) = cgrndl(p) + forc_rho(c)*wtgq(p)*wtalq(p)*dqgdT(c) cgrnd(p) = cgrnds(p) + cgrndl(p)*htvp(c) + ! save before updating + snocan_baseline(p) = snocan(p) + ! Update dew accumulation (kg/m2) if (t_veg(p) > tfrz ) then ! above freezing, update accumulation in liqcan if ((qflx_evap_veg(p)-qflx_tran_veg(p))*dtime > liqcan(p)) then ! all liq evap @@ -1537,6 +1621,12 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, end if end do + + ! Remove snocan that got reduced by more than a factor of rel_epsilon + ! snocan < rel_epsilon * snocan_baseline will be set to zero + ! See NumericsMod for rel_epsilon value + call truncate_small_values(fn, filterp, begp, endp, & + snocan_baseline(begp:endp), snocan(begp:endp)) if ( use_fates ) then @@ -1649,6 +1739,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, fn = fn + 1 filterp(fn) = p end if + end do do f = 1, fn diff --git a/src/biogeophys/CanopyStateType.F90 b/src/biogeophys/CanopyStateType.F90 index a94baaa319..313f7a83f3 100644 --- a/src/biogeophys/CanopyStateType.F90 +++ b/src/biogeophys/CanopyStateType.F90 @@ -225,9 +225,7 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='canopy top', & ptr_patch=this%htop_patch) endif - - - endif !fates or CN + endif if(use_fates_sp)then this%tlai_hist_patch(begp:endp) = spval diff --git a/src/biogeophys/FrictionVelocityMod.F90 b/src/biogeophys/FrictionVelocityMod.F90 index 21a09fbc13..7cea2a22f9 100644 --- a/src/biogeophys/FrictionVelocityMod.F90 +++ b/src/biogeophys/FrictionVelocityMod.F90 @@ -11,8 +11,9 @@ module FrictionVelocityMod use shr_log_mod , only : errMsg => shr_log_errMsg use shr_const_mod , only : SHR_CONST_PI use decompMod , only : bounds_type + use abortutils , only : endrun use clm_varcon , only : spval - use clm_varctl , only : use_cn, use_luna + use clm_varctl , only : use_cn, use_luna, z0param_method, use_z0m_snowmelt use LandunitType , only : lun use ColumnType , only : col use PatchType , only : patch @@ -22,6 +23,7 @@ module FrictionVelocityMod use atm2lndType , only : atm2lnd_type use WaterDiagnosticBulkType , only : waterdiagnosticbulk_type use CanopyStateType , only : canopystate_type + use WaterFluxBulkType , only : waterfluxbulk_type ! ! !PUBLIC TYPES: implicit none @@ -35,6 +37,7 @@ module FrictionVelocityMod real(r8), public :: zetamaxstable = -999._r8 ! Max value zeta ("height" used in Monin-Obukhov theory) can go to under stable conditions real(r8) :: zsno = -999._r8 ! Momentum roughness length for snow (m) real(r8) :: zlnd = -999._r8 ! Momentum roughness length for soil, glacier, wetland (m) + real(r8) :: zglc = -999._r8 ! Momentum roughness length for glacier (only used with z0param_method = 'Meier2022') (m) ! Roughness length/resistance for friction velocity calculation @@ -52,7 +55,12 @@ module FrictionVelocityMod real(r8), pointer, public :: z0mv_patch (:) ! patch roughness length over vegetation, momentum [m] real(r8), pointer, public :: z0hv_patch (:) ! patch roughness length over vegetation, sensible heat [m] real(r8), pointer, public :: z0qv_patch (:) ! patch roughness length over vegetation, latent heat [m] - real(r8), pointer, public :: z0mg_col (:) ! col roughness length over ground, momentum [m] + real(r8), pointer, public :: z0mg_patch (:) ! patch roughness length over ground, momentum [m] + real(r8), pointer, public :: z0hg_patch (:) ! patch roughness length over ground, sensible heat [m] + real(r8), pointer, public :: z0qg_patch (:) ! patch roughness length over ground, latent heat [m] + real(r8), pointer, public :: kbm1_patch (:) ! natural logarithm of z0mg_p/z0hg_p [-] + real(r8), pointer, public :: z0mg_col (:) ! col roughness length over ground, momentum [m] + real(r8), pointer, public :: z0mg_2D_col (:) ! 2-D field of input col roughness length over ground, momentum [m] real(r8), pointer, public :: z0hg_col (:) ! col roughness length over ground, sensible heat [m] real(r8), pointer, public :: z0qg_col (:) ! col roughness length over ground, latent heat [m] ! variables to add history output from CanopyFluxesMod @@ -149,7 +157,12 @@ subroutine InitAllocate(this, bounds) allocate(this%z0mv_patch (begp:endp)) ; this%z0mv_patch (:) = nan allocate(this%z0hv_patch (begp:endp)) ; this%z0hv_patch (:) = nan allocate(this%z0qv_patch (begp:endp)) ; this%z0qv_patch (:) = nan + allocate(this%z0mg_patch (begp:endp)) ; this%z0mg_patch (:) = nan + allocate(this%z0hg_patch (begp:endp)) ; this%z0hg_patch (:) = nan + allocate(this%z0qg_patch (begp:endp)) ; this%z0qg_patch (:) = nan + allocate(this%kbm1_patch (begp:endp)) ; this%kbm1_patch (:) = nan allocate(this%z0mg_col (begc:endc)) ; this%z0mg_col (:) = nan + allocate(this%z0mg_2D_col (begc:endc)) ; this%z0mg_2D_col (:) = nan allocate(this%z0qg_col (begc:endc)) ; this%z0qg_col (:) = nan allocate(this%z0hg_col (begc:endc)) ; this%z0hg_col (:) = nan allocate(this%rah1_patch (begp:endp)) ; this%rah1_patch (:) = nan @@ -299,20 +312,36 @@ subroutine InitHistory(this, bounds) call hist_addfld1d (fname='Z0HV', units='m', & avgflag='A', long_name='roughness length over vegetation, sensible heat', & ptr_patch=this%z0hv_patch, default='inactive', l2g_scale_type='veg') - end if - if (use_cn) then this%z0mv_patch(begp:endp) = spval call hist_addfld1d (fname='Z0MV', units='m', & avgflag='A', long_name='roughness length over vegetation, momentum', & ptr_patch=this%z0mv_patch, default='inactive', l2g_scale_type='veg') - end if - if (use_cn) then this%z0qv_patch(begp:endp) = spval call hist_addfld1d (fname='Z0QV', units='m', & avgflag='A', long_name='roughness length over vegetation, latent heat', & ptr_patch=this%z0qv_patch, default='inactive', l2g_scale_type='veg') + + this%z0hg_patch(begp:endp) = spval + call hist_addfld1d (fname='Z0HG_P', units='m', & + avgflag='A', long_name='patch roughness length over ground, sensible heat', & + ptr_patch=this%z0hg_patch, default='inactive') + + this%z0mg_patch(begp:endp) = spval + call hist_addfld1d (fname='Z0MG_P', units='m', & + avgflag='A', long_name='patch roughness length over ground, momentum', & + ptr_patch=this%z0mg_patch, default='inactive') + + this%z0qg_patch(begp:endp) = spval + call hist_addfld1d (fname='Z0QG_P', units='m', & + avgflag='A', long_name='patch roughness length over ground, latent heat', & + ptr_patch=this%z0qg_patch, default='inactive') + + this%kbm1_patch(begp:endp) = spval + call hist_addfld1d (fname='KBM1', units='unitless', & + avgflag='A', long_name='natural logarithm of Z0MG_P/Z0HG_P', & + ptr_patch=this%kbm1_patch, default='inactive') end if if (use_luna) then @@ -374,6 +403,11 @@ subroutine ReadParams( this, params_ncid ) ! Momentum roughness length for soil, glacier, wetland (m) call readNcdioScalar(params_ncid, 'zlnd', subname, this%zlnd) + ! Separated roughness length for glacier if z0param_method == 'Meier2022' + if (z0param_method == 'Meier2022') then + call readNcdioScalar(params_ncid, 'zglc', subname, this%zglc) + end if + end subroutine ReadParams !------------------------------------------------------------------------ @@ -424,7 +458,6 @@ subroutine ReadNamelist( this, NLFilename ) use shr_mpi_mod , only : shr_mpi_bcast use clm_varctl , only : iulog use shr_log_mod , only : errMsg => shr_log_errMsg - use abortutils , only : endrun ! ! !ARGUMENTS: class(frictionvel_type), intent(inout) :: this @@ -477,11 +510,13 @@ end subroutine ReadNamelist !----------------------------------------------------------------------- subroutine SetRoughnessLengthsAndForcHeightsNonLake(this, bounds, & num_nolakec, filter_nolakec, num_nolakep, filter_nolakep, & - atm2lnd_inst, waterdiagnosticbulk_inst, canopystate_inst) + atm2lnd_inst, waterdiagnosticbulk_inst, canopystate_inst, waterfluxbulk_inst) ! ! !DESCRIPTION: ! Set roughness lengths and forcing heights for non-lake points ! + ! !USES: + use clm_varcon , only : rpi, b1_param, b4_param, meier_param1, meier_param2 ! !ARGUMENTS: class(frictionvel_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds @@ -492,6 +527,7 @@ subroutine SetRoughnessLengthsAndForcHeightsNonLake(this, bounds, & type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(waterdiagnosticbulk_type) , intent(in) :: waterdiagnosticbulk_inst type(canopystate_type) , intent(in) :: canopystate_inst + type(waterfluxbulk_type) , intent(in) :: waterfluxbulk_inst ! ! !LOCAL VARIABLES: integer :: fc, c @@ -505,6 +541,10 @@ subroutine SetRoughnessLengthsAndForcHeightsNonLake(this, bounds, & z0mv => this%z0mv_patch , & ! Output: [real(r8) (:) ] roughness length over vegetation, momentum [m] z0hv => this%z0hv_patch , & ! Output: [real(r8) (:) ] roughness length over vegetation, sensible heat [m] z0qv => this%z0qv_patch , & ! Output: [real(r8) (:) ] roughness length over vegetation, latent heat [m] + z0mg_p => this%z0mg_patch , & ! Output: [real(r8) (:) ] patch roughness length over ground, momentum [m] + z0hg_p => this%z0hg_patch , & ! Output: [real(r8) (:) ] patch roughness length over ground, sensible heat [m] + z0qg_p => this%z0qg_patch , & ! Output: [real(r8) (:) ] patch roughness length over ground, latent heat [m] + kbm1 => this%kbm1_patch , & ! Output: [real(r8) (:) ] natural logarithm of z0mg_p/z0hg_p [-] z0hg => this%z0hg_col , & ! Output: [real(r8) (:) ] roughness length over ground, sensible heat [m] z0mg => this%z0mg_col , & ! Output: [real(r8) (:) ] roughness length over ground, momentum [m] z0qg => this%z0qg_col , & ! Output: [real(r8) (:) ] roughness length over ground, latent heat [m] @@ -516,12 +556,14 @@ subroutine SetRoughnessLengthsAndForcHeightsNonLake(this, bounds, & frac_veg_nosno => canopystate_inst%frac_veg_nosno_patch , & ! Input: [integer (:) ] fraction of vegetation not covered by snow (0 OR 1) [-] frac_sno => waterdiagnosticbulk_inst%frac_sno_col , & ! Input: [real(r8) (:) ] fraction of ground covered by snow (0 to 1) + snomelt_accum => waterdiagnosticbulk_inst%snomelt_accum_col , & ! Input: [real(r8) (:) ] accumulated col snow melt for z0m calculation (m H2O) urbpoi => lun%urbpoi , & ! Input: [logical (:) ] true => landunit is an urban point z_0_town => lun%z_0_town , & ! Input: [real(r8) (:) ] momentum roughness length of urban landunit (m) z_d_town => lun%z_d_town , & ! Input: [real(r8) (:) ] displacement height of urban landunit (m) forc_hgt_t => atm2lnd_inst%forc_hgt_t_grc , & ! Input: [real(r8) (:) ] observational height of temperature [m] forc_hgt_u => atm2lnd_inst%forc_hgt_u_grc , & ! Input: [real(r8) (:) ] observational height of wind [m] - forc_hgt_q => atm2lnd_inst%forc_hgt_q_grc & ! Input: [real(r8) (:) ] observational height of specific humidity [m] + forc_hgt_q => atm2lnd_inst%forc_hgt_q_grc , & ! Input: [real(r8) (:) ] observational height of specific humidity [m] + z0mg_2D => this%z0mg_2D_col & ! Input: [real(r8) (:) ] 2-D field of input col roughness length over ground, momentum [m] ) do fc = 1, num_nolakec @@ -529,13 +571,37 @@ subroutine SetRoughnessLengthsAndForcHeightsNonLake(this, bounds, & ! Ground roughness lengths over non-lake columns (includes bare ground, ground ! underneath canopy, wetlands, etc.) - if (frac_sno(c) > 0._r8) then - z0mg(c) = this%zsno - else - z0mg(c) = this%zlnd - end if + + select case (z0param_method) + case ('ZengWang2007') + if (frac_sno(c) > 0._r8) then + z0mg(c) = this%zsno + else + z0mg(c) = this%zlnd + end if + case ('Meier2022') ! Bare ground and ice have a different value + l = col%landunit(c) + if (frac_sno(c) > 0._r8) then ! Do snow first because ice could be snow-covered + if(use_z0m_snowmelt) then + if ( snomelt_accum(c) < 1.e-5_r8 )then + z0mg(c) = exp(-b1_param * rpi * 0.5_r8 + b4_param) * 1.e-3_r8 + else + z0mg(c) = exp(b1_param * (atan((log10(snomelt_accum(c)) + meier_param1) / meier_param2)) + b4_param) * 1.e-3_r8 + end if + else + z0mg(c) = this%zsno + end if + else if (lun%itype(l) == istice) then + z0mg(c) = this%zglc + else + z0mg(c) = this%zlnd + end if + end select + z0hg(c) = z0mg(c) ! initial set only z0qg(c) = z0mg(c) ! initial set only + + end do do fp = 1,num_nolakep @@ -545,6 +611,13 @@ subroutine SetRoughnessLengthsAndForcHeightsNonLake(this, bounds, & z0mv(p) = z0m(p) z0hv(p) = z0mv(p) z0qv(p) = z0mv(p) + + ! Set to arbitrary value (will be overwritten by respective modules + z0mg_p(p) = spval + z0hg_p(p) = spval + z0qg_p(p) = spval + kbm1(p) = spval + end do ! Make forcing height a patch-level quantity that is the atmospheric forcing @@ -557,17 +630,17 @@ subroutine SetRoughnessLengthsAndForcHeightsNonLake(this, bounds, & if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then if (frac_veg_nosno(p) == 0) then forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mg(c) + displa(p) - forc_hgt_t_patch(p) = forc_hgt_t(g) + z0mg(c) + displa(p) - forc_hgt_q_patch(p) = forc_hgt_q(g) + z0mg(c) + displa(p) + forc_hgt_t_patch(p) = forc_hgt_t(g) + z0hg(c) + displa(p) + forc_hgt_q_patch(p) = forc_hgt_q(g) + z0qg(c) + displa(p) else - forc_hgt_u_patch(p) = forc_hgt_u(g) + z0m(p) + displa(p) - forc_hgt_t_patch(p) = forc_hgt_t(g) + z0m(p) + displa(p) - forc_hgt_q_patch(p) = forc_hgt_q(g) + z0m(p) + displa(p) + forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mv(p) + displa(p) + forc_hgt_t_patch(p) = forc_hgt_t(g) + z0hv(p) + displa(p) + forc_hgt_q_patch(p) = forc_hgt_q(g) + z0qv(p) + displa(p) end if else if (lun%itype(l) == istwet .or. lun%itype(l) == istice) then - forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mg(c) - forc_hgt_t_patch(p) = forc_hgt_t(g) + z0mg(c) - forc_hgt_q_patch(p) = forc_hgt_q(g) + z0mg(c) + forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mg(c) + displa(p) + forc_hgt_t_patch(p) = forc_hgt_t(g) + z0hg(c) + displa(p) + forc_hgt_q_patch(p) = forc_hgt_q(g) + z0qg(c) + displa(p) else if (urbpoi(l)) then forc_hgt_u_patch(p) = forc_hgt_u(g) + z_0_town(l) + z_d_town(l) forc_hgt_t_patch(p) = forc_hgt_t(g) + z_0_town(l) + z_d_town(l) @@ -677,10 +750,13 @@ subroutine FrictionVelocity(this, lbn, ubn, fn, filtern, & real(r8) , intent(in) :: ur ( lbn: ) ! wind speed at reference height [m/s] [lbn:ubn] real(r8) , intent(in) :: um ( lbn: ) ! wind speed including the stablity effect [m/s] [lbn:ubn] real(r8) , intent(out) :: ustar ( lbn: ) ! friction velocity [m/s] [lbn:ubn] - real(r8) , intent(out) :: temp1 ( lbn: ) ! relation for potential temperature profile [lbn:ubn] - real(r8) , intent(out) :: temp12m ( lbn: ) ! relation for potential temperature profile applied at 2-m [lbn:ubn] - real(r8) , intent(out) :: temp2 ( lbn: ) ! relation for specific humidity profile [lbn:ubn] - real(r8) , intent(out) :: temp22m ( lbn: ) ! relation for specific humidity profile applied at 2-m [lbn:ubn] + ! temp1, temp12m, temp2, temp22m are "inout" rather than "out" to + ! prevent returning nan when the code returns from this subroutine + ! before assigning values to these variables + real(r8) , intent(inout) :: temp1 ( lbn: ) ! relation for potential temperature profile [lbn:ubn] + real(r8) , intent(inout) :: temp12m ( lbn: ) ! relation for potential temperature profile applied at 2-m [lbn:ubn] + real(r8) , intent(inout) :: temp2 ( lbn: ) ! relation for specific humidity profile [lbn:ubn] + real(r8) , intent(inout) :: temp22m ( lbn: ) ! relation for specific humidity profile applied at 2-m [lbn:ubn] real(r8) , intent(inout) :: fm ( lbn: ) ! diagnose 10m wind (DUST only) [lbn:ubn] logical , intent(in), optional :: landunit_index ! optional argument that defines landunit or pft level ! diff --git a/src/biogeophys/HumanIndexMod.F90 b/src/biogeophys/HumanIndexMod.F90 index 9c3bc319e8..17a1ef968e 100644 --- a/src/biogeophys/HumanIndexMod.F90 +++ b/src/biogeophys/HumanIndexMod.F90 @@ -16,6 +16,9 @@ module HumanIndexMod ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use decompMod , only : bounds_type + use abortutils , only : endrun + use clm_varctl , only : iulog + use shr_log_mod , only : errMsg => shr_log_errMsg ! !PUBLIC TYPES: implicit none save @@ -500,13 +503,10 @@ subroutine HumanIndexReadNML( NLFilename ) ! ! !USES: use shr_mpi_mod , only : shr_mpi_bcast - use abortutils , only : endrun use spmdMod , only : masterproc, mpicom use fileutils , only : getavu, relavu, opnfil use shr_nl_mod , only : shr_nl_find_group_name use shr_mpi_mod , only : shr_mpi_bcast - use clm_varctl , only : iulog - use shr_log_mod , only : errMsg => shr_log_errMsg ! ! !ARGUMENTS: implicit none @@ -1014,6 +1014,14 @@ subroutine Wet_BulbS (Tc_6,rh,wbt) ! !LOCAL VARIABLES: !EOP ! + if ( rh < 0.0d00 )then + write(iulog,*) 'rh = ', rh + call endrun(msg="ERROR RH is negative "//errmsg(sourcefile, __LINE__)) + else if ( rh > 100.d00 )then + write(iulog,*) 'rh = ', rh + call endrun(msg="ERROR RH is greater than a hundred "//errmsg(sourcefile, __LINE__)) + end if + wbt = Tc_6 * atan(0.151977_r8*sqrt(rh + 8.313659_r8)) + & atan(Tc_6+rh) - atan(rh-1.676331_r8) + & 0.00391838_r8*rh**(3._r8/2._r8)*atan(0.023101_r8*rh) - & diff --git a/src/biogeophys/LakeFluxesMod.F90 b/src/biogeophys/LakeFluxesMod.F90 index 4528d9dfb2..fdd105ad8f 100644 --- a/src/biogeophys/LakeFluxesMod.F90 +++ b/src/biogeophys/LakeFluxesMod.F90 @@ -37,6 +37,7 @@ module LakeFluxesMod real(r8) :: a_coef ! Drag coefficient under less dense canopy (unitless) real(r8) :: a_exp ! Drag exponent under less dense canopy (unitless) real(r8) :: zsno ! Momentum roughness length for snow (m) + real(r8) :: zglc ! Momentum roughness length for ice (m) real(r8) :: wind_min ! Minimum wind speed at the atmospheric forcing height (m/s) end type params_type type(params_type), private :: params_inst @@ -49,6 +50,7 @@ subroutine readParams( ncid ) ! !USES: use ncdio_pio, only: file_desc_t use paramUtilMod, only: readNcdioScalar + use clm_varctl, only: z0param_method ! ! !ARGUMENTS: implicit none @@ -64,6 +66,11 @@ subroutine readParams( ncid ) call readNcdioScalar(ncid, 'a_exp', subname, params_inst%a_exp) ! Momentum roughness length for snow (m) call readNcdioScalar(ncid, 'zsno', subname, params_inst%zsno) + + if (z0param_method == 'Meier2022') then + ! Momentum roughness length for ice (m) + call readNcdioScalar(ncid, 'zglc', subname, params_inst%zglc) + end if ! Minimum wind speed at the atmospheric forcing height (m/s) call readNcdioScalar(ncid, 'wind_min', subname, params_inst%wind_min) @@ -85,8 +92,10 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, ! !USES: use clm_varpar , only : nlevlak use clm_varcon , only : hvap, hsub, hfus, cpair, cpliq, tkwat, tkice, tkair - use clm_varcon , only : sb, vkc, grav, denh2o, tfrz, spval - use clm_varctl , only : use_lch4 + use clm_varcon , only : sb, vkc, grav, denh2o, tfrz, spval, rpi + use clm_varcon , only : beta_param, nu_param, b1_param, b4_param + use clm_varcon , only : meier_param1, meier_param2, meier_param3 + use clm_varctl , only : use_lch4, z0param_method, use_z0m_snowmelt use LakeCon , only : betavis, z0frzlake, tdmax, emg_lake use LakeCon , only : lake_use_old_fcrit_minz0 use LakeCon , only : minz0lake, cur0, cus, curm, fcrit @@ -118,6 +127,10 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, real(r8), pointer :: z0mg_col(:) ! roughness length over ground, momentum [m] real(r8), pointer :: z0hg_col(:) ! roughness length over ground, sensible heat [m] real(r8), pointer :: z0qg_col(:) ! roughness length over ground, latent heat [m] + real(r8), pointer :: z0mg(:) ! patch roughness length over ground, momentum [m] + real(r8), pointer :: z0hg(:) ! patch roughness length over ground, sensible heat [m] + real(r8), pointer :: z0qg(:) ! patch roughness length over ground, latent heat [m] + real(r8), pointer :: kbm1(:) ! natural logarithm of z0mg_p/z0hg_p [-] integer , parameter :: niters = 4 ! maximum number of iterations for surface temperature real(r8), parameter :: beta1 = 1._r8 ! coefficient of convective velocity (in computing W_*) [-] real(r8), parameter :: zii = 1000._r8 ! convective boundary height [m] @@ -159,12 +172,8 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, real(r8) :: ur(bounds%begp:bounds%endp) ! wind speed at reference height [m/s] real(r8) :: ustar(bounds%begp:bounds%endp) ! friction velocity [m/s] real(r8) :: wc ! convective velocity [m/s] - real(r8) :: zeta ! dimensionless height used in Monin-Obukhov theory real(r8) :: zldis(bounds%begp:bounds%endp) ! reference height "minus" zero displacement height [m] real(r8) :: displa(bounds%begp:bounds%endp) ! displacement (always zero) [m] - real(r8) :: z0mg(bounds%begp:bounds%endp) ! roughness length over ground, momentum [m] - real(r8) :: z0hg(bounds%begp:bounds%endp) ! roughness length over ground, sensible heat [m] - real(r8) :: z0qg(bounds%begp:bounds%endp) ! roughness length over ground, latent heat [m] real(r8) :: u2m ! 2 m wind speed (m/s) real(r8) :: fm(bounds%begp:bounds%endp) ! needed for BGC only to diagnose 10m wind speed real(r8) :: bw ! partial density of water (ice + liquid) @@ -219,7 +228,8 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, lakefetch => lakestate_inst%lakefetch_col , & ! Input: [real(r8) (:) ] lake fetch from surface data (m) h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) - h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice lens (kg/m2) + h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice lens (kg/m2) + snomelt_accum => waterdiagnosticbulk_inst%snomelt_accum_col , & ! Input: [real(r8) (:) ] accumulated col snow melt for z0m calculation (m H2O) t_skin_patch => temperature_inst%t_skin_patch , & ! Output: [real(r8) (:) ] patch skin temperature (K) t_lake => temperature_inst%t_lake_col , & ! Input: [real(r8) (:,:) ] lake temperature (Kelvin) @@ -230,6 +240,7 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, forc_hgt_t_patch => frictionvel_inst%forc_hgt_t_patch , & ! Input: [real(r8) (:) ] observational height of temperature at pft level [m] forc_hgt_q_patch => frictionvel_inst%forc_hgt_q_patch , & ! Input: [real(r8) (:) ] observational height of specific humidity at pft level [m] zetamax => frictionvel_inst%zetamaxstable , & ! Input: [real(r8) ] max zeta value under stable conditions + zeta => frictionvel_inst%zeta_patch , & ! Output: [real(r8) (:) ] dimensionless stability parameter ram1 => frictionvel_inst%ram1_patch , & ! Output: [real(r8) (:) ] aerodynamical resistance (s/m) q_ref2m => waterdiagnosticbulk_inst%q_ref2m_patch , & ! Output: [real(r8) (:) ] 2 m height surface specific humidity (kg/kg) @@ -270,7 +281,6 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, taux => energyflux_inst%taux_patch , & ! Output: [real(r8) (:) ] wind (shear) stress: e-w (kg/m/s**2) tauy => energyflux_inst%tauy_patch , & ! Output: [real(r8) (:) ] wind (shear) stress: n-s (kg/m/s**2) dhsdt_canopy => energyflux_inst%dhsdt_canopy_patch , & ! Output: [real(r8) (:) ] change in heat storage of stem (W/m**2) [+ to atm] - ks => lakestate_inst%ks_col , & ! Output: [real(r8) (:) ] coefficient passed to LakeTemperature ws => lakestate_inst%ws_col , & ! Output: [real(r8) (:) ] surface friction velocity (m/s) betaprime => lakestate_inst%betaprime_col , & ! Output: [real(r8) (:) ] fraction of solar rad absorbed at surface: equal to NIR fraction @@ -286,7 +296,10 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, z0mg_col => frictionvel_inst%z0mg_col z0hg_col => frictionvel_inst%z0hg_col z0qg_col => frictionvel_inst%z0qg_col - + z0mg => frictionvel_inst%z0mg_patch + z0hg => frictionvel_inst%z0hg_patch + z0qg => frictionvel_inst%z0qg_patch + kbm1 => frictionvel_inst%kbm1_patch kva0temp = 20._r8 + tfrz do fp = 1, num_lakep @@ -324,20 +337,52 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, z0qg(p) = max(z0qg(p), minz0lake) z0hg(p) = max(z0hg(p), minz0lake) else if (snl(c) == 0) then ! frozen lake with ice - z0mg(p) = z0frzlake - z0hg(p) = z0mg(p) / exp(params_inst%a_coef * (ust_lake(c) * z0mg(p) / 1.5e-5_r8)**params_inst%a_exp) ! Consistent with BareGroundFluxes + select case (z0param_method) + case ('Meier2022') + z0mg(p) = params_inst%zglc + + + z0hg(p) = meier_param3 * nu_param / ust_lake(c) ! For initial guess assume tstar = 0 + + case ('ZengWang2007') + z0mg(p) = z0frzlake + z0hg(p) = z0mg(p) / exp(params_inst%a_coef * (ust_lake(c) * z0mg(p) / nu_param)**params_inst%a_exp) ! Consistent with BareGroundFluxes + end select z0qg(p) = z0hg(p) else ! use roughness over snow as in Biogeophysics1 - z0mg(p) = params_inst%zsno - z0hg(p) = z0mg(p) / exp(params_inst%a_coef * (ust_lake(c) * z0mg(p) / 1.5e-5_r8)**params_inst%a_exp) ! Consistent with BareGroundFluxes + if(use_z0m_snowmelt) then + if ( snomelt_accum(c) < 1.e-5_r8 ) then + z0mg(p) = exp(-b1_param * rpi * 0.5_r8 + b4_param) * 1.e-3_r8 + else + z0mg(p) = exp(b1_param * (atan((log10(snomelt_accum(c)) + meier_param1) / meier_param2)) + b4_param) * 1.e-3_r8 + end if + else + z0mg(p) = params_inst%zsno + end if + + select case (z0param_method) + case ('Meier2022') + z0hg(p) = meier_param3 * nu_param / ust_lake(c) ! For initial guess assume tstar = 0 + case ('ZengWang2007') + z0hg(p) = z0mg(p) / exp(params_inst%a_coef * (ust_lake(c) * z0mg(p) / nu_param)**params_inst%a_exp) ! Consistent with BareGroundFluxes + end select + z0qg(p) = z0hg(p) end if ! Surface temperature and fluxes - forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mg(p) - forc_hgt_t_patch(p) = forc_hgt_t(g) + z0mg(p) - forc_hgt_q_patch(p) = forc_hgt_q(g) + z0mg(p) + ! Update forcing heights for updated roughness lengths + ! TODO(KWO, 2022-03-15) Only for Meier2022 for now to maintain bfb with ZengWang2007 + if (z0param_method == 'Meier2022') then + forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mg(p) + forc_hgt_t_patch(p) = forc_hgt_t(g) + z0hg(p) + forc_hgt_q_patch(p) = forc_hgt_q(g) + z0qg(p) + else + forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mg(p) + forc_hgt_t_patch(p) = forc_hgt_t(g) + z0mg(p) + forc_hgt_q_patch(p) = forc_hgt_q(g) + z0mg(p) + end if ! Find top layer jtop(c) = snl(c) + 1 @@ -379,6 +424,7 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, g = patch%gridcell(p) dhsdt_canopy(p) = 0.0_r8 + nmozsgn(p) = 0 obuold(p) = 0._r8 displa(p) = 0._r8 @@ -500,17 +546,17 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, qstar = temp2(p)*dqh(p) thvstar=tstar*(1._r8+0.61_r8*forc_q(c)) + 0.61_r8*forc_th(c)*qstar - zeta=zldis(p)*vkc * grav*thvstar/(ustar(p)**2*thv(c)) + zeta(p)=zldis(p)*vkc * grav*thvstar/(ustar(p)**2*thv(c)) - if (zeta >= 0._r8) then !stable - zeta = min(zetamax,max(zeta,0.01_r8)) + if (zeta(p) >= 0._r8) then !stable + zeta(p) = min(zetamax,max(zeta(p),0.01_r8)) um(p) = max(ur(p),0.1_r8) else !unstable - zeta = max(-100._r8,min(zeta,-0.01_r8)) + zeta(p) = max(-100._r8,min(zeta(p),-0.01_r8)) wc = beta1*(-grav*ustar(p)*thvstar*zii/thv(c))**0.333_r8 um(p) = sqrt(ur(p)*ur(p)+wc*wc) end if - obu(p) = zldis(p)/zeta + obu(p) = zldis(p)/zeta(p) if (obuold(p)*obu(p) < 0._r8) nmozsgn(p) = nmozsgn(p)+1 @@ -545,15 +591,48 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, z0hg(p) = max(z0hg(p), minz0lake) else if (snl(c) == 0) then ! in case it was above freezing and now below freezing - z0mg(p) = z0frzlake - z0hg(p) = z0mg(p) / exp(params_inst%a_coef * (ustar(p) * z0mg(p) / 1.5e-5_r8)**params_inst%a_exp) ! Consistent with BareGroundFluxes - z0qg(p) = z0hg(p) + select case (z0param_method) + case ('Meier2022') + z0mg(p) = params_inst%zglc + ! (...)**0.5 = sqrt(...) and (...)**0.25 = sqrt(sqrt(...)) + ! likely more efficient to calculate as exponents + z0hg(p) = meier_param3 * nu_param / ustar(p) * exp( -beta_param * ustar(p)**(0.5_r8) * (abs(tstar))**(0.25_r8)) ! Consistent with BareGroundFluxes + + case ('ZengWang2007') + z0mg(p) = z0frzlake + z0hg(p) = z0mg(p) / exp(params_inst%a_coef * (ustar(p) * z0mg(p) / nu_param)**params_inst%a_exp) ! Consistent with BareGroundFluxes + end select + z0qg(p) = z0hg(p) else ! Snow layers - ! z0mg won't have changed - z0hg(p) = z0mg(p) / exp(params_inst%a_coef * (ustar(p) * z0mg(p) / 1.5e-5_r8)**params_inst%a_exp) ! Consistent with BareGroundFluxes + if(use_z0m_snowmelt) then + if ( snomelt_accum(c) < 1.e-5_r8 )then + z0mg(p) = exp(-b1_param * rpi * 0.5_r8 + b4_param) * 1.e-3_r8 + else + z0mg(p) = exp(b1_param * (atan((log10(snomelt_accum(c)) + meier_param1) / meier_param2)) + b4_param) * 1.e-3_r8 + end if + end if + + select case (z0param_method) + case ('Meier2022') + ! (...)**0.5 = sqrt(...) and (...)**0.25 = sqrt(sqrt(...)) + ! likely more efficient to calculate as exponents + z0hg(p) = meier_param3 * nu_param / ustar(p) * exp( -beta_param * ustar(p)**(0.5_r8) * (abs(tstar))**(0.25_r8)) ! Consistent with BareGroundFluxes + + case ('ZengWang2007') + z0hg(p) = z0mg(p) / exp(params_inst%a_coef * (ustar(p) * z0mg(p) / nu_param)**params_inst%a_exp) ! Consistent with BareGroundFluxes + end select + z0qg(p) = z0hg(p) end if + ! Update forcing heights for updated roughness lengths + ! TODO(KWO, 2022-03-15) Only for Meier2022 for now to maintain bfb with ZengWang2007 + if (z0param_method == 'Meier2022') then + forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mg(p) + forc_hgt_t_patch(p) = forc_hgt_t(g) + z0hg(p) + forc_hgt_q_patch(p) = forc_hgt_q(g) + z0qg(p) + end if + end do ! end of filtered pft loop iter = iter + 1 @@ -690,6 +769,7 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, z0hg_col(c) = z0hg(p) z0qg_col(c) = z0qg(p) ust_lake(c) = ustar(p) + kbm1(p) = log(z0mg(p) / z0hg(p)) end do diff --git a/src/biogeophys/PhotosynthesisMod.F90 b/src/biogeophys/PhotosynthesisMod.F90 index 5b2c68a0fb..6176668f19 100644 --- a/src/biogeophys/PhotosynthesisMod.F90 +++ b/src/biogeophys/PhotosynthesisMod.F90 @@ -2266,7 +2266,10 @@ subroutine hybrid(x0, p, iv, c, gb_mol, je, cair, oair, lmr_z, par_z,& real(r8), intent(in) :: cair ! Atmospheric CO2 partial pressure (Pa) real(r8), intent(in) :: oair ! Atmospheric O2 partial pressure (Pa) integer, intent(in) :: p, iv, c ! pft, c3/c4, and column index - real(r8), intent(out) :: gs_mol ! leaf stomatal conductance (umol H2O/m**2/s) + ! gs_mol is "inout" rather than "out" to + ! prevent returning nan when the code returns from this subroutine + ! before assigning a value to this variable + real(r8), intent(inout) :: gs_mol ! leaf stomatal conductance (umol H2O/m**2/s) integer, intent(out) :: iter !number of iterations used, for record only type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(photosyns_type), intent(inout) :: photosyns_inst @@ -2378,7 +2381,10 @@ subroutine brent(x, x1,x2,f1, f2, tol, ip, iv, ic, gb_mol, je, cair, oair,& real(r8), intent(in) :: oair ! Atmospheric O2 partial pressure (Pa) real(r8), intent(in) :: rh_can ! inside canopy relative humidity integer, intent(in) :: ip, iv, ic ! pft, c3/c4, and column index - real(r8), intent(out) :: gs_mol ! leaf stomatal conductance (umol H2O/m**2/s) + ! gs_mol is "inout" rather than "out" to + ! prevent returning nan when the code returns from this subroutine + ! before assigning a value to this variable + real(r8), intent(inout) :: gs_mol ! leaf stomatal conductance (umol H2O/m**2/s) type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(photosyns_type), intent(inout) :: photosyns_inst ! @@ -2568,7 +2574,10 @@ subroutine ci_func(ci, fval, p, iv, c, gb_mol, je, cair, oair, lmr_z, par_z,& real(r8) , intent(in) :: rh_can ! canopy air realtive humidity integer , intent(in) :: p, iv, c ! pft, vegetation type and column indexes real(r8) , intent(out) :: fval ! return function of the value f(ci) - real(r8) , intent(out) :: gs_mol ! leaf stomatal conductance (umol H2O/m**2/s) + ! gs_mol is "inout" rather than "out" to + ! prevent returning nan when the code returns from this subroutine + ! before assigning a value to this variable + real(r8) , intent(inout) :: gs_mol ! leaf stomatal conductance (umol H2O/m**2/s) type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(photosyns_type) , intent(inout) :: photosyns_inst ! @@ -2706,7 +2715,6 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & use clm_varpar , only : nlevsoi use pftconMod , only : nbrdlf_dcd_tmp_shrub, npcropmin use ColumnType , only : col - use shr_infnan_mod , only : shr_infnan_isnan ! ! !ARGUMENTS: @@ -2724,7 +2732,7 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & real(r8) , intent(in) :: leafn( bounds%begp: ) ! leaf N (gN/m2) real(r8) , intent(out) :: bsun( bounds%begp: ) ! sunlit canopy transpiration wetness factor (0 to 1) real(r8) , intent(out) :: bsha( bounds%begp: ) ! shaded canopy transpiration wetness factor (0 to 1) - real(r8) , intent(out) :: btran( bounds%begp: ) ! transpiration wetness factor (0 to 1) [pft] + real(r8) , intent(inout) :: btran( bounds%begp: ) ! transpiration wetness factor (0 to 1) [pft] real(r8) , intent(in) :: froot_carbon( bounds%begp: ) ! fine root carbon (gC/m2) [pft] real(r8) , intent(in) :: croot_carbon( bounds%begp: ) ! live coarse root carbon (gC/m2) [pft] @@ -3477,6 +3485,7 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & else gsminsun = nan gsminsha = nan + call endrun( 'ERROR:: Photosynthesis::PhotosynthesisHydraulicStress must choose stomatalcond_mtd method' ) end if call calcstress(p,c,vegwp(p,:),bsun(p),bsha(p),gb_mol(p),gsminsun, gsminsha, & qsatl(p),qaf(p), atm2lnd_inst,canopystate_inst,waterdiagnosticbulk_inst, & @@ -4064,8 +4073,11 @@ subroutine brent_PHS(xsun, x1sun, x2sun, f1sun, f2sun, xsha, x1sha, x2sha, f1sha real(r8), intent(in) :: lmr_z_sun, lmr_z_sha ! canopy layer: leaf maintenance respiration rate (umol CO2/m**2/s) real(r8), intent(in) :: par_z_sun, par_z_sha ! par absorbed per unit lai for canopy layer (w/m**2) real(r8), intent(in) :: rh_can ! inside canopy relative humidity - real(r8), intent(out) :: gs_mol_sun ! sunlit leaf stomatal conductance (umol H2O/m**2/s) - real(r8), intent(out) :: gs_mol_sha ! shaded leaf stomatal conductance (umol H2O/m**2/s) + ! gs_mol_s* are "inout" rather than "out" to + ! prevent returning nan when the code returns from this subroutine + ! before assigning values to these variables + real(r8), intent(inout) :: gs_mol_sun ! sunlit leaf stomatal conductance (umol H2O/m**2/s) + real(r8), intent(inout) :: gs_mol_sha ! shaded leaf stomatal conductance (umol H2O/m**2/s) real(r8), intent(inout) :: bsun ! sunlit canopy transpiration wetness factor (0 to 1) real(r8), intent(inout) :: bsha ! shaded canopy transpiration wetness factor (0 to 1) real(r8), intent(in) :: qsatl ! leaf specific humidity [kg/kg] @@ -4344,6 +4356,7 @@ subroutine ci_func_PHS(x,cisun, cisha, fvalsun, fvalsha, p, iv, c, bsun, bsha, b gs_mol_sun = bbb(p) else gs_mol_sun = nan + call endrun( 'ERROR:: Photosynthesis::ci_func_PHS must choose stomatalcond_mtd method' ) end if gs_mol_sun = max( bsun*gs_mol_sun, 1._r8) fvalsun = 0._r8 ! really tho? zqz @@ -4355,6 +4368,7 @@ subroutine ci_func_PHS(x,cisun, cisha, fvalsun, fvalsha, p, iv, c, bsun, bsha, b gs_mol_sha = bbb(p) else gs_mol_sha = nan + call endrun( 'ERROR:: Photosynthesis::ci_func_PHS must choose stomatalcond_mtd method' ) end if gs_mol_sha = max( bsha*gs_mol_sha, 1._r8) fvalsha = 0._r8 diff --git a/src/biogeophys/SnowHydrologyMod.F90 b/src/biogeophys/SnowHydrologyMod.F90 index 242f6ac359..4698e1136d 100644 --- a/src/biogeophys/SnowHydrologyMod.F90 +++ b/src/biogeophys/SnowHydrologyMod.F90 @@ -383,7 +383,8 @@ subroutine UpdateQuantitiesForNewSnow(bounds, num_c, filter_c, & swe_old = b_waterdiagnostic_inst%swe_old_col(begc:endc,:), & frac_sno = b_waterdiagnostic_inst%frac_sno_col(begc:endc), & frac_sno_eff = b_waterdiagnostic_inst%frac_sno_eff_col(begc:endc), & - snow_depth = b_waterdiagnostic_inst%snow_depth_col(begc:endc)) + snow_depth = b_waterdiagnostic_inst%snow_depth_col(begc:endc), & + snomelt_accum = b_waterdiagnostic_inst%snomelt_accum_col(begc:endc)) do i = water_inst%bulk_and_tracers_beg, water_inst%bulk_and_tracers_end associate(w => water_inst%bulk_and_tracers(i)) @@ -407,7 +408,7 @@ subroutine BulkDiag_NewSnowDiagnostics(bounds, num_c, filter_c, & scf_method, & dtime, lun_itype_col, urbpoi, snl, bifall, h2osno_total, h2osoi_ice, h2osoi_liq, & qflx_snow_grnd, qflx_snow_drain, & - dz, int_snow, swe_old, frac_sno, frac_sno_eff, snow_depth) + dz, int_snow, swe_old, frac_sno, frac_sno_eff, snow_depth, snomelt_accum) ! ! !DESCRIPTION: ! Update various snow-related diagnostic quantities to account for new snow @@ -434,6 +435,7 @@ subroutine BulkDiag_NewSnowDiagnostics(bounds, num_c, filter_c, & real(r8) , intent(inout) :: frac_sno( bounds%begc: ) ! fraction of ground covered by snow (0 to 1) real(r8) , intent(inout) :: frac_sno_eff( bounds%begc: ) ! eff. fraction of ground covered by snow (0 to 1) real(r8) , intent(inout) :: snow_depth( bounds%begc: ) ! snow height (m) + real(r8) , intent(inout) :: snomelt_accum( bounds%begc: ) ! accumulated col snow melt for z0m calculation (m H2O) ! ! !LOCAL VARIABLES: integer :: fc, c @@ -462,6 +464,7 @@ subroutine BulkDiag_NewSnowDiagnostics(bounds, num_c, filter_c, & SHR_ASSERT_FL((ubound(frac_sno, 1) == bounds%endc), sourcefile, __LINE__) SHR_ASSERT_FL((ubound(frac_sno_eff, 1) == bounds%endc), sourcefile, __LINE__) SHR_ASSERT_FL((ubound(snow_depth, 1) == bounds%endc), sourcefile, __LINE__) + SHR_ASSERT_FL((ubound(snomelt_accum, 1) == bounds%endc), sourcefile, __LINE__) associate( & begc => bounds%begc, & @@ -488,6 +491,7 @@ subroutine BulkDiag_NewSnowDiagnostics(bounds, num_c, filter_c, & ! all snow falls on ground, no snow on h2osfc (note that qflx_snow_h2osfc is ! currently set to 0 always in CanopyHydrologyMod) newsnow(c) = qflx_snow_grnd(c) * dtime + snomelt_accum(c) = max(0._r8, snomelt_accum(c) - newsnow(c) * 1.e-3_r8) ! update int_snow int_snow(c) = max(int_snow(c),h2osno_total(c)) !h2osno_total could be larger due to frost @@ -805,6 +809,7 @@ subroutine InitializeExplicitSnowPack(bounds, num_c, filter_c, & h2osno_no_layers = w%waterstate_inst%h2osno_no_layers_col(begc:endc), & h2osoi_ice = w%waterstate_inst%h2osoi_ice_col(begc:endc,:), & h2osoi_liq = w%waterstate_inst%h2osoi_liq_col(begc:endc,:)) + end associate end do @@ -818,7 +823,8 @@ subroutine InitializeExplicitSnowPack(bounds, num_c, filter_c, & dz = col%dz(begc:endc,:), & z = col%z(begc:endc,:), & t_soisno = temperature_inst%t_soisno_col(begc:endc,:), & - frac_iceold = b_waterdiagnostic_inst%frac_iceold_col(begc:endc,:)) + frac_iceold = b_waterdiagnostic_inst%frac_iceold_col(begc:endc,:), & + snomelt_accum = b_waterdiagnostic_inst%snomelt_accum_col(begc:endc)) ! intitialize SNICAR variables for fresh snow: call aerosol_inst%ResetFilter( & @@ -932,7 +938,7 @@ end subroutine UpdateState_InitializeSnowPack !----------------------------------------------------------------------- subroutine Bulk_InitializeSnowPack(bounds, snowpack_initialized_filterc, & - forc_t, snow_depth, snl, zi, dz, z, t_soisno, frac_iceold) + forc_t, snow_depth, snl, zi, dz, z, t_soisno, frac_iceold, snomelt_accum) ! ! !DESCRIPTION: ! Initialize an explicit snow pack in columns where this is warranted based on snow depth @@ -952,6 +958,7 @@ subroutine Bulk_InitializeSnowPack(bounds, snowpack_initialized_filterc, & real(r8) , intent(inout) :: z( bounds%begc: , -nlevsno+1: ) ! layer depth (m) real(r8) , intent(inout) :: t_soisno( bounds%begc: , -nlevsno+1: ) ! soil temperature (Kelvin) real(r8) , intent(inout) :: frac_iceold( bounds%begc: , -nlevsno+1: ) ! fraction of ice relative to the tot water + real(r8) , intent(inout) :: snomelt_accum( bounds%begc: ) ! accumulated col snow melt for z0m calculation (m H2O) ! ! !LOCAL VARIABLES: integer :: fc, c @@ -967,6 +974,7 @@ subroutine Bulk_InitializeSnowPack(bounds, snowpack_initialized_filterc, & SHR_ASSERT_ALL_FL((ubound(z) == [bounds%endc, nlevmaxurbgrnd]), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(t_soisno) == [bounds%endc, nlevmaxurbgrnd]), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(frac_iceold) == [bounds%endc, nlevgrnd]), sourcefile, __LINE__) + SHR_ASSERT_ALL_FL((ubound(snomelt_accum, 1) == bounds%endc), sourcefile, __LINE__) do fc = 1, snowpack_initialized_filterc%num c = snowpack_initialized_filterc%indices(fc) @@ -982,6 +990,8 @@ subroutine Bulk_InitializeSnowPack(bounds, snowpack_initialized_filterc, & ! This value of frac_iceold makes sense together with the state initialization: ! h2osoi_ice is non-zero, while h2osoi_liq is zero. frac_iceold(c,0) = 1._r8 + + snomelt_accum(c) = 0._r8 end do end subroutine Bulk_InitializeSnowPack diff --git a/src/biogeophys/SoilFluxesMod.F90 b/src/biogeophys/SoilFluxesMod.F90 index c316d30fe3..44e6d0e1cd 100644 --- a/src/biogeophys/SoilFluxesMod.F90 +++ b/src/biogeophys/SoilFluxesMod.F90 @@ -11,7 +11,7 @@ module SoilFluxesMod use abortutils , only : endrun use perf_mod , only : t_startf, t_stopf use clm_varctl , only : iulog - use clm_varpar , only : nlevsno, nlevgrnd, nlevurb, max_patch_per_col + use clm_varpar , only : nlevsno, nlevgrnd, nlevurb use atm2lndType , only : atm2lnd_type use CanopyStateType , only : canopystate_type use EnergyFluxType , only : energyflux_type diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 27f49035a8..a525d1cdd6 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -278,6 +278,7 @@ subroutine SetSoilWaterFractions(bounds, num_hydrologyc, filter_hydrologyc, & integer :: j, fc, c real(r8) :: vol_ice(bounds%begc:bounds%endc,1:nlevsoi) !partial volume of ice lens in layer real(r8) :: icefrac_orig ! original formulation for icefrac + real(r8) :: dz_ext(bounds%begc:bounds%endc,1:nlevsoi) character(len=*), parameter :: subname = 'SetSoilWaterFractions' !----------------------------------------------------------------------- @@ -290,6 +291,7 @@ subroutine SetSoilWaterFractions(bounds, num_hydrologyc, filter_hydrologyc, & h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice water (kg/m2) + excess_ice => waterstatebulk_inst%excess_ice_col , & ! Input: [real(r8) (:,:) ] excess ice (kg/m2) icefrac => soilhydrology_inst%icefrac_col & ! Output: [real(r8) (:,:) ] ) @@ -300,7 +302,8 @@ subroutine SetSoilWaterFractions(bounds, num_hydrologyc, filter_hydrologyc, & ! Porosity of soil, partial volume of ice and liquid, fraction of ice in each layer, ! fractional impermeability - vol_ice(c,j) = min(watsat(c,j), h2osoi_ice(c,j)/(dz(c,j)*denice)) + dz_ext(c,j) = dz(c,j) + excess_ice(c,j)/denice ! extended layer thickness, should be good for all the columns + vol_ice(c,j) = min(watsat(c,j), (h2osoi_ice(c,j) + excess_ice(c,j))/(dz_ext(c,j)*denice)) eff_porosity(c,j) = max(0.01_r8,watsat(c,j)-vol_ice(c,j)) icefrac(c,j) = min(1._r8,vol_ice(c,j)/watsat(c,j)) diff --git a/src/biogeophys/SoilTemperatureMod.F90 b/src/biogeophys/SoilTemperatureMod.F90 index 513413e8a9..b868224a60 100644 --- a/src/biogeophys/SoilTemperatureMod.F90 +++ b/src/biogeophys/SoilTemperatureMod.F90 @@ -88,7 +88,8 @@ module SoilTemperatureMod contains !----------------------------------------------------------------------- - subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_urbanc, filter_urbanc, num_nolakec, filter_nolakec, & + subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_urbanc, filter_urbanc, & + num_nolakep, filter_nolakep, num_nolakec, filter_nolakec, & atm2lnd_inst, urbanparams_inst, canopystate_inst, waterstatebulk_inst, waterdiagnosticbulk_inst, waterfluxbulk_inst,& solarabs_inst, soilstate_inst, energyflux_inst, temperature_inst, urbantv_inst) ! @@ -114,8 +115,8 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_urbanc, filter ! !USES: use clm_time_manager , only : get_step_size_real use clm_varpar , only : nlevsno, nlevgrnd, nlevurb, nlevmaxurbgrnd - use clm_varctl , only : iulog - use clm_varcon , only : cnfac, cpice, cpliq, denh2o + use clm_varctl , only : iulog, use_excess_ice + use clm_varcon , only : cnfac, cpice, cpliq, denh2o, denice use landunit_varcon , only : istsoil, istcrop use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, icol_road_perv, icol_road_imperv use BandDiagonalMod , only : BandDiagonal @@ -124,6 +125,8 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_urbanc, filter ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_nolakep ! number of non-lake points in patch filter + integer , intent(in) :: filter_nolakep(:) ! patch filter for non-lake points integer , intent(in) :: num_nolakec ! number of column non-lake points in column filter integer , intent(in) :: filter_nolakec(:) ! column filter for non-lake points integer , intent(in) :: num_urbanl ! number of urban landunits in clump @@ -143,8 +146,8 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_urbanc, filter type(temperature_type) , intent(inout) :: temperature_inst ! ! !LOCAL VARIABLES: - integer :: j,c,l,g,pi ! indices - integer :: fc ! lake filtered column indices + integer :: j,c,l,g ! indices + integer :: fc, fp ! lake filtered column & patch indices integer :: fl ! urban filtered landunit indices integer :: jtop(bounds%begc:bounds%endc) ! top level at each column real(r8) :: dtime ! land model time step (sec) @@ -171,6 +174,10 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_urbanc, filter real(r8) :: hs_top_snow(bounds%begc:bounds%endc) ! heat flux on top snow layer [W/m2] real(r8) :: hs_h2osfc(bounds%begc:bounds%endc) ! heat flux on standing water [W/m2] integer :: jbot(bounds%begc:bounds%endc) ! bottom level at each column + real(r8) :: dz_0(bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd) ! original layer thickness [m] + real(r8) :: z_0(bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd) ! original layer depth [m] + real(r8) :: zi_0(bounds%begc:bounds%endc,-nlevsno+0:nlevmaxurbgrnd) ! original layer interface level bellow layer "z" [m] + !----------------------------------------------------------------------- associate( & @@ -194,6 +201,7 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_urbanc, filter frac_sno_eff => waterdiagnosticbulk_inst%frac_sno_eff_col , & ! Input: [real(r8) (:) ] eff. fraction of ground covered by snow (0 to 1) snow_depth => waterdiagnosticbulk_inst%snow_depth_col , & ! Input: [real(r8) (:) ] snow height (m) h2osfc => waterstatebulk_inst%h2osfc_col , & ! Input: [real(r8) (:) ] surface water (mm) + excess_ice => waterstatebulk_inst%excess_ice_col , & ! Input: [real(r8) (:,:) ] excess ice (kg/m2) (new) (1:nlevgrnd) frac_h2osfc => waterdiagnosticbulk_inst%frac_h2osfc_col , & ! Input: [real(r8) (:) ] fraction of ground covered by surface water (0 to 1) @@ -271,6 +279,29 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_urbanc, filter endif end do + + !-------------------------------------------------------------- + ! Vertical coordinates adjustment for excess ice calculations + !-------------------------------------------------------------- + if ( use_excess_ice ) then + ! Save original soil depth to get put them back in et the end + dz_0(begc:endc,-nlevsno+1:nlevmaxurbgrnd) = dz(begc:endc,-nlevsno+1:nlevmaxurbgrnd) + zi_0(begc:endc,-nlevsno+0:nlevmaxurbgrnd) = zi(begc:endc,-nlevsno+0:nlevmaxurbgrnd) + z_0(begc:endc,-nlevsno+1:nlevmaxurbgrnd) = z(begc:endc,-nlevsno+1:nlevmaxurbgrnd) + ! Adjust column depth for excess ice thickness + do fc = 1, num_nolakec + c = filter_nolakec(fc) + l = col%landunit(c) + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + dz(c,1:nlevmaxurbgrnd) = dz(c,1:nlevmaxurbgrnd) + excess_ice(c,1:nlevmaxurbgrnd) / denice ! add extra layer thickness + do j = 1, nlevmaxurbgrnd ! if excess ice amount dropped to zero there will be no adjustment + zi(c,j) = zi(c,j) + sum(excess_ice(c,1:j)) / denice + z(c,j) = (zi(c,j-1) + zi(c,j)) * 0.5_r8 + end do + end if + end do + end if + !------------------------------------------------------ ! Compute ground surface and soil temperatures !------------------------------------------------------ @@ -288,7 +319,8 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_urbanc, filter ! Added a patches loop here to get the average of hs and dhsdT over ! all Patches on the column. Precalculate the terms that do not depend on PFT. - call ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & + call ComputeGroundHeatFluxAndDeriv(bounds, & + num_nolakep, filter_nolakep, num_nolakec, filter_nolakec, & hs_h2osfc( begc:endc ), & hs_top_snow( begc:endc ), & hs_soil( begc:endc ), & @@ -488,6 +520,24 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_urbanc, filter dhsdT(bounds%begc:bounds%endc), & soilstate_inst, waterstatebulk_inst, waterdiagnosticbulk_inst, waterfluxbulk_inst, energyflux_inst, temperature_inst) + !-------------------------------------------------------------- + ! Vertical coordinates adjustment for excess ice calculations + !-------------------------------------------------------------- + ! bringing back the soil depth to the original state + if (use_excess_ice) then + ! Adjust column depth for excess ice thickness + do fc = 1, num_nolakec + c = filter_nolakec(fc) + l = col%landunit(c) + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + dz(c,1:nlevmaxurbgrnd)=dz_0(c,1:nlevmaxurbgrnd) + zi(c,1:nlevmaxurbgrnd)=zi_0(c,1:nlevmaxurbgrnd) + z(c,1:nlevmaxurbgrnd)=z_0(c,1:nlevmaxurbgrnd) + end if + end do + end if + + if ( IsProgBuildTemp() )then call BuildingTemperature(bounds, num_urbanl, filter_urbanl, num_nolakec, filter_nolakec, & tk(bounds%begc:bounds%endc, :), urbanparams_inst, & @@ -628,6 +678,7 @@ subroutine SoilThermProp (bounds, num_urbanc, filter_urbanc, num_nolakec, filter h2osno_no_layers => waterstatebulk_inst%h2osno_no_layers_col , & ! Input: [real(r8) (:) ] snow not resolved into layers (mm H2O) h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice lens (kg/m2) + excess_ice => waterstatebulk_inst%excess_ice_col , & ! Input: [real(r8) (:,:) ] excess ice lenses (kg/m2) (new) (1:nlevgrnd) bw => waterdiagnosticbulk_inst%bw_col , & ! Output: [real(r8) (:,:) ] partial density of water in the snow pack (ice + liquid) [kg/m3] tkmg => soilstate_inst%tkmg_col , & ! Input: [real(r8) (:,:) ] thermal conductivity, soil minerals [W/m-K] @@ -654,7 +705,7 @@ subroutine SoilThermProp (bounds, num_urbanc, filter_urbanc, num_nolakec, filter col%itype(c) /= icol_roof .and. col%itype(c) /= icol_road_imperv) .or. & (col%itype(c) == icol_road_imperv .and. j > nlev_improad(l))) then - satw = (h2osoi_liq(c,j)/denh2o + h2osoi_ice(c,j)/denice)/(dz(c,j)*watsat(c,j)) + satw = (h2osoi_liq(c,j)/denh2o + h2osoi_ice(c,j)/denice +excess_ice(c,j)/denice)/(dz(c,j)*watsat(c,j)) satw = min(1._r8, satw) if (satw > .1e-6_r8) then if (t_soisno(c,j) >= tfrz) then ! Unfrozen soil @@ -663,7 +714,7 @@ subroutine SoilThermProp (bounds, num_urbanc, filter_urbanc, num_nolakec, filter dke = satw end if fl = (h2osoi_liq(c,j)/(denh2o*dz(c,j))) / (h2osoi_liq(c,j)/(denh2o*dz(c,j)) + & - h2osoi_ice(c,j)/(denice*dz(c,j))) + h2osoi_ice(c,j)/(denice*dz(c,j))+excess_ice(c,j)/(denice*dz(c,j))) dksat = tkmg(c,j)*tkwat**(fl*watsat(c,j))*tkice**((1._r8-fl)*watsat(c,j)) thk(c,j) = dke*dksat + (1._r8-dke)*tkdry(c,j) else @@ -756,7 +807,8 @@ subroutine SoilThermProp (bounds, num_urbanc, filter_urbanc, num_nolakec, filter .and. col%itype(c) /= icol_sunwall .and. col%itype(c) /= icol_shadewall .and. & col%itype(c) /= icol_roof .and. col%itype(c) /= icol_road_imperv) .or. & (col%itype(c) == icol_road_imperv .and. j > nlev_improad(l))) then - cv(c,j) = csol(c,j)*(1._r8-watsat(c,j))*dz(c,j) + (h2osoi_ice(c,j)*cpice + h2osoi_liq(c,j)*cpliq) + cv(c,j) = csol(c,j)*(1._r8-watsat(c,j))*dz(c,j) + (h2osoi_ice(c,j)*cpice + & + h2osoi_liq(c,j)*cpliq) + excess_ice(c,j)*cpice if (j > nbedrock(c)) cv(c,j) = csol_bedrock*dz(c,j) else if (lun%itype(l) == istwet) then cv(c,j) = (h2osoi_ice(c,j)*cpice + h2osoi_liq(c,j)*cpliq) @@ -1057,7 +1109,7 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & use clm_time_manager , only : get_step_size_real use clm_varpar , only : nlevsno, nlevgrnd, nlevurb, nlevmaxurbgrnd use clm_varctl , only : iulog - use clm_varcon , only : tfrz, hfus, grav + use clm_varcon , only : tfrz, hfus, grav, denice use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, icol_road_perv use landunit_varcon , only : istsoil, istcrop, istice ! @@ -1081,13 +1133,17 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & real(r8) :: temp1 !temporary variables [kg/m2] real(r8) :: hm(bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd) !energy residual [W/m2] real(r8) :: xm(bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd) !melting or freezing within a time step [kg/m2] + real(r8) :: xm2(bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd) !additional melting or freezing within a time step [kg/m2] (needed for excess ice melt) real(r8) :: wmass0(bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd)!initial mass of ice and liquid (kg/m2) real(r8) :: wice0 (bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd)!initial mass of ice (kg/m2) real(r8) :: wliq0 (bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd)!initial mass of liquid (kg/m2) real(r8) :: supercool(bounds%begc:bounds%endc,nlevmaxurbgrnd) !supercooled water in soil (kg/m2) - real(r8) :: propor !proportionality constant (-) + real(r8) :: propor !proportionality constant (-) real(r8) :: tinc(bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd) !t(n+1)-t(n) [K] - real(r8) :: smp !frozen water potential (mm) + real(r8) :: smp !frozen water potential (mm) + real(r8) :: wexice0(bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd) !initial mass of excess_ice at the timestep (kg/m2) + + !----------------------------------------------------------------------- call t_startf( 'PhaseChangebeta' ) @@ -1106,14 +1162,17 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & frac_sno_eff => waterdiagnosticbulk_inst%frac_sno_eff_col , & ! Input: [real(r8) (:) ] eff. fraction of ground covered by snow (0 to 1) frac_h2osfc => waterdiagnosticbulk_inst%frac_h2osfc_col , & ! Input: [real(r8) (:) ] fraction of ground covered by surface water (0 to 1) snow_depth => waterdiagnosticbulk_inst%snow_depth_col , & ! Input: [real(r8) (:) ] snow height (m) + exice_subs_col => waterdiagnosticbulk_inst%exice_subs_col , & ! Output: [real(r8) (:,:) ] per layer subsidence due to excess ice melt (mm/s) h2osno_no_layers => waterstatebulk_inst%h2osno_no_layers_col , & ! Output: [real(r8) (:) ] snow not resolved into layers (mm H2O) - h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) (new) - h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) (new) + h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) (new) + h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) (new) + excess_ice => waterstatebulk_inst%excess_ice_col , & ! Input: [real(r8) (:,:) ] excess ice (kg/m2) (new) (1:nlevgrnd) qflx_snow_drain => waterfluxbulk_inst%qflx_snow_drain_col , & ! Output: [real(r8) (:) ] drainage from snow pack qflx_snofrz_lyr => waterfluxbulk_inst%qflx_snofrz_lyr_col , & ! Output: [real(r8) (:,:) ] snow freezing rate (positive definite) (col,lyr) [kg m-2 s-1] qflx_snofrz => waterfluxbulk_inst%qflx_snofrz_col , & ! Output: [real(r8) (:) ] column-integrated snow freezing rate (positive definite) [kg m-2 s-1] qflx_snomelt => waterfluxbulk_inst%qflx_snomelt_col , & ! Output: [real(r8) (:) ] snow melt (mm H2O /s) + snomelt_accum => waterdiagnosticbulk_inst%snomelt_accum_col , & ! Output: [real(r8) (:) ] accumulated snow melt (m) qflx_snomelt_lyr => waterfluxbulk_inst%qflx_snomelt_lyr_col , & ! Output: [real(r8) (:) ] snow melt in each layer (mm H2O /s) eflx_snomelt => energyflux_inst%eflx_snomelt_col , & ! Output: [real(r8) (:) ] snow melt heat flux (W/m**2) @@ -1152,9 +1211,14 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & imelt(c,j) = 0 hm(c,j) = 0._r8 xm(c,j) = 0._r8 + xm2(c,j) = 0._r8 wice0(c,j) = h2osoi_ice(c,j) wliq0(c,j) = h2osoi_liq(c,j) - wmass0(c,j) = h2osoi_ice(c,j) + h2osoi_liq(c,j) + wexice0(c,j) = excess_ice(c,j) + wmass0(c,j) = h2osoi_ice(c,j) + h2osoi_liq(c,j) + wexice0(c,j) + if (j >= 1) then + exice_subs_col(c,j) = 0._r8 + endif endif ! end of snow layer if-block if (j <= 0) then @@ -1173,7 +1237,7 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & ! Melting identification ! If ice exists above melt point, melt some to liquid. - if (h2osoi_ice(c,j) > 0._r8 .AND. t_soisno(c,j) > tfrz) then + if (h2osoi_ice(c,j) > 0._r8 .and. t_soisno(c,j) > tfrz) then imelt(c,j) = 1 ! tinc(c,j) = t_soisno(c,j) - tfrz tinc(c,j) = tfrz - t_soisno(c,j) @@ -1211,6 +1275,13 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & t_soisno(c,j) = tfrz endif + ! melt excess ice after normal ice + if (excess_ice(c,j) > 0._r8 .AND. t_soisno(c,j) > tfrz) then + imelt(c,j) = 1 + tinc(c,j) = tfrz - t_soisno(c,j) + t_soisno(c,j) = tfrz + endif + ! from Zhao (1997) and Koren (1999) supercool(c,j) = 0.0_r8 if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop .or. col%itype(c) == icol_road_perv) then @@ -1325,23 +1396,31 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & endif heatr = 0._r8 - if (xm(c,j) > 0._r8) then + if (xm(c,j) > 0._r8) then !if there is excess heat to melt the ice h2osoi_ice(c,j) = max(0._r8, wice0(c,j)-xm(c,j)) heatr = hm(c,j) - hfus*(wice0(c,j)-h2osoi_ice(c,j))/dtime + xm2(c,j) = xm(c,j) - h2osoi_ice(c,j) !excess ice melting + if (h2osoi_ice(c,j) == 0._r8) then ! this might be redundant + if (excess_ice(c,j) >= 0._r8 .and. xm2(c,j)>0._r8 .and. j>=2) then ! if there is excess ice to melt + excess_ice(c,j) = max(0._r8,wexice0(c,j) - xm2(c,j)) + heatr = hm(c,j) - hfus * (wexice0(c,j)-excess_ice(c,j)+wice0(c,j)-h2osoi_ice(c,j)) / dtime + endif + endif !end of excess ice block else if (xm(c,j) < 0._r8) then if (j <= 0) then h2osoi_ice(c,j) = min(wmass0(c,j), wice0(c,j)-xm(c,j)) ! snow else - if (wmass0(c,j) < supercool(c,j)) then + if (wmass0(c,j) - wexice0(c,j) < supercool(c,j)) then ! even if excess ice is present, it cannot refreeze h2osoi_ice(c,j) = 0._r8 else - h2osoi_ice(c,j) = min(wmass0(c,j) - supercool(c,j),wice0(c,j)-xm(c,j)) + h2osoi_ice(c,j) = min(wmass0(c,j) - wexice0(c,j) - supercool(c,j),wice0(c,j)-xm(c,j)) endif endif heatr = hm(c,j) - hfus*(wice0(c,j)-h2osoi_ice(c,j))/dtime endif - h2osoi_liq(c,j) = max(0._r8,wmass0(c,j)-h2osoi_ice(c,j)) + h2osoi_liq(c,j) = max(0._r8,wmass0(c,j)-h2osoi_ice(c,j)-excess_ice(c,j)) !melted excess ice is added to the respective soil layers + if (abs(heatr) > 0._r8) then if (j == snl(c)+1) then @@ -1373,14 +1452,18 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & endif ! end of heatr > 0 if-block if (j >= 1) then - xmf(c) = xmf(c) + hfus*(wice0(c,j)-h2osoi_ice(c,j))/dtime + xmf(c) = xmf(c) + hfus*(wice0(c,j)-h2osoi_ice(c,j))/dtime + & + hfus*(wexice0(c,j)-excess_ice(c,j))/dtime + ! subsidence calculation + exice_subs_col(c,j) = max(0._r8, (wexice0(c,j)-excess_ice(c,j))/denice) else xmf(c) = xmf(c) + hfus*(wice0(c,j)-h2osoi_ice(c,j))/dtime endif - + if (imelt(c,j) == 1 .AND. j < 1) then qflx_snomelt_lyr(c,j) = max(0._r8,(wice0(c,j)-h2osoi_ice(c,j)))/dtime qflx_snomelt(c) = qflx_snomelt(c) + qflx_snomelt_lyr(c,j) + snomelt_accum(c) = snomelt_accum(c) + qflx_snomelt_lyr(c,j) * dtime * 1.e-3_r8 endif ! layer freezing mass flux (positive): @@ -1398,6 +1481,7 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & end do ! end of column-loop enddo ! end of level-loop + ! Needed for history file output do fc = 1,num_nolakec @@ -1417,7 +1501,8 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & end subroutine Phasechange_beta !----------------------------------------------------------------------- - subroutine ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & + subroutine ComputeGroundHeatFluxAndDeriv(bounds, & + num_nolakep, filter_nolakep, num_nolakec, filter_nolakec, & hs_h2osfc, hs_top_snow, hs_soil, hs_top, dhsdT, sabg_lyr_col, & atm2lnd_inst, urbanparams_inst, canopystate_inst, waterdiagnosticbulk_inst, & waterfluxbulk_inst, solarabs_inst, energyflux_inst, temperature_inst) @@ -1433,12 +1518,14 @@ subroutine ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & ! !USES: use clm_varcon , only : sb, hvap use column_varcon , only : icol_road_perv, icol_road_imperv - use clm_varpar , only : nlevsno, max_patch_per_col + use clm_varpar , only : nlevsno use UrbanParamsType, only : IsSimpleBuildTemp, IsProgBuildTemp ! ! !ARGUMENTS: implicit none type(bounds_type) , intent(in) :: bounds ! bounds + integer , intent(in) :: num_nolakep ! number of non-lake points in patch filter + integer , intent(in) :: filter_nolakep( : ) ! patch filter for non-lake points integer , intent(in) :: num_nolakec ! number of column non-lake points in column filter integer , intent(in) :: filter_nolakec( : ) ! column filter for non-lake points real(r8) , intent(out) :: hs_h2osfc( bounds%begc: ) ! heat flux on standing water [W/m2] @@ -1457,8 +1544,8 @@ subroutine ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & type(temperature_type) , intent(in) :: temperature_inst ! ! !LOCAL VARIABLES: - integer :: j,c,p,l,g,pi ! indices - integer :: fc ! lake filtered column indices + integer :: j,c,p,l,g ! indices + integer :: fc, fp ! lake filtered column and patch indices real(r8) :: hs(bounds%begc:bounds%endc) ! net energy flux into the surface (w/m2) real(r8) :: lwrad_emit(bounds%begc:bounds%endc) ! emitted longwave radiation real(r8) :: dlwrad_emit(bounds%begc:bounds%endc) ! time derivative of emitted longwave radiation @@ -1550,79 +1637,71 @@ subroutine ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & hs_h2osfc(begc:endc) = 0._r8 hs(begc:endc) = 0._r8 dhsdT(begc:endc) = 0._r8 - do pi = 1,max_patch_per_col - do fc = 1,num_nolakec - c = filter_nolakec(fc) - if ( pi <= col%npatches(c) ) then - p = col%patchi(c) + pi - 1 - l = patch%landunit(p) - g = patch%gridcell(p) - - if (patch%active(p)) then - if (.not. lun%urbpoi(l)) then - eflx_gnet(p) = sabg(p) + dlrad(p) & - + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) - lwrad_emit(c) & - - (eflx_sh_grnd(p)+qflx_evap_soi(p)*htvp(c)) - ! save sabg for balancecheck, in case frac_sno is set to zero later - sabg_chk(p) = frac_sno_eff(c) * sabg_snow(p) + (1._r8 - frac_sno_eff(c) ) * sabg_soil(p) - - eflx_gnet_snow = sabg_snow(p) + dlrad(p) & - + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) - lwrad_emit_snow(c) & - - (eflx_sh_snow(p)+qflx_ev_snow(p)*htvp(c)) - - eflx_gnet_soil = sabg_soil(p) + dlrad(p) & - + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) - lwrad_emit_soil(c) & - - (eflx_sh_soil(p)+qflx_ev_soil(p)*htvp(c)) - - eflx_gnet_h2osfc = sabg_soil(p) + dlrad(p) & - + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) - lwrad_emit_h2osfc(c) & - - (eflx_sh_h2osfc(p)+qflx_ev_h2osfc(p)*htvp(c)) - else - ! For urban columns we use the net longwave radiation (eflx_lwrad_net) because of - ! interactions between urban columns. - - ! All wasteheat and traffic flux goes into canyon floor - if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - ! Note that we divide the following landunit variables by 1-wtlunit_roof which - ! essentially converts the flux from W/m2 of urban area to W/m2 of canyon floor area - eflx_wasteheat_patch(p) = eflx_wasteheat(l)/(1._r8-lun%wtlunit_roof(l)) - if ( IsSimpleBuildTemp() ) then - eflx_ventilation_patch(p) = 0._r8 - else if ( IsProgBuildTemp() ) then - eflx_ventilation_patch(p) = eflx_ventilation(l)/(1._r8-lun%wtlunit_roof(l)) - end if - eflx_heat_from_ac_patch(p) = eflx_heat_from_ac(l)/(1._r8-lun%wtlunit_roof(l)) - eflx_traffic_patch(p) = eflx_traffic(l)/(1._r8-lun%wtlunit_roof(l)) - else - eflx_wasteheat_patch(p) = 0._r8 - eflx_ventilation_patch(p) = 0._r8 - eflx_heat_from_ac_patch(p) = 0._r8 - eflx_traffic_patch(p) = 0._r8 - end if - ! Include transpiration term because needed for previous road - ! and include wasteheat and traffic flux - eflx_gnet(p) = sabg(p) + dlrad(p) & - - eflx_lwrad_net(p) & - - (eflx_sh_grnd(p) + qflx_evap_soi(p)*htvp(c) + qflx_tran_veg(p)*hvap) & - + eflx_wasteheat_patch(p) + eflx_heat_from_ac_patch(p) + eflx_traffic_patch(p) & - + eflx_ventilation_patch(p) - if ( IsSimpleBuildTemp() ) then - eflx_anthro(p) = eflx_wasteheat_patch(p) + eflx_traffic_patch(p) - end if - eflx_gnet_snow = eflx_gnet(p) - eflx_gnet_soil = eflx_gnet(p) - eflx_gnet_h2osfc = eflx_gnet(p) - end if - dgnetdT(p) = - cgrnd(p) - dlwrad_emit(c) - hs(c) = hs(c) + eflx_gnet(p) * patch%wtcol(p) - dhsdT(c) = dhsdT(c) + dgnetdT(p) * patch%wtcol(p) - ! separate surface fluxes for soil/snow - hs_soil(c) = hs_soil(c) + eflx_gnet_soil * patch%wtcol(p) - hs_h2osfc(c) = hs_h2osfc(c) + eflx_gnet_h2osfc * patch%wtcol(p) - + do fp = 1,num_nolakep + p = filter_nolakep(fp) + c = patch%column(p) + l = patch%landunit(p) + + if (.not. lun%urbpoi(l)) then + eflx_gnet(p) = sabg(p) + dlrad(p) & + + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) - lwrad_emit(c) & + - (eflx_sh_grnd(p)+qflx_evap_soi(p)*htvp(c)) + ! save sabg for balancecheck, in case frac_sno is set to zero later + sabg_chk(p) = frac_sno_eff(c) * sabg_snow(p) + (1._r8 - frac_sno_eff(c) ) * sabg_soil(p) + + eflx_gnet_snow = sabg_snow(p) + dlrad(p) & + + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) - lwrad_emit_snow(c) & + - (eflx_sh_snow(p)+qflx_ev_snow(p)*htvp(c)) + + eflx_gnet_soil = sabg_soil(p) + dlrad(p) & + + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) - lwrad_emit_soil(c) & + - (eflx_sh_soil(p)+qflx_ev_soil(p)*htvp(c)) + + eflx_gnet_h2osfc = sabg_soil(p) + dlrad(p) & + + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) - lwrad_emit_h2osfc(c) & + - (eflx_sh_h2osfc(p)+qflx_ev_h2osfc(p)*htvp(c)) + else + ! For urban columns we use the net longwave radiation (eflx_lwrad_net) because of + ! interactions between urban columns. + + ! All wasteheat and traffic flux goes into canyon floor + if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then + ! Note that we divide the following landunit variables by 1-wtlunit_roof which + ! essentially converts the flux from W/m2 of urban area to W/m2 of canyon floor area + eflx_wasteheat_patch(p) = eflx_wasteheat(l)/(1._r8-lun%wtlunit_roof(l)) + if ( IsSimpleBuildTemp() ) then + eflx_ventilation_patch(p) = 0._r8 + else if ( IsProgBuildTemp() ) then + eflx_ventilation_patch(p) = eflx_ventilation(l)/(1._r8-lun%wtlunit_roof(l)) end if + eflx_heat_from_ac_patch(p) = eflx_heat_from_ac(l)/(1._r8-lun%wtlunit_roof(l)) + eflx_traffic_patch(p) = eflx_traffic(l)/(1._r8-lun%wtlunit_roof(l)) + else + eflx_wasteheat_patch(p) = 0._r8 + eflx_ventilation_patch(p) = 0._r8 + eflx_heat_from_ac_patch(p) = 0._r8 + eflx_traffic_patch(p) = 0._r8 end if - end do + ! Include transpiration term because needed for previous road + ! and include wasteheat and traffic flux + eflx_gnet(p) = sabg(p) + dlrad(p) & + - eflx_lwrad_net(p) & + - (eflx_sh_grnd(p) + qflx_evap_soi(p)*htvp(c) + qflx_tran_veg(p)*hvap) & + + eflx_wasteheat_patch(p) + eflx_heat_from_ac_patch(p) + eflx_traffic_patch(p) & + + eflx_ventilation_patch(p) + if ( IsSimpleBuildTemp() ) then + eflx_anthro(p) = eflx_wasteheat_patch(p) + eflx_traffic_patch(p) + end if + eflx_gnet_snow = eflx_gnet(p) + eflx_gnet_soil = eflx_gnet(p) + eflx_gnet_h2osfc = eflx_gnet(p) + end if + dgnetdT(p) = - cgrnd(p) - dlwrad_emit(c) + hs(c) = hs(c) + eflx_gnet(p) * patch%wtcol(p) + dhsdT(c) = dhsdT(c) + dgnetdT(p) * patch%wtcol(p) + ! separate surface fluxes for soil/snow + hs_soil(c) = hs_soil(c) + eflx_gnet_soil * patch%wtcol(p) + hs_h2osfc(c) = hs_h2osfc(c) + eflx_gnet_h2osfc * patch%wtcol(p) end do ! Additional calculations with SNICAR: @@ -1639,44 +1718,38 @@ subroutine ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & hs_top(begc:endc) = 0._r8 hs_top_snow(begc:endc) = 0._r8 - do pi = 1,max_patch_per_col - do fc = 1,num_nolakec - c = filter_nolakec(fc) - lyr_top = snl(c) + 1 - if ( pi <= col%npatches(c) ) then - p = col%patchi(c) + pi - 1 - if (patch%active(p)) then - g = patch%gridcell(p) - l = patch%landunit(p) - if (.not. lun%urbpoi(l)) then + do fp = 1,num_nolakep + p = filter_nolakep(fp) + c = patch%column(p) + l = patch%landunit(p) - eflx_gnet_top = sabg_lyr(p,lyr_top) + dlrad(p) + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) & - - lwrad_emit(c) - (eflx_sh_grnd(p)+qflx_evap_soi(p)*htvp(c)) + lyr_top = snl(c) + 1 - hs_top(c) = hs_top(c) + eflx_gnet_top*patch%wtcol(p) + if (.not. lun%urbpoi(l)) then - eflx_gnet_snow = sabg_lyr(p,lyr_top) + dlrad(p) + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) & - - lwrad_emit_snow(c) - (eflx_sh_snow(p)+qflx_ev_snow(p)*htvp(c)) + eflx_gnet_top = sabg_lyr(p,lyr_top) + dlrad(p) + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) & + - lwrad_emit(c) - (eflx_sh_grnd(p)+qflx_evap_soi(p)*htvp(c)) - eflx_gnet_soil = sabg_lyr(p,lyr_top) + dlrad(p) + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) & - - lwrad_emit_soil(c) - (eflx_sh_soil(p)+qflx_ev_soil(p)*htvp(c)) + hs_top(c) = hs_top(c) + eflx_gnet_top*patch%wtcol(p) - hs_top_snow(c) = hs_top_snow(c) + eflx_gnet_snow*patch%wtcol(p) + eflx_gnet_snow = sabg_lyr(p,lyr_top) + dlrad(p) + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) & + - lwrad_emit_snow(c) - (eflx_sh_snow(p)+qflx_ev_snow(p)*htvp(c)) - do j = lyr_top,1,1 - sabg_lyr_col(c,j) = sabg_lyr_col(c,j) + sabg_lyr(p,j) * patch%wtcol(p) - enddo - else + eflx_gnet_soil = sabg_lyr(p,lyr_top) + dlrad(p) + (1._r8-frac_veg_nosno(p))*emg(c)*forc_lwrad(c) & + - lwrad_emit_soil(c) - (eflx_sh_soil(p)+qflx_ev_soil(p)*htvp(c)) - hs_top(c) = hs_top(c) + eflx_gnet(p)*patch%wtcol(p) - hs_top_snow(c) = hs_top_snow(c) + eflx_gnet(p)*patch%wtcol(p) - sabg_lyr_col(c,lyr_top) = sabg_lyr_col(c,lyr_top) + sabg(p) * patch%wtcol(p) + hs_top_snow(c) = hs_top_snow(c) + eflx_gnet_snow*patch%wtcol(p) - endif - endif + do j = lyr_top,1,1 + sabg_lyr_col(c,j) = sabg_lyr_col(c,j) + sabg_lyr(p,j) * patch%wtcol(p) + enddo + else - endif - enddo + hs_top(c) = hs_top(c) + eflx_gnet(p)*patch%wtcol(p) + hs_top_snow(c) = hs_top_snow(c) + eflx_gnet(p)*patch%wtcol(p) + sabg_lyr_col(c,lyr_top) = sabg_lyr_col(c,lyr_top) + sabg(p) * patch%wtcol(p) + + endif enddo end associate diff --git a/src/biogeophys/SoilWaterMovementMod.F90 b/src/biogeophys/SoilWaterMovementMod.F90 index b56e33706f..8b6f953918 100644 --- a/src/biogeophys/SoilWaterMovementMod.F90 +++ b/src/biogeophys/SoilWaterMovementMod.F90 @@ -380,7 +380,7 @@ subroutine BaseflowSink(bounds, num_hydrologyc, & !USES: use decompMod , only : bounds_type use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varpar , only : nlevsoi, max_patch_per_col + use clm_varpar , only : nlevsoi use SoilStateType , only : soilstate_type use WaterFluxBulkType , only : waterfluxbulk_type use PatchType , only : patch @@ -484,7 +484,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & use decompMod , only : bounds_type use clm_varcon , only : grav,hfus,tfrz use clm_varcon , only : denh2o, denice - use clm_varpar , only : nlevsoi, max_patch_per_col, nlevgrnd + use clm_varpar , only : nlevsoi, nlevgrnd use clm_time_manager , only : get_step_size_real, get_nstep use column_varcon , only : icol_roof, icol_road_imperv use clm_varctl , only : use_flexibleCN, use_hydrstress diff --git a/src/biogeophys/SoilWaterPlantSinkMod.F90 b/src/biogeophys/SoilWaterPlantSinkMod.F90 index 115e1cab76..2d9c1a03c6 100644 --- a/src/biogeophys/SoilWaterPlantSinkMod.F90 +++ b/src/biogeophys/SoilWaterPlantSinkMod.F90 @@ -149,7 +149,6 @@ subroutine Compute_EffecRootFrac_And_VertTranSink_HydStress_Roads(bounds, & use SoilStateType , only : soilstate_type use WaterFluxBulkType , only : waterfluxbulk_type use clm_varpar , only : nlevsoi - use clm_varpar , only : max_patch_per_col use PatchType , only : patch use ColumnType , only : col @@ -199,30 +198,25 @@ subroutine Compute_EffecRootFrac_And_VertTranSink_HydStress_Roads(bounds, & end do end do - do pi = 1,max_patch_per_col - do j = 1,nlevsoi - do fc = 1, num_filterc - c = filterc(fc) - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - if (patch%active(p)) then - rootr_col(c,j) = rootr_col(c,j) + rootr_patch(p,j) * & - qflx_tran_veg_patch(p) * patch%wtcol(p) - end if - end if - end do - end do + do j = 1,nlevsoi do fc = 1, num_filterc c = filterc(fc) - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 + do p = col%patchi(c), col%patchi(c) + col%npatches(c) - 1 if (patch%active(p)) then - temp(c) = temp(c) + qflx_tran_veg_patch(p) * patch%wtcol(p) + rootr_col(c,j) = rootr_col(c,j) + rootr_patch(p,j) * & + qflx_tran_veg_patch(p) * patch%wtcol(p) end if + end do + end do + end do + do fc = 1, num_filterc + c = filterc(fc) + do p = col%patchi(c), col%patchi(c) + col%npatches(c) - 1 + if (patch%active(p)) then + temp(c) = temp(c) + qflx_tran_veg_patch(p) * patch%wtcol(p) end if end do end do - do j = 1, nlevsoi do fc = 1, num_filterc @@ -248,7 +242,6 @@ subroutine Compute_EffecRootFrac_And_VertTranSink_HydStress( bounds, & !USES: use decompMod , only : bounds_type use clm_varpar , only : nlevsoi - use clm_varpar , only : max_patch_per_col use SoilStateType , only : soilstate_type use WaterFluxBulkType , only : waterfluxbulk_type use CanopyStateType , only : canopystate_type @@ -308,21 +301,18 @@ subroutine Compute_EffecRootFrac_And_VertTranSink_HydStress( bounds, & do j = 1, nlevsoi grav2 = z(c,j) * 1000._r8 temp(c) = 0._r8 - do pi = 1,max_patch_per_col - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - if (j == 1) then - qflx_hydr_redist_patch(p) = 0._r8 - end if - if (patch%active(p).and.frac_veg_nosno(p)>0) then - if (patch%wtcol(p) > 0._r8) then - patchflux = k_soil_root(p,j) * (smp(c,j) - vegwp(p,4) - grav2) - if (patchflux <0) then - qflx_hydr_redist_patch(p) = qflx_hydr_redist_patch(p) + patchflux - end if - temp(c) = temp(c) + patchflux * patch%wtcol(p) - endif - end if + do p = col%patchi(c), col%patchi(c) + col%npatches(c) - 1 + if (j == 1) then + qflx_hydr_redist_patch(p) = 0._r8 + end if + if (patch%active(p).and.frac_veg_nosno(p)>0) then + if (patch%wtcol(p) > 0._r8) then + patchflux = k_soil_root(p,j) * (smp(c,j) - vegwp(p,4) - grav2) + if (patchflux <0) then + qflx_hydr_redist_patch(p) = qflx_hydr_redist_patch(p) + patchflux + end if + temp(c) = temp(c) + patchflux * patch%wtcol(p) + endif end if end do qflx_rootsoi_col(c,j)= temp(c) @@ -351,7 +341,7 @@ subroutine Compute_EffecRootFrac_And_VertTranSink_Default(bounds, num_filterc, & !USES: use decompMod , only : bounds_type use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varpar , only : nlevsoi, max_patch_per_col + use clm_varpar , only : nlevsoi use SoilStateType , only : soilstate_type use WaterFluxBulkType , only : waterfluxbulk_type use PatchType , only : patch @@ -399,26 +389,22 @@ subroutine Compute_EffecRootFrac_And_VertTranSink_Default(bounds, num_filterc, & end do end do - do pi = 1,max_patch_per_col - do j = 1,nlevsoi - do fc = 1, num_filterc - c = filterc(fc) - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - if (patch%active(p)) then - rootr_col(c,j) = rootr_col(c,j) + rootr_patch(p,j) * & - qflx_tran_veg_patch(p) * patch%wtcol(p) - end if - end if - end do - end do + do j = 1,nlevsoi do fc = 1, num_filterc c = filterc(fc) - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 + do p = col%patchi(c), col%patchi(c) + col%npatches(c) - 1 if (patch%active(p)) then - temp(c) = temp(c) + qflx_tran_veg_patch(p) * patch%wtcol(p) + rootr_col(c,j) = rootr_col(c,j) + rootr_patch(p,j) * & + qflx_tran_veg_patch(p) * patch%wtcol(p) end if + end do + end do + end do + do fc = 1, num_filterc + c = filterc(fc) + do p = col%patchi(c), col%patchi(c) + col%npatches(c) - 1 + if (patch%active(p)) then + temp(c) = temp(c) + qflx_tran_veg_patch(p) * patch%wtcol(p) end if end do end do diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index f2d9317f82..d20fc862b1 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -647,11 +647,11 @@ subroutine InitCold(this, bounds, & ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use shr_const_mod , only : SHR_CONST_TKFRZ - use clm_varcon , only : denice, denh2o, sb - use landunit_varcon, only : istwet, istsoil, istdlak, istice + use clm_varcon , only : denice, denh2o + use landunit_varcon, only : istwet, istsoil, istdlak, istice, istcrop use column_varcon , only : icol_road_imperv, icol_roof, icol_sunwall use column_varcon , only : icol_shadewall, icol_road_perv - use clm_varctl , only : iulog, use_vancouver, use_mexicocity + use clm_varctl , only : iulog, use_vancouver, use_mexicocity, use_excess_ice ! ! !ARGUMENTS: class(temperature_type) :: this @@ -742,7 +742,9 @@ subroutine InitCold(this, bounds, & end if else this%t_soisno_col(c,1:nlevgrnd) = 274._r8 - + if (use_excess_ice .and. (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop)) then + this%t_soisno_col(c,1:nlevgrnd) = SHR_CONST_TKFRZ - 5.0_r8 !needs to be below freezing to properly initiate excess ice + end if endif endif end do diff --git a/src/biogeophys/TotalWaterAndHeatMod.F90 b/src/biogeophys/TotalWaterAndHeatMod.F90 index bfeea81949..885222f33b 100644 --- a/src/biogeophys/TotalWaterAndHeatMod.F90 +++ b/src/biogeophys/TotalWaterAndHeatMod.F90 @@ -358,7 +358,8 @@ subroutine AccumulateSoilLiqIceMassNonLake(bounds, num_c, filter_c, & associate( & h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice lens (kg/m2) - h2osoi_liq => waterstate_inst%h2osoi_liq_col & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) + h2osoi_liq => waterstate_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) + excess_ice => waterstate_inst%excess_ice_col & ! Input [real(r8) (:,:) ] excess ice (kg/m2) ) do j = 1, nlevmaxurbgrnd @@ -382,7 +383,7 @@ subroutine AccumulateSoilLiqIceMassNonLake(bounds, num_c, filter_c, & if (has_h2o) then liquid_mass(c) = liquid_mass(c) + h2osoi_liq(c,j) - ice_mass(c) = ice_mass(c) + h2osoi_ice(c,j) + ice_mass(c) = ice_mass(c) + h2osoi_ice(c,j) + excess_ice(c,j) end if end do end do diff --git a/src/biogeophys/UrbanFluxesMod.F90 b/src/biogeophys/UrbanFluxesMod.F90 index d02433a5bb..74f0d2612d 100644 --- a/src/biogeophys/UrbanFluxesMod.F90 +++ b/src/biogeophys/UrbanFluxesMod.F90 @@ -146,6 +146,7 @@ subroutine UrbanFluxes (bounds, num_nourbanl, filter_nourbanl, real(r8) :: dth(bounds%begl:bounds%endl) ! diff of virtual temp. between ref. height and surface real(r8) :: dqh(bounds%begl:bounds%endl) ! diff of humidity between ref. height and surface real(r8) :: zldis(bounds%begl:bounds%endl) ! reference height "minus" zero displacement height (m) + real(r8) :: zeta_lunit(bounds%begl:bounds%endl) ! landunit-level dimensionless stability parameter real(r8) :: um(bounds%begl:bounds%endl) ! wind speed including the stablity effect (m/s) real(r8) :: obu(bounds%begl:bounds%endl) ! Monin-Obukhov length (m) real(r8) :: taf_numer(bounds%begl:bounds%endl) ! numerator of taf equation (K m/s) @@ -187,7 +188,6 @@ subroutine UrbanFluxes (bounds, num_nourbanl, filter_nourbanl, real(r8) :: wtus_shadewall_unscl(bounds%begl:bounds%endl) ! sensible heat conductance for shadewall (not scaled) (m/s) real(r8) :: wtuq_shadewall_unscl(bounds%begl:bounds%endl) ! latent heat conductance for shadewall (not scaled) (m/s) real(r8) :: wc ! convective velocity (m/s) - real(r8) :: zeta ! dimensionless height used in Monin-Obukhov theory real(r8) :: eflx_sh_grnd_scale(bounds%begp:bounds%endp) ! scaled sensible heat flux from ground (W/m**2) [+ to atm] real(r8) :: qflx_evap_soi_scale(bounds%begp:bounds%endp) ! scaled soil evaporation (mm H2O/s) (+ = to atm) real(r8) :: eflx_wasteheat_roof(bounds%begl:bounds%endl) ! sensible heat flux from urban heating/cooling sources of waste heat for roof (W/m**2) @@ -293,6 +293,7 @@ subroutine UrbanFluxes (bounds, num_nourbanl, filter_nourbanl, forc_hgt_u_patch => frictionvel_inst%forc_hgt_u_patch , & ! Input: [real(r8) (:) ] observational height of wind at patch-level (m) forc_hgt_t_patch => frictionvel_inst%forc_hgt_t_patch , & ! Input: [real(r8) (:) ] observational height of temperature at patch-level (m) zetamax => frictionvel_inst%zetamaxstable , & ! Input: [real(r8) ] max zeta value under stable conditions + zeta => frictionvel_inst%zeta_patch , & ! Output: [real(r8) (:) ] dimensionless stability parameter ram1 => frictionvel_inst%ram1_patch , & ! Output: [real(r8) (:) ] aerodynamical resistance (s/m) u10_clm => frictionvel_inst%u10_clm_patch , & ! Input: [real(r8) (:) ] 10 m height winds (m/s) @@ -652,18 +653,18 @@ subroutine UrbanFluxes (bounds, num_nourbanl, filter_nourbanl, tstar = temp1(l)*dth(l) qstar = temp2(l)*dqh(l) thvstar = tstar*(1._r8+0.61_r8*forc_q(g)) + 0.61_r8*forc_th(g)*qstar - zeta = zldis(l)*vkc*grav*thvstar/(ustar(l)**2*thv_g(l)) + zeta_lunit(l) = zldis(l)*vkc*grav*thvstar/(ustar(l)**2*thv_g(l)) - if (zeta >= 0._r8) then !stable - zeta = min(zetamax,max(zeta,0.01_r8)) + if (zeta_lunit(l) >= 0._r8) then !stable + zeta_lunit(l) = min(zetamax,max(zeta_lunit(l),0.01_r8)) um(l) = max(ur(l),0.1_r8) else !unstable - zeta = max(-100._r8,min(zeta,-0.01_r8)) + zeta_lunit(l) = max(-100._r8,min(zeta_lunit(l),-0.01_r8)) wc = beta(l)*(-grav*ustar(l)*thvstar*zii(l)/thv_g(l))**0.333_r8 um(l) = sqrt(ur(l)*ur(l) + wc*wc) end if - obu(l) = zldis(l)/zeta + obu(l) = zldis(l)/zeta_lunit(l) end do end do ! end iteration @@ -682,7 +683,8 @@ subroutine UrbanFluxes (bounds, num_nourbanl, filter_nourbanl, g = patch%gridcell(p) l = patch%landunit(p) - ram1(p) = ramu(l) !pass value to global variable + ram1(p) = ramu(l) !pass value to global variable + zeta(p) = zeta_lunit(l) !pass value to global variable ! Upward and downward canopy longwave are zero diff --git a/src/biogeophys/WaterDiagnosticBulkType.F90 b/src/biogeophys/WaterDiagnosticBulkType.F90 index f7918d38cb..d0b1723a44 100644 --- a/src/biogeophys/WaterDiagnosticBulkType.F90 +++ b/src/biogeophys/WaterDiagnosticBulkType.F90 @@ -17,7 +17,7 @@ module WaterDiagnosticBulkType use decompMod , only : bounds_type use abortutils , only : endrun use clm_varctl , only : use_cn, iulog, use_luna, use_hillslope - use clm_varpar , only : nlevgrnd, nlevsno, nlevcan + use clm_varpar , only : nlevgrnd, nlevsno, nlevcan, nlevsoi use clm_varcon , only : spval use LandunitType , only : lun use ColumnType , only : col @@ -42,12 +42,16 @@ module WaterDiagnosticBulkType real(r8), pointer :: snowdp_col (:) ! col area-averaged snow height (m) real(r8), pointer :: snow_layer_unity_col (:,:) ! value 1 for each snow layer, used for history diagnostics real(r8), pointer :: bw_col (:,:) ! col partial density of water in the snow pack (ice + liquid) [kg/m3] - + real(r8), pointer :: snomelt_accum_col (:) ! accumulated col snow melt for z0m calculation (m H2O) real(r8), pointer :: h2osoi_liq_tot_col (:) ! vertically summed col liquid water (kg/m2) (new) (-nlevsno+1:nlevgrnd) real(r8), pointer :: h2osoi_ice_tot_col (:) ! vertically summed col ice lens (kg/m2) (new) (-nlevsno+1:nlevgrnd) real(r8), pointer :: air_vol_col (:,:) ! col air filled porosity real(r8), pointer :: h2osoi_liqvol_col (:,:) ! col volumetric liquid water content (v/v) real(r8), pointer :: swe_old_col (:,:) ! col initial snow water + real(r8), pointer :: exice_subs_tot_col (:) ! col total subsidence due to excess ice melt (m) + real(r8), pointer :: exice_subs_col (:,:) ! col per layer subsidence due to excess ice melt (m) + real(r8), pointer :: exice_vol_col (:,:) ! col per layer volumetric excess ice content (m3/m3) + real(r8), pointer :: exice_vol_tot_col (:) ! col averaged volumetric excess ice content (m3/m3) real(r8), pointer :: snw_rds_col (:,:) ! col snow grain radius (col,lyr) [m^-6, microns] real(r8), pointer :: snw_rds_top_col (:) ! col snow grain radius (top layer) [m^-6, microns] @@ -169,6 +173,7 @@ subroutine InitBulkAllocate(this, bounds) ! ! !USES: use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) + use clm_varpar , only : nlevmaxurbgrnd ! ! !ARGUMENTS: class(waterdiagnosticbulk_type), intent(inout) :: this @@ -190,6 +195,7 @@ subroutine InitBulkAllocate(this, bounds) allocate(this%snow_depth_col (begc:endc)) ; this%snow_depth_col (:) = nan allocate(this%snow_5day_col (begc:endc)) ; this%snow_5day_col (:) = nan allocate(this%snowdp_col (begc:endc)) ; this%snowdp_col (:) = nan + allocate(this%snomelt_accum_col (begc:endc)) ; this%snomelt_accum_col (:) = nan allocate(this%snow_layer_unity_col (begc:endc,-nlevsno+1:0)) ; this%snow_layer_unity_col (:,:) = nan allocate(this%bw_col (begc:endc,-nlevsno+1:0)) ; this%bw_col (:,:) = nan allocate(this%air_vol_col (begc:endc, 1:nlevgrnd)) ; this%air_vol_col (:,:) = nan @@ -197,6 +203,10 @@ subroutine InitBulkAllocate(this, bounds) allocate(this%h2osoi_ice_tot_col (begc:endc)) ; this%h2osoi_ice_tot_col (:) = nan allocate(this%h2osoi_liq_tot_col (begc:endc)) ; this%h2osoi_liq_tot_col (:) = nan allocate(this%swe_old_col (begc:endc,-nlevsno+1:0)) ; this%swe_old_col (:,:) = nan + allocate(this%exice_subs_tot_col (begc:endc)) ; this%exice_subs_tot_col (:) = 0.0_r8 + allocate(this%exice_subs_col (begc:endc, 1:nlevmaxurbgrnd)) ; this%exice_subs_col (:,:) = 0.0_r8 + allocate(this%exice_vol_col (begc:endc, 1:nlevsoi)) ; this%exice_vol_col (:,:) = 0.0_r8 + allocate(this%exice_vol_tot_col (begc:endc)) ; this%exice_vol_tot_col (:) = 0.0_r8 allocate(this%snw_rds_col (begc:endc,-nlevsno+1:0)) ; this%snw_rds_col (:,:) = nan allocate(this%snw_rds_top_col (begc:endc)) ; this%snw_rds_top_col (:) = nan @@ -237,6 +247,7 @@ subroutine InitBulkHistory(this, bounds) ! !USES: use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use histFileMod , only : hist_addfld1d, hist_addfld2d, no_snow_normal, no_snow_zero + use clm_varctl , only : use_excess_ice ! ! !ARGUMENTS: class(waterdiagnosticbulk_type), intent(in) :: this @@ -283,8 +294,28 @@ subroutine InitBulkHistory(this, bounds) fname=this%info%fname('TOTSOILICE'), & units='kg/m2', & avgflag='A', & - long_name=this%info%lname('vertically summed soil cie (veg landunits only)'), & + long_name=this%info%lname('vertically summed soil ice (veg landunits only)'), & ptr_col=this%h2osoi_ice_tot_col, l2g_scale_type='veg') + ! excess ice vars + if (use_excess_ice) then + this%exice_vol_tot_col(begc:endc) = 0.0_r8 + call hist_addfld1d ( & + fname=this%info%fname('TOTEXICE_VOL'), & + units='m3/m3', & + avgflag='A', & + l2g_scale_type='veg', & + long_name=this%info%lname('vertically averaged volumetric excess ice concentration (veg landunits only)'), & + ptr_col=this%exice_vol_tot_col) + + this%exice_subs_tot_col(begc:endc) = 0.0_r8 + call hist_addfld1d ( & + fname=this%info%fname('SUBSIDENCE'), & + units='m', & + avgflag='SUM', & + l2g_scale_type='veg', & + long_name=this%info%lname('subsidence due to excess ice melt (veg landunits only)'), & + ptr_col=this%exice_subs_tot_col) + end if this%iwue_ln_patch(begp:endp) = spval call hist_addfld1d ( & @@ -458,6 +489,14 @@ subroutine InitBulkHistory(this, bounds) long_name=this%info%lname('gridcell mean snow height'), & ptr_col=this%snowdp_col, c2l_scale_type='urbanf') + this%snomelt_accum_col(begc:endc) = 0._r8 + call hist_addfld1d ( & ! Have this as an output variable for now to check + fname=this%info%fname('SNOMELT_ACCUM'), & + units='m', & + avgflag='A', & + long_name=this%info%lname('accumulated snow melt for z0'), & + ptr_col=this%snomelt_accum_col, c2l_scale_type='urbanf') + if (use_cn) then this%wf_col(begc:endc) = spval call hist_addfld1d ( & @@ -755,9 +794,10 @@ subroutine RestartBulk(this, bounds, ncid, flag, writing_finidat_interp_dest_fil use spmdMod , only : masterproc use clm_varcon , only : pondmx, watmin, spval, nameg use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall - use clm_varctl , only : bound_h2osoi + use clm_varctl , only : bound_h2osoi, use_excess_ice, nsrest, nsrContinue use ncdio_pio , only : file_desc_t, ncd_io, ncd_double use restUtilMod + use ExcessIceStreamType, only : UseExcessIceStreams ! ! !ARGUMENTS: class(waterdiagnosticbulk_type), intent(inout) :: this @@ -769,6 +809,7 @@ subroutine RestartBulk(this, bounds, ncid, flag, writing_finidat_interp_dest_fil ! ! !LOCAL VARIABLES: logical :: readvar + logical :: excess_ice_on_restart !------------------------------------------------------------------------ @@ -800,6 +841,18 @@ subroutine RestartBulk(this, bounds, ncid, flag, writing_finidat_interp_dest_fil units='m', & interpinic_flag='interp', readvar=readvar, data=this%snow_depth_col) + call restartvar(ncid=ncid, flag=flag, & + varname=this%info%fname('SNOMELT_ACCUM'), & + xtype=ncd_double, & + dim1name='column', & + long_name=this%info%lname('accumulated snow melt for z0'), & + units='m', & + interpinic_flag='interp', readvar=readvar, data=this%snomelt_accum_col) + if (flag == 'read' .and. .not. readvar) then + ! initial run, not restart: initialize snomelt_accum_col to zero + this%snomelt_accum_col(bounds%begc:bounds%endc) = 0._r8 + endif + call restartvar(ncid=ncid, flag=flag, & varname=this%info%fname('frac_sno_eff'), & xtype=ncd_double, & @@ -889,7 +942,52 @@ subroutine RestartBulk(this, bounds, ncid, flag, writing_finidat_interp_dest_fil interpinic_flag='interp', readvar=readvar, data=this%wf_col) end if - + if (.not. use_excess_ice) then + ! no need to even define the restart vars + this%exice_subs_tot_col(bounds%begc:bounds%endc)=0.0_r8 + this%exice_vol_tot_col(bounds%begc:bounds%endc)=0.0_r8 + this%exice_subs_col(bounds%begc:bounds%endc,1:nlevgrnd)=0.0_r8 + this%exice_vol_col(bounds%begc:bounds%endc,1:nlevsoi)=0.0_r8 + else + ! initialization of these to zero is ok, since they might not be in the restart file + this%exice_subs_col(bounds%begc:bounds%endc,1:nlevgrnd)=0.0_r8 + this%exice_vol_col(bounds%begc:bounds%endc,1:nlevsoi)=0.0_r8 + call RestartExcessIceIssue( & + ncid = ncid, & + flag = flag, & + excess_ice_on_restart = excess_ice_on_restart) + ! have to at least define them + call restartvar(ncid=ncid, flag=flag, varname=this%info%fname('SUBSIDENCE'), & + dim1name='column', xtype=ncd_double, & + long_name=this%info%lname('vertically summed volumetric excess ice concentration (veg landunits only)'), & + units='m', & + interpinic_flag='interp', readvar=readvar, data=this%exice_subs_tot_col) + if (flag == 'read' .and. ((.not. readvar) .or. (.not. excess_ice_on_restart)) ) then ! when reading restart that does not have excess ice in it + if (nsrest == nsrContinue) then + call endrun(msg = "On a continue run, excess ice fields MUST be on the restart file "// & + errMsg(sourcefile, __LINE__)) + else if ( .not. UseExcessIceStreams() )then + call endrun(msg = "This input initial conditions file does NOT include excess ice fields" // & + ", and use_excess_ice_streams is off, one or the other needs to be changed "// & + errMsg(sourcefile, __LINE__)) + end if + this%exice_subs_tot_col(bounds%begc:bounds%endc)=0.0_r8 + this%exice_vol_tot_col(bounds%begc:bounds%endc)=0.0_r8 + this%exice_subs_col(bounds%begc:bounds%endc,1:nlevgrnd)=0.0_r8 + this%exice_vol_col(bounds%begc:bounds%endc,1:nlevsoi)=0.0_r8 + endif + call restartvar(ncid=ncid, flag=flag, varname=this%info%fname('TOTEXICE_VOL'), & + dim1name='column', xtype=ncd_double, & + long_name=this%info%lname('vertically averaged volumetric excess ice concentration (veg landunits only)'), & + units='m3/m3', & + interpinic_flag='interp', readvar=readvar, data=this%exice_vol_tot_col) + if (flag == 'read' .and. ((.not. readvar) .or. (.not. excess_ice_on_restart)) ) then ! when reading restart that does not have excess ice in it + if (nsrest == nsrContinue) then + call endrun(msg = "On a continue run, excess ice fields MUST be on the restart file "// & + errMsg(sourcefile, __LINE__)) + end if + end if + endif end subroutine RestartBulk @@ -995,7 +1093,8 @@ subroutine Summary(this, bounds, & ! Compute end-of-timestep summaries of water diagnostic terms ! ! !USES: - use clm_varpar , only : nlevsoi + use clm_varcon , only : denice + use landunit_varcon, only : istsoil, istcrop ! !ARGUMENTS: class(waterdiagnosticbulk_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds @@ -1011,6 +1110,8 @@ subroutine Summary(this, bounds, & ! !LOCAL VARIABLES: integer :: fp, p, j, l, fc, c ! Indices real(r8):: fracl ! fraction of soil layer contributing to 10cm total soil water + real(r8):: dz_ext ! extended layer thickness due to excess ice + real(r8):: dz_tot ! total depth with extended thicknesses character(len=*), parameter :: subname = 'Summary' !----------------------------------------------------------------------- @@ -1020,10 +1121,15 @@ subroutine Summary(this, bounds, & h2osoi_ice => waterstate_inst%h2osoi_ice_col, & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) h2osoi_liq => waterstate_inst%h2osoi_liq_col, & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) + excess_ice => waterstate_inst%excess_ice_col, & ! Input: [real(r8) (:,:) ] excess ice lenses (kg/m2) (new) (1:nlevgrnd) + exice_subs_col => this%exice_subs_col , & ! Output: [real(r8) (:,:) ] per layer subsidence due to excess ice melt (m) + exice_vol_col => this%exice_vol_col , & ! Output: [real(r8) (:,:) ] per layer volumetric excess ice content (m3/m3) h2osoi_ice_tot => this%h2osoi_ice_tot_col , & ! Output: [real(r8) (:) ] vertically summed ice lens (kg/m2) h2osoi_liq_tot => this%h2osoi_liq_tot_col , & ! Output: [real(r8) (:) ] vertically summed liquid water (kg/m2) - h2osoi_liqice_10cm => this%h2osoi_liqice_10cm_col & ! Output: [real(r8) (:) ] liquid water + ice lens in top 10cm of soil (kg/m2) + h2osoi_liqice_10cm => this%h2osoi_liqice_10cm_col , & ! Output: [real(r8) (:) ] liquid water + ice lens in top 10cm of soil (kg/m2) + exice_subs_tot_col => this%exice_subs_tot_col , & ! Output [real(r8) (:) ] vertically summed subsidence due to excess ice melt (m) + exice_vol_tot_col => this%exice_vol_tot_col & ! Output [real(r8) (:) ] vertically averaged volumetric excess ice content (m3/m3) ) call this%waterdiagnostic_type%Summary(bounds, & @@ -1056,6 +1162,7 @@ subroutine Summary(this, bounds, & h2osoi_liqice_10cm(c) = 0.0_r8 h2osoi_liq_tot(c) = 0._r8 h2osoi_ice_tot(c) = 0._r8 + exice_subs_tot_col(c) = 0._r8 end if end do do j = 1, nlevsoi @@ -1078,10 +1185,31 @@ subroutine Summary(this, bounds, & end if h2osoi_liq_tot(c) = h2osoi_liq_tot(c) + h2osoi_liq(c,j) h2osoi_ice_tot(c) = h2osoi_ice_tot(c) + h2osoi_ice(c,j) + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + exice_subs_tot_col(c) = exice_subs_tot_col(c) + exice_subs_col(c,j) + endif end if end do end do + do fc = 1, num_nolakec ! extra loop needed since the one above has outer loop with layers + c = filter_nolakec(fc) + l = col%landunit(c) + if (.not. lun%urbpoi(l)) then + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + dz_tot = 0.0_r8 + exice_vol_tot_col(c)=0.0_r8 + do j = 1, nlevsoi + dz_ext = dz(c,j)+excess_ice(c,j)/denice + exice_vol_col(c,j)=excess_ice(c,j)/(denice*dz_ext) + dz_tot=dz_tot+dz_ext + exice_vol_tot_col(c)=exice_vol_tot_col(c)+exice_vol_col(c,j)*dz_ext ! (m) + enddo + exice_vol_tot_col(c)=exice_vol_tot_col(c)/dz_tot ! (m3/m3) + end if + end if + end do + end associate end subroutine Summary diff --git a/src/biogeophys/WaterDiagnosticType.F90 b/src/biogeophys/WaterDiagnosticType.F90 index 7fa76b42b0..57be0e62af 100644 --- a/src/biogeophys/WaterDiagnosticType.F90 +++ b/src/biogeophys/WaterDiagnosticType.F90 @@ -164,13 +164,7 @@ subroutine InitHistory(this, bounds) begc = bounds%begc; endc= bounds%endc begg = bounds%begg; endg= bounds%endg - this%h2ocan_patch(begp:endp) = spval - call hist_addfld1d ( & - fname=this%info%fname('H2OCAN'), & - units='mm', & - avgflag='A', & - long_name=this%info%lname('intercepted water'), & - ptr_patch=this%h2ocan_patch) + this%h2osoi_liqice_10cm_col(begc:endc) = spval call hist_addfld1d ( & @@ -205,8 +199,15 @@ subroutine InitHistory(this, bounds) long_name=this%info%lname('2m specific humidity'), & ptr_patch=this%q_ref2m_patch) + this%h2ocan_patch(begp:endp) = spval + call hist_addfld1d ( & + fname=this%info%fname('H2OCAN'), & + units='mm', & + avgflag='A', & + long_name=this%info%lname('intercepted water'), & + ptr_patch=this%h2ocan_patch) - + ! Snow properties - these will be vertically averaged over the snow profile this%snowliq_col(begc:endc) = spval diff --git a/src/biogeophys/WaterStateBulkType.F90 b/src/biogeophys/WaterStateBulkType.F90 index 5c0298c8d5..ba3f0513c5 100644 --- a/src/biogeophys/WaterStateBulkType.F90 +++ b/src/biogeophys/WaterStateBulkType.F90 @@ -47,17 +47,17 @@ module WaterStateBulkType !------------------------------------------------------------------------ subroutine InitBulk(this, bounds, info, vars, & - h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer) + h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer, NLFilename) class(waterstatebulk_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds class(water_info_base_type), intent(in), target :: info type(water_tracer_container_type), intent(inout) :: vars real(r8) , intent(in) :: h2osno_input_col(bounds%begc:) - real(r8) , intent(in) :: watsat_col(bounds%begc:, 1:) ! volumetric soil water at saturation (porosity) + real(r8) , intent(in) :: watsat_col(bounds%begc:, 1:) ! volumetric soil water at saturation (porosity) real(r8) , intent(in) :: t_soisno_col(bounds%begc:, -nlevsno+1:) ! col soil temperature (Kelvin) - logical , intent(in) :: use_aquifer_layer ! whether an aquifer layer is used in this run - + logical , intent(in) :: use_aquifer_layer ! whether an aquifer layer is used in this run + character(len=*) , intent(in) :: NLFilename ! Namelist filename call this%Init(bounds = bounds, & info = info, & @@ -65,7 +65,8 @@ subroutine InitBulk(this, bounds, info, vars, & h2osno_input_col = h2osno_input_col, & watsat_col = watsat_col, & t_soisno_col = t_soisno_col, & - use_aquifer_layer = use_aquifer_layer) + use_aquifer_layer = use_aquifer_layer, & + NLFilename = NLFilename) call this%InitBulkAllocate(bounds) @@ -187,7 +188,7 @@ end subroutine InitBulkCold !------------------------------------------------------------------------ subroutine RestartBulk(this, bounds, ncid, flag, & - watsat_col) + watsat_col, t_soisno_col, altmax_lastyear_indx) ! ! !DESCRIPTION: ! Read/Write module information to/from restart file. @@ -199,9 +200,11 @@ subroutine RestartBulk(this, bounds, ncid, flag, & ! !ARGUMENTS: class(waterstatebulk_type), intent(in) :: this type(bounds_type), intent(in) :: bounds - type(file_desc_t), intent(inout) :: ncid ! netcdf id - character(len=*) , intent(in) :: flag ! 'read' or 'write' - real(r8) , intent(in) :: watsat_col (bounds%begc:, 1:) ! volumetric soil water at saturation (porosity) + type(file_desc_t), intent(inout) :: ncid ! netcdf id + character(len=*) , intent(in) :: flag ! 'read' or 'write' + real(r8) , intent(in) :: watsat_col (bounds%begc:, 1:) ! volumetric soil water at saturation (porosity) + real(r8) , intent(in) :: t_soisno_col(bounds%begc:, -nlevsno+1:) ! col soil temperature (Kelvin) + integer , intent(in) :: altmax_lastyear_indx(bounds%begc:) !col active layer index last year ! ! !LOCAL VARIABLES: integer :: c,l,j @@ -211,7 +214,9 @@ subroutine RestartBulk(this, bounds, ncid, flag, & SHR_ASSERT_ALL_FL((ubound(watsat_col) == (/bounds%endc,nlevmaxurbgrnd/)) , sourcefile, __LINE__) call this%restart (bounds, ncid, flag=flag, & - watsat_col=watsat_col(bounds%begc:bounds%endc,:)) + watsat_col=watsat_col(bounds%begc:bounds%endc,:), & + t_soisno_col=t_soisno_col(bounds%begc:, -nlevsno+1:), & + altmax_lastyear_indx=altmax_lastyear_indx(bounds%begc:)) call restartvar(ncid=ncid, flag=flag, & diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 6424613d9e..ca120ce8c2 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -13,8 +13,9 @@ module WaterStateType use abortutils , only : endrun use decompMod , only : bounds_type use decompMod , only : subgrid_level_patch, subgrid_level_column, subgrid_level_landunit, subgrid_level_gridcell - use clm_varctl , only : use_bedrock, iulog - use clm_varctl , only : use_fates, use_hillslope + use clm_varctl , only : use_bedrock, use_excess_ice, iulog + use spmdMod , only : masterproc + use clm_varctl , only : use_fates use clm_varpar , only : nlevgrnd, nlevsoi, nlevurb, nlevmaxurbgrnd, nlevsno use clm_varcon , only : spval use LandunitType , only : lun @@ -22,6 +23,7 @@ module WaterStateType use WaterInfoBaseType, only : water_info_base_type use WaterTracerContainerType, only : water_tracer_container_type use WaterTracerUtils, only : AllocateVar1d, AllocateVar2d + use ExcessIceStreamType, only : excessicestream_type, UseExcessIceStreams ! implicit none save @@ -46,10 +48,15 @@ module WaterStateType ! For the following dynbal baseline variables: positive values are subtracted to ! avoid counting liquid water content of "virtual" states; negative values are added ! to account for missing states in the model. - real(r8), pointer :: dynbal_baseline_liq_col(:) ! baseline liquid water content subtracted from each column's total liquid water calculation (mm H2O) - real(r8), pointer :: dynbal_baseline_ice_col(:) ! baseline ice content subtracted from each column's total ice calculation (mm H2O) + real(r8), pointer :: dynbal_baseline_liq_col(:) ! baseline liquid water content subtracted from each column's total liquid water calculation (mm H2O) + real(r8), pointer :: dynbal_baseline_ice_col(:) ! baseline ice content subtracted from each column's total ice calculation (mm H2O) - real(r8) :: aquifer_water_baseline ! baseline value for water in the unconfined aquifer (wa_col) for this bulk / tracer (mm) + real(r8) :: aquifer_water_baseline ! baseline value for water in the unconfined aquifer (wa_col) for this bulk / tracer (mm) + + real(r8), pointer :: excess_ice_col (:,:) ! col excess ice (kg/m2) (new) (-nlevsno+1:nlevgrnd) + real(r8), pointer :: exice_bulk_init (:) ! inital value for excess ice (new) (unitless) + + type(excessicestream_type), private :: exicestream ! stream type for excess ice initialization NUOPC only ! Hillslope stream variables real(r8), pointer :: stream_water_volume_lun(:) ! landunit volume of water in the streams (m3) @@ -75,7 +82,7 @@ module WaterStateType !------------------------------------------------------------------------ subroutine Init(this, bounds, info, tracer_vars, & - h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer) + h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer, NLFilename) class(waterstate_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds @@ -85,18 +92,19 @@ subroutine Init(this, bounds, info, tracer_vars, & real(r8) , intent(in) :: watsat_col(bounds%begc:, 1:) ! volumetric soil water at saturation (porosity) real(r8) , intent(in) :: t_soisno_col(bounds%begc:, -nlevsno+1:) ! col soil temperature (Kelvin) logical , intent(in) :: use_aquifer_layer ! whether an aquifer layer is used in this run + character(len=*) , intent(in) :: NLFilename ! Namelist filename this%info => info call this%InitAllocate(bounds, tracer_vars) call this%InitHistory(bounds, use_aquifer_layer) - call this%InitCold(bounds = bounds, & - h2osno_input_col = h2osno_input_col, & - watsat_col = watsat_col, & - t_soisno_col = t_soisno_col, & - use_aquifer_layer = use_aquifer_layer) + h2osno_input_col = h2osno_input_col, & + watsat_col = watsat_col, & + t_soisno_col = t_soisno_col, & + use_aquifer_layer = use_aquifer_layer, & + NLFilename = NLFilename) end subroutine Init @@ -156,6 +164,14 @@ subroutine InitAllocate(this, bounds, tracer_vars) call AllocateVar1d(var = this%stream_water_volume_lun, name = 'stream_water_volume_lun', & container = tracer_vars, & bounds = bounds, subgrid_level = subgrid_level_landunit) + !excess ice vars + call AllocateVar2d(var = this%excess_ice_col, name = 'excess_ice_col', & + container = tracer_vars, & + bounds = bounds, subgrid_level = subgrid_level_column, & + dim2beg = -nlevsno+1, dim2end = nlevmaxurbgrnd) + call AllocateVar1d(var = this%exice_bulk_init, name = 'exice_bulk_init', & + container = tracer_vars, & + bounds = bounds, subgrid_level = subgrid_level_column) end subroutine InitAllocate @@ -285,6 +301,13 @@ subroutine InitHistory(this, bounds, use_aquifer_layer) long_name=this%info%lname('volume of water in stream channel (hillslope hydrology only)'), & ptr_lunit=this%stream_water_volume_lun, l2g_scale_type='natveg', default='inactive') + ! Add excess ice fields to history + + if (use_excess_ice) then + data2dptr => this%excess_ice_col(begc:endc,1:nlevsoi) + call hist_addfld2d (fname='EXCESS_ICE', units='kg/m2', type2d='levsoi', & + avgflag='A', long_name='excess soil ice (vegetated landunits only)', & + ptr_col=this%excess_ice_col, l2g_scale_type='veg', default = 'inactive') end if ! (rgk 02-02-2017) There is intentionally no entry here for stored plant water @@ -300,7 +323,7 @@ end subroutine InitHistory !----------------------------------------------------------------------- subroutine InitCold(this, bounds, & - h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer) + h2osno_input_col, watsat_col, t_soisno_col, use_aquifer_layer, NLFilename) ! ! !DESCRIPTION: ! Initialize time constant variables and cold start conditions @@ -309,20 +332,22 @@ subroutine InitCold(this, bounds, & use shr_const_mod , only : SHR_CONST_TKFRZ use landunit_varcon , only : istwet, istsoil, istcrop, istice use column_varcon , only : icol_road_perv, icol_road_imperv - use clm_varcon , only : denice, denh2o, bdsno + use clm_varcon , only : denice, denh2o, bdsno , zisoi use clm_varcon , only : tfrz, aquifer_water_baseline + use initVerticalMod , only : find_soil_layer_containing_depth ! ! !ARGUMENTS: class(waterstate_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds real(r8) , intent(in) :: h2osno_input_col(bounds%begc:) - real(r8) , intent(in) :: watsat_col(bounds%begc:, 1:) ! volumetric soil water at saturation (porosity) + real(r8) , intent(in) :: watsat_col(bounds%begc:, 1:) ! volumetric soil water at saturation (porosity) real(r8) , intent(in) :: t_soisno_col(bounds%begc:, -nlevsno+1:) ! col soil temperature (Kelvin) - logical , intent(in) :: use_aquifer_layer ! whether an aquifer layer is used in this run + logical , intent(in) :: use_aquifer_layer ! whether an aquifer layer is used in this run + character(len=*) , intent(in) :: NLFilename ! Namelist filename ! ! !LOCAL VARIABLES: - integer :: c,j,l,nlevs - integer :: nbedrock + integer :: c,j,l,nlevs,g + integer :: nbedrock, n05m ! layer containing 0.5 m real(r8) :: ratio !----------------------------------------------------------------------- @@ -359,7 +384,7 @@ subroutine InitCold(this, bounds, & if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then nlevs = nlevgrnd do j = 1, nlevs - if (use_bedrock) then + if (use_bedrock .and. col%nbedrock(c) <=nlevsoi) then nbedrock = col%nbedrock(c) else nbedrock = nlevsoi @@ -524,39 +549,91 @@ subroutine InitCold(this, bounds, & this%dynbal_baseline_liq_col(bounds%begc:bounds%endc) = 0._r8 this%dynbal_baseline_ice_col(bounds%begc:bounds%endc) = 0._r8 + !Initialize excess ice + if (use_excess_ice .and. NLFilename /= '') then + ! enforce initialization with 0 for everything + this%excess_ice_col(bounds%begc:bounds%endc,-nlevsno+1:nlevmaxurbgrnd)=0.0_r8 + this%exice_bulk_init(bounds%begc:bounds%endc)=0.0_r8 + call this%exicestream%Init(bounds, NLFilename) ! get initial fraction of excess ice per column + ! + ! If excess ice is being read from streams, use the streams to + ! initialize + ! + if ( UseExcessIceStreams() )then + call this%exicestream%CalcExcessIce(bounds, this%exice_bulk_init) + do c = bounds%begc,bounds%endc + g = col%gridcell(c) + l = col%landunit(c) + if (.not. lun%lakpoi(l)) then !not lake + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + if (zisoi(nlevsoi) >= 0.5_r8) then + call find_soil_layer_containing_depth(0.5_r8,n05m) + else + n05m=nlevsoi-1 + endif + if (use_bedrock .and. col%nbedrock(c) <=nlevsoi) then + nbedrock = col%nbedrock(c) + else + nbedrock = nlevsoi + endif + do j = 2, nlevmaxurbgrnd ! ignore first layer + if (n05m= n05m .and. jnlevsoi) then + nbedrock = col%nbedrock(c) + else + nbedrock = nlevsoi + end if + do j = 2, nlevmaxurbgrnd ! ignore first layer + if(altmax_lastyear_indx(c) < nbedrock) then + if (j>altmax_lastyear_indx(c) .and. j shr_kind_r8, CL => shr_kind_CL + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : mpicom, masterproc + use clm_varctl , only : iulog + use abortutils , only : endrun + use decompMod , only : bounds_type + + ! !PUBLIC TYPES: + implicit none + private + + public :: UseExcessIceStreams ! If streams will be used + + type, public :: excessicestream_type + contains + + ! !PUBLIC MEMBER FUNCTIONS: + procedure, public :: Init ! Initialize and read data in + procedure, public :: CalcExcessIce ! Calculate excess ice ammount + + ! !PRIVATE MEMBER FUNCTIONS: + procedure, private :: ReadNML ! Read in namelist + + end type excessicestream_type + ! ! PRIVATE DATA: + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + +!============================================================================== +contains +!============================================================================== + + subroutine Init(this, bounds, NLFilename) + ! + ! + ! arguments + implicit none + class(excessicestream_type) :: this + type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: NLFilename ! Namelist filename + + ! + ! local variables + + call this%ReadNML( bounds, NLFileName ) + end subroutine Init + + subroutine CalcExcessIce(this,bounds,exice_bulk_init) + + ! only transfers grid values to columns + implicit none + class(excessicestream_type) :: this + type(bounds_type), intent(in) :: bounds + real(r8) , intent(inout) :: exice_bulk_init(bounds%begc:bounds%endc) + ! + ! !LOCAL VARIABLES: + + end subroutine CalcExcessIce + + logical function UseExcessIceStreams() + ! + ! !DESCRIPTION: + ! Return true if + ! + ! !USES: + ! + ! !ARGUMENTS: + implicit none + ! + ! !LOCAL VARIABLES: + UseExcessIceStreams = .false. +end function UseExcessIceStreams + +subroutine ReadNML(this, bounds, NLFilename) + ! + ! Read the namelist data stream information. + ! + ! Uses: + use shr_nl_mod , only : shr_nl_find_group_name + use shr_log_mod , only : errMsg => shr_log_errMsg + use shr_mpi_mod , only : shr_mpi_bcast + ! + ! arguments + implicit none + class(excessicestream_type) :: this + type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: NLFilename ! Namelist filename + ! + ! local variables + integer :: nu_nml ! unit for namelist file + integer :: nml_error ! namelist i/o error flag + logical :: use_excess_ice_streams = .false. ! logical to turn on use of excess ice streams + character(len=CL) :: stream_fldFileName_exice = ' ' + character(len=CL) :: stream_mapalgo_exice = 'none' + character(len=*), parameter :: namelist_name = 'exice_streams' ! MUST agree with name in namelist and read + character(len=*), parameter :: subName = "('exice_streams::ReadNML')" + !----------------------------------------------------------------------- + + namelist /exice_streams/ & ! MUST agree with namelist_name above + stream_mapalgo_exice, stream_fldFileName_exice, use_excess_ice_streams + !----------------------------------------------------------------------- + ! Default values for namelist + + ! Read excess ice namelist + if (masterproc) then + open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) + call shr_nl_find_group_name(nu_nml, namelist_name, status=nml_error) + if (nml_error == 0) then + read(nu_nml, nml=exice_streams,iostat=nml_error) ! MUST agree with namelist_name above + if (nml_error /= 0) then + call endrun(msg=' ERROR reading '//namelist_name//' namelist'//errMsg(sourcefile, __LINE__)) + end if + else + call endrun(msg=' ERROR finding '//namelist_name//' namelist'//errMsg(sourcefile, __LINE__)) + end if + close(nu_nml) + endif + + call shr_mpi_bcast(use_excess_ice_streams , mpicom) + + if (masterproc) then + if ( use_excess_ice_streams ) then + call endrun(msg=' ERROR excess ice streams can NOT be on for the MCT driver'//errMsg(sourcefile, __LINE__)) + end if + if ( trim(stream_fldFileName_exice) /= '' ) then + call endrun(msg=' ERROR stream_fldFileName_exice can NOT be set for the MCT driver'//errMsg(sourcefile, __LINE__)) + end if + if ( trim(stream_mapalgo_exice) /= 'none' ) then + call endrun(msg=' ERROR stream_mapalgo_exice can only be none for the MCT driver'//errMsg(sourcefile, __LINE__)) + end if + endif + +end subroutine ReadNML + +end module ExcessIceStreamType diff --git a/src/cpl/share_esmf/ExcessIceStreamType.F90 b/src/cpl/share_esmf/ExcessIceStreamType.F90 new file mode 100644 index 0000000000..92d5632aff --- /dev/null +++ b/src/cpl/share_esmf/ExcessIceStreamType.F90 @@ -0,0 +1,325 @@ +module ExcessIceStreamType + +#include "shr_assert.h" + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Contains methods for reading in excess ice initial bulk values from data stream. + ! Needed in parameterization for excess ice in soil (Lee et al., 2014). + ! Used when use_excess_ice is true for initialization: + ! startup type runs starting from coldstart and initial datasets + ! that do not have required variables + ! or hybrid runs from cases with use_excess_ice was false. + ! Dataset is interpolated to 0.125x0.125 degrees grid from Brown et al., 1997 + ! with values derived from permafrost types. + ! Values represent fraction of excess ice within soil column + ! and are distributed within it later in initialization + ! + ! !USES + use ESMF + use dshr_strdata_mod , only : shr_strdata_type + use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_cl + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : mpicom, masterproc + use clm_varctl , only : iulog + use abortutils , only : endrun + use decompMod , only : bounds_type + + ! !PUBLIC TYPES: + implicit none + private + + public :: UseExcessIceStreams ! If streams will be used + + type, public :: excessicestream_type + real(r8), pointer, private :: exice_bulk (:) ! excess ice bulk value (-) + contains + + ! !PUBLIC MEMBER FUNCTIONS: + procedure, public :: Init ! Initialize and read data in + procedure, public :: CalcExcessIce ! Calculate excess ice ammount + + ! !PRIVATE MEMBER FUNCTIONS: + procedure, private :: InitAllocate ! Allocate data + + end type excessicestream_type + ! ! PRIVATE DATA: + type, private :: streamcontrol_type + character(len=CL) :: stream_fldFileName_exice ! data Filename + character(len=CL) :: stream_meshfile_exice ! mesh Filename + character(len=CL) :: stream_mapalgo_exice ! map algo + contains + procedure, private :: ReadNML ! Read in namelist + end type streamcontrol_type + + logical :: namelist_read = .false. + type(streamcontrol_type), private :: control ! Stream control data + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + +!============================================================================== +contains +!============================================================================== + + subroutine Init(this, bounds, NLFilename) + ! + use spmdMod , only : iam + use lnd_comp_shr , only : mesh, model_clock + use dshr_strdata_mod , only : shr_strdata_init_from_inline, shr_strdata_print + use dshr_strdata_mod , only : shr_strdata_advance + use dshr_methods_mod , only : dshr_fldbun_getfldptr + ! + ! arguments + implicit none + class(excessicestream_type) :: this + type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: NLFilename ! Namelist filename + + ! + ! local variables + integer :: ig, g, n ! Indices + integer :: year ! year (0, ...) for nstep+1 + integer :: mon ! month (1, ..., 12) for nstep+1 + integer :: day ! day of month (1, ..., 31) for nstep+1 + integer :: sec ! seconds into current date for nstep+1 + integer :: mcdate ! Current model date (yyyymmdd) + type(shr_strdata_type) :: sdat_exice ! input data stream + character(len=16), allocatable :: stream_varnames(:) ! array of stream field names + integer :: rc ! error code + real(r8), pointer :: dataptr1d(:) ! temporary pointer + character(len=*), parameter :: stream_name = 'excess ice' + + call this%InitAllocate( bounds ) + call control%ReadNML( bounds, NLFileName ) + if ( UseExcessIceStreams() )then + allocate(stream_varnames(1)) + stream_varnames = (/"EXICE"/) + + if (masterproc) then + write(iulog,*) ' stream_varnames = ',stream_varnames + write(iulog,*) ' Values will be used if the variable is not on the initial conditions dataset' + end if + + call shr_strdata_init_from_inline(sdat_exice, & + my_task = iam, & + logunit = iulog, & + compname = 'LND', & + model_clock = model_clock, & + model_mesh = mesh, & + stream_meshfile = control%stream_meshfile_exice, & + stream_lev_dimname = 'null', & + stream_mapalgo = control%stream_mapalgo_exice, & + stream_filenames = (/trim(control%stream_fldFileName_exice)/), & + stream_fldlistFile = stream_varnames, & + stream_fldListModel = stream_varnames, & + stream_yearFirst = 1996, & + stream_yearLast = 1996, & + stream_yearAlign = 1, & + stream_offset = 0, & + stream_taxmode = 'extend', & + stream_dtlimit = 1.0e30_r8, & + ! in ch4FinundatedStreamType it is set to linear but we have a single date dataset + stream_tintalgo = 'nearest', & + stream_name = 'excess ice ', & + rc = rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + !TODO + ! Explicitly set current date to a hardcoded constant value. Otherwise + ! using the real date can cause roundoff differences that are + ! detrected as issues with exact restart. EBK M05/20/2017 + ! call get_curr_date(year, mon, day, sec) + year = 1996 + mon = 12 + day = 31 + sec = 0 + mcdate = year*10000 + mon*100 + day + + call shr_strdata_advance(sdat_exice, ymd=mcdate, tod=sec, logunit=iulog, istr='exice', rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! Get pointer for stream data that is time and spatially interpolate to model time and grid + do n = 1,size(stream_varnames) + call dshr_fldbun_getFldPtr(sdat_exice%pstrm(1)%fldbun_model, stream_varnames(n), fldptr1=dataptr1d, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + if (trim(stream_varnames(n)) == 'EXICE') then + ig = 0 + do g = bounds%begg,bounds%endg + ig = ig+1 + this%exice_bulk(g) = dataptr1d(ig) + end do + end if + end do + end if + end subroutine Init + + subroutine InitAllocate(this, bounds) + ! + ! !DESCRIPTION: + ! Allocate module variables and data structures + ! + ! !USES: + use shr_infnan_mod, only: nan => shr_infnan_nan, assignment(=) + ! + ! !ARGUMENTS: + implicit none + class(excessicestream_type) :: this + type(bounds_type), intent(in) :: bounds + ! + ! !LOCAL VARIABLES: + integer :: begc, endc + integer :: begg, endg + !--------------------------------------------------------------------- + + begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg + + + allocate(this%exice_bulk(begg:endg)) ; this%exice_bulk(:) = nan + + end subroutine InitAllocate + + subroutine CalcExcessIce(this,bounds,exice_bulk_init) + + ! only transfers grid values to columns + use shr_const_mod , only : SHR_CONST_TKFRZ + use landunit_varcon , only : istwet, istsoil, istcrop, istice + use column_varcon , only : icol_road_perv, icol_road_imperv + use clm_varcon , only : denice + use clm_varcon , only : tfrz + use ColumnType , only : col + use LandunitType , only : lun + implicit none + class(excessicestream_type) :: this + type(bounds_type), intent(in) :: bounds + real(r8) , intent(inout) :: exice_bulk_init(bounds%begc:bounds%endc) + ! + ! !LOCAL VARIABLES: + integer :: begc, endc + integer :: begg, endg + integer :: c, l, g !counters + + exice_bulk_init(bounds%begc:bounds%endc)=0.0_r8 + + do c = bounds%begc,bounds%endc + g = col%gridcell(c) + l = col%landunit(c) + if ((.not. lun%lakpoi(l)) .and. (.not. lun%urbpoi(l)) .and. (.not. lun%itype(l) == istwet) .and. (.not. lun%itype(l) == istice)) then !not lake + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + exice_bulk_init(c)=this%exice_bulk(g) + else + exice_bulk_init(c) = 0.0_r8 + endif + else + exice_bulk_init(c)=0.0_r8 + endif + enddo + + end subroutine CalcExcessIce + + logical function UseExcessIceStreams() + ! + ! !DESCRIPTION: + ! Return true if + ! + ! !USES: + ! + ! !ARGUMENTS: + implicit none + ! + ! !LOCAL VARIABLES: + if ( .not. namelist_read ) then + call endrun(msg=' ERROR UseExcessIceStreams being called, but namelist has not been read yet'//errMsg(sourcefile, __LINE__)) + end if + if ( trim(control%stream_fldFileName_exice) == '' )then + UseExcessIceStreams = .false. + else + UseExcessIceStreams = .true. + end if +end function UseExcessIceStreams + +subroutine ReadNML(this, bounds, NLFilename) + ! + ! Read the namelist data stream information. + ! + ! Uses: + use shr_nl_mod , only : shr_nl_find_group_name + use shr_log_mod , only : errMsg => shr_log_errMsg + use shr_mpi_mod , only : shr_mpi_bcast + ! + ! arguments + implicit none + class(streamcontrol_type) :: this + type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: NLFilename ! Namelist filename + ! + ! local variables + integer :: nu_nml ! unit for namelist file + integer :: nml_error ! namelist i/o error flag + logical :: use_excess_ice_streams = .false. ! logical to turn on use of excess ice streams + character(len=CL) :: stream_fldFileName_exice = ' ' + character(len=CL) :: stream_meshfile_exice = ' ' + character(len=CL) :: stream_mapalgo_exice = 'bilinear' + character(len=*), parameter :: namelist_name = 'exice_streams' ! MUST agree with name in namelist and read + character(len=*), parameter :: subName = "('exice_streams::ReadNML')" + !----------------------------------------------------------------------- + + namelist /exice_streams/ & ! MUST agree with namelist_name above + stream_mapalgo_exice, stream_fldFileName_exice, stream_meshfile_exice, use_excess_ice_streams + + ! Default values for namelist + + ! Read excess ice namelist + if (masterproc) then + open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) + call shr_nl_find_group_name(nu_nml, namelist_name, status=nml_error) + if (nml_error == 0) then + read(nu_nml, nml=exice_streams,iostat=nml_error) ! MUST agree with namelist_name above + if (nml_error /= 0) then + call endrun(msg=' ERROR reading '//namelist_name//' namelist'//errMsg(sourcefile, __LINE__)) + end if + else + call endrun(msg=' ERROR finding '//namelist_name//' namelist'//errMsg(sourcefile, __LINE__)) + end if + close(nu_nml) + endif + + call shr_mpi_bcast(use_excess_ice_streams , mpicom) + call shr_mpi_bcast(stream_mapalgo_exice , mpicom) + call shr_mpi_bcast(stream_fldFileName_exice , mpicom) + call shr_mpi_bcast(stream_meshfile_exice , mpicom) + + if (masterproc) then + write(iulog,*) ' ' + if ( use_excess_ice_streams ) then + write(iulog,*) 'excess ice streams are enabled: ' + write(iulog,*) namelist_name, ' stream settings:' + write(iulog,*) ' stream_fldFileName_exice = ',stream_fldFileName_exice + write(iulog,*) ' stream_meshfile_exice = ',stream_meshfile_exice + write(iulog,*) ' stream_mapalgo_exice = ',stream_mapalgo_exice + if ( trim(stream_fldFileName_exice) == '' )then + call endrun(msg=' ERROR excess ice streams are on, but stream_fldFileName_exice is NOT set'//errMsg(sourcefile, __LINE__)) + end if + else + write(iulog,*) 'excess ice streams are off' + if ( trim(stream_fldFileName_exice) /= '' )then + call endrun(msg=' ERROR excess ice streams are off, but stream_fldFileName_exice is set'//errMsg(sourcefile, __LINE__)) + end if + end if + endif + this%stream_fldFileName_exice = stream_fldFileName_exice + this%stream_meshfile_exice = stream_meshfile_exice + this%stream_mapalgo_exice = stream_mapalgo_exice + namelist_read = .true. + +end subroutine ReadNML + + +end module ExcessIceStreamType diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 new file mode 100644 index 0000000000..8c2168d01d --- /dev/null +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -0,0 +1,409 @@ +module cropcalStreamMod + +#include "shr_assert.h" + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Read crop calendars from streams + ! + ! !USES: + use ESMF + use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_CL, CS => shr_kind_CS + use dshr_strdata_mod , only : shr_strdata_type + use decompMod , only : bounds_type + use abortutils , only : endrun + use clm_varctl , only : iulog + use clm_varctl , only : use_cropcal_rx_sdates, use_cropcal_rx_cultivar_gdds, use_cropcal_streams + use clm_varpar , only : mxpft + use perf_mod , only : t_startf, t_stopf + use spmdMod , only : masterproc, mpicom, iam + use pftconMod , only : npcropmin + use CNPhenologyMod , only : generate_crop_gdds + ! + ! !PUBLIC TYPES: + implicit none + private + + ! !PUBLIC MEMBER FUNCTIONS: + public :: cropcal_init ! position datasets for crop calendars + public :: cropcal_advance ! Advance the crop calendar streams (outside of a Open-MP threading loop) + public :: cropcal_interp ! interpolates between two years of crop calendar data + + ! !PRIVATE MEMBER DATA: + integer, allocatable :: g_to_ig(:) ! Array matching gridcell index to data index + type(shr_strdata_type) :: sdat_cropcal_sdate ! sdate input data stream + type(shr_strdata_type) :: sdat_cropcal_cultivar_gdds ! sdate input data stream + character(len=CS), allocatable :: stream_varnames_sdate(:) + character(len=CS), allocatable :: stream_varnames_cultivar_gdds(:) + integer :: ncft ! Number of crop functional types (excl. generic crops) + character(len=CL) :: stream_fldFileName_sdate ! sdate stream filename to read + character(len=CL) :: stream_fldFileName_cultivar_gdds ! cultivar growing degree-days stream filename to read + + character(len=*), parameter :: sourcefile = & + __FILE__ + +!============================================================================== +contains +!============================================================================== + + subroutine cropcal_init(bounds) + ! + ! Initialize data stream information for crop calendars. + ! + ! !USES: + use shr_mpi_mod , only : shr_mpi_bcast + use clm_nlUtilsMod , only : find_nlgroup_name + use lnd_comp_shr , only : mesh, model_clock + use dshr_strdata_mod , only : shr_strdata_init_from_inline + use controlMod , only : NLFilename + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds ! bounds + ! + ! !LOCAL VARIABLES: + integer :: i,n,ivt ! index + integer :: stream_year_first_cropcal ! first year in crop calendar streams to use + integer :: stream_year_last_cropcal ! last year in crop calendar streams to use + integer :: model_year_align_cropcal ! align stream_year_first_cropcal with + integer :: nu_nml ! unit for namelist file + integer :: nml_error ! namelist i/o error flag + character(len=CL) :: stream_meshfile_cropcal ! crop calendar stream meshfile + character(len=CL) :: cropcal_mapalgo = 'nn' ! Mapping alogrithm + character(len=CL) :: cropcal_tintalgo = 'nearest' ! Time interpolation alogrithm + integer :: cropcal_offset = 0 ! Offset in time for dataset (sec) + integer :: rc + character(*), parameter :: subName = "('cropcaldyn_init')" + !----------------------------------------------------------------------- + ! + ! deal with namelist variables here in init + ! + namelist /cropcal_streams/ & + stream_year_first_cropcal, & + stream_year_last_cropcal, & + model_year_align_cropcal, & + stream_fldFileName_sdate, & + stream_fldFileName_cultivar_gdds, & + stream_meshfile_cropcal + + ! Default values for namelist + stream_year_first_cropcal = 1 ! first year in stream to use + stream_year_last_cropcal = 1 ! last year in stream to use + model_year_align_cropcal = 1 ! align stream_year_first_cropcal with this model year + stream_meshfile_cropcal = '' + stream_fldFileName_sdate = '' + stream_fldFileName_cultivar_gdds = '' + ! Will need modification to work with mxsowings > 1 + ncft = mxpft - npcropmin + 1 ! Ignores generic crops + allocate(stream_varnames_sdate(ncft)) + allocate(stream_varnames_cultivar_gdds(ncft)) + do n = 1,ncft + ivt = npcropmin + n - 1 + write(stream_varnames_sdate(n),'(a,i0)') "sdate1_",ivt + write(stream_varnames_cultivar_gdds(n),'(a,i0)') "gdd1_",ivt + end do + + ! Read cropcal_streams namelist + if (masterproc) then + open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) + call find_nlgroup_name(nu_nml, 'cropcal_streams', status=nml_error) + if (nml_error == 0) then + read(nu_nml, nml=cropcal_streams,iostat=nml_error) + if (nml_error /= 0) then + call endrun(subname // ':: ERROR reading cropcal_streams namelist') + end if + else + call endrun(subname // ':: ERROR finding cropcal_streams namelist') + end if + close(nu_nml) + endif + call shr_mpi_bcast(stream_year_first_cropcal , mpicom) + call shr_mpi_bcast(stream_year_last_cropcal , mpicom) + call shr_mpi_bcast(model_year_align_cropcal , mpicom) + call shr_mpi_bcast(stream_fldFileName_sdate , mpicom) + call shr_mpi_bcast(stream_fldFileName_cultivar_gdds, mpicom) + call shr_mpi_bcast(stream_meshfile_cropcal , mpicom) + + if (masterproc) then + write(iulog,*) + write(iulog,*) 'cropcal_stream settings:' + write(iulog,'(a,i8)') ' stream_year_first_cropcal = ',stream_year_first_cropcal + write(iulog,'(a,i8)') ' stream_year_last_cropcal = ',stream_year_last_cropcal + write(iulog,'(a,i8)') ' model_year_align_cropcal = ',model_year_align_cropcal + write(iulog,'(a,a)' ) ' stream_fldFileName_sdate = ',trim(stream_fldFileName_sdate) + write(iulog,'(a,a)' ) ' stream_fldFileName_cultivar_gdds = ',trim(stream_fldFileName_cultivar_gdds) + write(iulog,'(a,a)' ) ' stream_meshfile_cropcal = ',trim(stream_meshfile_cropcal) + do n = 1,ncft + write(iulog,'(a,a)' ) ' stream_varnames_sdate = ',trim(stream_varnames_sdate(n)) + write(iulog,'(a,a)' ) ' stream_varnames_cultivar_gdds = ',trim(stream_varnames_cultivar_gdds(n)) + end do + write(iulog,*) + endif + + use_cropcal_rx_sdates = stream_fldFileName_sdate /= '' + use_cropcal_rx_cultivar_gdds = stream_fldFileName_cultivar_gdds /= '' + use_cropcal_streams = use_cropcal_rx_sdates .or. use_cropcal_rx_cultivar_gdds + + ! Initialize the cdeps data type sdat_cropcal_sdate + ! NOTE: stream_dtlimit 1.5 didn't work for some reason + if (use_cropcal_rx_sdates) then + call shr_strdata_init_from_inline(sdat_cropcal_sdate, & + my_task = iam, & + logunit = iulog, & + compname = 'LND', & + model_clock = model_clock, & + model_mesh = mesh, & + stream_meshfile = trim(stream_meshfile_cropcal), & + stream_lev_dimname = 'null', & + stream_mapalgo = trim(cropcal_mapalgo), & + stream_filenames = (/trim(stream_fldFileName_sdate)/), & + stream_fldlistFile = stream_varnames_sdate, & + stream_fldListModel = stream_varnames_sdate, & + stream_yearFirst = stream_year_first_cropcal, & + stream_yearLast = stream_year_last_cropcal, & + stream_yearAlign = model_year_align_cropcal, & + stream_offset = cropcal_offset, & + stream_taxmode = 'extend', & + stream_dtlimit = 1.0e30_r8, & + stream_tintalgo = cropcal_tintalgo, & + stream_name = 'sowing date data', & + rc = rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + end if + + ! Initialize the cdeps data type sdat_cropcal_cultivar_gdds + ! NOTE: stream_dtlimit 1.5 didn't work for some reason + if (use_cropcal_rx_cultivar_gdds) then + call shr_strdata_init_from_inline(sdat_cropcal_cultivar_gdds, & + my_task = iam, & + logunit = iulog, & + compname = 'LND', & + model_clock = model_clock, & + model_mesh = mesh, & + stream_meshfile = trim(stream_meshfile_cropcal), & + stream_lev_dimname = 'null', & + stream_mapalgo = trim(cropcal_mapalgo), & + stream_filenames = (/trim(stream_fldFileName_cultivar_gdds)/), & + stream_fldlistFile = stream_varnames_cultivar_gdds, & + stream_fldListModel = stream_varnames_cultivar_gdds, & + stream_yearFirst = stream_year_first_cropcal, & + stream_yearLast = stream_year_last_cropcal, & + stream_yearAlign = model_year_align_cropcal, & + stream_offset = cropcal_offset, & + stream_taxmode = 'extend', & + stream_dtlimit = 1.0e30_r8, & + stream_tintalgo = cropcal_tintalgo, & + stream_name = 'cultivar gdd data', & + rc = rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + end if + + end subroutine cropcal_init + + !================================================================ + subroutine cropcal_advance( bounds ) + ! + ! Advance crop calendar streams + ! + ! !USES: + use clm_time_manager , only : get_curr_date + use dshr_strdata_mod , only : shr_strdata_advance + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + ! + ! !LOCAL VARIABLES: + integer :: g, ig ! Indices + integer :: year ! year (0, ...) for nstep+1 + integer :: mon ! month (1, ..., 12) for nstep+1 + integer :: day ! day of month (1, ..., 31) for nstep+1 + integer :: sec ! seconds into current date for nstep+1 + integer :: mcdate ! Current model date (yyyymmdd) + integer :: rc + !----------------------------------------------------------------------- + + call get_curr_date(year, mon, day, sec) + mcdate = year*10000 + mon*100 + day + if (use_cropcal_rx_sdates) then + call shr_strdata_advance(sdat_cropcal_sdate, ymd=mcdate, tod=sec, logunit=iulog, istr='cropcaldyn', rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + end if + if (use_cropcal_rx_cultivar_gdds) then + call shr_strdata_advance(sdat_cropcal_cultivar_gdds, ymd=mcdate, tod=sec, logunit=iulog, istr='cropcaldyn', rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + end if + + if ( .not. allocated(g_to_ig) )then + allocate (g_to_ig(bounds%begg:bounds%endg) ) + ig = 0 + do g = bounds%begg,bounds%endg + ig = ig+1 + g_to_ig(g) = ig + end do + end if + + end subroutine cropcal_advance + + !================================================================ + + subroutine cropcal_interp(bounds, num_pcropp, filter_pcropp, crop_inst) + ! + ! Interpolate data stream information for crop calendars. + ! + ! !USES: + use CropType , only : crop_type + use PatchType , only : patch + use dshr_methods_mod , only : dshr_fldbun_getfldptr + ! + ! !ARGUMENTS: + implicit none + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_pcropp ! number of prog. crop patches in filter + integer , intent(in) :: filter_pcropp(:) ! filter for prognostic crop patches + type(crop_type) , intent(inout) :: crop_inst + ! + ! !LOCAL VARIABLES: + integer :: ivt, p, ip, ig + integer :: nc, fp + integer :: n, g + integer :: lsize + integer :: rc + real(r8), pointer :: dataptr1d_sdate(:) + real(r8), pointer :: dataptr2d_sdate(:,:) + real(r8), pointer :: dataptr1d_cultivar_gdds(:) + real(r8), pointer :: dataptr2d_cultivar_gdds(:,:) + !----------------------------------------------------------------------- + + SHR_ASSERT_FL( (lbound(g_to_ig,1) <= bounds%begg ), sourcefile, __LINE__) + SHR_ASSERT_FL( (ubound(g_to_ig,1) >= bounds%endg ), sourcefile, __LINE__) + + ! Get pointer for stream data that is time and spatially interpolate to model time and grid + ! Place all data from each type into a temporary 2d array + lsize = bounds%endg - bounds%begg + 1 + + ! Read prescribed sowing dates from input files + allocate(dataptr2d_sdate(lsize, ncft)) + if (use_cropcal_rx_sdates) then + ! Starting with npcropmin will skip generic crops + do n = 1, ncft + call dshr_fldbun_getFldPtr(sdat_cropcal_sdate%pstrm(1)%fldbun_model, trim(stream_varnames_sdate(n)), & + fldptr1=dataptr1d_sdate, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize + ! So an explicit loop is required here + do g = 1,lsize + + ! If read-in value is invalid, allow_unprescribed_planting in CropPhenology() + if (dataptr1d_sdate(g) <= 0 .or. dataptr1d_sdate(g) > 365) then + dataptr1d_sdate(g) = -1 + end if + + dataptr2d_sdate(g,n) = dataptr1d_sdate(g) + end do + end do + + ! Set rx_sdate for each gridcell/patch combination + do fp = 1, num_pcropp + p = filter_pcropp(fp) + ivt = patch%itype(p) + ! Will skip generic crops + if (ivt >= npcropmin) then + n = ivt - npcropmin + 1 + ! vegetated pft + ig = g_to_ig(patch%gridcell(p)) + crop_inst%rx_sdates_thisyr_patch(p,1) = dataptr2d_sdate(ig,n) + + ! Sanity check: Should only read in valid values + if (crop_inst%rx_sdates_thisyr_patch(p,1) > 365) then + write(iulog,'(a,i0,a,i0)') 'cropcal_interp(): Crop patch (ivt ',ivt,') has dataptr2d prescribed sowing date ',& + crop_inst%rx_sdates_thisyr_patch(p,1) + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! Only for first sowing date of the year + ! The conditional here is to ensure nothing weird happens if it's called incorrectly on day 365 + if (crop_inst%sdates_thisyr_patch(p,1) <= 0) then + crop_inst%next_rx_sdate_patch(p) = crop_inst%rx_sdates_thisyr_patch(p,1) + end if + else + write(iulog,'(a,i0)') 'cropcal_interp(), rx_sdates: Crop patch has ivt ',ivt + call ESMF_Finalize(endflag=ESMF_END_ABORT) + endif + end do + end if ! use_cropcal_rx_sdates + deallocate(dataptr2d_sdate) + + allocate(dataptr2d_cultivar_gdds(lsize, ncft)) + if (use_cropcal_rx_cultivar_gdds) then + ! Read prescribed cultivar GDDs from input files + ! Starting with npcropmin will skip generic crops + do n = 1, ncft + call dshr_fldbun_getFldPtr(sdat_cropcal_cultivar_gdds%pstrm(1)%fldbun_model, trim(stream_varnames_cultivar_gdds(n)), & + fldptr1=dataptr1d_cultivar_gdds, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! Note that the size of dataptr1d includes ocean points so it will be around 3x larger than lsize + ! So an explicit loop is required here + do g = 1,lsize + + ! If read-in value is invalid, have PlantCrop() set gddmaturity to PFT-default value. + if (dataptr1d_cultivar_gdds(g) < 0 .or. dataptr1d_cultivar_gdds(g) > 1000000._r8) then + dataptr1d_cultivar_gdds(g) = -1 + end if + + dataptr2d_cultivar_gdds(g,n) = dataptr1d_cultivar_gdds(g) + end do + end do + + ! Set rx_cultivar_gdd for each gridcell/patch combination + do fp = 1, num_pcropp + p = filter_pcropp(fp) + +! if (.not. patch%active(p)) then +! continue +! end if + + ivt = patch%itype(p) + ! Will skip generic crops + if (ivt >= npcropmin) then + n = ivt - npcropmin + 1 + + if (n > ncft) then + write(iulog,'(a,i0,a,i0,a)') 'n (',n,') > ncft (',ncft,')' + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! vegetated pft + ig = g_to_ig(patch%gridcell(p)) + + if (ig > lsize) then + write(iulog,'(a,i0,a,i0,a)') 'ig (',ig,') > lsize (',lsize,')' + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + crop_inst%rx_cultivar_gdds_thisyr_patch(p,1) = dataptr2d_cultivar_gdds(ig,n) + + else + write(iulog,'(a,i0)') 'cropcal_interp(), rx_cultivar_gdds: Crop patch has ivt ',ivt + call ESMF_Finalize(endflag=ESMF_END_ABORT) + endif + end do + write(iulog,*) 'cropcal_interp(): Reading cultivar_gdds file DONE' + end if ! use_cropcal_rx_cultivar_gdds + + deallocate(dataptr2d_cultivar_gdds) + + end subroutine cropcal_interp + +end module cropcalStreamMod diff --git a/src/cpl/share_esmf/laiStreamMod.F90 b/src/cpl/share_esmf/laiStreamMod.F90 index 3966488e0b..3e4074fbde 100644 --- a/src/cpl/share_esmf/laiStreamMod.F90 +++ b/src/cpl/share_esmf/laiStreamMod.F90 @@ -54,7 +54,7 @@ subroutine lai_init(bounds) type(bounds_type), intent(in) :: bounds ! bounds ! ! !LOCAL VARIABLES: - integer :: i,n ! index + integer :: i,n, ig, g ! index integer :: stream_year_first_lai ! first year in Lai stream to use integer :: stream_year_last_lai ! last year in Lai stream to use integer :: model_year_align_lai ! align stream_year_first_lai with @@ -151,6 +151,15 @@ subroutine lai_init(bounds) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then call ESMF_Finalize(endflag=ESMF_END_ABORT) end if + + if ( .not. allocated(g_to_ig) )then + allocate (g_to_ig(bounds%begg:bounds%endg) ) + ig = 0 + do g = bounds%begg,bounds%endg + ig = ig+1 + g_to_ig(g) = ig + end do + end if end subroutine lai_init diff --git a/src/dyn_subgrid/dynGrossUnrepMod.F90 b/src/dyn_subgrid/dynGrossUnrepMod.F90 index bc49e72f4c..8d0e7ee004 100644 --- a/src/dyn_subgrid/dynGrossUnrepMod.F90 +++ b/src/dyn_subgrid/dynGrossUnrepMod.F90 @@ -146,7 +146,7 @@ end subroutine dynGrossUnrep_interp !----------------------------------------------------------------------- - subroutine CNGrossUnrep (num_soilc, filter_soilc, num_soilp, filter_soilp, & + subroutine CNGrossUnrep (num_soilp, filter_soilp, & soilbiogeochem_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) ! @@ -159,8 +159,6 @@ subroutine CNGrossUnrep (num_soilc, filter_soilc, num_soilp, filter_soilp, & use clm_time_manager, only : get_step_size_real, is_beg_curr_year ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! column filter for soil points integer , intent(in) :: num_soilp ! number of soil patches in filter integer , intent(in) :: filter_soilp(:) ! patch filter for soil points type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst @@ -359,7 +357,7 @@ subroutine CNGrossUnrep (num_soilc, filter_soilc, num_soilp, filter_soilp, & ! gather all patch-level litterfall fluxes from grossunrep to the column ! for litter C and N inputs - call CNGrossUnrepPftToColumn(num_soilc, filter_soilc, & + call CNGrossUnrepPftToColumn(num_soilp, filter_soilp, & soilbiogeochem_state_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) end associate @@ -367,7 +365,7 @@ subroutine CNGrossUnrep (num_soilc, filter_soilc, num_soilp, filter_soilp, & end subroutine CNGrossUnrep !----------------------------------------------------------------------- - subroutine CNGrossUnrepPftToColumn (num_soilc, filter_soilc, & + subroutine CNGrossUnrepPftToColumn (num_soilp, filter_soilp, & soilbiogeochem_state_inst, CNVeg_carbonflux_inst, cnveg_nitrogenflux_inst) ! ! !DESCRIPTION: @@ -378,14 +376,14 @@ subroutine CNGrossUnrepPftToColumn (num_soilc, filter_soilc, & use clm_varpar , only : maxsoil_patches, nlevdecomp ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! soil column filter + integer , intent(in) :: num_soilp ! number of soil patches in filter + integer , intent(in) :: filter_soilp(:) ! soil patch filter type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst ! ! !LOCAL VARIABLES: - integer :: fc,c,pi,p,j,i ! indices + integer :: fp,c,p,j,i ! indices !----------------------------------------------------------------------- associate( & @@ -425,74 +423,56 @@ subroutine CNGrossUnrepPftToColumn (num_soilc, filter_soilc, & ) do j = 1, nlevdecomp - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) - - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - - if (patch%active(p)) then - - do i = i_litr_min, i_litr_max - gru_c_to_litr_c(c,j,i) = gru_c_to_litr_c(c,j,i) + & - ! leaf gross unrepresented landcover change mortality carbon fluxes - gru_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & - ! fine root gross unrepresented landcover change mortality carbon fluxes - gru_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) - gru_n_to_litr_c(c,j,i) = gru_n_to_litr_c(c,j,i) + & - ! leaf gross unrepresented landcover change mortality nitrogen fluxes - gru_leafn_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & - ! fine root gross unrepresented landcover change mortality nitrogen fluxes - gru_frootn_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) - end do - - ! coarse root gross unrepresented landcover change mortality carbon fluxes - gru_c_to_cwdc_c(c,j) = gru_c_to_cwdc_c(c,j) + & - gru_livecrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) - gru_c_to_cwdc_c(c,j) = gru_c_to_cwdc_c(c,j) + & - gru_deadcrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) - - ! coarse root gross unrepresented landcover change mortality nitrogen fluxes - gru_n_to_cwdn_c(c,j) = gru_n_to_cwdn_c(c,j) + & - gru_livecrootn_to_litter(p) * wtcol(p) * croot_prof(p,j) - gru_n_to_cwdn_c(c,j) = gru_n_to_cwdn_c(c,j) + & - gru_deadcrootn_to_litter(p) * wtcol(p) * croot_prof(p,j) - - ! retranslocated N pool gross unrepresented landcover change mortality fluxes - ! process specific to i_met_lit, so we keep it outside - ! the i_litr_min to i_litr_max loop above - gru_n_to_litr_c(c,j,i_met_lit) = & - gru_n_to_litr_c(c,j,i_met_lit) + & - gru_retransn_to_litter(p) * wtcol(p) * leaf_prof(p,j) - - end if - end if - + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) + + do i = i_litr_min, i_litr_max + gru_c_to_litr_c(c,j,i) = gru_c_to_litr_c(c,j,i) + & + ! leaf gross unrepresented landcover change mortality carbon fluxes + gru_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & + ! fine root gross unrepresented landcover change mortality carbon fluxes + gru_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) + gru_n_to_litr_c(c,j,i) = gru_n_to_litr_c(c,j,i) + & + ! leaf gross unrepresented landcover change mortality nitrogen fluxes + gru_leafn_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & + ! fine root gross unrepresented landcover change mortality nitrogen fluxes + gru_frootn_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) end do + ! coarse root gross unrepresented landcover change mortality carbon fluxes + gru_c_to_cwdc_c(c,j) = gru_c_to_cwdc_c(c,j) + & + gru_livecrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) + gru_c_to_cwdc_c(c,j) = gru_c_to_cwdc_c(c,j) + & + gru_deadcrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) + + ! coarse root gross unrepresented landcover change mortality nitrogen fluxes + gru_n_to_cwdn_c(c,j) = gru_n_to_cwdn_c(c,j) + & + gru_livecrootn_to_litter(p) * wtcol(p) * croot_prof(p,j) + gru_n_to_cwdn_c(c,j) = gru_n_to_cwdn_c(c,j) + & + gru_deadcrootn_to_litter(p) * wtcol(p) * croot_prof(p,j) + + ! retranslocated N pool gross unrepresented landcover change mortality fluxes + ! process specific to i_met_lit, so we keep it outside + ! the i_litr_min to i_litr_max loop above + gru_n_to_litr_c(c,j,i_met_lit) = & + gru_n_to_litr_c(c,j,i_met_lit) + & + gru_retransn_to_litter(p) * wtcol(p) * leaf_prof(p,j) + end do end do - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) - - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) - if (patch%active(p)) then - ! wood gross unrepresented landcover change mortality carbon fluxes to product pools - gru_wood_productc_gain_c(c) = gru_wood_productc_gain_c(c) + & - gru_wood_productc_gain(p) * wtcol(p) + ! wood gross unrepresented landcover change mortality carbon fluxes to product pools + gru_wood_productc_gain_c(c) = gru_wood_productc_gain_c(c) + & + gru_wood_productc_gain(p) * wtcol(p) - ! wood gross unrepresented landcover change mortality nitrogen fluxes to product pools - gru_wood_productn_gain_c(c) = gru_wood_productn_gain_c(c) + & - gru_wood_productn_gain(p) * wtcol(p) - end if - end if - - end do + ! wood gross unrepresented landcover change mortality nitrogen fluxes to product pools + gru_wood_productn_gain_c(c) = gru_wood_productn_gain_c(c) + & + gru_wood_productn_gain(p) * wtcol(p) end do diff --git a/src/dyn_subgrid/dynHarvestMod.F90 b/src/dyn_subgrid/dynHarvestMod.F90 index a55da036f3..d5a72aa547 100644 --- a/src/dyn_subgrid/dynHarvestMod.F90 +++ b/src/dyn_subgrid/dynHarvestMod.F90 @@ -234,7 +234,7 @@ subroutine dynHarvest_interp_resolve_harvesttypes(bounds, harvest_rates, after_s end subroutine dynHarvest_interp_resolve_harvesttypes !----------------------------------------------------------------------- - subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & + subroutine CNHarvest (num_soilp, filter_soilp, & soilbiogeochem_state_inst, cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, & cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) ! @@ -247,8 +247,6 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & use clm_time_manager, only : get_step_size_real, is_beg_curr_year ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! column filter for soil points integer , intent(in) :: num_soilp ! number of soil patches in filter integer , intent(in) :: filter_soilp(:) ! patch filter for soil points type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst @@ -457,7 +455,7 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & ! gather all patch-level litterfall fluxes from harvest to the column ! for litter C and N inputs - call CNHarvestPftToColumn(num_soilc, filter_soilc, & + call CNHarvestPftToColumn(num_soilp, filter_soilp, & soilbiogeochem_state_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) end associate @@ -465,7 +463,7 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & end subroutine CNHarvest !----------------------------------------------------------------------- - subroutine CNHarvestPftToColumn (num_soilc, filter_soilc, & + subroutine CNHarvestPftToColumn (num_soilp, filter_soilp, & soilbiogeochem_state_inst, CNVeg_carbonflux_inst, cnveg_nitrogenflux_inst) ! ! !DESCRIPTION: @@ -476,14 +474,14 @@ subroutine CNHarvestPftToColumn (num_soilc, filter_soilc, & use clm_varpar , only : nlevdecomp, maxsoil_patches, i_litr_min, i_litr_max, i_met_lit ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! soil column filter + integer , intent(in) :: num_soilp ! number of soil patches in filter + integer , intent(in) :: filter_soilp(:) ! patch filter for soil points type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst ! ! !LOCAL VARIABLES: - integer :: fc,c,pi,p,j,i ! indices + integer :: fp,c,p,j,i ! indices !----------------------------------------------------------------------- associate( & @@ -547,124 +545,106 @@ subroutine CNHarvestPftToColumn (num_soilc, filter_soilc, & ) do j = 1, nlevdecomp - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) - - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - - if (patch%active(p)) then - - do i = i_litr_min, i_litr_max - ! leaf harvest mortality carbon fluxes - harvest_c_to_litr_c(c,j,i) = & - harvest_c_to_litr_c(c,j,i) + & - hrv_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) - - ! fine root harvest mortality carbon fluxes - harvest_c_to_litr_c(c,j,i) = & - harvest_c_to_litr_c(c,j,i) + & - hrv_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) - end do - - ! wood harvest mortality carbon fluxes - harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & - hrv_livestemc_to_litter(p) * wtcol(p) * stem_prof(p,j) - harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & - hrv_livecrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) - harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & - hrv_deadcrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) - - ! storage harvest mortality carbon fluxes - ! Metabolic litter is treated differently than other types - ! of litter, so it gets this additional line after the - ! most recent loop over all litter types - harvest_c_to_litr_c(c,j,i_met_lit) = & - harvest_c_to_litr_c(c,j,i_met_lit) + & - hrv_leafc_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - hrv_frootc_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - hrv_livestemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_deadstemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_livecrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - hrv_deadcrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - hrv_gresp_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - - ! transfer harvest mortality carbon fluxes - hrv_leafc_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - hrv_frootc_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - hrv_livestemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_deadstemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_livecrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - hrv_deadcrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - hrv_gresp_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) - - do i = i_litr_min, i_litr_max - harvest_n_to_litr_n(c,j,i) = & - harvest_n_to_litr_n(c,j,i) + & - ! leaf harvest mortality nitrogen fluxes - hrv_leafn_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & - ! fine root litter nitrogen fluxes - hrv_frootn_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) - end do - - ! wood harvest mortality nitrogen fluxes - harvest_n_to_cwdn(c,j) = harvest_n_to_cwdn(c,j) + & - hrv_livestemn_to_litter(p) * wtcol(p) * stem_prof(p,j) - harvest_n_to_cwdn(c,j) = harvest_n_to_cwdn(c,j) + & - hrv_livecrootn_to_litter(p) * wtcol(p) * croot_prof(p,j) - harvest_n_to_cwdn(c,j) = harvest_n_to_cwdn(c,j) + & - hrv_deadcrootn_to_litter(p) * wtcol(p) * croot_prof(p,j) - - ! Metabolic litter is treated differently than other types - ! of litter, so it gets this additional line after the - ! most recent loop over all litter types - harvest_n_to_litr_n(c,j,i_met_lit) = & - harvest_n_to_litr_n(c,j,i_met_lit) + & - ! retranslocated N pool harvest mortality fluxes - hrv_retransn_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - ! storage harvest mortality nitrogen fluxes - hrv_leafn_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - hrv_frootn_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - hrv_livestemn_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_deadstemn_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_livecrootn_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - hrv_deadcrootn_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - ! transfer harvest mortality nitrogen fluxes - hrv_leafn_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & - hrv_frootn_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & - hrv_livestemn_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_deadstemn_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & - hrv_livecrootn_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & - hrv_deadcrootn_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) - - end if - end if + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) + + do i = i_litr_min, i_litr_max + ! leaf harvest mortality carbon fluxes + harvest_c_to_litr_c(c,j,i) = & + harvest_c_to_litr_c(c,j,i) + & + hrv_leafc_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + + ! fine root harvest mortality carbon fluxes + harvest_c_to_litr_c(c,j,i) = & + harvest_c_to_litr_c(c,j,i) + & + hrv_frootc_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) + end do + ! wood harvest mortality carbon fluxes + harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & + hrv_livestemc_to_litter(p) * wtcol(p) * stem_prof(p,j) + harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & + hrv_livecrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) + harvest_c_to_cwdc(c,j) = harvest_c_to_cwdc(c,j) + & + hrv_deadcrootc_to_litter(p) * wtcol(p) * croot_prof(p,j) + + ! storage harvest mortality carbon fluxes + ! Metabolic litter is treated differently than other types + ! of litter, so it gets this additional line after the + ! most recent loop over all litter types + harvest_c_to_litr_c(c,j,i_met_lit) = & + harvest_c_to_litr_c(c,j,i_met_lit) + & + hrv_leafc_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + hrv_frootc_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + hrv_livestemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_deadstemc_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_livecrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + hrv_deadcrootc_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + hrv_gresp_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + + ! transfer harvest mortality carbon fluxes + hrv_leafc_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + hrv_frootc_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + hrv_livestemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_deadstemc_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_livecrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + hrv_deadcrootc_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + hrv_gresp_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + + do i = i_litr_min, i_litr_max + harvest_n_to_litr_n(c,j,i) = & + harvest_n_to_litr_n(c,j,i) + & + ! leaf harvest mortality nitrogen fluxes + hrv_leafn_to_litter(p) * lf_f(ivt(p),i) * wtcol(p) * leaf_prof(p,j) + & + ! fine root litter nitrogen fluxes + hrv_frootn_to_litter(p) * fr_f(ivt(p),i) * wtcol(p) * froot_prof(p,j) end do + ! wood harvest mortality nitrogen fluxes + harvest_n_to_cwdn(c,j) = harvest_n_to_cwdn(c,j) + & + hrv_livestemn_to_litter(p) * wtcol(p) * stem_prof(p,j) + harvest_n_to_cwdn(c,j) = harvest_n_to_cwdn(c,j) + & + hrv_livecrootn_to_litter(p) * wtcol(p) * croot_prof(p,j) + harvest_n_to_cwdn(c,j) = harvest_n_to_cwdn(c,j) + & + hrv_deadcrootn_to_litter(p) * wtcol(p) * croot_prof(p,j) + + ! Metabolic litter is treated differently than other types + ! of litter, so it gets this additional line after the + ! most recent loop over all litter types + harvest_n_to_litr_n(c,j,i_met_lit) = & + harvest_n_to_litr_n(c,j,i_met_lit) + & + ! retranslocated N pool harvest mortality fluxes + hrv_retransn_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + ! storage harvest mortality nitrogen fluxes + hrv_leafn_storage_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + hrv_frootn_storage_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + hrv_livestemn_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_deadstemn_storage_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_livecrootn_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + hrv_deadcrootn_storage_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + ! transfer harvest mortality nitrogen fluxes + hrv_leafn_xfer_to_litter(p) * wtcol(p) * leaf_prof(p,j) + & + hrv_frootn_xfer_to_litter(p) * wtcol(p) * froot_prof(p,j) + & + hrv_livestemn_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_deadstemn_xfer_to_litter(p) * wtcol(p) * stem_prof(p,j) + & + hrv_livecrootn_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + & + hrv_deadcrootn_xfer_to_litter(p) * wtcol(p) * croot_prof(p,j) + end do end do - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) - - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) - if (patch%active(p)) then - ! wood harvest mortality carbon fluxes to product pools - cwood_harvestc(c) = cwood_harvestc(c) + & - pwood_harvestc(p) * wtcol(p) + ! wood harvest mortality carbon fluxes to product pools + cwood_harvestc(c) = cwood_harvestc(c) + & + pwood_harvestc(p) * wtcol(p) - ! wood harvest mortality nitrogen fluxes to product pools - cwood_harvestn(c) = cwood_harvestn(c) + & - pwood_harvestn(p) * wtcol(p) - end if - end if - - end do + ! wood harvest mortality nitrogen fluxes to product pools + cwood_harvestn(c) = cwood_harvestn(c) + & + pwood_harvestn(p) * wtcol(p) end do diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index bda1517bad..722eba5ab7 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -9,12 +9,13 @@ module clm_driver ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varctl , only : iulog, use_fates, use_fates_sp + use clm_varctl , only : iulog, use_fates, use_fates_sp, use_fates_bgc use clm_varctl , only : use_cn, use_lch4, use_noio, use_c13, use_c14 use CNSharedParamsMod , only : use_matrixcn use clm_varctl , only : use_crop, irrigate, ndep_from_cpl use clm_varctl , only : use_soil_moisture_streams - use clm_time_manager , only : get_nstep, is_beg_curr_day + use clm_varctl , only : use_cropcal_streams + use clm_time_manager , only : get_nstep, is_beg_curr_day, is_beg_curr_year use clm_time_manager , only : get_prev_date, is_first_step use clm_varpar , only : nlevsno, nlevgrnd use clm_varorb , only : obliqr @@ -59,6 +60,7 @@ module clm_driver use SoilBiogeochemVerticalProfileMod , only : SoilBiogeochemVerticalProfile use SatellitePhenologyMod , only : SatellitePhenology, interpMonthlyVeg use ndepStreamMod , only : ndep_interp + use cropcalStreamMod , only : cropcal_advance, cropcal_interp use ch4Mod , only : ch4, ch4_init_gridcell_balance_check, ch4_init_column_balance_check use DUSTMod , only : DustDryDep, DustEmission use VOCEmissionMod , only : VOCEmission @@ -80,7 +82,6 @@ module clm_driver use ColumnType , only : col use PatchType , only : patch use clm_instMod - use EDBGCDynMod , only : EDBGCDyn, EDBGCDynSummary use SoilMoistureStreamMod , only : PrescribedSoilMoistureInterp, PrescribedSoilMoistureAdvance use SoilBiogeochemDecompCascadeConType , only : no_soil_decomp, decomp_method ! @@ -205,7 +206,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! ======================================================================== need_glacier_initialization = is_first_step() - + if (need_glacier_initialization) then !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) do nc = 1, nclumps @@ -224,7 +225,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! Specified phenology ! Done in SP mode, FATES-SP mode and also when dry-deposition is active ! ============================================================================ - + if (use_cn) then ! For dry-deposition need to call CLMSP so that mlaidiff is obtained ! NOTE: This is also true of FATES below @@ -263,7 +264,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro end if end if - + ! ================================================================================== ! Determine decomp vertical profiles ! @@ -289,10 +290,12 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call active_layer_inst%alt_calc(filter_inactive_and_active(nc)%num_soilc, filter_inactive_and_active(nc)%soilc, & temperature_inst) - if (use_cn .and. decomp_method /= no_soil_decomp) then + ! Filter bgc_soilc operates on all non-sp soil columns + ! Filter bgc_vegp operates on all non-fates, non-sp patches (use_cn) on soil + if ((use_cn .or. use_fates_bgc) .and. decomp_method /= no_soil_decomp) then call SoilBiogeochemVerticalProfile(bounds_clump , & - filter_inactive_and_active(nc)%num_soilc, filter_inactive_and_active(nc)%soilc , & - filter_inactive_and_active(nc)%num_soilp, filter_inactive_and_active(nc)%soilp , & + filter_inactive_and_active(nc)%num_bgc_soilc, filter_inactive_and_active(nc)%bgc_soilc , & + filter_inactive_and_active(nc)%num_bgc_vegp, filter_inactive_and_active(nc)%bgc_vegp , & active_layer_inst, soilstate_inst, soilbiogeochem_state_inst) end if @@ -325,12 +328,12 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call get_clump_bounds(nc, bounds_clump) call t_startf('begcnbal_grc') - if (use_cn) then + if (use_cn .or. use_fates_bgc) then ! Initialize gridcell-level balance check call bgc_vegetation_inst%InitGridcellBalance(bounds_clump, & filter(nc)%num_allc, filter(nc)%allc, & - filter(nc)%num_soilc, filter(nc)%soilc, & - filter(nc)%num_soilp, filter(nc)%soilp, & + filter(nc)%num_bgc_soilc, filter(nc)%bgc_soilc, & + filter(nc)%num_bgc_vegp, filter(nc)%bgc_vegp, & soilbiogeochem_carbonstate_inst, & c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonstate_inst, & @@ -415,12 +418,12 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call t_stopf('begwbal') call t_startf('begcnbal_col') - if (use_cn) then + if (use_cn .or. use_fates_bgc) then ! Initialize column-level balance check call bgc_vegetation_inst%InitColumnBalance(bounds_clump, & filter(nc)%num_allc, filter(nc)%allc, & - filter(nc)%num_soilc, filter(nc)%soilc, & - filter(nc)%num_soilp, filter(nc)%soilp, & + filter(nc)%num_bgc_soilc, filter(nc)%bgc_soilc, & + filter(nc)%num_bgc_vegp, filter(nc)%bgc_vegp, & soilbiogeochem_carbonstate_inst, & c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonstate_inst, & @@ -444,15 +447,18 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! re-written to go inside. ! ============================================================================ - if (use_cn) then - call t_startf('bgc_interp') + if (use_cn) then ! .or. use_fates_bgc) then (ndep with fates will be added soon) if (.not. ndep_from_cpl) then call ndep_interp(bounds_proc, atm2lnd_inst) end if + end if + + if(use_cn) then + call t_startf('bgc_interp') call bgc_vegetation_inst%InterpFileInputs(bounds_proc) call t_stopf('bgc_interp') - ! fates_spitfire_mode is assigned an integer value in the namelist - ! see bld/namelist_files/namelist_definition_clm4_5.xml for details + ! fates_spitfire_mode is assigned an integer value in the namelist + ! see bld/namelist_files/namelist_definition_clm4_5.xml for details else if (fates_spitfire_mode > scalar_lightning) then call clm_fates%InterpFileInputs(bounds_proc) end if @@ -462,10 +468,16 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! When LAI streams are being used ! NOTE: This call needs to happen outside loops over nclumps (as streams are not threadsafe) - if ((.not. use_cn) .and. (.not. use_fates) .and. (doalb) .and. use_lai_streams) then - call lai_advance( bounds_proc ) + if (doalb .and. use_lai_streams) then + call lai_advance(bounds_proc) endif + ! When crop calendar streams are being used + ! NOTE: This call needs to happen outside loops over nclumps (as streams are not threadsafe) + if (use_cropcal_streams .and. is_beg_curr_year()) then + call cropcal_advance( bounds_proc ) + end if + ! ============================================================================ ! Initialize variables from previous time step, downscale atm forcings, and ! Determine canopy interception and precipitation onto ground surface. @@ -637,7 +649,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro atm2lnd_inst, canopystate_inst, energyflux_inst, frictionvel_inst, & soilstate_inst, temperature_inst, & water_inst%wateratm2lndbulk_inst, water_inst%waterdiagnosticbulk_inst, & - water_inst%waterstatebulk_inst) + water_inst%waterstatebulk_inst, water_inst%waterfluxbulk_inst) call ozone_inst%CalcOzoneStress(bounds_clump, & filter(nc)%num_exposedvegp, filter(nc)%exposedvegp, & @@ -831,6 +843,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call SoilTemperature(bounds_clump, & filter(nc)%num_urbanl , filter(nc)%urbanl, & filter(nc)%num_urbanc , filter(nc)%urbanc, & + filter(nc)%num_nolakep , filter(nc)%nolakep, & filter(nc)%num_nolakec , filter(nc)%nolakec, & atm2lnd_inst, urbanparams_inst, canopystate_inst, water_inst%waterstatebulk_inst, & water_inst%waterdiagnosticbulk_inst, water_inst%waterfluxbulk_inst, & @@ -997,17 +1010,20 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! - CNDV defined: prognostic biogeography; else prescribed ! - crop model: crop algorithms called from within CNDriver - if (use_cn) then + ! Filter bgc_soilc operates on all non-sp soil columns + ! Filter bgc_vegp operates on all non-fates, non-sp patches (use_cn) on soil + + if(use_cn .or. use_fates_bgc)then call t_startf('ecosysdyn') call bgc_vegetation_inst%EcosystemDynamicsPreDrainage(bounds_clump, & - filter(nc)%num_soilc, filter(nc)%soilc, & - filter(nc)%num_soilp, filter(nc)%soilp, & - filter(nc)%num_actfirec, filter(nc)%actfirec, & - filter(nc)%num_actfirep, filter(nc)%actfirep, & - filter(nc)%num_pcropp, filter(nc)%pcropp, & - filter(nc)%num_soilnopcropp, filter(nc)%soilnopcropp, & - filter(nc)%num_exposedvegp, filter(nc)%exposedvegp, & - filter(nc)%num_noexposedvegp, filter(nc)%noexposedvegp, & + filter(nc)%num_bgc_soilc, filter(nc)%bgc_soilc, & + filter(nc)%num_bgc_vegp, filter(nc)%bgc_vegp, & + filter(nc)%num_actfirec, filter(nc)%actfirec, & + filter(nc)%num_actfirep, filter(nc)%actfirep, & + filter(nc)%num_pcropp, filter(nc)%pcropp, & + filter(nc)%num_soilnopcropp, filter(nc)%soilnopcropp, & + filter(nc)%num_exposedvegp, filter(nc)%exposedvegp, & + filter(nc)%num_noexposedvegp, filter(nc)%noexposedvegp, & soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & c13_soilbiogeochem_carbonflux_inst, c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonflux_inst, c14_soilbiogeochem_carbonstate_inst, & @@ -1020,9 +1036,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro soil_water_retention_curve, crop_inst, ch4_inst, & photosyns_inst, saturated_excess_runoff_inst, energyflux_inst, & nutrient_competition_method, fireemis_inst) - call t_stopf('ecosysdyn') - end if ! Prescribed biogeography - prescribed canopy structure, some prognostic carbon fluxes @@ -1058,6 +1072,13 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro frictionvel_inst, photosyns_inst, drydepvel_inst) call t_stopf('depvel') + if (use_cropcal_streams .and. is_beg_curr_year()) then + ! ============================================================================ + ! Update crop calendars + ! ============================================================================ + call cropcal_interp(bounds_clump, filter_inactive_and_active(nc)%num_pcropp, filter_inactive_and_active(nc)%pcropp, crop_inst) + end if + ! ============================================================================ ! Calculate soil/snow hydrology with drainage (subsurface runoff) ! ============================================================================ @@ -1077,13 +1098,13 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call t_stopf('hydro2_drainage') - if (use_cn) then - + + if (use_cn .or. use_fates_bgc) then call t_startf('EcosysDynPostDrainage') call bgc_vegetation_inst%EcosystemDynamicsPostDrainage(bounds_clump, & filter(nc)%num_allc, filter(nc)%allc, & - filter(nc)%num_soilc, filter(nc)%soilc, & - filter(nc)%num_soilp, filter(nc)%soilp, & + filter(nc)%num_bgc_soilc, filter(nc)%bgc_soilc, & + filter(nc)%num_bgc_vegp, filter(nc)%bgc_vegp, & filter(nc)%num_actfirec, filter(nc)%actfirec, & filter(nc)%num_actfirep, filter(nc)%actfirep, & doalb, crop_inst, & @@ -1095,11 +1116,8 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro c14_soilbiogeochem_carbonflux_inst, c14_soilbiogeochem_carbonstate_inst, & soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst) call t_stopf('EcosysDynPostDrainage') - end if - - if ( use_fates) then ! FATES has its own running mean functions, such as 24hr @@ -1108,30 +1126,6 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! moving averages are updated here call clm_fates%WrapUpdateFatesRmean(nc,temperature_inst) - call EDBGCDyn(bounds_clump, & - filter(nc)%num_soilc, filter(nc)%soilc, & - filter(nc)%num_soilp, filter(nc)%soilp, & - filter(nc)%num_pcropp, filter(nc)%pcropp, doalb, & - bgc_vegetation_inst%cnveg_carbonflux_inst, & - bgc_vegetation_inst%cnveg_carbonstate_inst, & - soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & - soilbiogeochem_state_inst, clm_fates, & - soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst, & - c13_soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonflux_inst, & - c14_soilbiogeochem_carbonstate_inst, c14_soilbiogeochem_carbonflux_inst, & - active_layer_inst, atm2lnd_inst, water_inst%waterfluxbulk_inst, & - canopystate_inst, soilstate_inst, temperature_inst, crop_inst, ch4_inst) - - if ( decomp_method /= no_soil_decomp )then - call EDBGCDynSummary(bounds_clump, & - filter(nc)%num_soilc, filter(nc)%soilc, & - filter(nc)%num_soilp, filter(nc)%soilp, & - soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & - c13_soilbiogeochem_carbonflux_inst, c13_soilbiogeochem_carbonstate_inst, & - c14_soilbiogeochem_carbonflux_inst, c14_soilbiogeochem_carbonstate_inst, & - soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst, & - nc) - end if call clm_fates%wrap_update_hifrq_hist(bounds_clump, & soilbiogeochem_carbonflux_inst, & @@ -1144,9 +1138,6 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! This is the main call to FATES dynamics ! -------------------------------------------------------------------------- - if ( masterproc ) then - write(iulog,*) 'clm: calling FATES model ', get_nstep() - end if call clm_fates%dynamics_driv( nc, bounds_clump, & atm2lnd_inst, soilstate_inst, temperature_inst, active_layer_inst, & water_inst%waterstatebulk_inst, water_inst%waterdiagnosticbulk_inst, & @@ -1176,15 +1167,18 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! Check the carbon and nitrogen balance ! ============================================================================ - if (use_cn) then + if(use_cn .or. use_fates_bgc)then call t_startf('cnbalchk') call bgc_vegetation_inst%BalanceCheck( & - bounds_clump, filter(nc)%num_soilc, filter(nc)%soilc, & - soilbiogeochem_carbonflux_inst, & - soilbiogeochem_nitrogenflux_inst, atm2lnd_inst ) + bounds_clump, filter(nc)%num_bgc_soilc, filter(nc)%bgc_soilc, & + soilbiogeochem_carbonflux_inst, & + soilbiogeochem_nitrogenflux_inst, & + soilbiogeochem_carbonstate_inst, & + soilbiogeochem_nitrogenstate_inst, & + atm2lnd_inst, clm_fates ) call t_stopf('cnbalchk') end if - + ! Calculation of methane fluxes if (use_lch4) then @@ -1403,7 +1397,6 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! Update history buffer ! ============================================================================ - call t_startf('hbuf') call hist_update_hbuf(bounds_proc) call t_stopf('hbuf') diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index e515d756c1..daf1011cab 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -10,10 +10,11 @@ module clm_initializeMod use spmdMod , only : masterproc, mpicom use decompMod , only : bounds_type, get_proc_bounds, get_proc_clumps, get_clump_bounds use abortutils , only : endrun - use clm_varctl , only : nsrest, nsrStartup, nsrContinue, nsrBranch, use_fates_sp + use clm_varctl , only : nsrest, nsrStartup, nsrContinue, nsrBranch + use clm_varctl , only : use_fates_sp, use_fates_bgc, use_fates use clm_varctl , only : is_cold_start use clm_varctl , only : iulog - use clm_varctl , only : use_lch4, use_cn, use_cndv, use_c13, use_c14, use_fates + use clm_varctl , only : use_lch4, use_cn, use_cndv, use_c13, use_c14 use clm_varctl , only : nhillslope use clm_varctl , only : use_soil_moisture_streams use clm_instur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, fert_cft @@ -140,6 +141,7 @@ subroutine initialize2(ni,nj) use clm_varctl , only : use_crop, ndep_from_cpl, fates_spitfire_mode use clm_varctl , only : use_hillslope use clm_varorb , only : eccen, mvelpp, lambm0, obliqr + use clm_varctl , only : use_cropcal_streams use landunit_varcon , only : landunit_varcon_init, max_lunit, numurbl use pftconMod , only : pftcon use decompInitMod , only : decompInit_clumps, decompInit_glcp @@ -167,6 +169,7 @@ subroutine initialize2(ni,nj) use restFileMod , only : restFile_getfile, restFile_open, restFile_close use restFileMod , only : restFile_read, restFile_write use ndepStreamMod , only : ndep_init, ndep_interp + use cropcalStreamMod , only : cropcal_init, cropcal_interp, cropcal_advance use LakeCon , only : LakeConInit use SatellitePhenologyMod , only : SatellitePhenologyInit, readAnnualVegetation, interpMonthlyVeg, SatellitePhenology use SnowSnicarMod , only : SnowAge_init, SnowOptics_init @@ -353,7 +356,7 @@ subroutine initialize2(ni,nj) end if ! Pass model timestep info to FATES - call CLMFatesTimesteps() + if (use_fates) call CLMFatesTimesteps() ! Initialize daylength from the previous time step (needed so prev_dayl can be set correctly) call t_startf('init_orbd') @@ -445,8 +448,11 @@ subroutine initialize2(ni,nj) !$OMP END PARALLEL DO ! Initialize modules (after time-manager initialization in most cases) - if (use_cn) then + if (use_cn .or. use_fates) then call bgc_vegetation_inst%Init2(bounds_proc, NLFilename) + end if + + if (use_cn) then ! NOTE(wjs, 2016-02-23) Maybe the rest of the body of this conditional should also ! be moved into bgc_vegetation_inst%Init2 @@ -638,7 +644,7 @@ subroutine initialize2(ni,nj) !$OMP END PARALLEL DO ! Initialize nitrogen deposition - if (use_cn) then + if (use_cn ) then !.or. use_fates_bgc) then (ndep with fates will be added soon RGK) call t_startf('init_ndep') if (.not. ndep_from_cpl) then call ndep_init(bounds_proc, NLFilename) @@ -647,6 +653,21 @@ subroutine initialize2(ni,nj) call t_stopf('init_ndep') end if + ! Initialize crop calendars + call t_startf('init_cropcal') + call cropcal_init(bounds_proc) + if (use_cropcal_streams) then + call cropcal_advance( bounds_proc ) + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) + do nc = 1,nclumps + call get_clump_bounds(nc, bounds_clump) + call cropcal_interp(bounds_clump, filter_inactive_and_active(nc)%num_pcropp, & + filter_inactive_and_active(nc)%pcropp, crop_inst) + end do + !$OMP END PARALLEL DO + end if + call t_stopf('init_cropcal') + ! Initialize active history fields. ! This is only done if not a restart run. If a restart run, then this ! information has already been obtained from the restart data read above. @@ -686,7 +707,7 @@ subroutine initialize2(ni,nj) elseif ( use_fates_sp ) then call interpMonthlyVeg(bounds_proc, canopystate_inst) end if - + ! Determine gridcell averaged properties to send to atm if (nsrest == nsrStartup) then call t_startf('init_map2gc') @@ -722,7 +743,6 @@ subroutine initialize2(ni,nj) !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) do nc = 1,nclumps call get_clump_bounds(nc, bounds_clump) - ! FATES satellite phenology mode needs to include all active and inactive patch-level soil ! filters due to the translation between the hlm pfts and the fates pfts. ! E.g. in FATES, an active PFT vector of 1, 0, 0, 0, 1, 0, 1, 0 would be mapped into @@ -735,11 +755,12 @@ subroutine initialize2(ni,nj) end do !$OMP END PARALLEL DO end if + call clm_fates%init_coldstart(water_inst%waterstatebulk_inst, & water_inst%waterdiagnosticbulk_inst, canopystate_inst, & soilstate_inst, soilbiogeochem_carbonflux_inst) end if - + ! topo_glc_mec was allocated in initialize1, but needed to be kept around through ! initialize2 because it is used to initialize other variables; now it can be deallocated deallocate(topo_glc_mec, fert_cft, irrig_method) diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 7393116da6..7f2e3c1d18 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -8,7 +8,7 @@ module clm_instMod use shr_kind_mod , only : r8 => shr_kind_r8 use decompMod , only : bounds_type use clm_varpar , only : ndecomp_pools, nlevdecomp_full - use clm_varctl , only : use_cn, use_c13, use_c14, use_lch4, use_cndv, use_fates + use clm_varctl , only : use_cn, use_c13, use_c14, use_lch4, use_cndv, use_fates, use_fates_bgc use clm_varctl , only : iulog use clm_varctl , only : use_crop, snow_cover_fraction_method, paramfile use SoilBiogeochemDecompCascadeConType , only : mimics_decomp, no_soil_decomp, century_decomp, decomp_method @@ -236,7 +236,6 @@ subroutine clm_instInit(bounds) allocate (h2osno_col(begc:endc)) allocate (snow_depth_col(begc:endc)) - ! snow water do c = begc,endc l = col%landunit(c) @@ -384,7 +383,7 @@ subroutine clm_instInit(bounds) call drydepvel_inst%Init(bounds) - if (decomp_method /= no_soil_decomp) then + if_decomp: if (decomp_method /= no_soil_decomp) then ! Initialize soilbiogeochem_state_inst @@ -436,9 +435,10 @@ subroutine clm_instInit(bounds) call SoilBiogeochemPrecisionControlInit( soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonstate_inst, soilbiogeochem_nitrogenstate_inst) - end if ! end of if use_cn + end if if_decomp ! Note - always call Init for bgc_vegetation_inst: some pieces need to be initialized always + ! Even for a FATES simulation, we call this to initialize product pools call bgc_vegetation_inst%Init(bounds, nlfilename, GetBalanceCheckSkipSteps(), params_ncid ) if (use_cn .or. use_fates) then @@ -499,6 +499,7 @@ subroutine clm_instRest(bounds, ncid, flag, writing_finidat_interp_dest_file) use ncdio_pio , only : file_desc_t use UrbanParamsType , only : IsSimpleBuildTemp, IsProgBuildTemp use decompMod , only : get_proc_bounds, get_proc_clumps, get_clump_bounds + use clm_varpar , only : nlevsno ! ! !DESCRIPTION: @@ -545,7 +546,9 @@ subroutine clm_instRest(bounds, ncid, flag, writing_finidat_interp_dest_file) call water_inst%restart(bounds, ncid, flag=flag, & writing_finidat_interp_dest_file = writing_finidat_interp_dest_file, & - watsat_col = soilstate_inst%watsat_col(bounds%begc:bounds%endc,:)) + watsat_col = soilstate_inst%watsat_col(bounds%begc:bounds%endc,:), & + t_soisno_col=temperature_inst%t_soisno_col(bounds%begc:bounds%endc, -nlevsno+1:), & + altmax_lastyear_indx=active_layer_inst%altmax_lastyear_indx_col(bounds%begc:bounds%endc)) call irrigation_inst%restart (bounds, ncid, flag=flag) @@ -563,7 +566,7 @@ subroutine clm_instRest(bounds, ncid, flag, writing_finidat_interp_dest_file) call ch4_inst%restart(bounds, ncid, flag=flag) end if - if ( use_cn ) then + if ( use_cn .or. use_fates_bgc) then ! Need to do vegetation restart before soil bgc restart to get totvegc_col for purpose ! of resetting soil carbon at exit spinup when no vegetation is growing. call bgc_vegetation_inst%restart(bounds, ncid, flag=flag) @@ -571,7 +574,7 @@ subroutine clm_instRest(bounds, ncid, flag, writing_finidat_interp_dest_file) call soilbiogeochem_nitrogenstate_inst%restart(bounds, ncid, flag=flag, & totvegc_col=bgc_vegetation_inst%get_totvegc_col(bounds)) - call crop_inst%restart(bounds, ncid, flag=flag) + call crop_inst%restart(bounds, ncid, bgc_vegetation_inst%cnveg_state_inst, flag=flag) end if if (decomp_method /= no_soil_decomp) then @@ -601,7 +604,8 @@ subroutine clm_instRest(bounds, ncid, flag, writing_finidat_interp_dest_file) canopystate_inst=canopystate_inst, & soilstate_inst=soilstate_inst, & active_layer_inst=active_layer_inst, & - soilbiogeochem_carbonflux_inst=soilbiogeochem_carbonflux_inst) + soilbiogeochem_carbonflux_inst=soilbiogeochem_carbonflux_inst, & + soilbiogeochem_nitrogenflux_inst=soilbiogeochem_nitrogenflux_inst) end if diff --git a/src/main/clm_varcon.F90 b/src/main/clm_varcon.F90 index 340115fe90..e45f5c440e 100644 --- a/src/main/clm_varcon.F90 +++ b/src/main/clm_varcon.F90 @@ -90,6 +90,7 @@ module clm_varcon integer, public, parameter :: fun_period = 1 ! A FUN parameter, and probably needs to be changed for testing real(r8),public, parameter :: smallValue = 1.e-12_r8 ! A small values used by FUN + real(r8),public, parameter :: sum_to_1_tol = 1.e-13_r8 ! error tolerance ! ------------------------------------------------------------------------ ! Special value flags @@ -154,6 +155,18 @@ module clm_varcon real(r8), public :: c14ratio = 1.e-12_r8 ! real(r8) :: c14ratio = 1._r8 ! debug lets set to 1 to try to avoid numerical errors + !------------------------------------------------------------------ + ! Surface roughness constants + !------------------------------------------------------------------ + real(r8), public, parameter :: beta_param = 7.2_r8 ! Meier et al. (2022) https://doi.org/10.5194/gmd-15-2365-2022 + real(r8), public, parameter :: nu_param = 1.5e-5_r8 ! Meier et al. (2022) kinematic viscosity of air + real(r8), public, parameter :: b1_param = 1.4_r8 ! Meier et al. (2022) empirical constant + real(r8), public, parameter :: b4_param = -0.31_r8 ! Meier et al. (2022) empirical constant + real(r8), public, parameter :: cd1_param = 7.5_r8 ! Meier et al. (2022) originally from Raupach (1994) + real(r8), public, parameter :: meier_param1 = 0.23_r8 ! slevis did not find it documented + real(r8), public, parameter :: meier_param2 = 0.08_r8 ! slevis did not find it documented + real(r8), public, parameter :: meier_param3 = 70.0_r8 ! slevis did not find it documented, but to the question "What is the 70 in the formula for roughness length" bard.google.com responds "[...] a dimensionless constant [...] originally introduced by von Karman. It is based on experimental data and is thought to represent the ratio of the average height of the surface roughness elements to the distance that the wind travels before it is slowed down by the roughness." + !------------------------------------------------------------------ ! Urban building temperature constants !------------------------------------------------------------------ diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 55abf84ed5..fa9bd243f6 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -251,31 +251,44 @@ module clm_varctl ! this error-check. logical, public :: for_testing_allow_interp_non_ciso_to_ciso = .false. + !---------------------------------------------------------- + ! Surface roughness parameterization + !---------------------------------------------------------- + + character(len=64), public :: z0param_method ! ZengWang2007 or Meier2022 + logical, public :: use_z0m_snowmelt = .false. ! true => use snow z0m parameterization of Brock2006 + !---------------------------------------------------------- ! FATES switches !---------------------------------------------------------- - logical, public :: use_fates = .false. ! true => use fates + logical, public :: use_fates = .false. ! true => use fates ! These are INTERNAL to the FATES module - integer, public :: fates_parteh_mode = -9 ! 1 => carbon only - ! 2 => C+N+P (not enabled yet) - ! no others enabled + + integer, public :: fates_parteh_mode = -9 ! 1 => carbon only + ! 2 => C+N+P (not enabled yet) + ! no others enabled integer, public :: fates_spitfire_mode = 0 - ! 0 for no fire; 1 for constant ignitions; > 1 for external data (lightning and/or anthropogenic ignitions) - ! see bld/namelist_files/namelist_definition_clm4_5.xml for details - logical, public :: use_fates_tree_damage = .false. ! true => turn on tree damage module - logical, public :: use_fates_logging = .false. ! true => turn on logging module - logical, public :: use_fates_planthydro = .false. ! true => turn on fates hydro + ! 0 for no fire; 1 for constant ignitions; + ! > 1 for external data (lightning and/or anthropogenic ignitions) + ! see bld/namelist_files/namelist_definition_clm4_5.xml for details + logical, public :: use_fates_tree_damage = .false. ! true => turn on tree damage module + logical, public :: use_fates_logging = .false. ! true => turn on logging module + logical, public :: use_fates_planthydro = .false. ! true => turn on fates hydro logical, public :: use_fates_cohort_age_tracking = .false. ! true => turn on cohort age tracking - logical, public :: use_fates_ed_st3 = .false. ! true => static stand structure - logical, public :: use_fates_ed_prescribed_phys = .false. ! true => prescribed physiology - logical, public :: use_fates_inventory_init = .false. ! true => initialize fates from inventory - logical, public :: use_fates_fixed_biogeog = .false. ! true => use fixed biogeography mode - logical, public :: use_fates_nocomp = .false. ! true => use no comopetition mode - logical, public :: use_fates_sp = .false. ! true => use FATES satellite phenology mode - character(len=256), public :: fates_inventory_ctrl_filename = '' ! filename for inventory control - + logical, public :: use_fates_ed_st3 = .false. ! true => static stand structure + logical, public :: use_fates_ed_prescribed_phys = .false. ! true => prescribed physiology + logical, public :: use_fates_inventory_init = .false. ! true => initialize fates from inventory + logical, public :: use_fates_fixed_biogeog = .false. ! true => use fixed biogeography mode + logical, public :: use_fates_nocomp = .false. ! true => use no comopetition mode + character(len=256), public :: fates_inventory_ctrl_filename = '' ! filename for inventory control + + ! FATES SP AND FATES BGC are MUTUTALLY EXCLUSIVE, THEY CAN'T BOTH BE ON + ! BUT... THEY CAN BOTH BE OFF (IF FATES IS OFF) + logical, public :: use_fates_sp = .false. ! true => use FATES satellite phenology mode + logical, public :: use_fates_bgc = .false. ! true => use FATES along with CLM soil biogeochemistry + !---------------------------------------------------------- ! LUNA switches !---------------------------------------------------------- @@ -308,6 +321,14 @@ module clm_varctl logical, public :: use_lai_streams = .false. ! true => use lai streams in SatellitePhenologyMod.F90 + !---------------------------------------------------------- + ! crop calendar streams switch for CropPhenology + !---------------------------------------------------------- + + logical, public :: use_cropcal_streams = .false. + logical, public :: use_cropcal_rx_sdates = .false. + logical, public :: use_cropcal_rx_cultivar_gdds = .false. + !---------------------------------------------------------- ! biomass heat storage switch !---------------------------------------------------------- @@ -331,6 +352,11 @@ module clm_varctl logical, public :: downscale_hillslope_meteorology = .false. ! true => downscale meteorological forcing in hillslope model logical, public :: use_hillslope_routing = .false. ! true => use surface water routing in hillslope hydrology + !---------------------------------------------------------- + ! excess ice physics switch + !---------------------------------------------------------- + logical, public :: use_excess_ice = .false. ! true. => use excess ice physics + !---------------------------------------------------------- ! plant hydraulic stress switch !---------------------------------------------------------- @@ -391,8 +417,8 @@ module clm_varctl ! namelist: write CH4 extra diagnostic output logical, public :: hist_wrtch4diag = .false. - ! namelist: write history master list to a file for use in documentation - logical, public :: hist_master_list_file = .false. + ! namelist: write list of all history fields to a file for use in documentation + logical, public :: hist_fields_list_file = .false. !---------------------------------------------------------- ! FATES diff --git a/src/main/clm_varpar.F90 b/src/main/clm_varpar.F90 index f54b750181..ffa851482a 100644 --- a/src/main/clm_varpar.F90 +++ b/src/main/clm_varpar.F90 @@ -113,7 +113,6 @@ module clm_varpar integer, public :: cft_size ! Number of PFTs on crop landunit in arrays of PFTs integer, public :: maxpatch_glc ! max number of elevation classes - integer, public :: max_patch_per_col ! ! !PUBLIC MEMBER FUNCTIONS: public clm_varpar_init ! set parameters @@ -195,13 +194,6 @@ subroutine clm_varpar_init(actual_maxsoil_patches, surf_numpft, surf_numcft) mxharvests = mxsowings + 1 - ! TODO(wjs, 2015-10-04, bugz 2227) Using surf_numcft in this 'max' gives a significant - ! overestimate of max_patch_per_col when use_crop is true. This should be reworked - - ! or, better, removed from the code entirely (because it is a maintenance problem, and - ! I can't imagine that looping idioms that use it help performance that much, and - ! likely they hurt performance.) - max_patch_per_col= max(maxsoil_patches, surf_numcft, maxpatch_urb) - nlevsoifl = 10 nlevurb = 5 diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 59c10493c5..69129706f9 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -162,7 +162,7 @@ subroutine control_init(dtime) hist_fexcl4, hist_fexcl5, hist_fexcl6, & hist_fexcl7, hist_fexcl8, & hist_fexcl9, hist_fexcl10 - namelist /clm_inparm/ hist_wrtch4diag, hist_master_list_file + namelist /clm_inparm/ hist_wrtch4diag, hist_fields_list_file ! BGC info @@ -203,7 +203,8 @@ subroutine control_init(dtime) irrigate, run_zero_weight_urban, all_active, & crop_fsat_equals_zero, for_testing_run_ncdiopio_tests, & for_testing_use_second_grain_pool, for_testing_use_repr_structure_pool, & - for_testing_no_crop_seed_replenishment + for_testing_no_crop_seed_replenishment, & + z0param_method, use_z0m_snowmelt ! vertical soil mixing variables namelist /clm_inparm/ & @@ -232,8 +233,8 @@ subroutine control_init(dtime) fates_parteh_mode, & use_fates_tree_damage - ! Ozone vegetation stress method - namelist / clm_inparam / o3_veg_stress_method + ! Ozone vegetation stress method + namelist / clm_inparam / o3_veg_stress_method ! CLM 5.0 nitrogen flags namelist /clm_inparm/ use_flexibleCN, use_luna @@ -244,6 +245,8 @@ subroutine control_init(dtime) namelist /clm_inparm/ use_soil_moisture_streams + namelist /clm_inparm/ use_excess_ice + namelist /clm_inparm/ use_lai_streams namelist /clm_inparm/ use_bedrock @@ -439,6 +442,21 @@ subroutine control_init(dtime) ! Check compatibility with the FATES model if ( use_fates ) then + if(use_fates_sp) then + use_fates_bgc = .false. + else + use_fates_bgc = .true. + end if + + if (fates_parteh_mode == 1 .and. suplnitro == suplnNon .and. use_fates_bgc )then + write(iulog,*) ' When FATES with fates_parteh_mode == 1 (ie carbon only mode),' + write(iulog,*) ' you must have supplemental nitrogen turned on, there will be' + write(iulog,*) ' no nitrogen dynamics with the plants, and therefore no' + write(iulog,*) ' meaningful limitations to nitrogen.' + call endrun(msg=' ERROR: fates_parteh_mode=1 must have suplnitro set to suplnAll.'//& + errMsg(sourcefile, __LINE__)) + end if + if ( use_cn) then call endrun(msg=' ERROR: use_cn and use_fates cannot both be set to true.'//& errMsg(sourcefile, __LINE__)) @@ -464,8 +482,28 @@ subroutine control_init(dtime) errMsg(sourcefile, __LINE__)) end if + if (use_c13 .or. use_c14) then + call endrun(msg=' ERROR: C13 and C14 dynamics are not compatible with FATES.'//& + errMsg(sourcefile, __LINE__)) + end if + + else + + ! These do default to false anyway, but this emphasizes they + ! are false when fates is false + use_fates_sp = .false. + use_fates_bgc = .false. + end if + ! Check compatibility with use_lai_streams + if (use_lai_streams) then + if ((use_fates .and. .not. use_fates_sp) .or. use_cn) then + call endrun(msg=' ERROR: cannot use LAI streams unless in SP mode (use_cn = .false. or use_fates_sp=.true.).'//& + errMsg(sourcefile, __LINE__)) + end if + end if + ! If nfix_timeconst is equal to the junk default value, then it was not specified ! by the user namelist and we need to assign it the correct default value. If the ! user specified it in the namelist, we leave it alone. @@ -698,7 +736,10 @@ subroutine control_spmd() ! BGC call mpi_bcast (co2_type, len(co2_type), MPI_CHARACTER, 0, mpicom, ier) - if (use_cn) then + + call mpi_bcast (use_fates, 1, MPI_LOGICAL, 0, mpicom, ier) + + if (use_cn .or. use_fates) then call mpi_bcast (suplnitro, len(suplnitro), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (nfix_timeconst, 1, MPI_REAL8, 0, mpicom, ier) call mpi_bcast (spinup_state, 1, MPI_INTEGER, 0, mpicom, ier) @@ -710,8 +751,6 @@ subroutine control_spmd() call mpi_bcast (use_c14, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (for_testing_allow_interp_non_ciso_to_ciso, 1, MPI_LOGICAL, 0, mpicom, ier) - call mpi_bcast (use_fates, 1, MPI_LOGICAL, 0, mpicom, ier) - call mpi_bcast (fates_spitfire_mode, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (use_fates_logging, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_planthydro, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -723,6 +762,7 @@ subroutine control_spmd() call mpi_bcast (use_fates_fixed_biogeog, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_nocomp, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fates_sp, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_fates_bgc, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (fates_inventory_ctrl_filename, len(fates_inventory_ctrl_filename), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (fates_paramfile, len(fates_paramfile) , MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (fates_parteh_mode, 1, MPI_INTEGER, 0, mpicom, ier) @@ -742,8 +782,12 @@ subroutine control_spmd() call mpi_bcast (use_soil_moisture_streams, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_excess_ice, 1, MPI_LOGICAL, 0, mpicom,ier) + call mpi_bcast (use_lai_streams, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_cropcal_streams, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_bedrock, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_biomass_heat_storage, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -758,7 +802,7 @@ subroutine control_spmd() call mpi_bcast (use_dynroot, 1, MPI_LOGICAL, 0, mpicom, ier) - if (use_cn ) then + if (use_cn .or. use_fates) then ! vertical soil mixing variables call mpi_bcast (som_adv_flux, 1, MPI_REAL8, 0, mpicom, ier) call mpi_bcast (max_depth_cryoturb, 1, MPI_REAL8, 0, mpicom, ier) @@ -767,7 +811,7 @@ subroutine control_spmd() call mpi_bcast (surfprof_exp, 1, MPI_REAL8, 0, mpicom, ier) end if - if (use_cn .and. use_nitrif_denitrif) then + if ((use_cn.or.use_fates) .and. use_nitrif_denitrif) then call mpi_bcast (no_frozen_nitrif_denitrif, 1, MPI_LOGICAL, 0, mpicom, ier) end if @@ -794,6 +838,8 @@ subroutine control_spmd() call mpi_bcast (nsegspc, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (use_subgrid_fluxes , 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (snow_cover_fraction_method , len(snow_cover_fraction_method), MPI_CHARACTER, 0, mpicom, ier) + call mpi_bcast (z0param_method , len(z0param_method), MPI_CHARACTER, 0, mpicom, ier) + call mpi_bcast (use_z0m_snowmelt, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (single_column,1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (scmlat, 1, MPI_REAL8,0, mpicom, ier) call mpi_bcast (scmlon, 1, MPI_REAL8,0, mpicom, ier) @@ -823,7 +869,7 @@ subroutine control_spmd() if (use_lch4) then call mpi_bcast (hist_wrtch4diag, 1, MPI_LOGICAL, 0, mpicom, ier) end if - call mpi_bcast (hist_master_list_file, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (hist_fields_list_file, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (hist_fexcl1, max_namlen*size(hist_fexcl1), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (hist_fexcl2, max_namlen*size(hist_fexcl2), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (hist_fexcl3, max_namlen*size(hist_fexcl3), MPI_CHARACTER, 0, mpicom, ier) @@ -882,6 +928,7 @@ subroutine control_print () write(iulog,*) ' use_nitrif_denitrif = ', use_nitrif_denitrif write(iulog,*) ' use_extralakelayers = ', use_extralakelayers write(iulog,*) ' use_vichydro = ', use_vichydro + write(iulog,*) ' use_excess_ice = ', use_excess_ice write(iulog,*) ' use_cn = ', use_cn write(iulog,*) ' use_cndv = ', use_cndv write(iulog,*) ' use_crop = ', use_crop @@ -914,7 +961,8 @@ subroutine control_print () write(iulog,*) ' Threshold above which the model keeps the lake landunit =', toosmall_lake write(iulog,*) ' Threshold above which the model keeps the wetland landunit =', toosmall_wetland write(iulog,*) ' Threshold above which the model keeps the urban landunits =', toosmall_urban - if (use_cn) then + + if (use_cn .or. use_fates) then if (suplnitro /= suplnNon)then write(iulog,*) ' Supplemental Nitrogen mode is set to run over Patches: ', & trim(suplnitro) @@ -945,13 +993,13 @@ subroutine control_print () write(iulog,*) ' override_bgc_restart_mismatch_dump : ', override_bgc_restart_mismatch_dump end if - if (use_cn ) then + if (use_cn .or. use_fates) then write(iulog, *) ' som_adv_flux, the advection term in soil mixing (m/s) : ', som_adv_flux write(iulog, *) ' max_depth_cryoturb (m) : ', max_depth_cryoturb write(iulog, *) ' surfprof_exp : ', surfprof_exp end if - if (use_cn .and. .not. use_nitrif_denitrif) then + if ((use_cn .or. use_fates) .and. .not. use_nitrif_denitrif) then write(iulog, *) ' no_frozen_nitrif_denitrif : ', no_frozen_nitrif_denitrif end if diff --git a/src/main/filterMod.F90 b/src/main/filterMod.F90 index 526cb7c8f3..2fb7d23079 100644 --- a/src/main/filterMod.F90 +++ b/src/main/filterMod.F90 @@ -19,6 +19,7 @@ module filterMod use ColumnType , only : col use PatchType , only : patch use glcBehaviorMod , only : glc_behavior_type + use clm_varctl , only : use_cn, use_fates, use_fates_bgc ! ! !PUBLIC TYPES: implicit none @@ -32,9 +33,10 @@ module filterMod integer, pointer :: natvegp(:) ! CNDV nat-vegetated (present) filter (patches) integer :: num_natvegp ! number of patches in nat-vegetated filter - integer, pointer :: pcropp(:) ! prognostic crop filter (patches) + integer, pointer :: pcropp(:) ! prognostic crop filter (patches) integer :: num_pcropp ! number of patches in prognostic crop filter - integer, pointer :: soilnopcropp(:) ! soil w/o prog. crops (patches) + + integer, pointer :: soilnopcropp(:) ! soil w/o prog. crops (patches) integer :: num_soilnopcropp ! number of patches in soil w/o prog crops integer, pointer :: all_soil_patches(:) ! all soil or crop patches. Used for updating FATES SP drivers @@ -49,6 +51,14 @@ module filterMod integer, pointer :: nolakec(:) ! non-lake filter (columns) integer :: num_nolakec ! number of columns in non-lake filter + integer, pointer :: bgc_soilc(:) ! soil with biogeochemistry active, negates + ! SP type runs, could be CN, FATES or CROP + integer :: num_bgc_soilc + + integer, pointer :: bgc_vegp(:) ! patches with vegetation biochemistry active, negates + ! SP type runs, could be CN or Crop (NOT FATES) + integer :: num_bgc_vegp + integer, pointer :: soilc(:) ! soil filter (columns) integer :: num_soilc ! number of columns in soil filter integer, pointer :: soilp(:) ! soil filter (patches) @@ -211,6 +221,9 @@ subroutine allocFiltersOneGroup(this_filter) allocate(this_filter(nc)%soilc(bounds%endc-bounds%begc+1)) allocate(this_filter(nc)%soilp(bounds%endp-bounds%begp+1)) + allocate(this_filter(nc)%bgc_soilc(bounds%endc-bounds%begc+1)) + allocate(this_filter(nc)%bgc_vegp(bounds%endp-bounds%begp+1)) + allocate(this_filter(nc)%snowc(bounds%endc-bounds%begc+1)) allocate(this_filter(nc)%nosnowc(bounds%endc-bounds%begc+1)) @@ -380,6 +393,39 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio this_filter(nc)%num_nolakep = fnl this_filter(nc)%num_nolakeurbanp = fnlu + + ! Create the soil bgc filter, all non-sp columns for vegetation + fs = 0 + if( use_cn .or. use_fates_bgc )then + do c = bounds%begc,bounds%endc + if (col%active(c) .or. include_inactive) then + l =col%landunit(c) + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + fs = fs + 1 + this_filter(nc)%bgc_soilc(fs) = c + end if + end if + end do + end if + this_filter(nc)%num_bgc_soilc = fs + + ! Create a filter at patch-level for vegetation biochemistry + ! all non-SP and non-fates patches on soil + fs = 0 + if(use_cn)then + do p = bounds%begp,bounds%endp + if (patch%active(p) .or. include_inactive) then + l =patch%landunit(p) + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + fs = fs + 1 + this_filter(nc)%bgc_vegp(fs) = p + end if + end if + end do + end if + this_filter(nc)%num_bgc_vegp = fs + + ! Create soil filter at column-level fs = 0 @@ -393,8 +439,12 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio end if end do this_filter(nc)%num_soilc = fs - ! Create soil filter at patch-level + + + + + ! Create soil filter at patch-level fs = 0 do p = bounds%begp,bounds%endp if (patch%active(p) .or. include_inactive) then @@ -405,6 +455,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio end if end if end do + this_filter(nc)%num_soilp = fs ! Create column-level hydrology filter (soil and Urban pervious road cols) @@ -426,15 +477,17 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio fl = 0 fnl = 0 do p = bounds%begp,bounds%endp - if (patch%active(p) .or. include_inactive) then - if (patch%itype(p) >= npcropmin) then !skips 2 generic crop types - fl = fl + 1 - this_filter(nc)%pcropp(fl) = p - else - l =patch%landunit(p) - if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then - fnl = fnl + 1 - this_filter(nc)%soilnopcropp(fnl) = p + if(.not.use_fates)then + if (patch%active(p) .or. include_inactive) then + if (patch%itype(p) >= npcropmin) then !skips 2 generic crop types + fl = fl + 1 + this_filter(nc)%pcropp(fl) = p + else + l =patch%landunit(p) + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + fnl = fnl + 1 + this_filter(nc)%soilnopcropp(fnl) = p + end if end if end if end if diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index b6790ee8d5..19591710b2 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -22,12 +22,12 @@ module histFileMod use LandunitType , only : lun use ColumnType , only : col use PatchType , only : patch - use EDTypesMod , only : nclmax - use EDTypesMod , only : nlevleaf + use EDParamsMod , only : nclmax + use EDParamsMod , only : nlevleaf use FatesInterfaceTypesMod , only : nlevsclass, nlevage, nlevcoage use FatesInterfaceTypesMod , only : nlevheight use FatesInterfaceTypesMod , only : nlevdamage - use EDTypesMod , only : nfsc + use FatesLitterMod , only : nfsc use FatesLitterMod , only : ncwd use PRTGenericMod , only : num_elements_fates => num_elements use FatesInterfaceTypesMod , only : numpft_fates => numpft @@ -141,13 +141,13 @@ module histFileMod logical, private :: if_disphist(max_tapes) ! restart, true => save history file ! ! !PUBLIC MEMBER FUNCTIONS: (in rough call order) - public :: hist_addfld1d ! Add a 1d single-level field to the master field list - public :: hist_addfld2d ! Add a 2d multi-level field to the master field list + public :: hist_addfld1d ! Add a 1d single-level field to the list of all history fields + public :: hist_addfld2d ! Add a 2d multi-level field to the list of all history fields public :: hist_addfld_decomp ! Add a 1d/2d field based on patch or column data public :: hist_add_subscript ! Add a 2d subscript dimension - public :: hist_printflds ! Print summary of master field list - public :: htapes_fieldlist ! Finalize history file field lists, intersecting masterlist with + public :: hist_printflds ! Print summary of list of all history fields + public :: htapes_fieldlist ! Finalize history file field lists, intersecting allhistfldlist with ! namelist params. public :: hist_htapes_build ! Initialize history file handler (for initial or continued run) @@ -158,10 +158,10 @@ module histFileMod ! ! !PRIVATE MEMBER FUNCTIONS: private :: is_mapping_upto_subgrid ! Is this field being mapped up to a higher subgrid level? - private :: masterlist_make_active ! Declare a single field active for a single tape - private :: masterlist_addfld ! Add a field to the master field list - private :: masterlist_change_timeavg ! Override default history tape contents for specific tape - private :: htape_addfld ! Transfer field metadata from masterlist to a history tape. + private :: allhistfldlist_make_active ! Declare a single field active for a single tape + private :: allhistfldlist_addfld ! Add a field to the list of all history fields + private :: allhistfldlist_change_timeavg ! Override default history tape contents for specific tape + private :: htape_addfld ! Transfer field metadata from allhistfldlist to a history tape. private :: htape_create ! Define netcdf metadata of history file t private :: htape_add_ltype_metadata ! Add global metadata defining landunit types private :: htape_add_ctype_metadata ! Add global metadata defining column types @@ -197,6 +197,20 @@ module histFileMod integer :: num_subs = 0 ! actual number of subscripts character(len=32) :: subs_name(max_subs) ! name of subscript integer :: subs_dim(max_subs) ! dimension of subscript + + ! type2d value for a field without a level dimension. This value is important for the + ! following reasons (as of 2023-08-21): + ! - type2d is used to determine the sort order of history fields both within the history + ! file (e.g., what you see from 'ncdump -h') and in the documentation that lists all + ! history fields. For these purposes, it is important that variables with + ! type2d_unset appear before variables with a real type2d, so type2d_unset should + ! appear early in alphabetical sort order. (If type2d_unset were changed to something + ! that appeared later in alphabetical sort order, then sort_hist_list should be + ! changed to have some special handling of fields with type2d_unset, forcing them to + ! appear first.) + ! - This will soon be added to the history field documentation, so should be a sensible + ! value for the type2d column in that output. + character(len=*), parameter :: type2d_unset = '-' ! type field_info character(len=max_namlen) :: name ! field name @@ -241,14 +255,14 @@ end subroutine copy_entry_interface ! Additional per-field metadata. See also history_entry. ! These values are specified in hist_addfld* calls but then can be ! overridden by namelist params like hist_fincl1. - type, extends(entry_base) :: master_entry + type, extends(entry_base) :: allhistfldlist_entry logical :: actflag(max_tapes) ! which history tapes to write to. character(len=avgflag_strlen) :: avgflag(max_tapes) ! type of time averaging contains - procedure :: copy => copy_master_entry - end type master_entry + procedure :: copy => copy_allhistfldlist_entry + end type allhistfldlist_entry - ! Actual per-field history data, accumulated from clmptr_r* vars. See also master_entry. + ! Actual per-field history data, accumulated from clmptr_r* vars. See also allhistfldlist_entry. type, extends(entry_base) :: history_entry character(len=avgflag_strlen) :: avgflag ! time averaging flag ("X","A","M","I","SUM") real(r8), pointer :: hbuf(:,:) ! history buffer (dimensions: dim1d x num2d) @@ -261,7 +275,7 @@ end subroutine copy_entry_interface ! at a given time frequency and precision. The first ('primary') tape defaults to a non-empty set ! of active fields (see hist_addfld* methods), overridable by namelist flags, while the other ! tapes are entirely manually configured via namelist flags. The set of active fields across all - ! tapes is assembled in the 'masterlist' variable. Note that the first history tape is index 1 in + ! tapes is assembled in the 'allhistfldlist' variable. Note that the first history tape is index 1 in ! the code but contains 'h0' in its output filenames (see set_hist_filename method). type history_tape integer :: nflds ! number of active fields on tape @@ -273,7 +287,7 @@ end subroutine copy_entry_interface logical :: is_endhist ! true => current time step is end of history interval real(r8) :: begtime ! time at beginning of history averaging interval type (history_entry) :: hlist(max_flds) ! array of active history tape entries. - ! The ordering matches the masterlist's. + ! The ordering matches the allhistfldlist's. end type history_tape type clmpoint_rs ! Pointer to real scalar data (1D) @@ -294,7 +308,7 @@ end subroutine copy_entry_interface ! hist_addfld* calls in the code. ! For the field data itself, see 'tape'. ! - type (master_entry) :: masterlist(max_flds) ! master field list + type (allhistfldlist_entry) :: allhistfldlist(max_flds) ! list of all history fields ! ! Whether each history tape is in use in this run. If history_tape_in_use(i) is false, ! then data in tape(i) is undefined and should not be referenced. @@ -302,7 +316,7 @@ end subroutine copy_entry_interface logical :: history_tape_in_use(max_tapes) ! whether each history tape is in use in this run ! ! The actual (accumulated) history data for all active fields in each in-use tape. See - ! 'history_tape_in_use' for in-use tapes, and 'masterlist' for active fields. See also + ! 'history_tape_in_use' for in-use tapes, and 'allhistfldlist' for active fields. See also ! clmptr_r* variables for raw history data. ! type (history_tape) :: tape(max_tapes) ! array of history tapes @@ -311,7 +325,7 @@ end subroutine copy_entry_interface ! ! Counters ! - integer :: nfmaster = 0 ! number of fields in master field list + integer :: nallhistflds = 0 ! number of fields in list of all history fields ! ! Other variables ! @@ -347,10 +361,10 @@ end subroutine copy_entry_interface subroutine hist_printflds() ! ! !DESCRIPTION: - ! Print summary of master field list. + ! Print summary of list of all history fields. ! ! !USES: - use clm_varctl, only: hist_master_list_file + use clm_varctl, only: hist_fields_list_file use fileutils, only: getavu, relavu ! ! !ARGUMENTS: @@ -358,43 +372,43 @@ subroutine hist_printflds() ! !LOCAL VARIABLES: integer, parameter :: ncol = 5 ! number of table columns integer nf, i, j ! do-loop counters - integer master_list_file ! file unit number + integer hist_fields_file ! file unit number integer width_col(ncol) ! widths of table columns integer width_col_sum ! widths of columns summed, including spaces character(len=3) str_width_col(ncol) ! string version of width_col character(len=3) str_w_col_sum ! string version of width_col_sum character(len=7) file_identifier ! fates identifier used in file_name - character(len=23) file_name ! master_list_file.rst with or without fates + character(len=26) file_name ! hist_fields_file.rst with or without fates character(len=99) fmt_txt ! format statement character(len=*),parameter :: subname = 'CLM_hist_printflds' !----------------------------------------------------------------------- if (masterproc) then - write(iulog,*) trim(subname),' : number of master fields = ',nfmaster - write(iulog,*)' ******* MASTER FIELD LIST *******' - do nf = 1,nfmaster - write(iulog,9000)nf, masterlist(nf)%field%name, masterlist(nf)%field%units + write(iulog,*) trim(subname),' : number of history fields = ',nallhistflds + write(iulog,*)' ******* LIST OF ALL HISTORY FIELDS *******' + do nf = 1,nallhistflds + write(iulog,9000)nf, allhistfldlist(nf)%field%name, allhistfldlist(nf)%field%units 9000 format (i5,1x,a32,1x,a16) end do call shr_sys_flush(iulog) end if - ! Print master field list in separate text file when namelist + ! Print list of all history fields in separate text file when namelist ! variable requests it. Text file is formatted in the .rst ! (reStructuredText) format for easy introduction of the file to ! the CTSM's web-based documentation. ! First sort the list to be in alphabetical order - call sort_hist_list(1, nfmaster, masterlist) + call sort_hist_list(1, nallhistflds, allhistfldlist) - if (masterproc .and. hist_master_list_file) then + if (masterproc .and. hist_fields_list_file) then ! Hardwired table column widths to fit the table on a computer ! screen. Some strings will be truncated as a result of the - ! current choices (4, 35, 94, 65, 7). In sphinx (ie the web-based + ! current choices (35, 16, 94, 65, 7). In sphinx (ie the web-based ! documentation), text that has not been truncated will wrap ! around in the available space. - width_col(1) = 4 ! column that shows the variable number, nf - width_col(2) = 35 ! variable name column + width_col(1) = 35 ! variable name column + width_col(2) = hist_dim_name_length ! level dimension column width_col(3) = 94 ! long description column width_col(4) = 65 ! units column width_col(5) = 7 ! active (T or F) column @@ -407,97 +421,98 @@ subroutine hist_printflds() end do write(str_w_col_sum,'(i0)') width_col_sum - ! Open master_list_file - master_list_file = getavu() ! get next available file unit number + ! Open hist_fields_file + hist_fields_file = getavu() ! get next available file unit number if (use_fates) then file_identifier = 'fates' else file_identifier = 'nofates' end if - file_name = 'master_list_' // trim(file_identifier) // '.rst' - open(unit = master_list_file, file = file_name, & + file_name = 'history_fields_' // trim(file_identifier) // '.rst' + open(unit = hist_fields_file, file = file_name, & status = 'replace', action = 'write', form = 'formatted') ! File title fmt_txt = '(a)' - write(master_list_file,fmt_txt) '=============================' - write(master_list_file,fmt_txt) 'CTSM History Fields (' // trim(file_identifier) // ')' - write(master_list_file,fmt_txt) '=============================' - write(master_list_file,*) + write(hist_fields_file,fmt_txt) '=============================' + write(hist_fields_file,fmt_txt) 'CTSM History Fields (' // trim(file_identifier) // ')' + write(hist_fields_file,fmt_txt) '=============================' + write(hist_fields_file,*) ! A warning message and flags from the current CTSM case - write(master_list_file,fmt_txt) 'CAUTION: Not all variables are relevant / present for all CTSM cases.' - write(master_list_file,fmt_txt) 'Key flags used in this CTSM case:' + write(hist_fields_file,fmt_txt) 'CAUTION: Not all variables are relevant / present for all CTSM cases.' + write(hist_fields_file,fmt_txt) 'Key flags used in this CTSM case:' fmt_txt = '(a,l)' - write(master_list_file,fmt_txt) 'use_cn = ', use_cn - write(master_list_file,fmt_txt) 'use_crop = ', use_crop - write(master_list_file,fmt_txt) 'use_fates = ', use_fates - write(master_list_file,*) + write(hist_fields_file,fmt_txt) 'use_cn = ', use_cn + write(hist_fields_file,fmt_txt) 'use_crop = ', use_crop + write(hist_fields_file,fmt_txt) 'use_fates = ', use_fates + write(hist_fields_file,*) ! Table header ! Concatenate strings needed in format statement do i = 1, ncol fmt_txt = '('//str_width_col(i)//'a,x)' - write(master_list_file,fmt_txt,advance='no') ('=', j=1,width_col(i)) + write(hist_fields_file,fmt_txt,advance='no') ('=', j=1,width_col(i)) end do - write(master_list_file,*) ! next write statement will now appear in new line + write(hist_fields_file,*) ! next write statement will now appear in new line ! Table title fmt_txt = '(a)' - write(master_list_file,fmt_txt) 'CTSM History Fields' + write(hist_fields_file,fmt_txt) 'CTSM History Fields' ! Sub-header ! Concatenate strings needed in format statement fmt_txt = '('//str_w_col_sum//'a)' - write(master_list_file,fmt_txt) ('-', i=1, width_col_sum) + write(hist_fields_file,fmt_txt) ('-', i=1, width_col_sum) ! Concatenate strings needed in format statement fmt_txt = '(a'//str_width_col(1)//',x,a'//str_width_col(2)//',x,a'//str_width_col(3)//',x,a'//str_width_col(4)//',x,a'//str_width_col(5)//')' - write(master_list_file,fmt_txt) '#', 'Variable Name', & - 'Long Description', 'Units', 'Active?' + write(hist_fields_file,fmt_txt) 'Variable Name', & + 'Level Dim.', 'Long Description', 'Units', 'Active?' ! End header, same as header ! Concatenate strings needed in format statement do i = 1, ncol fmt_txt = '('//str_width_col(i)//'a,x)' - write(master_list_file,fmt_txt,advance='no') ('=', j=1,width_col(i)) + write(hist_fields_file,fmt_txt,advance='no') ('=', j=1,width_col(i)) end do - write(master_list_file,*) ! next write statement will now appear in new line + write(hist_fields_file,*) ! next write statement will now appear in new line ! Main table ! Concatenate strings needed in format statement - fmt_txt = '(i'//str_width_col(1)//',x,a'//str_width_col(2)//',x,a'//str_width_col(3)//',x,a'//str_width_col(4)//',l'//str_width_col(5)//')' - do nf = 1,nfmaster - write(master_list_file,fmt_txt) nf, & - masterlist(nf)%field%name, & - masterlist(nf)%field%long_name, & - masterlist(nf)%field%units, & - masterlist(nf)%actflag(1) + fmt_txt = '(a'//str_width_col(1)//',x,a'//str_width_col(2)//',x,a'//str_width_col(3)//',x,a'//str_width_col(4)//',l'//str_width_col(5)//')' + do nf = 1,nallhistflds + write(hist_fields_file,fmt_txt) & + allhistfldlist(nf)%field%name, & + allhistfldlist(nf)%field%type2d, & + allhistfldlist(nf)%field%long_name, & + allhistfldlist(nf)%field%units, & + allhistfldlist(nf)%actflag(1) end do ! Table footer, same as header ! Concatenate strings needed in format statement do i = 1, ncol fmt_txt = '('//str_width_col(i)//'a,x)' - write(master_list_file,fmt_txt,advance='no') ('=', j=1,width_col(i)) + write(hist_fields_file,fmt_txt,advance='no') ('=', j=1,width_col(i)) end do - call shr_sys_flush(master_list_file) - close(unit = master_list_file) - call relavu(master_list_file) ! close and release file unit number + call shr_sys_flush(hist_fields_file) + close(unit = hist_fields_file) + call relavu(hist_fields_file) ! close and release file unit number end if end subroutine hist_printflds !----------------------------------------------------------------------- - subroutine masterlist_addfld (fname, numdims, type1d, type1d_out, & + subroutine allhistfldlist_addfld (fname, numdims, type1d, type1d_out, & type2d, num2d, units, avgflag, long_name, hpindex, & p2c_scale_type, c2l_scale_type, l2g_scale_type, & no_snow_behavior) ! ! !DESCRIPTION: - ! Add a field to the master field list. Put input arguments of + ! Add a field to the list of all history fields. Put input arguments of ! field name, units, number of levels, averaging flag, and long name - ! into a type entry in the global master field list (masterlist). + ! into a type entry in the global list of all history fields (allhistfldlist). ! ! The optional argument no_snow_behavior should be given when this is a multi-layer ! snow field, and should be absent otherwise. It should take on one of the no_snow_* @@ -521,14 +536,14 @@ subroutine masterlist_addfld (fname, numdims, type1d, type1d_out, & ! ! !LOCAL VARIABLES: integer :: n ! loop index - integer :: f ! masterlist index + integer :: f ! allhistfldlist index integer :: numa ! total number of atm cells across all processors integer :: numg ! total number of gridcells across all processors integer :: numl ! total number of landunits across all processors integer :: numc ! total number of columns across all processors integer :: nump ! total number of pfts across all processors type(bounds_type) :: bounds - character(len=*),parameter :: subname = 'masterlist_addfld' + character(len=*),parameter :: subname = 'allhistfldlist_addfld' !------------------------------------------------------------------------ if (.not. avgflag_valid(avgflag, blank_valid=.true.)) then @@ -556,82 +571,82 @@ subroutine masterlist_addfld (fname, numdims, type1d, type1d_out, & end if ! Ensure that new field doesn't already exist - do n = 1,nfmaster - if (masterlist(n)%field%name == fname) then + do n = 1,nallhistflds + if (allhistfldlist(n)%field%name == fname) then write(iulog,*) trim(subname),' ERROR:', fname, ' already on list' call endrun(msg=errMsg(sourcefile, __LINE__)) end if end do - ! Increase number of fields on master field list + ! Increase number of fields on list of all history fields - nfmaster = nfmaster + 1 - f = nfmaster + nallhistflds = nallhistflds + 1 + f = nallhistflds - ! Check number of fields in master list against maximum number for master list + ! Check number of fields in list against maximum number - if (nfmaster > max_flds) then + if (nallhistflds > max_flds) then write(iulog,*) trim(subname),' ERROR: too many fields for primary history file ', & - '-- max_flds,nfmaster=', max_flds, nfmaster + '-- max_flds,nallhistflds=', max_flds, nallhistflds call endrun(msg=errMsg(sourcefile, __LINE__)) end if - ! Add field to master list - - masterlist(f)%field%name = fname - masterlist(f)%field%long_name = long_name - masterlist(f)%field%units = units - masterlist(f)%field%type1d = type1d - masterlist(f)%field%type1d_out = type1d_out - masterlist(f)%field%type2d = type2d - masterlist(f)%field%numdims = numdims - masterlist(f)%field%num2d = num2d - masterlist(f)%field%hpindex = hpindex - masterlist(f)%field%p2c_scale_type = p2c_scale_type - masterlist(f)%field%c2l_scale_type = c2l_scale_type - masterlist(f)%field%l2g_scale_type = l2g_scale_type + ! Add field to list of all history fields + + allhistfldlist(f)%field%name = fname + allhistfldlist(f)%field%long_name = long_name + allhistfldlist(f)%field%units = units + allhistfldlist(f)%field%type1d = type1d + allhistfldlist(f)%field%type1d_out = type1d_out + allhistfldlist(f)%field%type2d = type2d + allhistfldlist(f)%field%numdims = numdims + allhistfldlist(f)%field%num2d = num2d + allhistfldlist(f)%field%hpindex = hpindex + allhistfldlist(f)%field%p2c_scale_type = p2c_scale_type + allhistfldlist(f)%field%c2l_scale_type = c2l_scale_type + allhistfldlist(f)%field%l2g_scale_type = l2g_scale_type select case (type1d) case (grlnd) - masterlist(f)%field%beg1d = bounds%begg - masterlist(f)%field%end1d = bounds%endg - masterlist(f)%field%num1d = numg + allhistfldlist(f)%field%beg1d = bounds%begg + allhistfldlist(f)%field%end1d = bounds%endg + allhistfldlist(f)%field%num1d = numg case (nameg) - masterlist(f)%field%beg1d = bounds%begg - masterlist(f)%field%end1d = bounds%endg - masterlist(f)%field%num1d = numg + allhistfldlist(f)%field%beg1d = bounds%begg + allhistfldlist(f)%field%end1d = bounds%endg + allhistfldlist(f)%field%num1d = numg case (namel) - masterlist(f)%field%beg1d = bounds%begl - masterlist(f)%field%end1d = bounds%endl - masterlist(f)%field%num1d = numl + allhistfldlist(f)%field%beg1d = bounds%begl + allhistfldlist(f)%field%end1d = bounds%endl + allhistfldlist(f)%field%num1d = numl case (namec) - masterlist(f)%field%beg1d = bounds%begc - masterlist(f)%field%end1d = bounds%endc - masterlist(f)%field%num1d = numc + allhistfldlist(f)%field%beg1d = bounds%begc + allhistfldlist(f)%field%end1d = bounds%endc + allhistfldlist(f)%field%num1d = numc case (namep) - masterlist(f)%field%beg1d = bounds%begp - masterlist(f)%field%end1d = bounds%endp - masterlist(f)%field%num1d = nump + allhistfldlist(f)%field%beg1d = bounds%begp + allhistfldlist(f)%field%end1d = bounds%endp + allhistfldlist(f)%field%num1d = nump case default write(iulog,*) trim(subname),' ERROR: unknown 1d output type= ',type1d call endrun(msg=errMsg(sourcefile, __LINE__)) end select if (present(no_snow_behavior)) then - masterlist(f)%field%no_snow_behavior = no_snow_behavior + allhistfldlist(f)%field%no_snow_behavior = no_snow_behavior else - masterlist(f)%field%no_snow_behavior = no_snow_unset + allhistfldlist(f)%field%no_snow_behavior = no_snow_unset end if - ! The following two fields are used only in master field list, + ! The following two fields are used only in list of all history fields, ! NOT in the runtime active field list - ! ALL FIELDS IN THE MASTER LIST ARE INITIALIZED WITH THE ACTIVE + ! ALL FIELDS IN THE FORMER ARE INITIALIZED WITH THE ACTIVE ! FLAG SET TO FALSE - masterlist(f)%avgflag(:) = avgflag - masterlist(f)%actflag(:) = .false. + allhistfldlist(f)%avgflag(:) = avgflag + allhistfldlist(f)%actflag(:) = .false. - end subroutine masterlist_addfld + end subroutine allhistfldlist_addfld !----------------------------------------------------------------------- subroutine hist_htapes_build () @@ -715,7 +730,7 @@ subroutine hist_htapes_build () end subroutine hist_htapes_build !----------------------------------------------------------------------- - subroutine masterlist_make_active (name, tape_index, avgflag) + subroutine allhistfldlist_make_active (name, tape_index, avgflag) ! ! !DESCRIPTION: ! Add a field to the default ``on'' list for a given history file. @@ -728,8 +743,8 @@ subroutine masterlist_make_active (name, tape_index, avgflag) ! ! !LOCAL VARIABLES: integer :: f ! field index - logical :: found ! flag indicates field found in masterlist - character(len=*),parameter :: subname = 'masterlist_make_active' + logical :: found ! flag indicates field found in allhistfldlist + character(len=*),parameter :: subname = 'allhistfldlist_make_active' !----------------------------------------------------------------------- ! Check validity of input arguments @@ -746,16 +761,16 @@ subroutine masterlist_make_active (name, tape_index, avgflag) endif end if - ! Look through master list for input field name. + ! Look through list of all history fields for input field name. ! When found, set active flag for that tape to true. ! Also reset averaging flag if told to use other than default. found = .false. - do f = 1,nfmaster - if (trim(name) == trim(masterlist(f)%field%name)) then - masterlist(f)%actflag(tape_index) = .true. + do f = 1,nallhistflds + if (trim(name) == trim(allhistfldlist(f)%field%name)) then + allhistfldlist(f)%actflag(tape_index) = .true. if (present(avgflag)) then - if (avgflag/= ' ') masterlist(f)%avgflag(tape_index) = avgflag + if (avgflag/= ' ') allhistfldlist(f)%avgflag(tape_index) = avgflag end if found = .true. exit @@ -766,14 +781,14 @@ subroutine masterlist_make_active (name, tape_index, avgflag) call endrun(msg=errMsg(sourcefile, __LINE__)) end if - end subroutine masterlist_make_active + end subroutine allhistfldlist_make_active !----------------------------------------------------------------------- - subroutine masterlist_change_timeavg (t) + subroutine allhistfldlist_change_timeavg (t) ! ! !DESCRIPTION: ! Override default history tape contents for a specific tape. - ! Copy the flag into the master field list. + ! Copy the flag into the list of all history fields. ! ! !ARGUMENTS: integer, intent(in) :: t ! history tape index @@ -781,7 +796,7 @@ subroutine masterlist_change_timeavg (t) ! !LOCAL VARIABLES: integer :: f ! field index character(len=avgflag_strlen) :: avgflag ! local equiv of hist_avgflag_pertape(t) - character(len=*),parameter :: subname = 'masterlist_change_timeavg' + character(len=*),parameter :: subname = 'allhistfldlist_change_timeavg' !----------------------------------------------------------------------- avgflag = hist_avgflag_pertape(t) @@ -790,11 +805,11 @@ subroutine masterlist_change_timeavg (t) call endrun(msg=errMsg(sourcefile, __LINE__)) end if - do f = 1,nfmaster - masterlist(f)%avgflag(t) = avgflag + do f = 1,nallhistflds + allhistfldlist(f)%avgflag(t) = avgflag end do - end subroutine masterlist_change_timeavg + end subroutine allhistfldlist_change_timeavg !----------------------------------------------------------------------- subroutine htapes_fieldlist() @@ -806,7 +821,7 @@ subroutine htapes_fieldlist() ! Then sort the result alphanumerically. ! ! Sets history_tape_in_use and htapes_defined. Fills fields in 'tape' array. - ! Optionally updates masterlist avgflag. + ! Optionally updates allhistfldlist avgflag. ! ! !ARGUMENTS: ! @@ -814,7 +829,7 @@ subroutine htapes_fieldlist() integer :: t, f ! tape, field indices integer :: ff ! index into include, exclude and fprec list character(len=max_namlen) :: name ! field name portion of fincl (i.e. no avgflag separator) - character(len=max_namlen) :: mastername ! name from masterlist field + character(len=max_namlen) :: allhistfldname ! name from allhistfldlist field character(len=avgflag_strlen) :: avgflag ! averaging flag character(len=1) :: prec_acc ! history buffer precision flag character(len=1) :: prec_wrt ! history buffer write precision flag @@ -826,7 +841,7 @@ subroutine htapes_fieldlist() do t=1,max_tapes if (hist_avgflag_pertape(t) /= ' ') then - call masterlist_change_timeavg (t) + call allhistfldlist_change_timeavg (t) end if end do @@ -859,11 +874,11 @@ subroutine htapes_fieldlist() f = 1 do while (f < max_flds .and. fincl(f,t) /= ' ') name = getname (fincl(f,t)) - do ff = 1,nfmaster - mastername = masterlist(ff)%field%name - if (name == mastername) exit + do ff = 1,nallhistflds + allhistfldname = allhistfldlist(ff)%field%name + if (name == allhistfldname) exit end do - if (name /= mastername) then + if (name /= allhistfldname) then write(iulog,*) trim(subname),' ERROR: ', trim(name), ' in fincl(', f, ') ',& 'for history tape ',t,' not found' call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -873,11 +888,11 @@ subroutine htapes_fieldlist() f = 1 do while (f < max_flds .and. fexcl(f,t) /= ' ') - do ff = 1,nfmaster - mastername = masterlist(ff)%field%name - if (fexcl(f,t) == mastername) exit + do ff = 1,nallhistflds + allhistfldname = allhistfldlist(ff)%field%name + if (fexcl(f,t) == allhistfldname) exit end do - if (fexcl(f,t) /= mastername) then + if (fexcl(f,t) /= allhistfldname) then write(iulog,*) trim(subname),' ERROR: ', fexcl(f,t), ' in fexcl(', f, ') ', & 'for history tape ',t,' not found' call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -890,16 +905,16 @@ subroutine htapes_fieldlist() tape(:)%nflds = 0 do t = 1,max_tapes - ! Loop through the masterlist set of field names and determine if any of those + ! Loop through the allhistfldlist set of field names and determine if any of those ! are in the FINCL or FEXCL arrays ! The call to list_index determines the index in the FINCL or FEXCL arrays - ! that the masterlist field corresponds to + ! that the allhistfldlist field corresponds to ! Add the field to the tape if specified via namelist (FINCL[1-max_tapes]), ! or if it is on by default and was not excluded via namelist (FEXCL[1-max_tapes]). - do f = 1,nfmaster - mastername = masterlist(f)%field%name - call list_index (fincl(1,t), mastername, ff) + do f = 1,nallhistflds + allhistfldname = allhistfldlist(f)%field%name + call list_index (fincl(1,t), allhistfldname, ff) if (ff > 0) then @@ -913,7 +928,7 @@ subroutine htapes_fieldlist() ! find index of field in exclude list - call list_index (fexcl(1,t), mastername, ff) + call list_index (fexcl(1,t), allhistfldname, ff) ! if field is in exclude list, ff > 0 and htape_addfld ! will not be called for field @@ -922,7 +937,7 @@ subroutine htapes_fieldlist() ! called below only if field is not in exclude list OR in ! include list - if (ff == 0 .and. masterlist(f)%actflag(t)) then + if (ff == 0 .and. allhistfldlist(f)%actflag(t)) then call htape_addfld (t, f, ' ') end if @@ -1002,7 +1017,7 @@ subroutine htapes_fieldlist() call shr_sys_flush(iulog) end if - ! Set flag indicating h-tape contents are now defined (needed by masterlist_addfld) + ! Set flag indicating h-tape contents are now defined (needed by allhistfldlist_addfld) htapes_defined = .true. @@ -1010,23 +1025,23 @@ subroutine htapes_fieldlist() end subroutine htapes_fieldlist !----------------------------------------------------------------------- - subroutine copy_master_entry(this, other) + subroutine copy_allhistfldlist_entry(this, other) ! set this = other - class(master_entry), intent(out) :: this + class(allhistfldlist_entry), intent(out) :: this class(entry_base), intent(in) :: other select type(this) - type is (master_entry) + type is (allhistfldlist_entry) select type(other) - type is (master_entry) + type is (allhistfldlist_entry) this = other class default - call endrun('Unexpected type of "other" in copy_master_entry') + call endrun('Unexpected type of "other" in copy_allhistfldlist_entry') end select class default - call endrun('Unexpected type of "this" in copy_master_entry') + call endrun('Unexpected type of "this" in copy_allhistfldlist_entry') end select - end subroutine copy_master_entry + end subroutine copy_allhistfldlist_entry !----------------------------------------------------------------------- subroutine copy_history_entry(this, other) @@ -1076,18 +1091,18 @@ subroutine sort_hist_list(t, n_fields, hist_list) do f = n_fields-1, 1, -1 do ff = 1, f - if (hist_list(ff)%field%name > hist_list(ff+1)%field%name) then + ! First sort by the name of the level dimension; then, within the list of + ! fields with the same level dimension, sort by field name. Sorting first by + ! the level dimension gives a significant performance improvement especially + ! notable on lustre file systems such as on derecho. + if (hist_list(ff)%field%type2d > hist_list(ff+1)%field%type2d .or. & + (hist_list(ff)%field%type2d == hist_list(ff+1)%field%type2d .and. & + hist_list(ff)%field%name > hist_list(ff+1)%field%name)) then call tmp%copy(hist_list(ff)) call hist_list(ff )%copy(hist_list(ff+1)) call hist_list(ff+1)%copy(tmp) - else if (hist_list(ff)%field%name == hist_list(ff+1)%field%name) then - - write(iulog,*) trim(subname),' ERROR: Duplicate field ', & - hist_list(ff)%field%name, & - 't,ff,name=',t,ff,hist_list(ff+1)%field%name - call endrun(msg=errMsg(sourcefile, __LINE__)) end if end do end do @@ -1133,11 +1148,11 @@ end function is_mapping_upto_subgrid subroutine htape_addfld (t, f, avgflag) ! ! !DESCRIPTION: - ! Add a field to a history tape, copying metadata from the master field list + ! Add a field to a history tape, copying metadata from the list of all history fields ! ! !ARGUMENTS: integer, intent(in) :: t ! history tape index - integer, intent(in) :: f ! field index from master field list + integer, intent(in) :: f ! field index from list of all history fields character(len=*), intent(in) :: avgflag ! time averaging flag ! ! !LOCAL VARIABLES: @@ -1161,7 +1176,7 @@ subroutine htape_addfld (t, f, avgflag) if (htapes_defined) then write(iulog,*) trim(subname),' ERROR: attempt to add field ', & - masterlist(f)%field%name, ' after history files are set' + allhistfldlist(f)%field%name, ' after history files are set' call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -1170,7 +1185,7 @@ subroutine htape_addfld (t, f, avgflag) ! Copy field information - tape(t)%hlist(n)%field = masterlist(f)%field + tape(t)%hlist(n)%field = allhistfldlist(f)%field ! Determine bounds @@ -1254,8 +1269,8 @@ subroutine htape_addfld (t, f, avgflag) tape(t)%hlist(n)%field%num1d_out = num1d_out ! Fields native bounds - beg1d = masterlist(f)%field%beg1d - end1d = masterlist(f)%field%end1d + beg1d = allhistfldlist(f)%field%beg1d + end1d = allhistfldlist(f)%field%end1d ! Alloccate and initialize history buffer and related info @@ -1270,7 +1285,7 @@ subroutine htape_addfld (t, f, avgflag) tape(t)%hlist(n)%hbuf(:,:) = 0._r8 tape(t)%hlist(n)%nacs(:,:) = 0 - ! Set time averaging flag based on masterlist setting or + ! Set time averaging flag based on allhistfldlist setting or ! override the default averaging flag with namelist setting if (.not. avgflag_valid(avgflag, blank_valid=.true.)) then @@ -1279,7 +1294,7 @@ subroutine htape_addfld (t, f, avgflag) end if if (avgflag == ' ') then - tape(t)%hlist(n)%avgflag = masterlist(f)%avgflag(t) + tape(t)%hlist(n)%avgflag = allhistfldlist(f)%avgflag(t) else tape(t)%hlist(n)%avgflag = avgflag end if @@ -5262,7 +5277,7 @@ subroutine hist_addfld1d (fname, units, avgflag, long_name, type1d_out, & ! !DESCRIPTION: ! Initialize a single level history field. The pointer inputs, ptr\_*, ! point to the appropriate-type array storing the raw history data points. - ! The value of type1d passed to masterlist\_add\_fld determines which of the + ! The value of type1d passed to allhistfldlist\_add\_fld determines which of the ! 1d type of the output and the beginning and ending indices the history ! buffer field). All fields default to being written to the first history tape ! unless 'default' is set to 'inactive'. @@ -5450,10 +5465,10 @@ subroutine hist_addfld1d (fname, units, avgflag, long_name, type1d_out, & if (present(l2g_scale_type)) scale_type_l2g = l2g_scale_type if (present(type1d_out)) l_type1d_out = type1d_out - ! Add field to masterlist + ! Add field to allhistfldlist - call masterlist_addfld (fname=trim(fname), numdims=1, type1d=l_type1d, & - type1d_out=l_type1d_out, type2d='unset', num2d=1, & + call allhistfldlist_addfld (fname=trim(fname), numdims=1, type1d=l_type1d, & + type1d_out=l_type1d_out, type2d=type2d_unset, num2d=1, & units=units, avgflag=avgflag, long_name=long_name, hpindex=hpindex, & p2c_scale_type=scale_type_p2c, c2l_scale_type=scale_type_c2l, & l2g_scale_type=scale_type_l2g) @@ -5465,7 +5480,7 @@ subroutine hist_addfld1d (fname, units, avgflag, long_name, type1d_out, & if (trim(l_default) == 'inactive') then return else - call masterlist_make_active (name=trim(fname), tape_index=1) + call allhistfldlist_make_active (name=trim(fname), tape_index=1) end if end subroutine hist_addfld1d @@ -5480,7 +5495,7 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, ! !DESCRIPTION: ! Initialize a single level history field. The pointer inputs, ptr\_*, ! point to the appropriate-type array storing the raw history data points. - ! The value of type1d passed to masterlist\_add\_fld determines which of the + ! The value of type1d passed to allhistfldlist\_add\_fld determines which of the ! 1d type of the output and the beginning and ending indices the history ! buffer field). All fields default to being written to the first history tape ! unless 'default' is set to 'inactive'. @@ -5786,9 +5801,9 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, if (present(l2g_scale_type)) scale_type_l2g = l2g_scale_type if (present(type1d_out)) l_type1d_out = type1d_out - ! Add field to masterlist + ! Add field to allhistfldlist - call masterlist_addfld (fname=trim(fname), numdims=2, type1d=l_type1d, & + call allhistfldlist_addfld (fname=trim(fname), numdims=2, type1d=l_type1d, & type1d_out=l_type1d_out, type2d=type2d, num2d=num2d, & units=units, avgflag=avgflag, long_name=long_name, hpindex=hpindex, & p2c_scale_type=scale_type_p2c, c2l_scale_type=scale_type_c2l, & @@ -5801,7 +5816,7 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, if (trim(l_default) == 'inactive') then return else - call masterlist_make_active (name=trim(fname), tape_index=1) + call allhistfldlist_make_active (name=trim(fname), tape_index=1) end if end subroutine hist_addfld2d diff --git a/src/main/initGridCellsMod.F90 b/src/main/initGridCellsMod.F90 index 3cd5ecf1e6..987611f5fc 100644 --- a/src/main/initGridCellsMod.F90 +++ b/src/main/initGridCellsMod.F90 @@ -279,7 +279,8 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) SHR_ASSERT_FL(npatches_added == npatches, sourcefile, __LINE__) end subroutine set_landunit_veg_compete - + + !------------------------------------------------------------------------ subroutine set_landunit_wet_lake (ltype, gi, li, ci, pi) ! diff --git a/src/main/pftconMod.F90 b/src/main/pftconMod.F90 index 7e7ecded3c..e5379100e0 100644 --- a/src/main/pftconMod.F90 +++ b/src/main/pftconMod.F90 @@ -122,6 +122,12 @@ module pftconMod real(r8), allocatable :: taul (:,:) ! leaf transmittance: 1=vis, 2=nir real(r8), allocatable :: taus (:,:) ! stem transmittance: 1=vis, 2=nir real(r8), allocatable :: z0mr (:) ! ratio of momentum roughness length to canopy top height (-) + real(r8), allocatable :: z0v_Cr (:) ! roughness-element drag coefficient for Raupach92 parameterization (-) + real(r8), allocatable :: z0v_Cs (:) ! substrate-element drag coefficient for Raupach92 parameterization (-) + real(r8), allocatable :: z0v_c (:) ! c parameter for Raupach92 parameterization (-) + real(r8), allocatable :: z0v_cw (:) ! roughness sublayer depth coefficient for Raupach92 parameterization (-) + real(r8), allocatable :: z0v_LAIoff (:) ! leaf area index offset for Raupach92 parameterization (-) + real(r8), allocatable :: z0v_LAImax (:) ! onset of over-sheltering for Raupach92 parameterization (-) real(r8), allocatable :: displar (:) ! ratio of displacement height to canopy top height (-) real(r8), allocatable :: roota_par (:) ! CLM rooting distribution parameter [1/m] real(r8), allocatable :: rootb_par (:) ! CLM rooting distribution parameter [1/m] @@ -361,11 +367,17 @@ subroutine InitAllocate (this) allocate( this%rhos (0:mxpft,numrad) ) allocate( this%taul (0:mxpft,numrad) ) allocate( this%taus (0:mxpft,numrad) ) - allocate( this%z0mr (0:mxpft) ) - allocate( this%displar (0:mxpft) ) - allocate( this%roota_par (0:mxpft) ) - allocate( this%rootb_par (0:mxpft) ) - allocate( this%crop (0:mxpft) ) + allocate( this%z0mr (0:mxpft) ) + allocate( this%z0v_Cr (0:mxpft) ) + allocate( this%z0v_Cs (0:mxpft) ) + allocate( this%z0v_c (0:mxpft) ) + allocate( this%z0v_cw (0:mxpft) ) + allocate( this%z0v_LAIoff (0:mxpft) ) + allocate( this%z0v_LAImax (0:mxpft) ) + allocate( this%displar (0:mxpft) ) + allocate( this%roota_par (0:mxpft) ) + allocate( this%rootb_par (0:mxpft) ) + allocate( this%crop (0:mxpft) ) allocate( this%mergetoclmpft (0:mxpft) ) allocate( this%is_pft_known_to_model (0:mxpft) ) allocate( this%irrigated (0:mxpft) ) @@ -508,7 +520,7 @@ subroutine InitRead(this) use fileutils , only : getfil use ncdio_pio , only : ncd_io, ncd_pio_closefile, ncd_pio_openfile, file_desc_t use ncdio_pio , only : ncd_inqdid, ncd_inqdlen - use clm_varctl , only : paramfile, use_fates, use_flexibleCN, use_dynroot, use_biomass_heat_storage + use clm_varctl , only : paramfile, use_fates, use_flexibleCN, use_dynroot, use_biomass_heat_storage, z0param_method use spmdMod , only : masterproc use CLMFatesParamInterfaceMod, only : FatesReadPFTs use SoilBiogeochemDecompCascadeConType, only : mimics_decomp, decomp_method @@ -639,8 +651,47 @@ subroutine InitRead(this) call ncd_io('pftname',pftname, 'read', ncid, readvar=readv, posNOTonfile=.true.) if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) - call ncd_io('z0mr', this%z0mr, 'read', ncid, readvar=readv, posNOTonfile=.true.) - if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + + + select case (z0param_method) + case ('ZengWang2007') + call ncd_io('z0mr', this%z0mr, 'read', ncid, readvar=readv, posNOTonfile=.true.) + if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + this%z0v_Cr = 0._r8 + this%z0v_Cs = 0._r8 + this%z0v_c = 0._r8 + this%z0v_cw = 0._r8 + this%z0v_LAImax = 0._r8 + this%z0v_LAIoff = 0._r8 + + case ('Meier2022') + call ncd_io('z0v_Cr', this%z0v_Cr, 'read', ncid, readvar=readv, posNOTonfile=.true.) + if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + + call ncd_io('z0v_Cs', this%z0v_Cs, 'read', ncid, readvar=readv, posNOTonfile=.true.) + if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + + call ncd_io('z0v_c', this%z0v_c, 'read', ncid, readvar=readv, posNOTonfile=.true.) + if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + + call ncd_io('z0v_cw', this%z0v_cw, 'read', ncid, readvar=readv, posNOTonfile=.true.) + if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + + call ncd_io('z0v_LAImax', this%z0v_LAImax, 'read', ncid, readvar=readv, posNOTonfile=.true.) + if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + + call ncd_io('z0v_LAIoff', this%z0v_LAIoff, 'read', ncid, readvar=readv, posNOTonfile=.true.) + if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + + this%z0mr = 0._r8 + + case default + write(iulog,*) subname//' ERROR: unknown z0param_method: ', & + z0param_method + call endrun(msg = 'unknown z0param_method', & + additional_msg = errMsg(sourcefile, __LINE__)) + end select + call ncd_io('displar', this%displar, 'read', ncid, readvar=readv, posNOTonfile=.true.) if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) @@ -1408,6 +1459,12 @@ subroutine Clean(this) deallocate( this%taul) deallocate( this%taus) deallocate( this%z0mr) + deallocate( this%z0v_Cr) + deallocate( this%z0v_Cs) + deallocate( this%z0v_c) + deallocate( this%z0v_cw) + deallocate( this%z0v_LAImax) + deallocate( this%z0v_LAIoff) deallocate( this%displar) deallocate( this%roota_par) deallocate( this%rootb_par) diff --git a/src/main/restFileMod.F90 b/src/main/restFileMod.F90 index d9c23d49f3..6a574406fd 100644 --- a/src/main/restFileMod.F90 +++ b/src/main/restFileMod.F90 @@ -27,6 +27,7 @@ module restFileMod use glcBehaviorMod , only : glc_behavior_type use reweightMod , only : reweight_wrapup use IssueFixedMetadataHandler, only : write_issue_fixed_metadata, read_issue_fixed_metadata + use restUtilMod , only : excess_ice_issue ! ! !PUBLIC TYPES: implicit none @@ -592,6 +593,8 @@ subroutine restFile_write_issues_fixed(ncid, writing_finidat_interp_dest_file) ! !DESCRIPTION: ! Write metadata for issues fixed ! + ! !USES: + use clm_varctl, only : use_excess_ice ! !ARGUMENTS: type(file_desc_t), intent(inout) :: ncid ! local file id logical , intent(in) :: writing_finidat_interp_dest_file ! true if we are writing a finidat_interp_dest file @@ -606,6 +609,15 @@ subroutine restFile_write_issues_fixed(ncid, writing_finidat_interp_dest_file) ncid = ncid, & writing_finidat_interp_dest_file = writing_finidat_interp_dest_file, & issue_num = lake_dynbal_baseline_issue) + ! If running with execess ice then mark the restart file as having excess ice fixed + ! This is a permanent feature, i.e. not expected to be removed from here. + ! It would only be removed if we decided to make use_excess_ice = .true. the default. + if ( use_excess_ice ) then + call write_issue_fixed_metadata( & + ncid = ncid, & + writing_finidat_interp_dest_file = writing_finidat_interp_dest_file, & + issue_num = excess_ice_issue) + end if end subroutine restFile_write_issues_fixed diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index 2480bf2413..2116d9c5d8 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -141,6 +141,7 @@ subroutine subgrid_get_info_natveg(gi, npatches, ncols, nlunits) ! ! !ARGUMENTS: integer, intent(in) :: gi ! grid cell index + integer, intent(out) :: npatches ! number of nat veg patches in this grid cell integer, intent(out) :: ncols ! number of nat veg columns in this grid cell integer, intent(out) :: nlunits ! number of nat veg landunits in this grid cell diff --git a/src/main/surfrdUtilsMod.F90 b/src/main/surfrdUtilsMod.F90 index 0763d43a16..6b581a59c1 100644 --- a/src/main/surfrdUtilsMod.F90 +++ b/src/main/surfrdUtilsMod.F90 @@ -7,6 +7,7 @@ module surfrdUtilsMod ! !USES: #include "shr_assert.h" use shr_kind_mod , only : r8 => shr_kind_r8 + use clm_varcon , only : sum_to_1_tol use clm_varctl , only : iulog,use_fates use abortutils , only : endrun use shr_log_mod , only : errMsg => shr_log_errMsg @@ -45,13 +46,12 @@ subroutine check_sums_equal_1(arr, lb, name, caller, ier, sumto) character(len=*), intent(in) :: name ! name of array character(len=*), intent(in) :: caller ! identifier of caller, for more meaningful error messages integer, optional, intent(out):: ier ! Return an error code rather than abort - real(r8), optional, intent(out):: sumto(lb:) ! The value the array should sum to (1.0 if not provided) + real(r8), optional, intent(in):: sumto(lb:) ! The value the array should sum to (1.0 if not provided) ! ! !LOCAL VARIABLES: logical :: found integer :: nl integer :: nindx - real(r8), parameter :: eps = 1.e-13_r8 real(r8), allocatable :: TotalSum(:) integer :: ub ! upper bound of the first dimension of arr !----------------------------------------------------------------------- @@ -63,8 +63,8 @@ subroutine check_sums_equal_1(arr, lb, name, caller, ier, sumto) if( present(ier) ) ier = 0 found = .false. - do nl = lbound(arr, 1), ub - if (abs(sum(arr(nl,:)) - TotalSum(nl)) > eps) then + do nl = lb, ub + if (abs(sum(arr(nl,:)) - TotalSum(nl)) > sum_to_1_tol) then found = .true. nindx = nl exit diff --git a/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 b/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 index 114019a3d7..2cb28f04e9 100644 --- a/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 @@ -6,6 +6,7 @@ module SoilBiogeochemCarbonFluxType use clm_varpar , only : ndecomp_cascade_transitions, ndecomp_pools, nlevcan use clm_varpar , only : nlevdecomp_full, nlevgrnd, nlevdecomp, nlevsoi, i_cwdl2 use clm_varcon , only : spval, ispval, dzsoi_decomp + use clm_varctl , only : use_fates,use_cn use pftconMod , only : pftcon use landunit_varcon , only : istsoil, istcrop, istdlak use ch4varcon , only : allowlakeprod @@ -14,7 +15,6 @@ module SoilBiogeochemCarbonFluxType use ColumnType , only : col use LandunitType , only : lun use SparseMatrixMultiplyMod , only : sparse_matrix_type, diag_matrix_type, vector_type - use clm_varctl , only : use_fates ! ! !PUBLIC TYPES: @@ -58,13 +58,11 @@ module SoilBiogeochemCarbonFluxType real(r8), pointer :: lithr_col (:) ! (gC/m2/s) litter heterotrophic respiration: donor-pool based definition real(r8), pointer :: somhr_col (:) ! (gC/m2/s) soil organic matter heterotrophic res: donor-pool based definition real(r8), pointer :: soilc_change_col (:) ! (gC/m2/s) FUN used soil C + real(r8), pointer :: fates_litter_flux (:) ! (gC/m2/s) A summary of the total litter + ! flux passed in from FATES. + ! This is a diagnostic for balance checks only - ! fluxes to receive carbon inputs from FATES - real(r8), pointer :: FATES_c_to_litr_c_col (:,:,:) ! total litter coming from ED. gC/m3/s - real(r8), pointer :: FATES_c_to_litr_lab_c_col (:,:) ! total labile litter coming from ED. gC/m3/s - real(r8), pointer :: FATES_c_to_litr_cel_c_col (:,:) ! total cellulose litter coming from ED. gC/m3/s - real(r8), pointer :: FATES_c_to_litr_lig_c_col (:,:) ! total lignin litter coming from ED. gC/m3/s - + contains procedure , public :: Init @@ -162,25 +160,16 @@ subroutine InitAllocate(this, bounds) allocate(this%lithr_col (begc:endc)) ; this%lithr_col (:) = nan allocate(this%somhr_col (begc:endc)) ; this%somhr_col (:) = nan allocate(this%soilc_change_col (begc:endc)) ; this%soilc_change_col (:) = nan - + + if(use_fates)then + allocate(this%fates_litter_flux(begc:endc)); this%fates_litter_flux(:) = nan + else + allocate(this%fates_litter_flux(0:0)); this%fates_litter_flux(:) = nan + end if + if(use_soil_matrixcn)then end if - if ( use_fates ) then - ! initialize these variables to be zero rather than a bad number since they are not zeroed every timestep (due to a need for them to persist) - - allocate(this%FATES_c_to_litr_c_col(begc:endc,1:nlevdecomp_full,1:ndecomp_pools)) - this%FATES_c_to_litr_c_col(begc:endc,1:nlevdecomp_full,1:ndecomp_pools) = 0._r8 - - allocate(this%FATES_c_to_litr_lab_c_col(begc:endc,1:nlevdecomp_full)) - this%FATES_c_to_litr_lab_c_col(begc:endc,1:nlevdecomp_full) = 0._r8 - - allocate(this%FATES_c_to_litr_cel_c_col(begc:endc,1:nlevdecomp_full)) - this%FATES_c_to_litr_cel_c_col(begc:endc,1:nlevdecomp_full) = 0._r8 - - allocate(this%FATES_c_to_litr_lig_c_col(begc:endc,1:nlevdecomp_full)) - this%FATES_c_to_litr_lig_c_col(begc:endc,1:nlevdecomp_full) = 0._r8 - endif allocate(this%litr_lig_c_to_n_col(begc:endc)) this%litr_lig_c_to_n_col(:)= 0._r8 @@ -315,8 +304,8 @@ subroutine InitHistory(this, bounds, carbon_type) if ( decomp_cascade_con%cascade_receiver_pool(l) /= 0 ) then data1dptr => this%decomp_cascade_ctransfer_col(:,l) fieldname = & - trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))//'C_TO_'//& - trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l)))//'C' + trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))//'_C_TO_'//& + trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l)))//'_C' longname = 'decomp. of '//trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_donor_pool(l)))//& ' C to '//trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_receiver_pool(l)))//' C' call hist_addfld1d (fname=fieldname, units='gC/m^2/s', & @@ -353,9 +342,9 @@ subroutine InitHistory(this, bounds, carbon_type) if ( decomp_cascade_con%cascade_receiver_pool(l) /= 0 ) then data2dptr => this%decomp_cascade_ctransfer_vr_col(:,:,l) fieldname = & - trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))//'C_TO_'//& + trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))//'_C_TO_'//& trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l)))& - //'C'//trim(vr_suffix) + //'_C'//trim(vr_suffix) longname = 'decomp. of '//& trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_donor_pool(l)))//& ' C to '//& @@ -423,14 +412,14 @@ subroutine InitHistory(this, bounds, carbon_type) do k = 1, ndecomp_pools ! none from CWD if ( .not. decomp_cascade_con%is_cwd(k) ) then data1dptr => this%decomp_cpools_leached_col(:,k) - fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'C_TO_LEACHING' + fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'_C_TO_LEACHING' longname = trim(decomp_cascade_con%decomp_pool_name_long(k))//' C leaching loss' call hist_addfld1d (fname=fieldname, units='gC/m^2/s', & avgflag='A', long_name=longname, & ptr_col=data1dptr, default='inactive') data2dptr => this%decomp_cpools_transport_tendency_col(:,:,k) - fieldname = trim(decomp_cascade_con%decomp_pool_name_history(k))//'C_TNDNCY_VERT_TRANSPORT' + fieldname = trim(decomp_cascade_con%decomp_pool_name_history(k))//'_C_TNDNCY_VERT_TRANSPORT' longname = trim(decomp_cascade_con%decomp_pool_name_long(k))//' C tendency due to vertical transport' call hist_addfld_decomp (fname=fieldname, units='gC/m^3/s', type2d='levdcmp', & avgflag='A', long_name=longname, & @@ -513,9 +502,9 @@ subroutine InitHistory(this, bounds, carbon_type) data2dptr => this%decomp_cascade_ctransfer_vr_col(:,:,l) fieldname = 'C13_'//& trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))& - //'C_TO_'//& + //'_C_TO_'//& trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l)))& - //'C'//trim(vr_suffix) + //'_C'//trim(vr_suffix) longname = 'C13 decomp. of '& //trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_donor_pool(l)))& //' C to '//& @@ -597,9 +586,9 @@ subroutine InitHistory(this, bounds, carbon_type) fieldname = 'C14_'//& trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))& - //'C_TO_'//& + //'_C_TO_'//& trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l)))& - //'C'//trim(vr_suffix) + //'_C'//trim(vr_suffix) longname = 'C14 decomp. of '& //trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_donor_pool(l)))//& ' C to '//trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_receiver_pool(l)))//' C' @@ -625,23 +614,6 @@ subroutine InitHistory(this, bounds, carbon_type) end do - if ( use_fates ) then - - call hist_addfld_decomp(fname='FATES_c_to_litr_lab_c', units='gC/m^3/s', type2d='levdcmp', & - avgflag='A', long_name='litter labile carbon flux from FATES to BGC', & - ptr_col=this%FATES_c_to_litr_lab_c_col) - - call hist_addfld_decomp(fname='FATES_c_to_litr_cel_c', units='gC/m^3/s', type2d='levdcmp', & - avgflag='A', long_name='litter celluluse carbon flux from FATES to BGC', & - ptr_col=this%FATES_c_to_litr_cel_c_col) - - call hist_addfld_decomp(fname='FATES_c_to_litr_lig_c', units='gC/m^3/s', type2d='levdcmp', & - avgflag='A', long_name='litter lignin carbon flux from FATES to BGC', & - ptr_col=this%FATES_c_to_litr_lig_c_col) - - endif - - end subroutine InitHistory !----------------------------------------------------------------------- @@ -694,40 +666,6 @@ subroutine Restart(this, bounds, ncid, flag) logical :: readvar !----------------------------------------------------------------------- - ! - ! if FATES is enabled, need to restart the variables used to transfer from FATES to CLM as they - ! are persistent between daily FATES dynamics calls and half-hourly CLM timesteps - ! - if ( use_fates ) then - - ptr2d => this%FATES_c_to_litr_lab_c_col - call restartvar(ncid=ncid, flag=flag, varname='FATES_c_to_litr_lab_c_col', xtype=ncd_double, & - dim1name='column', dim2name='levgrnd', switchdim=.true., & - long_name='', units='gC/m3/s', scale_by_thickness=.false., & - interpinic_flag='interp', readvar=readvar, data=ptr2d) - - ptr2d => this%FATES_c_to_litr_cel_c_col - call restartvar(ncid=ncid, flag=flag, varname='FATES_c_to_litr_cel_c_col', xtype=ncd_double, & - dim1name='column', dim2name='levgrnd', switchdim=.true., & - long_name='', units='gC/m3/s', scale_by_thickness=.false., & - interpinic_flag='interp', readvar=readvar, data=ptr2d) - - ptr2d => this%FATES_c_to_litr_lig_c_col - call restartvar(ncid=ncid, flag=flag, varname='FATES_c_to_litr_lig_c_col', xtype=ncd_double, & - dim1name='column', dim2name='levgrnd', switchdim=.true., & - long_name='', units='gC/m3/s', scale_by_thickness=.false., & - interpinic_flag='interp', readvar=readvar, data=ptr2d) - - ! Copy last 3 variables to an array of litter pools for use in do loops. - ! Repeat copy in src/utils/clmfates_interfaceMod.F90. - ! Keep the three originals to avoid backwards compatibility issues with - ! restart files. - this%FATES_c_to_litr_c_col(:,:,1) = this%FATES_c_to_litr_lab_c_col(:,:) - this%FATES_c_to_litr_c_col(:,:,2) = this%FATES_c_to_litr_cel_c_col(:,:) - this%FATES_c_to_litr_c_col(:,:,3) = this%FATES_c_to_litr_lig_c_col(:,:) - - end if - call restartvar(ncid=ncid, flag=flag, varname='ligninNratioAvg', xtype=ncd_double, & dim1name='column', & long_name='', units='', & @@ -806,13 +744,11 @@ subroutine SetValues ( this, num_column, filter_column, value_column) this%soilc_change_col(i) = value_column end do - ! NOTE: do not zero the fates to BGC C flux variables since they need to persist from the daily fates timestep s to the half-hourly BGC timesteps. I.e. FATES_c_to_litr_lab_c_col, FATES_c_to_litr_cel_c_col, FATES_c_to_litr_lig_c_col - end subroutine SetValues !----------------------------------------------------------------------- subroutine Summary(this, bounds, & - num_soilc, filter_soilc, num_soilp, filter_soilp, & + num_bgc_soilc, filter_bgc_soilc, num_soilp, filter_soilp, & soilbiogeochem_decomp_cascade_ctransfer_col, & soilbiogeochem_cwdc_col, soilbiogeochem_cwdn_col, & leafc_to_litter_patch, frootc_to_litter_patch) @@ -827,15 +763,16 @@ subroutine Summary(this, bounds, & ! !ARGUMENTS: class(soilbiogeochem_carbonflux_type) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns integer, intent(in), optional :: num_soilp ! number of patches in filter integer, intent(in), optional :: filter_soilp(:) ! filter for patches real(r8), intent(in), optional :: soilbiogeochem_cwdc_col(bounds%begc:) real(r8), intent(in), optional :: soilbiogeochem_cwdn_col(bounds%begc:) real(r8), intent(in), optional :: soilbiogeochem_decomp_cascade_ctransfer_col(bounds%begc:,1:) - real(r8), intent(in), optional :: leafc_to_litter_patch(bounds%begp:) - real(r8), intent(in), optional :: frootc_to_litter_patch(bounds%begp:) + + real(r8), intent(in), optional :: leafc_to_litter_patch(:) + real(r8), intent(in), optional :: frootc_to_litter_patch(:) ! ! !LOCAL VARIABLES: integer :: c,j,k,l,p @@ -850,16 +787,16 @@ subroutine Summary(this, bounds, & !----------------------------------------------------------------------- - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%som_c_leached_col(c) = 0._r8 end do ! vertically integrate HR and decomposition cascade fluxes do k = 1, ndecomp_cascade_transitions do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%decomp_cascade_hr_col(c,k) = & this%decomp_cascade_hr_col(c,k) + & this%decomp_cascade_hr_vr_col(c,j,k) * dzsoi_decomp(j) @@ -873,15 +810,15 @@ subroutine Summary(this, bounds, & ! total heterotrophic respiration, vertically resolved (HR) do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%hr_vr_col(c,j) = 0._r8 end do end do do k = 1, ndecomp_cascade_transitions do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%hr_vr_col(c,j) = & this%hr_vr_col(c,j) + & this%decomp_cascade_hr_vr_col(c,j,k) @@ -891,19 +828,19 @@ subroutine Summary(this, bounds, & ! add up all vertical transport tendency terms and calculate total som leaching loss as the sum of these do l = 1, ndecomp_pools - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%decomp_cpools_leached_col(c,l) = 0._r8 end do do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%decomp_cpools_leached_col(c,l) = this%decomp_cpools_leached_col(c,l) + & this%decomp_cpools_transport_tendency_col(c,j,l) * dzsoi_decomp(j) end do end do - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%som_c_leached_col(c) = this%som_c_leached_col(c) + this%decomp_cpools_leached_col(c,l) end do end do @@ -912,8 +849,8 @@ subroutine Summary(this, bounds, & associate(is_soil => decomp_cascade_con%is_soil) ! TRUE => pool is a soil pool do k = 1, ndecomp_cascade_transitions if ( is_soil(decomp_cascade_con%cascade_donor_pool(k)) ) then - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%somhr_col(c) = this%somhr_col(c) + this%decomp_cascade_hr_col(c,k) end do end if @@ -924,8 +861,8 @@ subroutine Summary(this, bounds, & associate(is_litter => decomp_cascade_con%is_litter) ! TRUE => pool is a litter pool do k = 1, ndecomp_cascade_transitions if ( is_litter(decomp_cascade_con%cascade_donor_pool(k)) ) then - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%lithr_col(c) = this%lithr_col(c) + this%decomp_cascade_hr_col(c,k) end do end if @@ -936,8 +873,8 @@ subroutine Summary(this, bounds, & associate(is_cwd => decomp_cascade_con%is_cwd) ! TRUE => pool is a cwd pool do k = 1, ndecomp_cascade_transitions if ( is_cwd(decomp_cascade_con%cascade_donor_pool(k)) ) then - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%cwdhr_col(c) = this%cwdhr_col(c) + this%decomp_cascade_hr_col(c,k) end do end if @@ -948,8 +885,8 @@ subroutine Summary(this, bounds, & associate(is_microbe => decomp_cascade_con%is_microbe) ! TRUE => pool is a microbial pool do k = 1, ndecomp_cascade_transitions if ( is_microbe(decomp_cascade_con%cascade_donor_pool(k)) ) then - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%michr_col(c) = this%michr_col(c) + this%decomp_cascade_hr_col(c,k) end do end if @@ -957,64 +894,73 @@ subroutine Summary(this, bounds, & end associate ! total heterotrophic respiration (HR) - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) - this%hr_col(c) = & - this%michr_col(c) + & - this%cwdhr_col(c) + & - this%lithr_col(c) + & - this%somhr_col(c) + this%hr_col(c) = & + this%michr_col(c) + & + this%cwdhr_col(c) + & + this%lithr_col(c) + & + this%somhr_col(c) - end do + end do ! Calculate ligninNratio ! FATES does its own calculation - if (.not. use_fates .and. decomp_method == mimics_decomp) then - do fp = 1,num_soilp - p = filter_soilp(fp) - - associate(ivt => patch%itype) ! Input: [integer (:)] patch plant type - ligninNratio_leaf_patch(p) = pftcon%lf_flig(ivt(p)) * & - pftcon%lflitcn(ivt(p)) * & - leafc_to_litter_patch(p) - ligninNratio_froot_patch(p) = pftcon%fr_flig(ivt(p)) * & - pftcon%frootcn(ivt(p)) * & - frootc_to_litter_patch(p) - end associate - end do - - call p2c(bounds, num_soilc, filter_soilc, & - ligninNratio_leaf_patch(bounds%begp:bounds%endp), & - ligninNratio_leaf_col(bounds%begc:bounds%endc)) - call p2c(bounds, num_soilc, filter_soilc, & - ligninNratio_froot_patch(bounds%begp:bounds%endp), & - ligninNratio_froot_col(bounds%begc:bounds%endc)) - call p2c(bounds, num_soilc, filter_soilc, & - leafc_to_litter_patch(bounds%begp:bounds%endp), & - leafc_to_litter_col(bounds%begc:bounds%endc)) - call p2c(bounds, num_soilc, filter_soilc, & - frootc_to_litter_patch(bounds%begp:bounds%endp), & - frootc_to_litter_col(bounds%begc:bounds%endc)) + if_mimics: if (decomp_method == mimics_decomp ) then + + if(num_soilp>0)then + do fp = 1,num_soilp + p = filter_soilp(fp) + associate(ivt => patch%itype) ! Input: [integer (:)] patch plant type + ligninNratio_leaf_patch(p) = pftcon%lf_flig(ivt(p)) * & + pftcon%lflitcn(ivt(p)) * & + leafc_to_litter_patch(p) + ligninNratio_froot_patch(p) = pftcon%fr_flig(ivt(p)) * & + pftcon%frootcn(ivt(p)) * & + frootc_to_litter_patch(p) + end associate + end do + + call p2c(bounds, num_bgc_soilc, filter_bgc_soilc, & + ligninNratio_leaf_patch(bounds%begp:bounds%endp), & + ligninNratio_leaf_col(bounds%begc:bounds%endc)) + call p2c(bounds, num_bgc_soilc, filter_bgc_soilc, & + ligninNratio_froot_patch(bounds%begp:bounds%endp), & + ligninNratio_froot_col(bounds%begc:bounds%endc)) + call p2c(bounds, num_bgc_soilc, filter_bgc_soilc, & + leafc_to_litter_patch(bounds%begp:bounds%endp), & + leafc_to_litter_col(bounds%begc:bounds%endc)) + call p2c(bounds, num_bgc_soilc, filter_bgc_soilc, & + frootc_to_litter_patch(bounds%begp:bounds%endp), & + frootc_to_litter_col(bounds%begc:bounds%endc)) + + end if ! Calculate ligninNratioAve - do fc = 1,num_soilc - c = filter_soilc(fc) - if (soilbiogeochem_cwdn_col(c) > 0._r8) then - ligninNratio_cwd = CNParamsShareInst%cwd_flig * & - (soilbiogeochem_cwdc_col(c) / soilbiogeochem_cwdn_col(c)) * & - soilbiogeochem_decomp_cascade_ctransfer_col(c,i_cwdl2) - else - ligninNratio_cwd = 0._r8 + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) + if(.not.col%is_fates(c)) then + if (soilbiogeochem_cwdn_col(c) > 0._r8) then + ligninNratio_cwd = CNParamsShareInst%cwd_flig * & + (soilbiogeochem_cwdc_col(c) / soilbiogeochem_cwdn_col(c)) * & + soilbiogeochem_decomp_cascade_ctransfer_col(c,i_cwdl2) + else + ligninNratio_cwd = 0._r8 + end if + this%litr_lig_c_to_n_col(c) = & + (ligninNratio_leaf_col(c) + ligninNratio_froot_col(c) + & + ligninNratio_cwd) / & + max(1.0e-3_r8, leafc_to_litter_col(c) + & + frootc_to_litter_col(c) + & + soilbiogeochem_decomp_cascade_ctransfer_col(c,i_cwdl2)) + !else + ! For FATES: + ! this array is currently updated here: + ! clmfates_interfaceMod.F90:wrap_update_hlmfates_dyn() end if - this%litr_lig_c_to_n_col(c) = & - (ligninNratio_leaf_col(c) + ligninNratio_froot_col(c) + & - ligninNratio_cwd) / & - max(1.0e-3_r8, leafc_to_litter_col(c) + & - frootc_to_litter_col(c) + & - soilbiogeochem_decomp_cascade_ctransfer_col(c,i_cwdl2)) end do - end if + end if if_mimics end subroutine Summary diff --git a/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 b/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 index a09441069a..de269a4c78 100644 --- a/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 @@ -7,7 +7,7 @@ module SoilBiogeochemCarbonStateType use clm_varpar , only : ndecomp_cascade_transitions, ndecomp_pools, nlevcan use clm_varpar , only : nlevdecomp_full, nlevdecomp, nlevsoi use clm_varcon , only : spval, ispval, dzsoi_decomp, zisoi, zsoi, c3_r2 - use clm_varctl , only : iulog, spinup_state, use_fates + use clm_varctl , only : iulog, spinup_state, use_fates_bgc use landunit_varcon , only : istcrop, istsoil use abortutils , only : endrun use spmdMod , only : masterproc @@ -17,6 +17,7 @@ module SoilBiogeochemCarbonStateType use GridcellType , only : grc use SoilBiogeochemStateType , only : get_spinup_latitude_term use SparseMatrixMultiplyMod , only : sparse_matrix_type, vector_type + use CNVegCarbonStateType , only : cnveg_carbonstate_type ! ! !PUBLIC TYPES: implicit none @@ -30,19 +31,28 @@ module SoilBiogeochemCarbonStateType real(r8), pointer :: ctrunc_vr_col (:,:) ! (gC/m3) vertically-resolved column-level sink for C truncation ! summary (diagnostic) state variables, not involved in mass balance - real(r8), pointer :: ctrunc_col (:) ! (gC/m2) column-level sink for C truncation - real(r8), pointer :: totmicc_col (:) ! (gC/m2) total microbial carbon - real(r8), pointer :: totlitc_col (:) ! (gC/m2) total litter carbon - real(r8), pointer :: totlitc_1m_col (:) ! (gC/m2) total litter carbon to 1 meter - real(r8), pointer :: totsomc_col (:) ! (gC/m2) total soil organic matter carbon - real(r8), pointer :: totsomc_1m_col (:) ! (gC/m2) total soil organic matter carbon to 1 meter - real(r8), pointer :: cwdc_col (:) ! (gC/m2) coarse woody debris C (diagnostic) - real(r8), pointer :: decomp_cpools_1m_col (:,:) ! (gC/m2) Diagnostic: decomposing (litter, cwd, soil) c pools to 1 meter - real(r8), pointer :: decomp_cpools_col (:,:) ! (gC/m2) decomposing (litter, cwd, soil) c pools - real(r8), pointer :: dyn_cbal_adjustments_col(:) ! (gC/m2) adjustments to each column made in this timestep via dynamic column area adjustments (note: this variable only makes sense at the column-level: it is meaningless if averaged to the gridcell-level) - integer :: restart_file_spinup_state ! spinup state as read from restart file, for determining whether to enter or exit spinup mode. - real(r8) :: totvegcthresh ! threshold for total vegetation carbon to zero out decomposition pools + real(r8), pointer :: ctrunc_col (:) ! (gC/m2) column-level sink for C truncation + real(r8), pointer :: totmicc_col (:) ! (gC/m2) total microbial carbon + real(r8), pointer :: totlitc_col (:) ! (gC/m2) total litter carbon + real(r8), pointer :: totlitc_1m_col (:) ! (gC/m2) total litter carbon to 1 meter + real(r8), pointer :: totsomc_col (:) ! (gC/m2) total soil organic matter carbon + real(r8), pointer :: totsomc_1m_col (:) ! (gC/m2) total soil organic matter carbon to 1 meter + real(r8), pointer :: cwdc_col (:) ! (gC/m2) coarse woody debris C (diagnostic) + real(r8), pointer :: decomp_cpools_1m_col (:,:) ! (gC/m2) Diagnostic: decomposing (litter, cwd, soil) c pools to 1 meter + real(r8), pointer :: decomp_cpools_col (:,:) ! (gC/m2) decomposing (litter, cwd, soil) c pools + real(r8), pointer :: dyn_cbal_adjustments_col(:) ! (gC/m2) adjustments to each column made in this timestep via dynamic column + ! area adjustments (note: this variable only makes sense at the column-level: + ! it is meaningless if averaged to the gridcell-level) + integer :: restart_file_spinup_state ! spinup state as read from restart file, for determining whether to enter or exit spinup mode. + real(r8) :: totvegcthresh ! threshold for total vegetation carbon to zero out decomposition pools + + + ! Carbon totals, includes soil, cpool and vegetation + real(r8), pointer :: totc_col (:) ! (gC/m2) total column carbon, incl veg and cpool + real(r8), pointer :: totecosysc_col (:) ! (gC/m2) total ecosystem carbon, incl veg but excl cpool + real(r8), pointer :: totc_grc (:) ! (gC/m2) total gridcell carbon + ! Matrix-cn contains @@ -95,9 +105,11 @@ subroutine InitAllocate(this, bounds) ! ! !LOCAL VARIABLES: integer :: begc,endc + integer :: begg,endg !------------------------------------------------------------------------ begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg allocate( this%decomp_cpools_col (begc :endc,1:ndecomp_pools)) ; this%decomp_cpools_col (:,:) = nan allocate( this%decomp_cpools_1m_col (begc :endc,1:ndecomp_pools)) ; this%decomp_cpools_1m_col (:,:) = nan @@ -116,9 +128,8 @@ subroutine InitAllocate(this, bounds) this%decomp_soilc_vr_col(:,:)= nan allocate(this%ctrunc_col (begc :endc)) ; this%ctrunc_col (:) = nan - if ( .not. use_fates ) then - allocate(this%cwdc_col (begc :endc)) ; this%cwdc_col (:) = nan - endif + allocate(this%cwdc_col (begc :endc)) ; this%cwdc_col (:) = nan + allocate(this%totmicc_col (begc :endc)) ; this%totmicc_col (:) = nan allocate(this%totlitc_col (begc :endc)) ; this%totlitc_col (:) = nan allocate(this%totsomc_col (begc :endc)) ; this%totsomc_col (:) = nan @@ -126,6 +137,10 @@ subroutine InitAllocate(this, bounds) allocate(this%totsomc_1m_col (begc :endc)) ; this%totsomc_1m_col (:) = nan allocate(this%dyn_cbal_adjustments_col (begc:endc)) ; this%dyn_cbal_adjustments_col (:) = nan + allocate(this%totc_col (begc:endc)) ; this%totc_col (:) = nan + allocate(this%totecosysc_col (begc:endc)) ; this%totecosysc_col (:) = nan + allocate(this%totc_grc (begg:endg)) ; this%totc_grc (:) = nan + this%restart_file_spinup_state = huge(1) end subroutine InitAllocate @@ -169,7 +184,7 @@ subroutine InitHistory(this, bounds, carbon_type) do l = 1, ndecomp_pools if ( nlevdecomp_full > 1 ) then data2dptr => this%decomp_cpools_vr_col(:,1:nlevsoi,l) - fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'C_vr' + fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'_C_vr' longname = trim(decomp_cascade_con%decomp_pool_name_history(l))//' C (vertically resolved)' call hist_addfld2d (fname=fieldname, units='gC/m^3', type2d='levsoi', & avgflag='A', long_name=longname, & @@ -177,7 +192,7 @@ subroutine InitHistory(this, bounds, carbon_type) endif data1dptr => this%decomp_cpools_col(:,l) - fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'C' + fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'_C' longname = trim(decomp_cascade_con%decomp_pool_name_history(l))//' C' call hist_addfld1d (fname=fieldname, units='gC/m^2', & avgflag='A', long_name=longname, & @@ -185,7 +200,7 @@ subroutine InitHistory(this, bounds, carbon_type) if ( nlevdecomp_full > 1 ) then data1dptr => this%decomp_cpools_1m_col(:,l) - fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'C_1m' + fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'_C_1m' longname = trim(decomp_cascade_con%decomp_pool_name_history(l))//' C to 1 meter' call hist_addfld1d (fname=fieldname, units='gC/m^2', & avgflag='A', long_name=longname, & @@ -249,6 +264,16 @@ subroutine InitHistory(this, bounds, carbon_type) &only makes sense at the column level: should not be averaged to gridcell', & ptr_col=this%dyn_cbal_adjustments_col, default='inactive') + this%totc_col(begc:endc) = spval + call hist_addfld1d (fname='TOTCOLC', units='gC/m^2', & + avgflag='A', long_name='total column carbon, incl veg and cpool but excl product pools', & + ptr_col=this%totc_col) + + this%totecosysc_col(begc:endc) = spval + call hist_addfld1d (fname='TOTECOSYSC', units='gC/m^2', & + avgflag='A', long_name='total ecosystem carbon, incl veg but excl cpool and product pools', & + ptr_col=this%totecosysc_col) + end if !------------------------------- @@ -268,7 +293,7 @@ subroutine InitHistory(this, bounds, carbon_type) do l = 1, ndecomp_pools if ( nlevdecomp_full > 1 ) then data2dptr => this%decomp_cpools_vr_col(:,1:nlevsoi,l) - fieldname = 'C13_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'C_vr' + fieldname = 'C13_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'_C_vr' longname = 'C13 '//trim(decomp_cascade_con%decomp_pool_name_history(l))//' C (vertically resolved)' call hist_addfld2d (fname=fieldname, units='gC13/m^3', type2d='levsoi', & avgflag='A', long_name=longname, & @@ -276,7 +301,7 @@ subroutine InitHistory(this, bounds, carbon_type) endif data1dptr => this%decomp_cpools_col(:,l) - fieldname = 'C13_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'C' + fieldname = 'C13_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'_C' longname = 'C13 '//trim(decomp_cascade_con%decomp_pool_name_history(l))//' C' call hist_addfld1d (fname=fieldname, units='gC13/m^2', & avgflag='A', long_name=longname, & @@ -336,6 +361,17 @@ subroutine InitHistory(this, bounds, carbon_type) long_name='C13 adjustments in soil carbon due to dynamic column areas; & &only makes sense at the column level: should not be averaged to gridcell', & ptr_col=this%dyn_cbal_adjustments_col, default='inactive') + + this%totc_col(begc:endc) = spval + call hist_addfld1d (fname='C13_TOTCOLC', units='gC13/m^2', & + avgflag='A', long_name='C13 total column carbon, incl veg and cpool but excl product pools', & + ptr_col=this%totc_col, default='inactive') + + this%totecosysc_col(begc:endc) = spval + call hist_addfld1d (fname='C13_TOTECOSYSC', units='gC13/m^2', & + avgflag='A', long_name='C13 total ecosystem carbon, incl veg but excl cpool and product pools', & + ptr_col=this%totecosysc_col) + endif !------------------------------- @@ -355,21 +391,21 @@ subroutine InitHistory(this, bounds, carbon_type) do l = 1, ndecomp_pools if ( nlevdecomp_full > 1 ) then data2dptr => this%decomp_cpools_vr_col(:,1:nlevsoi,l) - fieldname = 'C14_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'C_vr' + fieldname = 'C14_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'_C_vr' longname = 'C14 '//trim(decomp_cascade_con%decomp_pool_name_history(l))//' C (vertically resolved)' call hist_addfld2d (fname=fieldname, units='gC14/m^3', type2d='levsoi', & avgflag='A', long_name=longname, ptr_col=data2dptr, default='inactive') endif data1dptr => this%decomp_cpools_col(:,l) - fieldname = 'C14_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'C' + fieldname = 'C14_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'_C' longname = 'C14 '//trim(decomp_cascade_con%decomp_pool_name_history(l))//' C' call hist_addfld1d (fname=fieldname, units='gC14/m^2', & avgflag='A', long_name=longname, ptr_col=data1dptr, default='inactive') if ( nlevdecomp_full > 1 ) then data1dptr => this%decomp_cpools_1m_col(:,l) - fieldname = 'C14_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'C_1m' + fieldname = 'C14_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'_C_1m' longname = 'C14_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//' C to 1 meter' call hist_addfld1d (fname=fieldname, units='gC/m^2', & avgflag='A', long_name=longname, ptr_col=data1dptr, default='inactive') @@ -426,6 +462,17 @@ subroutine InitHistory(this, bounds, carbon_type) long_name='C14 adjustments in soil carbon due to dynamic column areas; & &only makes sense at the column level: should not be averaged to gridcell', & ptr_col=this%dyn_cbal_adjustments_col, default='inactive') + + this%totc_col(begc:endc) = spval + call hist_addfld1d (fname='C14_TOTCOLC', units='gC14/m^2', & + avgflag='A', long_name='C14 total column carbon, incl veg and cpool but excl product pools', & + ptr_col=this%totc_col, default='inactive') + + this%totecosysc_col(begc:endc) = spval + call hist_addfld1d (fname='C14_TOTECOSYSC', units='gC14/m^2', & + avgflag='A', long_name='C14 total ecosystem carbon, incl veg but excl cpool and product pools', & + ptr_col=this%totecosysc_col) + endif end subroutine InitHistory @@ -445,7 +492,7 @@ subroutine InitCold(this, bounds, ratio, c12_soilbiogeochem_carbonstate_inst) type(soilbiogeochem_carbonstate_type), intent(in), optional :: c12_soilbiogeochem_carbonstate_inst ! ! !LOCAL VARIABLES: - integer :: p,c,l,j,k + integer :: p,c,l,j,k,g integer :: fc ! filter index integer :: num_special_col ! number of good values in special_col filter integer :: special_col(bounds%endc-bounds%begc+1) ! special landunit filter - columns @@ -523,23 +570,30 @@ subroutine InitCold(this, bounds, ratio, c12_soilbiogeochem_carbonstate_inst) end if end if - if ( .not. use_fates ) then - if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then - if (present(c12_soilbiogeochem_carbonstate_inst)) then - this%cwdc_col(c) = c12_soilbiogeochem_carbonstate_inst%cwdc_col(c) * ratio - else - this%cwdc_col(c) = 0._r8 - end if - this%ctrunc_col(c) = 0._r8 - this%totmicc_col(c) = 0._r8 - this%totlitc_col(c) = 0._r8 - this%totsomc_col(c) = 0._r8 - this%totlitc_1m_col(c) = 0._r8 - this%totsomc_1m_col(c) = 0._r8 + + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + if (present(c12_soilbiogeochem_carbonstate_inst) .and. (.not.col%is_fates(c)) ) then + this%cwdc_col(c) = c12_soilbiogeochem_carbonstate_inst%cwdc_col(c) * ratio + else + this%cwdc_col(c) = 0._r8 end if + this%ctrunc_col(c) = 0._r8 + this%totmicc_col(c) = 0._r8 + this%totlitc_col(c) = 0._r8 + this%totsomc_col(c) = 0._r8 + this%totlitc_1m_col(c) = 0._r8 + this%totsomc_1m_col(c) = 0._r8 + + this%totc_col(c) = 0._r8 + this%totecosysc_col(c) = 0._r8 end if + end do + do g = bounds%begg, bounds%endg + this%totc_grc(g) = 0._r8 + end do + ! now loop through special filters and explicitly set the variables that ! have to be in place for biogeophysics @@ -815,7 +869,7 @@ subroutine SetValues ( this, num_column, filter_column, value_column) do fi = 1,num_column i = filter_column(fi) - if ( .not. use_fates ) then + if ( .not. col%is_fates(i) ) then this%cwdc_col(i) = value_column end if this%ctrunc_col(i) = value_column @@ -824,6 +878,8 @@ subroutine SetValues ( this, num_column, filter_column, value_column) this%totlitc_1m_col(i) = value_column this%totsomc_col(i) = value_column this%totsomc_1m_col(i) = value_column + this%totc_col(i) = value_column + this%totecosysc_col(i) = value_column end do do j = 1,nlevdecomp_full @@ -875,7 +931,7 @@ subroutine SetValues ( this, num_column, filter_column, value_column) end subroutine SetValues !----------------------------------------------------------------------- - subroutine Summary(this, bounds, num_allc, filter_allc) + subroutine Summary(this, bounds, num_allc, filter_allc, num_bgc_soilc, filter_bgc_soilc,cnveg_carbonstate_inst) ! ! !DESCRIPTION: ! Perform column-level carbon summary calculations @@ -883,13 +939,22 @@ subroutine Summary(this, bounds, num_allc, filter_allc) ! !ARGUMENTS: class(soilbiogeochem_carbonstate_type) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_allc ! number of columns in allc filter + integer , intent(in) :: num_allc ! number of columns in soil filter integer , intent(in) :: filter_allc(:) ! filter for all active columns + integer , intent(in) :: num_bgc_soilc ! number of columns in soil filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for all active columns + type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst + ! ! !LOCAL VARIABLES: integer :: c,j,k,l ! indices integer :: fc ! filter indices real(r8) :: maxdepth ! depth to integrate soil variables + integer :: num_local ! Either num_bgc_soilc or num_allc, depending + ! on if its a fates run, its different because + ! the cnveg variables are not allocated w/ fates + real(r8) :: ecovegc_col + real(r8) :: totvegc_col !----------------------------------------------------------------------- ! vertically integrate each of the decomposing C pools @@ -1056,23 +1121,53 @@ subroutine Summary(this, bounds, num_allc, filter_allc) end if end do - ! coarse woody debris carbon - if (.not. use_fates ) then - do fc = 1,num_allc + do fc = 1,num_allc + c = filter_allc(fc) + ! coarse woody debris carbon + this%cwdc_col(c) = 0._r8 + end do + + if (use_fates_bgc) then + num_local = num_bgc_soilc + else + num_local = num_allc + end if + do fc = 1,num_local + if(use_fates_bgc) then + c = filter_bgc_soilc(fc) + else c = filter_allc(fc) - this%cwdc_col(c) = 0._r8 - end do - do l = 1, ndecomp_pools - if ( decomp_cascade_con%is_cwd(l) ) then - do fc = 1,num_allc - c = filter_allc(fc) + end if + if(col%is_fates(c)) then + totvegc_col = 0._r8 + ecovegc_col = 0._r8 + else + do l = 1, ndecomp_pools + if ( decomp_cascade_con%is_cwd(l) ) then this%cwdc_col(c) = this%cwdc_col(c) + this%decomp_cpools_col(c,l) - end do - end if - end do + end if + end do + totvegc_col = cnveg_carbonstate_inst%totc_p2c_col(c) + ecovegc_col = cnveg_carbonstate_inst%totvegc_col(c) + end if + + ! total ecosystem carbon, including veg but excluding cpool (TOTECOSYSC) + this%totecosysc_col(c) = & + this%cwdc_col(c) + & + this%totmicc_col(c) + & + this%totlitc_col(c) + & + this%totsomc_col(c) + & + ecovegc_col + ! total column carbon, including veg and cpool (TOTCOLC) + this%totc_col(c) = & + this%cwdc_col(c) + & + this%totmicc_col(c) + & + this%totlitc_col(c) + & + this%totsomc_col(c) + & + this%ctrunc_col(c) + & + totvegc_col + end do - end if - end subroutine Summary !------------------------------------------------------------------------ diff --git a/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 b/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 index eec9e00f80..57bc82984e 100644 --- a/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 @@ -165,7 +165,7 @@ subroutine SoilBiogeochemCompetitionInit ( bounds) end subroutine SoilBiogeochemCompetitionInit !----------------------------------------------------------------------- - subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, filter_soilp, & + subroutine SoilBiogeochemCompetition (bounds, num_bgc_soilc, filter_bgc_soilc,num_bgc_vegp, filter_bgc_vegp, & p_decomp_cn_gain, pmnf_decomp_cascade, waterstatebulk_inst, & waterfluxbulk_inst, temperature_inst,soilstate_inst, & cnveg_state_inst,cnveg_carbonstate_inst, & @@ -187,10 +187,10 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_vegp ! number of veg patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for veg patches real(r8) , intent(in) :: pmnf_decomp_cascade(bounds%begc:,1:,1:) ! potential mineral N flux from one pool to another (gN/m3/s) real(r8) , intent(in) :: p_decomp_cn_gain(bounds%begc:,1:,1:) ! C:N ratio of the flux gained by the receiver pool type(waterstatebulk_type) , intent(in) :: waterstatebulk_inst @@ -284,7 +284,7 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, ! calcualte nitrogen uptake profile ! nuptake_prof(:,:) = nan ! call SoilBiogelchemNitrogenUptakeProfile(bounds, & - ! nlevdecomp, num_soilc, filter_soilc, & + ! nlevdecomp, num_bgc_soilc, filter_bgc_soilc, & ! sminn_vr, dzsoi_decomp, nfixation_prof, nuptake_prof) ! column loops to resolve plant/heterotroph competition for mineral N @@ -293,24 +293,24 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, local_use_fun = use_fun - if (.not. use_nitrif_denitrif) then + if_nitrif: if (.not. use_nitrif_denitrif) then ! init sminn_tot - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_tot(c) = 0. end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_tot(c) = sminn_tot(c) + sminn_vr(c,j) * dzsoi_decomp(j) end do end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (sminn_tot(c) > 0.) then nuptake_prof(c,j) = sminn_vr(c,j) / sminn_tot(c) else @@ -320,15 +320,15 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sum_ndemand_vr(c,j) = plant_ndemand(c) * nuptake_prof(c,j) + potential_immob_vr(c,j) end do end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) l = col%landunit(c) if (sum_ndemand_vr(c,j)*dt < sminn_vr(c,j)) then @@ -376,7 +376,7 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, if ( local_use_fun ) then call t_startf( 'CNFUN' ) - call CNFUN(bounds,num_soilc,filter_soilc,num_soilp,filter_soilp,waterstatebulk_inst, & + call CNFUN(bounds,num_bgc_soilc,filter_bgc_soilc,num_bgc_vegp,filter_bgc_vegp,waterstatebulk_inst, & waterfluxbulk_inst,temperature_inst,soilstate_inst,cnveg_state_inst,cnveg_carbonstate_inst,& cnveg_carbonflux_inst,cnveg_nitrogenstate_inst,cnveg_nitrogenflux_inst ,& soilbiogeochem_nitrogenflux_inst,soilbiogeochem_carbonflux_inst,canopystate_inst, & @@ -390,8 +390,8 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, ! sum up N fluxes to plant do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant(c) = sminn_to_plant(c) + sminn_to_plant_vr(c,j) * dzsoi_decomp(j) if ( local_use_fun ) then if (sminn_to_plant_fun_vr(c,j).gt.sminn_to_plant_vr(c,j)) then @@ -402,19 +402,19 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, end do ! give plants a second pass to see if there is any mineral N left over with which to satisfy residual N demand. - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) residual_sminn(c) = 0._r8 end do ! sum up total N left over after initial plant and immobilization fluxes - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) residual_plant_ndemand(c) = plant_ndemand(c) - sminn_to_plant(c) end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (residual_plant_ndemand(c) > 0._r8 ) then if (nlimit(c,j) .eq. 0) then residual_sminn_vr(c,j) = max(sminn_vr(c,j) - (actual_immob_vr(c,j) + sminn_to_plant_vr(c,j) ) * dt, 0._r8) @@ -428,8 +428,8 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, ! distribute residual N to plants do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) if ( residual_plant_ndemand(c) > 0._r8 .and. residual_sminn(c) > 0._r8 .and. nlimit(c,j) .eq. 0) then sminn_to_plant_vr(c,j) = sminn_to_plant_vr(c,j) + residual_sminn_vr(c,j) * & min(( residual_plant_ndemand(c) * dt ) / residual_sminn(c), 1._r8) / dt @@ -438,13 +438,13 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, end do ! re-sum up N fluxes to plant - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant(c) = 0._r8 end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant(c) = sminn_to_plant(c) + sminn_to_plant_vr(c,j) * dzsoi_decomp(j) if ( .not. local_use_fun ) then sum_ndemand_vr(c,j) = potential_immob_vr(c,j) + sminn_to_plant_vr(c,j) @@ -459,8 +459,8 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, ! be lost to denitrification, in addition to the constant ! proportion lost in the decomposition pathways do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) if ( .not. local_use_fun ) then if ((sminn_to_plant_vr(c,j) + actual_immob_vr(c,j))*dt < sminn_vr(c,j)) then sminn_to_denit_excess_vr(c,j) = max(bdnr*((sminn_vr(c,j)/dt) - sum_ndemand_vr(c,j)),0._r8) @@ -479,15 +479,15 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, ! sum up N fluxes to immobilization do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) actual_immob(c) = actual_immob(c) + actual_immob_vr(c,j) * dzsoi_decomp(j) potential_immob(c) = potential_immob(c) + potential_immob_vr(c,j) * dzsoi_decomp(j) end do end do - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! calculate the fraction of potential growth that can be ! acheived with the N available to plants if (plant_ndemand(c) > 0.0_r8) then @@ -520,23 +520,23 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, compet_nit = params_inst%compet_nit ! init total mineral N pools - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_tot(c) = 0. end do ! sum up total mineral N pools do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_tot(c) = sminn_tot(c) + (smin_no3_vr(c,j) + smin_nh4_vr(c,j)) * dzsoi_decomp(j) end do end do ! define N uptake profile for initial vertical distribution of plant N uptake, assuming plant seeks N from where it is most abundant do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (sminn_tot(c) > 0.) then nuptake_prof(c,j) = sminn_vr(c,j) / sminn_tot(c) else @@ -547,8 +547,8 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, ! main column/vertical loop do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) l = col%landunit(c) ! first compete for nh4 @@ -630,8 +630,6 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, sum_no3_demand_scaled(c,j) = (plant_ndemand(c)*nuptake_prof(c,j))*compet_plant_no3 + & (potential_immob_vr(c,j)-actual_immob_nh4_vr(c,j))*compet_decomp_no3 + pot_f_denit_vr(c,j)*compet_denit endif - - if (sum_no3_demand(c,j)*dt < smin_no3_vr(c,j)) then @@ -655,7 +653,7 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, smin_no3_to_plant_vr(c,j) = smin_no3_vr(c,j)/dt - actual_immob_no3_vr(c,j) - f_denit_vr(c,j) end if endif - + else ! NO3 availability can not satisfy the sum of immobilization, denitrification, and @@ -756,7 +754,7 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, if ( local_use_fun ) then call t_startf( 'CNFUN' ) - call CNFUN(bounds,num_soilc,filter_soilc,num_soilp,filter_soilp,waterstatebulk_inst,& + call CNFUN(bounds,num_bgc_soilc,filter_bgc_soilc,num_bgc_vegp,filter_bgc_vegp,waterstatebulk_inst,& waterfluxbulk_inst,temperature_inst,soilstate_inst,cnveg_state_inst,cnveg_carbonstate_inst,& cnveg_carbonflux_inst,cnveg_nitrogenstate_inst,cnveg_nitrogenflux_inst ,& soilbiogeochem_nitrogenflux_inst,soilbiogeochem_carbonflux_inst,canopystate_inst, & @@ -778,20 +776,20 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, if(.not.local_use_fun)then - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! sum up N fluxes to plant after initial competition sminn_to_plant(c) = 0._r8 end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant(c) = sminn_to_plant(c) + sminn_to_plant_vr(c,j) * dzsoi_decomp(j) end do end do else - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! sum up N fluxes to plant after initial competition sminn_to_plant(c) = 0._r8 !this isn't use in fun. do j = 1, nlevdecomp @@ -815,8 +813,8 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, if (decomp_method == mimics_decomp) then do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) do k = 1, ndecomp_cascade_transitions if (cascade_receiver_pool(k) == i_cop_mic .or. & @@ -848,14 +846,14 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, if(.not.local_use_fun)then ! give plants a second pass to see if there is any mineral N left over with which to satisfy residual N demand. ! first take frm nh4 pool; then take from no3 pool - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) residual_plant_ndemand(c) = plant_ndemand(c) - sminn_to_plant(c) residual_smin_nh4(c) = 0._r8 end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (residual_plant_ndemand(c) > 0._r8 ) then if (nlimit_nh4(c,j) .eq. 0) then residual_smin_nh4_vr(c,j) = max(smin_nh4_vr(c,j) - (actual_immob_nh4_vr(c,j) + & @@ -875,13 +873,13 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, end do ! re-sum up N fluxes to plant after second pass for nh4 - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant(c) = 0._r8 end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant_vr(c,j) = smin_nh4_to_plant_vr(c,j) + smin_no3_to_plant_vr(c,j) sminn_to_plant(c) = sminn_to_plant(c) + (sminn_to_plant_vr(c,j)) * dzsoi_decomp(j) end do @@ -889,15 +887,15 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, ! ! and now do second pass for no3 - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) residual_plant_ndemand(c) = plant_ndemand(c) - sminn_to_plant(c) residual_smin_no3(c) = 0._r8 end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (residual_plant_ndemand(c) > 0._r8 ) then if (nlimit_no3(c,j) .eq. 0) then residual_smin_no3_vr(c,j) = max(smin_no3_vr(c,j) - (actual_immob_no3_vr(c,j) + & @@ -916,13 +914,13 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, end do ! re-sum up N fluxes to plant after second passes of both no3 and nh4 - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant(c) = 0._r8 end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant_vr(c,j) = smin_nh4_to_plant_vr(c,j) + smin_no3_to_plant_vr(c,j) sminn_to_plant(c) = sminn_to_plant(c) + (sminn_to_plant_vr(c,j)) * dzsoi_decomp(j) end do @@ -930,13 +928,13 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, else !use_fun !calculate maximum N available to plants. - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant(c) = 0._r8 end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant_vr(c,j) = smin_nh4_to_plant_vr(c,j) + smin_no3_to_plant_vr(c,j) sminn_to_plant(c) = sminn_to_plant(c) + (sminn_to_plant_vr(c,j)) * dzsoi_decomp(j) end do @@ -945,8 +943,8 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, ! add up fun fluxes from SMINN to plant. do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_to_plant_new(c) = sminn_to_plant_new(c) + & (sminn_to_plant_fun_no3_vr(c,j) + sminn_to_plant_fun_nh4_vr(c,j)) * dzsoi_decomp(j) @@ -956,14 +954,14 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, end if !use_f ! sum up N fluxes to immobilization - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) actual_immob(c) = 0._r8 potential_immob(c) = 0._r8 end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) actual_immob(c) = actual_immob(c) + actual_immob_vr(c,j) * dzsoi_decomp(j) potential_immob(c) = potential_immob(c) + potential_immob_vr(c,j) * dzsoi_decomp(j) end do @@ -972,8 +970,8 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! calculate the fraction of potential growth that can be ! acheived with the N available to plants ! calculate the fraction of immobilization realized (for diagnostic purposes) @@ -993,7 +991,7 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, end if end do ! end of column loops - end if !end of if_not_use_nitrif_denitrif + end if if_nitrif !end of if_not_use_nitrif_denitrif end associate diff --git a/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 b/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 index b65fc5f17f..e1b6e68aad 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 @@ -311,7 +311,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i i_met_lit = i_litr_min floating_cn_ratio_decomp_pools(i_met_lit) = .true. decomp_cascade_con%decomp_pool_name_restart(i_met_lit) = 'litr1' - decomp_cascade_con%decomp_pool_name_history(i_met_lit) = 'MET_LIT' + decomp_cascade_con%decomp_pool_name_history(i_met_lit) = 'LIT_MET' decomp_cascade_con%decomp_pool_name_long(i_met_lit) = 'metabolic litter' decomp_cascade_con%decomp_pool_name_short(i_met_lit) = 'L1' is_litter(i_met_lit) = .true. @@ -326,7 +326,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i i_cel_lit = i_met_lit + 1 floating_cn_ratio_decomp_pools(i_cel_lit) = .true. decomp_cascade_con%decomp_pool_name_restart(i_cel_lit) = 'litr2' - decomp_cascade_con%decomp_pool_name_history(i_cel_lit) = 'CEL_LIT' + decomp_cascade_con%decomp_pool_name_history(i_cel_lit) = 'LIT_CEL' decomp_cascade_con%decomp_pool_name_long(i_cel_lit) = 'cellulosic litter' decomp_cascade_con%decomp_pool_name_short(i_cel_lit) = 'L2' is_litter(i_cel_lit) = .true. @@ -341,7 +341,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i i_lig_lit = i_cel_lit + 1 floating_cn_ratio_decomp_pools(i_lig_lit) = .true. decomp_cascade_con%decomp_pool_name_restart(i_lig_lit) = 'litr3' - decomp_cascade_con%decomp_pool_name_history(i_lig_lit) = 'LIG_LIT' + decomp_cascade_con%decomp_pool_name_history(i_lig_lit) = 'LIT_LIG' decomp_cascade_con%decomp_pool_name_long(i_lig_lit) = 'lignin litter' decomp_cascade_con%decomp_pool_name_short(i_lig_lit) = 'L3' is_litter(i_lig_lit) = .true. @@ -366,7 +366,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i i_act_som = i_lig_lit + 1 floating_cn_ratio_decomp_pools(i_act_som) = .false. decomp_cascade_con%decomp_pool_name_restart(i_act_som) = 'soil1' - decomp_cascade_con%decomp_pool_name_history(i_act_som) = 'ACT_SOM' + decomp_cascade_con%decomp_pool_name_history(i_act_som) = 'SOM_ACT' decomp_cascade_con%decomp_pool_name_long(i_act_som) = 'active soil organic matter' decomp_cascade_con%decomp_pool_name_short(i_act_som) = 'S1' is_litter(i_act_som) = .false. @@ -381,7 +381,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i i_slo_som = i_act_som + 1 floating_cn_ratio_decomp_pools(i_slo_som) = .false. decomp_cascade_con%decomp_pool_name_restart(i_slo_som) = 'soil2' - decomp_cascade_con%decomp_pool_name_history(i_slo_som) = 'SLO_SOM' + decomp_cascade_con%decomp_pool_name_history(i_slo_som) = 'SOM_SLO' decomp_cascade_con%decomp_pool_name_long(i_slo_som) = 'slow soil organic matter' decomp_cascade_con%decomp_pool_name_short(i_slo_som) = 'S2' is_litter(i_slo_som) = .false. @@ -396,7 +396,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i i_pas_som = i_slo_som + 1 floating_cn_ratio_decomp_pools(i_pas_som) = .false. decomp_cascade_con%decomp_pool_name_restart(i_pas_som) = 'soil3' - decomp_cascade_con%decomp_pool_name_history(i_pas_som) = 'PAS_SOM' + decomp_cascade_con%decomp_pool_name_history(i_pas_som) = 'SOM_PAS' decomp_cascade_con%decomp_pool_name_long(i_pas_som) = 'passive soil organic matter' decomp_cascade_con%decomp_pool_name_short(i_pas_som) = 'S3' is_litter(i_pas_som) = .false. @@ -510,7 +510,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i end subroutine init_decompcascade_bgc !----------------------------------------------------------------------- - subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & + subroutine decomp_rate_constants_bgc(bounds, num_bgc_soilc, filter_bgc_soilc, & soilstate_inst, temperature_inst, ch4_inst, soilbiogeochem_carbonflux_inst) ! ! !DESCRIPTION: @@ -524,8 +524,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns type(soilstate_type) , intent(in) :: soilstate_inst type(temperature_type) , intent(in) :: temperature_inst type(ch4_type) , intent(in) :: ch4_inst @@ -619,8 +619,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & catanf_30 = catanf(30._r8) if ( spinup_state >= 1 ) then - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! if ( abs(spinup_factor(i_met_lit) - 1._r8) .gt. eps) then spinup_geogterm_l1(c) = spinup_factor(i_met_lit) * get_spinup_latitude_term(grc%latdeg(col%gridcell(c))) @@ -662,8 +662,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & ! end do else - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) spinup_geogterm_l1(c) = 1._r8 spinup_geogterm_l23(c) = 1._r8 spinup_geogterm_cwd(c) = 1._r8 @@ -686,14 +686,14 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & nlev_soildecomp_standard=5 allocate(fr(bounds%begc:bounds%endc,nlev_soildecomp_standard)) do j=1,nlev_soildecomp_standard - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) frw(c) = frw(c) + col%dz(c,j) end do end do do j = 1,nlev_soildecomp_standard - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (frw(c) /= 0._r8) then fr(c,j) = col%dz(c,j) / frw(c) else @@ -708,8 +708,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & ! limiting conditions at 25 C. do j = 1,nlev_soildecomp_standard - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (j==1) t_scalar(c,:) = 0._r8 if (t_soisno(c,j) >= SHR_CONST_TKFRZ) then t_scalar(c,1)=t_scalar(c,1) + & @@ -724,8 +724,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & else ! original century uses an arctangent function to calculate the temperature dependence of decomposition do j = 1,nlev_soildecomp_standard - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (j==1) t_scalar(c,:) = 0._r8 t_scalar(c,1)=t_scalar(c,1) +max(catanf(t_soisno(c,j)-SHR_CONST_TKFRZ)/catanf_30*fr(c,j),0.01_r8) @@ -743,8 +743,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & ! and soil moisture. Soil Biol. Biochem., 15(4):447-453. do j = 1,nlev_soildecomp_standard - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (j==1) w_scalar(c,:) = 0._r8 psi = min(soilpsi(c,j),maxpsi) ! decomp only if soilpsi is higher than minpsi @@ -760,8 +760,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & ! Check for anoxia w/o LCH4 now done in controlMod. do j = 1,nlev_soildecomp_standard - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (j==1) o_scalar(c,:) = 0._r8 @@ -790,8 +790,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & ! the base rates at 25 C, which are calibrated from microcosm studies. do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (t_soisno(c,j) >= SHR_CONST_TKFRZ) then t_scalar(c,j)= (Q10**((t_soisno(c,j)-(SHR_CONST_TKFRZ+25._r8))/10._r8)) else @@ -803,8 +803,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & else do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) t_scalar(c,j)= max(catanf(t_soisno(c,j)-SHR_CONST_TKFRZ)/catanf_30, 0.01_r8) end do end do @@ -820,8 +820,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & ! and soil moisture. Soil Biol. Biochem., 15(4):447-453. do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) psi = min(soilpsi(c,j),maxpsi) ! decomp only if soilpsi is higher than minpsi if (psi > minpsi) then @@ -838,8 +838,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & if (anoxia) then do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) o_scalar(c,j) = max(o2stress_unsat(c,j), mino2lim) end do @@ -857,8 +857,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & ! scale all decomposition rates by a constant to compensate for offset between original CENTURY temp func and Q10 normalization_factor = (catanf(normalization_tref)/catanf_30) / (q10**((normalization_tref-25._r8)/10._r8)) do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) t_scalar(c,j) = t_scalar(c,j) * normalization_factor end do end do @@ -867,16 +867,16 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & ! add a term to reduce decomposition rate at depth ! for now used a fixed e-folding depth do j = 1, nlevdecomp - do fc = 1, num_soilc - c = filter_soilc(fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc(fc) depth_scalar(c,j) = exp(-zsoi(j) / decomp_depth_efolding) end do end do ! calculate rate constants for all litter and som pools do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) decomp_k(c,j,i_met_lit) = k_l1 * t_scalar(c,j) * w_scalar(c,j) * & depth_scalar(c,j) * o_scalar(c,j) * spinup_geogterm_l1(c) decomp_k(c,j,i_cel_lit) = k_l2_l3 * t_scalar(c,j) * w_scalar(c,j) * & diff --git a/src/soilbiogeochem/SoilBiogeochemDecompCascadeConType.F90 b/src/soilbiogeochem/SoilBiogeochemDecompCascadeConType.F90 index 4f6cf04eaf..0474ab9a63 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompCascadeConType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompCascadeConType.F90 @@ -63,7 +63,7 @@ module SoilBiogeochemDecompCascadeConType !------------------------------------------------------------------------ subroutine decomp_cascade_par_init( NLFilename ) - use clm_varctl , only : use_fates, use_cn, use_fates_sp + use clm_varctl , only : use_cn, use_fates_bgc use clm_varpar , only : ndecomp_pools_max use spmdMod , only : masterproc, mpicom use clm_nlUtilsMod , only : find_nlgroup_name @@ -110,9 +110,9 @@ subroutine decomp_cascade_par_init( NLFilename ) if ( decomp_method == no_soil_decomp )then call endrun('When running with BGC an active soil_decomp_method must be used') end if - else if ( use_fates ) then - if ( .not. use_fates_sp .and. (decomp_method == no_soil_decomp) )then - call endrun('When running with FATES and without FATES-SP an active soil_decomp_method must be used') + else if ( use_fates_bgc ) then + if ( decomp_method == no_soil_decomp )then + call endrun('When running with FATES and without FATES-SP, an active soil_decomp_method must be used') end if else if ( decomp_method /= no_soil_decomp )then @@ -128,7 +128,7 @@ subroutine decomp_cascade_par_init( NLFilename ) ! ndecomp_pools would get the value of i_pas_som or i_cwd and ! ndecomp_cascade_transitions would get the value of i_s3s1 or i_cwdl3 ! depending on how use_fates is set. - if ( use_fates ) then + if ( use_fates_bgc ) then if (decomp_method == century_decomp) then ndecomp_pools = 6 ndecomp_cascade_transitions = 8 diff --git a/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 b/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 index f820db01b6..b8e7137a32 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 @@ -481,7 +481,7 @@ subroutine init_decompcascade_mimics(bounds, soilbiogeochem_state_inst, soilstat i_met_lit = i_litr_min floating_cn_ratio_decomp_pools(i_met_lit) = .true. decomp_cascade_con%decomp_pool_name_restart(i_met_lit) = 'litr1' - decomp_cascade_con%decomp_pool_name_history(i_met_lit) = 'MET_LIT' + decomp_cascade_con%decomp_pool_name_history(i_met_lit) = 'LIT_MET' decomp_cascade_con%decomp_pool_name_long(i_met_lit) = 'metabolic litter' decomp_cascade_con%decomp_pool_name_short(i_met_lit) = 'L1' is_microbe(i_met_lit) = .false. @@ -497,7 +497,7 @@ subroutine init_decompcascade_mimics(bounds, soilbiogeochem_state_inst, soilstat i_str_lit = i_met_lit + 1 floating_cn_ratio_decomp_pools(i_str_lit) = .true. decomp_cascade_con%decomp_pool_name_restart(i_str_lit) = 'litr2' - decomp_cascade_con%decomp_pool_name_history(i_str_lit) = 'STR_LIT' + decomp_cascade_con%decomp_pool_name_history(i_str_lit) = 'LIT_STR' decomp_cascade_con%decomp_pool_name_long(i_str_lit) = 'structural litter' decomp_cascade_con%decomp_pool_name_short(i_str_lit) = 'L2' is_microbe(i_str_lit) = .false. @@ -523,7 +523,7 @@ subroutine init_decompcascade_mimics(bounds, soilbiogeochem_state_inst, soilstat i_avl_som = i_str_lit + 1 floating_cn_ratio_decomp_pools(i_avl_som) = .true. decomp_cascade_con%decomp_pool_name_restart(i_avl_som) = 'soil1' - decomp_cascade_con%decomp_pool_name_history(i_avl_som) = 'AVL_SOM' + decomp_cascade_con%decomp_pool_name_history(i_avl_som) = 'SOM_AVL' decomp_cascade_con%decomp_pool_name_long(i_avl_som) = 'available soil organic matter' decomp_cascade_con%decomp_pool_name_short(i_avl_som) = 'S1' is_microbe(i_avl_som) = .false. @@ -539,7 +539,7 @@ subroutine init_decompcascade_mimics(bounds, soilbiogeochem_state_inst, soilstat i_chem_som = i_avl_som + 1 floating_cn_ratio_decomp_pools(i_chem_som) = .true. decomp_cascade_con%decomp_pool_name_restart(i_chem_som) = 'soil2' - decomp_cascade_con%decomp_pool_name_history(i_chem_som) = 'CHEM_SOM' + decomp_cascade_con%decomp_pool_name_history(i_chem_som) = 'SOM_CHEM' decomp_cascade_con%decomp_pool_name_long(i_chem_som) = 'chemically protected soil organic matter' decomp_cascade_con%decomp_pool_name_short(i_chem_som) = 'S2' is_microbe(i_chem_som) = .false. @@ -555,7 +555,7 @@ subroutine init_decompcascade_mimics(bounds, soilbiogeochem_state_inst, soilstat i_phys_som = i_chem_som + 1 floating_cn_ratio_decomp_pools(i_phys_som) = .true. decomp_cascade_con%decomp_pool_name_restart(i_phys_som) = 'soil3' - decomp_cascade_con%decomp_pool_name_history(i_phys_som) = 'PHYS_SOM' + decomp_cascade_con%decomp_pool_name_history(i_phys_som) = 'SOM_PHYS' decomp_cascade_con%decomp_pool_name_long(i_phys_som) = 'physically protected soil organic matter' decomp_cascade_con%decomp_pool_name_short(i_phys_som) = 'S3' is_microbe(i_phys_som) = .false. @@ -571,7 +571,7 @@ subroutine init_decompcascade_mimics(bounds, soilbiogeochem_state_inst, soilstat i_cop_mic = i_phys_som + 1 floating_cn_ratio_decomp_pools(i_cop_mic) = .true. decomp_cascade_con%decomp_pool_name_restart(i_cop_mic) = 'micr1' - decomp_cascade_con%decomp_pool_name_history(i_cop_mic) = 'COP_MIC' + decomp_cascade_con%decomp_pool_name_history(i_cop_mic) = 'MIC_COP' decomp_cascade_con%decomp_pool_name_long(i_cop_mic) = 'copiotrophic microbes' decomp_cascade_con%decomp_pool_name_short(i_cop_mic) = 'M1' is_microbe(i_cop_mic) = .true. @@ -587,7 +587,7 @@ subroutine init_decompcascade_mimics(bounds, soilbiogeochem_state_inst, soilstat i_oli_mic = i_cop_mic + 1 floating_cn_ratio_decomp_pools(i_oli_mic) = .true. decomp_cascade_con%decomp_pool_name_restart(i_oli_mic) = 'micr2' - decomp_cascade_con%decomp_pool_name_history(i_oli_mic) = 'OLI_MIC' + decomp_cascade_con%decomp_pool_name_history(i_oli_mic) = 'MIC_OLI' decomp_cascade_con%decomp_pool_name_long(i_oli_mic) = 'oligotrophic microbes' decomp_cascade_con%decomp_pool_name_short(i_oli_mic) = 'M2' is_microbe(i_oli_mic) = .true. @@ -752,7 +752,7 @@ subroutine init_decompcascade_mimics(bounds, soilbiogeochem_state_inst, soilstat end subroutine init_decompcascade_mimics !----------------------------------------------------------------------- - subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & + subroutine decomp_rates_mimics(bounds, num_bgc_soilc, filter_bgc_soilc, & num_soilp, filter_soilp, clm_fates, & soilstate_inst, temperature_inst, cnveg_carbonflux_inst, & ch4_inst, soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst) @@ -773,8 +773,8 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_soilp ! number of soil patches in filter integer , intent(in) :: filter_soilp(:) ! filter for soil patches - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns type(soilstate_type) , intent(in) :: soilstate_inst type(temperature_type) , intent(in) :: temperature_inst type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst @@ -895,8 +895,8 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & ! calc ref rate if ( spinup_state >= 1 ) then - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! if ( abs(spinup_factor(i_met_lit) - 1._r8) .gt. eps) then spinup_geogterm_l1(c) = spinup_factor(i_met_lit) * get_spinup_latitude_term(grc%latdeg(col%gridcell(c))) @@ -950,8 +950,8 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & ! end do else - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) spinup_geogterm_l1(c) = 1._r8 spinup_geogterm_l2(c) = 1._r8 spinup_geogterm_cwd(c) = 1._r8 @@ -975,14 +975,14 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & frw(bounds%begc:bounds%endc) = 0._r8 allocate(fr(bounds%begc:bounds%endc,nlev_soildecomp_standard)) do j=1,nlev_soildecomp_standard - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) frw(c) = frw(c) + col%dz(c,j) end do end do do j = 1,nlev_soildecomp_standard - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (frw(c) /= 0._r8) then fr(c,j) = col%dz(c,j) / frw(c) else @@ -1000,8 +1000,8 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & ! and soil moisture. Soil Biol. Biochem., 15(4):447-453. do j = 1,nlev_soildecomp_standard - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (j==1) w_scalar(c,:) = 0._r8 psi = min(soilpsi(c,j),maxpsi) ! decomp only if soilpsi is higher than minpsi @@ -1017,8 +1017,8 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & if (anoxia) then do j = 1,nlev_soildecomp_standard - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (j==1) o_scalar(c,:) = 0._r8 @@ -1042,8 +1042,8 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & ! and soil moisture. Soil Biol. Biochem., 15(4):447-453. do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) psi = min(soilpsi(c,j),maxpsi) ! decomp only if soilpsi is higher than minpsi if (psi > minpsi) then @@ -1059,8 +1059,8 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & if (anoxia) then do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) o_scalar(c,j) = max(o2stress_unsat(c,j), mino2lim) end do @@ -1074,8 +1074,8 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & ! Term that reduces decomposition rate at depth ! Placeholder. For now depth_scalar = 1. do j = 1, nlevdecomp - do fc = 1, num_soilc - c = filter_soilc(fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc(fc) ! Using fixed e-folding depth as in ! SoilBiogeochemDecompCascadeBGCMod.F90 ! depth_scalar(c,j) = exp(-zsoi(j) / decomp_depth_efolding) @@ -1135,7 +1135,7 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & end do ! p loop ! Calculate the column-level average - call p2c(bounds, num_soilc, filter_soilc, & + call p2c(bounds, num_bgc_soilc, filter_bgc_soilc, & annsum_npp(bounds%begp:bounds%endp), & annsum_npp_col_local(bounds%begc:bounds%endc)) else @@ -1146,8 +1146,8 @@ subroutine decomp_rates_mimics(bounds, num_soilc, filter_soilc, & end if fates_if ! calculate rates for all litter and som pools - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (use_fates) then annsum_npp_col_scalar = max(0._r8, annsum_npp_col_local(c)) diff --git a/src/soilbiogeochem/SoilBiogeochemDecompMod.F90 b/src/soilbiogeochem/SoilBiogeochemDecompMod.F90 index a46f999143..9bd8b13008 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompMod.F90 @@ -11,7 +11,7 @@ module SoilBiogeochemDecompMod use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type use clm_varpar , only : nlevdecomp, ndecomp_cascade_transitions, ndecomp_pools - use clm_varctl , only : use_nitrif_denitrif, use_lch4, use_fates, iulog + use clm_varctl , only : use_nitrif_denitrif, use_lch4, iulog use clm_varcon , only : dzsoi_decomp use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con, mimics_decomp, decomp_method, use_soil_matrixcn use SoilBiogeochemStateType , only : soilbiogeochem_state_type @@ -67,7 +67,7 @@ subroutine readParams ( ncid ) end subroutine readParams !----------------------------------------------------------------------- - subroutine SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, & + subroutine SoilBiogeochemDecomp (bounds, num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_state_inst, soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst, & soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst, & cn_decomp_pools, p_decomp_cpool_loss, pmnf_decomp_cascade, & @@ -78,8 +78,8 @@ subroutine SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, ! ! !ARGUMENT: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns type(soilbiogeochem_state_type) , intent(inout) :: soilbiogeochem_state_inst type(soilbiogeochem_carbonstate_type) , intent(in) :: soilbiogeochem_carbonstate_inst type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst @@ -137,13 +137,12 @@ subroutine SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, ! column loop to calculate actual immobilization and decomp rates, following ! resolution of plant/heterotroph competition for mineral N - if ( .not. use_fates) then ! calculate c:n ratios of applicable pools do l = 1, ndecomp_pools if ( floating_cn_ratio_decomp_pools(l) ) then do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if ( decomp_npools_vr(c,j,l) > 0._r8 ) then cn_decomp_pools(c,j,l) = decomp_cpools_vr(c,j,l) / decomp_npools_vr(c,j,l) end if @@ -151,8 +150,8 @@ subroutine SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, end do else do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) cn_decomp_pools(c,j,l) = initial_cn_ratio(l) end do end do @@ -170,8 +169,8 @@ subroutine SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, do k = 1, ndecomp_cascade_transitions do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (decomp_cpools_vr(c,j,cascade_donor_pool(k)) > 0._r8) then if ( pmnf_decomp_cascade(c,j,k) > 0._r8 ) then @@ -221,38 +220,21 @@ subroutine SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, end do end do end do - else - do k = 1, ndecomp_cascade_transitions - do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) - ! - decomp_cascade_hr_vr(c,j,k) = rf_decomp_cascade(c,j,k) * p_decomp_cpool_loss(c,j,k) - decomp_cascade_ctransfer_vr(c,j,k) = (1._r8 - rf_decomp_cascade(c,j,k)) * p_decomp_cpool_loss(c,j,k) - if (decomp_method == mimics_decomp) then - decomp_cascade_hr_vr(c,j,k) = min( & - p_decomp_cpool_loss(c,j,k), & - decomp_cascade_hr_vr(c,j,k) + c_overflow_vr(c,j,k)) - decomp_cascade_ctransfer_vr(c,j,k) = max(0.0_r8, p_decomp_cpool_loss(c,j,k) - decomp_cascade_hr_vr(c,j,k)) - end if - ! - end do - end do - end do - end if + + if (use_lch4) then ! Calculate total fraction of potential HR, for methane code do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) hrsum(c,j) = 0._r8 end do end do do k = 1, ndecomp_cascade_transitions do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) hrsum(c,j) = hrsum(c,j) + rf_decomp_cascade(c,j,k) * p_decomp_cpool_loss(c,j,k) end do end do @@ -261,8 +243,8 @@ subroutine SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, ! Nitrogen limitation / (low)-moisture limitation do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (phr_vr(c,j) > 0._r8) then fphr(c,j) = hrsum(c,j) / phr_vr(c,j) * w_scalar(c,j) fphr(c,j) = max(fphr(c,j), 0.01_r8) ! Prevent overflow errors for 0 respiration @@ -276,16 +258,11 @@ subroutine SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, ! vertically integrate net and gross mineralization fluxes for diagnostic output - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) do j = 1,nlevdecomp - if(.not.use_fates)then net_nmin(c) = net_nmin(c) + net_nmin_vr(c,j) * dzsoi_decomp(j) gross_nmin(c) = gross_nmin(c) + gross_nmin_vr(c,j) * dzsoi_decomp(j) - ! else - ! net_nmin(c) = 0.0_r8 - ! gross_nmin(c) = 0.0_r8 - endif end do end do diff --git a/src/soilbiogeochem/SoilBiogeochemLittVertTranspMod.F90 b/src/soilbiogeochem/SoilBiogeochemLittVertTranspMod.F90 index 616f995bd7..e58e2f22d6 100644 --- a/src/soilbiogeochem/SoilBiogeochemLittVertTranspMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemLittVertTranspMod.F90 @@ -5,7 +5,7 @@ module SoilBiogeochemLittVertTranspMod ! use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg - use clm_varctl , only : iulog, use_c13, use_c14, spinup_state, use_fates, use_cn + use clm_varctl , only : iulog, use_c13, use_c14, spinup_state use clm_varcon , only : secspday use decompMod , only : bounds_type use abortutils , only : endrun @@ -81,7 +81,7 @@ subroutine readParams ( ncid ) end subroutine readParams !----------------------------------------------------------------------- - subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & + subroutine SoilBiogeochemLittVertTransp(bounds, num_bgc_soilc, filter_bgc_soilc, & active_layer_inst, soilbiogeochem_state_inst, & soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst, & c13_soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonflux_inst, & @@ -105,8 +105,8 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns type(active_layer_type) , intent(in) :: active_layer_inst type(soilbiogeochem_state_type) , intent(inout) :: soilbiogeochem_state_inst type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst @@ -182,16 +182,13 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & if ( use_c14 ) then ntype = ntype+1 endif - if ( use_fates ) then - ntype = 1 - endif spinup_term = 1._r8 epsilon = 1.e-30 !------ first get diffusivity / advection terms -------! ! use different mixing rates for bioturbation and cryoturbation, with fixed bioturbation and cryoturbation set to a maximum depth - do fc = 1, num_soilc - c = filter_soilc (fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc (fc) if (( max(altmax(c), altmax_lastyear(c)) <= max_altdepth_cryoturbation ) .and. & ( max(altmax(c), altmax_lastyear(c)) > 0._r8) ) then ! use mixing profile modified slightly from Koven et al. (2009): constant through active layer, linear decrease from base of active layer to zero at a fixed depth @@ -247,11 +244,9 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & source => soilbiogeochem_carbonflux_inst%decomp_cpools_sourcesink_col trcr_tendency_ptr => soilbiogeochem_carbonflux_inst%decomp_cpools_transport_tendency_col case (2) ! N - if (use_cn ) then - conc_ptr => soilbiogeochem_nitrogenstate_inst%decomp_npools_vr_col - source => soilbiogeochem_nitrogenflux_inst%decomp_npools_sourcesink_col - trcr_tendency_ptr => soilbiogeochem_nitrogenflux_inst%decomp_npools_transport_tendency_col - endif + conc_ptr => soilbiogeochem_nitrogenstate_inst%decomp_npools_vr_col + source => soilbiogeochem_nitrogenflux_inst%decomp_npools_sourcesink_col + trcr_tendency_ptr => soilbiogeochem_nitrogenflux_inst%decomp_npools_transport_tendency_col case (3) if ( use_c13 ) then ! C13 @@ -280,8 +275,8 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & if ( .not. is_cwd(s) ) then if(.not. use_soil_matrixcn .or. s .eq. 1)then do j = 1,nlevdecomp+1 - do fc = 1, num_soilc - c = filter_soilc (fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc (fc) ! if ( spinup_state >= 1 ) then ! increase transport (both advection and diffusion) by the same factor as accelerated decomposition for a given pool @@ -311,16 +306,16 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & ! Set Pe (Peclet #) and D/dz throughout column - do fc = 1, num_soilc ! dummy terms here - c = filter_soilc (fc) + do fc = 1, num_bgc_soilc ! dummy terms here + c = filter_bgc_soilc (fc) conc_trcr(c,0) = 0._r8 conc_trcr(c,col%nbedrock(c)+1:nlevdecomp+1) = 0._r8 end do do j = 1,nlevdecomp+1 - do fc = 1, num_soilc - c = filter_soilc (fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc (fc) conc_trcr(c,j) = conc_ptr(c,j,s) @@ -384,8 +379,8 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & ! Calculate the tridiagonal coefficients do j = 0,nlevdecomp +1 - do fc = 1, num_soilc - c = filter_soilc (fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc (fc) ! g = cgridcell(c) if (j > 0 .and. j < nlevdecomp+1) then @@ -433,14 +428,14 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & enddo ! fc; column enddo ! j; nlevdecomp - do fc = 1, num_soilc - c = filter_soilc (fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc (fc) jtop(c) = 0 enddo ! subtract initial concentration and source terms for tendency calculation - do fc = 1, num_soilc - c = filter_soilc (fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc (fc) do j = 1, nlevdecomp if (.not. use_soil_matrixcn) then trcr_tendency_ptr(c,j,s) = 0.-(conc_trcr(c,j) + source(c,j,s)) @@ -454,15 +449,15 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & ! Solve for the concentration profile for this time step call Tridiagonal(bounds, 0, nlevdecomp+1, & jtop(bounds%begc:bounds%endc), & - num_soilc, filter_soilc, & + num_bgc_soilc, filter_bgc_soilc, & a_tri(bounds%begc:bounds%endc, :), & b_tri(bounds%begc:bounds%endc, :), & c_tri(bounds%begc:bounds%endc, :), & r_tri(bounds%begc:bounds%endc, :), & conc_trcr(bounds%begc:bounds%endc,0:nlevdecomp+1)) ! add post-transport concentration to calculate tendency term - do fc = 1, num_soilc - c = filter_soilc (fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc (fc) do j = 1, nlevdecomp trcr_tendency_ptr(c,j,s) = trcr_tendency_ptr(c,j,s) + conc_trcr(c,j) trcr_tendency_ptr(c,j,s) = trcr_tendency_ptr(c,j,s) / dtime @@ -471,16 +466,16 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & else ! For matrix solution set the matrix input array do j = 1,nlevdecomp - do fc =1,num_soilc - c = filter_soilc(fc) + do fc =1,num_bgc_soilc + c = filter_bgc_soilc(fc) end do end do end if !soil_matrix else ! for CWD pools, just add do j = 1,nlevdecomp - do fc = 1, num_soilc - c = filter_soilc (fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc (fc) if(.not. use_soil_matrixcn)then conc_trcr(c,j) = conc_ptr(c,j,s) + source(c,j,s) else @@ -498,8 +493,8 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & if (.not. use_soil_matrixcn) then do j = 1,nlevdecomp - do fc = 1, num_soilc - c = filter_soilc (fc) + do fc = 1, num_bgc_soilc + c = filter_bgc_soilc (fc) conc_ptr(c,j,s) = conc_trcr(c,j) ! Correct for small amounts of carbon that leak into bedrock if (j > col%nbedrock(c)) then diff --git a/src/soilbiogeochem/SoilBiogeochemNLeachingMod.F90 b/src/soilbiogeochem/SoilBiogeochemNLeachingMod.F90 index 02d22d6613..a646feb1d7 100644 --- a/src/soilbiogeochem/SoilBiogeochemNLeachingMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemNLeachingMod.F90 @@ -72,7 +72,7 @@ subroutine readParams ( ncid ) end subroutine readParams !----------------------------------------------------------------------- - subroutine SoilBiogeochemNLeaching(bounds, num_soilc, filter_soilc, & + subroutine SoilBiogeochemNLeaching(bounds, num_bgc_soilc, filter_bgc_soilc, & waterstatebulk_inst, waterfluxbulk_inst, & soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) ! @@ -86,8 +86,8 @@ subroutine SoilBiogeochemNLeaching(bounds, num_soilc, filter_soilc, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns type(waterstatebulk_type) , intent(in) :: waterstatebulk_inst type(waterfluxbulk_type) , intent(in) :: waterfluxbulk_inst type(soilbiogeochem_nitrogenstate_type) , intent(in) :: soilbiogeochem_nitrogenstate_inst @@ -133,8 +133,8 @@ subroutine SoilBiogeochemNLeaching(bounds, num_soilc, filter_soilc, & ! calculate the total soil water tot_water(bounds%begc:bounds%endc) = 0._r8 do j = 1,nlevsoi - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) tot_water(c) = tot_water(c) + h2osoi_liq(c,j) end do end do @@ -143,21 +143,21 @@ subroutine SoilBiogeochemNLeaching(bounds, num_soilc, filter_soilc, & surface_water(bounds%begc:bounds%endc) = 0._r8 do j = 1,nlevsoi if ( zisoi(j) <= depth_runoff_Nloss) then - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) surface_water(c) = surface_water(c) + h2osoi_liq(c,j) end do elseif ( zisoi(j-1) < depth_runoff_Nloss) then - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) surface_water(c) = surface_water(c) + h2osoi_liq(c,j) * ( (depth_runoff_Nloss - zisoi(j-1)) / col%dz(c,j)) end do endif end do ! Loop through columns - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) drain_tot(c) = qflx_drain(c) end do @@ -170,8 +170,8 @@ subroutine SoilBiogeochemNLeaching(bounds, num_soilc, filter_soilc, & do j = 1,nlevdecomp ! Loop through columns - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! calculate the dissolved mineral N concentration (gN/kg water) ! assumes that 10% of mineral nitrogen is soluble @@ -203,8 +203,8 @@ subroutine SoilBiogeochemNLeaching(bounds, num_soilc, filter_soilc, & do j = 1,nlevdecomp ! Loop through columns - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! calculate the dissolved mineral N concentration (gN/kg water) ! assumes that 10% of mineral nitrogen is soluble diff --git a/src/soilbiogeochem/SoilBiogeochemNStateUpdate1Mod.F90 b/src/soilbiogeochem/SoilBiogeochemNStateUpdate1Mod.F90 index 197a1d015b..4b70459aca 100644 --- a/src/soilbiogeochem/SoilBiogeochemNStateUpdate1Mod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemNStateUpdate1Mod.F90 @@ -27,7 +27,7 @@ module SoilBiogeochemNStateUpdate1Mod contains !----------------------------------------------------------------------- - subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & + subroutine SoilBiogeochemNStateUpdate1(num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_state_inst, soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst) ! ! !DESCRIPTION: @@ -35,8 +35,8 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & ! variables (except for gap-phase mortality and fire fluxes) ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns type(soilbiogeochem_state_type) , intent(in) :: soilbiogeochem_state_inst type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst type(soilbiogeochem_nitrogenstate_type) , intent(inout) :: soilbiogeochem_nitrogenstate_inst @@ -63,8 +63,8 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & dt = get_step_size_real() do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if(use_fun)then !RF in FUN logic, the fixed N goes straight into the plant, and not into the SMINN pool. ! N deposition and fixation (put all into NH4 pool) ns%smin_nh4_vr_col(c,j) = ns%smin_nh4_vr_col(c,j) + nf%ndep_to_sminn_col(c)*dt * ndep_prof(c,j) @@ -94,8 +94,8 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & do j = 1, nlevdecomp ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (.not. use_nitrif_denitrif) then ! N deposition and fixation @@ -122,8 +122,8 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & do k = 1, ndecomp_cascade_transitions do j = 1, nlevdecomp ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) nf%decomp_npools_sourcesink_col(c,j,cascade_donor_pool(k)) = & nf%decomp_npools_sourcesink_col(c,j,cascade_donor_pool(k)) - & @@ -137,8 +137,8 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions do j = 1, nlevdecomp ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) nf%decomp_npools_sourcesink_col(c,j,cascade_receiver_pool(k)) = & nf%decomp_npools_sourcesink_col(c,j,cascade_receiver_pool(k)) + & @@ -149,8 +149,8 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & else ! terminal transitions do j = 1, nlevdecomp ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) nf%decomp_npools_sourcesink_col(c,j,cascade_donor_pool(k)) = & nf%decomp_npools_sourcesink_col(c,j,cascade_donor_pool(k)) - & nf%decomp_cascade_sminn_flux_vr_col(c,j,k) * dt @@ -173,8 +173,8 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & if ( cascade_receiver_pool(k) /= 0 ) then ! skip terminal transitions do j = 1, nlevdecomp ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ns%sminn_vr_col(c,j) = ns%sminn_vr_col(c,j) - & (nf%sminn_to_denit_decomp_cascade_vr_col(c,j,k) + & nf%decomp_cascade_sminn_flux_vr_col(c,j,k))* dt @@ -183,8 +183,8 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & else do j = 1, nlevdecomp ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ns%sminn_vr_col(c,j) = ns%sminn_vr_col(c,j) - & nf%sminn_to_denit_decomp_cascade_vr_col(c,j,k)* dt @@ -198,8 +198,8 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & do j = 1, nlevdecomp ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! "bulk denitrification" ns%sminn_vr_col(c,j) = ns%sminn_vr_col(c,j) - nf%sminn_to_denit_excess_vr_col(c,j) * dt @@ -222,8 +222,8 @@ subroutine SoilBiogeochemNStateUpdate1(num_soilc, filter_soilc, & do j = 1, nlevdecomp ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! mineralization fluxes (divert a fraction of this stream to nitrification flux, add the rest to NH4 pool) ns%smin_nh4_vr_col(c,j) = ns%smin_nh4_vr_col(c,j) + nf%gross_nmin_vr_col(c,j)*dt diff --git a/src/soilbiogeochem/SoilBiogeochemNitrifDenitrifMod.F90 b/src/soilbiogeochem/SoilBiogeochemNitrifDenitrifMod.F90 index 3993439a1c..b30ff759b4 100644 --- a/src/soilbiogeochem/SoilBiogeochemNitrifDenitrifMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemNitrifDenitrifMod.F90 @@ -12,7 +12,7 @@ module SoilBiogeochemNitrifDenitrifMod use clm_varpar , only : nlevdecomp use clm_varcon , only : rpi, grav use clm_varcon , only : d_con_g, d_con_w, secspday - use clm_varctl , only : use_lch4, use_fates + use clm_varctl , only : use_lch4 use abortutils , only : endrun use decompMod , only : bounds_type use SoilStatetype , only : soilstate_type @@ -74,6 +74,7 @@ subroutine readParams ( ncid ) ! ! read in constants ! + tString='surface_tension_water' call ncd_io(trim(tString),tempr, 'read', ncid, readvar=readv) if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) @@ -137,7 +138,7 @@ subroutine readParams ( ncid ) end subroutine readParams !----------------------------------------------------------------------- - subroutine SoilBiogeochemNitrifDenitrif(bounds, num_soilc, filter_soilc, & + subroutine SoilBiogeochemNitrifDenitrif(bounds, num_bgc_soilc, filter_bgc_soilc, & soilstate_inst, waterstatebulk_inst, temperature_inst, ch4_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) ! @@ -150,8 +151,8 @@ subroutine SoilBiogeochemNitrifDenitrif(bounds, num_soilc, filter_soilc, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns type(soilstate_type) , intent(in) :: soilstate_inst type(waterstatebulk_type) , intent(in) :: waterstatebulk_inst type(temperature_type) , intent(in) :: temperature_inst @@ -260,8 +261,8 @@ subroutine SoilBiogeochemNitrifDenitrif(bounds, num_soilc, filter_soilc, & co2diff_con(2) = 0.0009_r8 do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) !---------------- calculate soil anoxia state ! calculate gas diffusivity of soil at field capacity here diff --git a/src/soilbiogeochem/SoilBiogeochemNitrogenFluxType.F90 b/src/soilbiogeochem/SoilBiogeochemNitrogenFluxType.F90 index 839f69379a..040a47f6a6 100644 --- a/src/soilbiogeochem/SoilBiogeochemNitrogenFluxType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemNitrogenFluxType.F90 @@ -7,7 +7,7 @@ module SoilBiogeochemNitrogenFluxType use clm_varpar , only : nlevdecomp_full, nlevdecomp use clm_varcon , only : spval, ispval, dzsoi_decomp use decompMod , only : bounds_type - use clm_varctl , only : use_nitrif_denitrif, use_crop + use clm_varctl , only : use_nitrif_denitrif, use_crop, use_fates use CNSharedParamsMod , only : use_fun use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con, use_soil_matrixcn use abortutils , only : endrun @@ -127,8 +127,10 @@ module SoilBiogeochemNitrogenFluxType ! all n pools involved in decomposition real(r8), pointer :: decomp_npools_sourcesink_col (:,:,:) ! col (gN/m3) change in decomposing n pools ! (sum of all additions and subtractions from stateupdate1). - real(r8), pointer :: sminn_to_plant_fun_vr_col (:,:) ! col total layer soil N uptake of FUN (gN/m2/s) - + real(r8), pointer :: sminn_to_plant_fun_vr_col (:,:) ! col total layer soil N uptake of FUN (gN/m2/s) + real(r8), pointer :: fates_litter_flux (:) ! (gN/m2/s) A summary of the total litter + ! flux passed in from FATES. + ! This is a diagnostic for balance checks only ! track tradiagonal matrix contains @@ -274,6 +276,12 @@ subroutine InitAllocate(this, bounds) allocate(this%decomp_npools_sourcesink_col (begc:endc,1:nlevdecomp_full,1:ndecomp_pools)) this%decomp_npools_sourcesink_col (:,:,:) = nan + if(use_fates)then + allocate(this%fates_litter_flux(begc:endc)); this%fates_litter_flux(:) = nan + else + allocate(this%fates_litter_flux(0:0)); this%fates_litter_flux(:) = nan + end if + ! Allocate soil Matrix setug if(use_soil_matrixcn)then end if @@ -351,7 +359,7 @@ subroutine InitHistory(this, bounds) 'to '//trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l))) else fieldname = trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))& - //'N_TO_SMINN' + //'_N_TO_SMINN' longname = 'mineral N flux for decomp. of '& //trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l))) endif @@ -364,8 +372,8 @@ subroutine InitHistory(this, bounds) if ( decomp_cascade_con%cascade_receiver_pool(l) /= 0 ) then this%decomp_cascade_ntransfer_col(begc:endc,l) = spval data1dptr => this%decomp_cascade_ntransfer_col(:,l) - fieldname = trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))//'N_TO_'//& - trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l)))//'N' + fieldname = trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))//'_N_TO_'//& + trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l)))//'_N' longname = 'decomp. of '//trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_donor_pool(l)))//& ' N to '//trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_receiver_pool(l)))//' N' call hist_addfld1d (fname=fieldname, units='gN/m^2', & @@ -388,7 +396,7 @@ subroutine InitHistory(this, bounds) 'to '//trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l))) else fieldname = trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))& - //'N_TO_SMINN'//trim(vr_suffix) + //'_N_TO_SMINN'//trim(vr_suffix) longname = 'mineral N flux for decomp. of '& //trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l))) endif @@ -401,9 +409,9 @@ subroutine InitHistory(this, bounds) if ( decomp_cascade_con%cascade_receiver_pool(l) /= 0 ) then this%decomp_cascade_ntransfer_vr_col(begc:endc,:,l) = spval data2dptr => this%decomp_cascade_ntransfer_vr_col(:,:,l) - fieldname = trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))//'N_TO_'//& + fieldname = trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_donor_pool(l)))//'_N_TO_'//& trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l)))& - //'N'//trim(vr_suffix) + //'_N'//trim(vr_suffix) longname = 'decomp. of '& //trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_donor_pool(l)))//& ' N to '//trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_receiver_pool(l)))//' N' @@ -429,7 +437,7 @@ subroutine InitHistory(this, bounds) if ( .not. decomp_cascade_con%is_cwd(k) ) then this%decomp_npools_leached_col(begc:endc,k) = spval data1dptr => this%decomp_npools_leached_col(:,k) - fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'N_TO_LEACHING' + fieldname = 'M_'//trim(decomp_cascade_con%decomp_pool_name_history(k))//'_N_TO_LEACHING' longname = trim(decomp_cascade_con%decomp_pool_name_long(k))//' N leaching loss' call hist_addfld1d (fname=fieldname, units='gN/m^2/s', & avgflag='A', long_name=longname, & @@ -437,7 +445,7 @@ subroutine InitHistory(this, bounds) this%decomp_npools_transport_tendency_col(begc:endc,:,k) = spval data2dptr => this%decomp_npools_transport_tendency_col(:,:,k) - fieldname = trim(decomp_cascade_con%decomp_pool_name_history(k))//'N_TNDNCY_VERT_TRANSPORT' + fieldname = trim(decomp_cascade_con%decomp_pool_name_history(k))//'_N_TNDNCY_VERT_TRANSPORT' longname = trim(decomp_cascade_con%decomp_pool_name_long(k))//' N tendency due to vertical transport' call hist_addfld_decomp (fname=fieldname, units='gN/m^3/s', type2d='levdcmp', & avgflag='A', long_name=longname, & @@ -1044,7 +1052,7 @@ subroutine SetValues ( this, & end subroutine SetValues !----------------------------------------------------------------------- - subroutine Summary(this, bounds, num_soilc, filter_soilc) + subroutine Summary(this, bounds, num_bgc_soilc, filter_bgc_soilc) ! ! !USES: use clm_varpar , only: nlevdecomp, ndecomp_cascade_transitions,ndecomp_pools @@ -1053,16 +1061,16 @@ subroutine Summary(this, bounds, num_soilc, filter_soilc) ! !ARGUMENTS: class (soilbiogeochem_nitrogenflux_type) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns ! ! !LOCAL VARIABLES: integer :: c,j,k,l ! indices integer :: fc ! filter indices !----------------------------------------------------------------------- - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%denit_col(c) = 0._r8 this%supplement_to_sminn_col(c) = 0._r8 this%som_n_leached_col(c) = 0._r8 @@ -1071,8 +1079,8 @@ subroutine Summary(this, bounds, num_soilc, filter_soilc) ! vertically integrate decomposing N cascade fluxes and soil mineral N fluxes associated with decomposition cascade do k = 1, ndecomp_cascade_transitions do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%decomp_cascade_ntransfer_col(c,k) = & this%decomp_cascade_ntransfer_col(c,k) + & @@ -1090,8 +1098,8 @@ subroutine Summary(this, bounds, num_soilc, filter_soilc) ! vertically integrate each denitrification flux do l = 1, ndecomp_cascade_transitions do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%sminn_to_denit_decomp_cascade_col(c,l) = & this%sminn_to_denit_decomp_cascade_col(c,l) + & this%sminn_to_denit_decomp_cascade_vr_col(c,j,l) * dzsoi_decomp(j) @@ -1101,8 +1109,8 @@ subroutine Summary(this, bounds, num_soilc, filter_soilc) ! vertically integrate bulk denitrification and leaching flux do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%sminn_to_denit_excess_col(c) = & this%sminn_to_denit_excess_col(c) + & this%sminn_to_denit_excess_vr_col(c,j) * dzsoi_decomp(j) @@ -1115,16 +1123,16 @@ subroutine Summary(this, bounds, num_soilc, filter_soilc) ! total N denitrification (DENIT) do l = 1, ndecomp_cascade_transitions - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%denit_col(c) = & this%denit_col(c) + & this%sminn_to_denit_decomp_cascade_col(c,l) end do end do - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%denit_col(c) = & this%denit_col(c) + & this%sminn_to_denit_excess_col(c) @@ -1134,8 +1142,8 @@ subroutine Summary(this, bounds, num_soilc, filter_soilc) ! vertically integrate NO3 NH4 N2O fluxes and pools do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! nitrification and denitrification fluxes this%f_nit_col(c) = & @@ -1174,8 +1182,8 @@ subroutine Summary(this, bounds, num_soilc, filter_soilc) end do end do - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%denit_col(c) = this%f_denit_col(c) end do @@ -1183,8 +1191,8 @@ subroutine Summary(this, bounds, num_soilc, filter_soilc) ! supplementary N supplement_to_sminn do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%supplement_to_sminn_col(c) = & this%supplement_to_sminn_col(c) + & this%supplement_to_sminn_vr_col(c,j) * dzsoi_decomp(j) @@ -1193,22 +1201,22 @@ subroutine Summary(this, bounds, num_soilc, filter_soilc) ! add up all vertical transport tendency terms and calculate total som leaching loss as the sum of these do l = 1, ndecomp_pools - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%decomp_npools_leached_col(c,l) = 0._r8 end do do j = 1, nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%decomp_npools_leached_col(c,l) = & this%decomp_npools_leached_col(c,l) + & this%decomp_npools_transport_tendency_col(c,j,l) * dzsoi_decomp(j) end do end do - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) this%som_n_leached_col(c) = & this%som_n_leached_col(c) + & this%decomp_npools_leached_col(c,l) diff --git a/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 b/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 index 3e54e52436..ee889503d0 100644 --- a/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 @@ -11,7 +11,7 @@ module SoilBiogeochemNitrogenStateType use clm_varpar , only : ndecomp_cascade_transitions, ndecomp_pools, nlevcan use clm_varpar , only : nlevdecomp_full, nlevdecomp, nlevsoi use clm_varcon , only : spval, dzsoi_decomp, zisoi - use clm_varctl , only : use_nitrif_denitrif + use clm_varctl , only : use_nitrif_denitrif, use_fates_bgc use SoilBiogeochemDecompCascadeConType , only : mimics_decomp, century_decomp, decomp_method, use_soil_matrixcn use clm_varctl , only : iulog, override_bgc_restart_mismatch_dump, spinup_state use landunit_varcon , only : istcrop, istsoil @@ -21,6 +21,7 @@ module SoilBiogeochemNitrogenStateType use GridcellType , only : grc use SoilBiogeochemStateType , only : get_spinup_latitude_term use SparseMatrixMultiplyMod , only : sparse_matrix_type, vector_type + use CNVegNitrogenStateType , only : cnveg_nitrogenstate_type ! ! !PUBLIC TYPES: implicit none @@ -59,7 +60,11 @@ module SoilBiogeochemNitrogenStateType real(r8), pointer :: dyn_no3bal_adjustments_col (:) ! (gN/m2) NO3 adjustments to each column made in this timestep via dynamic column area adjustments (only makes sense at the column-level: meaningless if averaged to the gridcell-level) real(r8), pointer :: dyn_nh4bal_adjustments_col (:) ! (gN/m2) NH4 adjustments to each column made in this timestep via dynamic column adjustments (only makes sense at the column-level: meaningless if averaged to the gridcell-level) real(r8) :: totvegcthresh ! threshold for total vegetation carbon to zero out decomposition pools - + + real(r8), pointer :: totn_col (:) ! (gN/m2) total column nitrogen, incl veg + real(r8), pointer :: totecosysn_col (:) ! (gN/m2) total ecosystem nitrogen, incl veg + real(r8), pointer :: totn_grc (:) ! (gN/m2) total gridcell nitrogen + ! Matrix-cn contains @@ -144,6 +149,10 @@ subroutine InitAllocate(this, bounds) allocate(this%decomp_soiln_vr_col(begc:endc,1:nlevdecomp_full)) this%decomp_soiln_vr_col(:,:)= nan + allocate(this%totn_col (begc:endc)) ; this%totn_col (:) = nan + allocate(this%totecosysn_col (begc:endc)) ; this%totecosysn_col (:) = nan + allocate(this%totn_grc (bounds%begg:bounds%endg)) ; this%totn_grc (:) = nan + end subroutine InitAllocate !------------------------------------------------------------------------ @@ -194,7 +203,7 @@ subroutine InitHistory(this, bounds) do l = 1, ndecomp_pools if ( nlevdecomp_full > 1 ) then data2dptr => this%decomp_npools_vr_col(:,:,l) - fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'N_vr' + fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'_N_vr' longname = trim(decomp_cascade_con%decomp_pool_name_history(l))//' N (vertically resolved)' call hist_addfld2d (fname=fieldname, units='gN/m^3', type2d='levdcmp', & avgflag='A', long_name=longname, & @@ -204,7 +213,7 @@ subroutine InitHistory(this, bounds) endif data1dptr => this%decomp_npools_col(:,l) - fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'N' + fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'_N' longname = trim(decomp_cascade_con%decomp_pool_name_history(l))//' N' call hist_addfld1d (fname=fieldname, units='gN/m^2', & avgflag='A', long_name=longname, & @@ -216,7 +225,7 @@ subroutine InitHistory(this, bounds) if ( nlevdecomp_full > 1 ) then data1dptr => this%decomp_npools_1m_col(:,l) - fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'N_1m' + fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'_N_1m' longname = trim(decomp_cascade_con%decomp_pool_name_history(l))//' N to 1 meter' call hist_addfld1d (fname=fieldname, units='gN/m^2', & avgflag='A', long_name=longname, & @@ -329,6 +338,17 @@ subroutine InitHistory(this, bounds) &only makes sense at the column level: should not be averaged to gridcell', & ptr_col=this%dyn_nh4bal_adjustments_col, default='inactive') end if + + this%totecosysn_col(begc:endc) = spval + call hist_addfld1d (fname='TOTECOSYSN', units='gN/m^2', & + avgflag='A', long_name='total ecosystem N, excluding product pools', & + ptr_col=this%totecosysn_col) + + this%totn_col(begc:endc) = spval + call hist_addfld1d (fname='TOTCOLN', units='gN/m^2', & + avgflag='A', long_name='total column-level N, excluding product pools', & + ptr_col=this%totn_col) + end subroutine InitHistory !----------------------------------------------------------------------- @@ -434,6 +454,21 @@ subroutine InitCold(this, bounds, & end if end do + do c = bounds%begc, bounds%endc + l = col%landunit(c) + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + ! total nitrogen pools + this%totecosysn_col(c) = 0._r8 + this%totn_col(c) = 0._r8 + end if + end do + + + do g = bounds%begg, bounds%endg + this%totn_grc(g) = 0._r8 + end do + + call this%SetValues (num_column=num_special_col, filter_column=special_col, value_column=0._r8) end subroutine InitCold @@ -756,6 +791,12 @@ subroutine SetValues ( this, num_column, filter_column, value_column ) end do end do + do fi = 1,num_column + i = filter_column(fi) + this%totecosysn_col(i) = value_column + this%totn_col(i) = value_column + end do + ! Set values for the matrix solution if(use_soil_matrixcn)then end if @@ -763,18 +804,29 @@ subroutine SetValues ( this, num_column, filter_column, value_column ) end subroutine SetValues !----------------------------------------------------------------------- - subroutine Summary(this, bounds, num_allc, filter_allc) + + subroutine Summary(this, bounds, num_allc, filter_allc, num_bgc_soilc, filter_bgc_soilc, cnveg_nitrogenstate_inst) + ! ! !ARGUMENTS: class (soilbiogeochem_nitrogenstate_type) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_allc ! number of columns in allc filter - integer , intent(in) :: filter_allc(:) ! filter for all active columns + integer , intent(in) :: num_allc ! number of bgc columns in soilc filter + integer , intent(in) :: filter_allc(:) ! filter for bgc columns + integer , intent(in) :: num_bgc_soilc ! number of bgc columns in soilc filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for bgc columns + type(cnveg_nitrogenstate_type) , intent(inout) :: cnveg_nitrogenstate_inst + ! ! !LOCAL VARIABLES: integer :: c,j,k,l ! indices integer :: fc ! lake filter indices + integer :: num_local ! we do summary on different set when fates is + ! active becuase the CN variables aren't allocated + ! this preserves B4B real(r8) :: maxdepth ! depth to integrate soil variables + real(r8) :: totvegn_col ! local total ecosys veg N, allows 0 for fates + real(r8) :: ecovegn_col ! local total veg N, allows 0 for fates !----------------------------------------------------------------------- ! vertically integrate NO3 NH4 N2O pools @@ -952,21 +1004,6 @@ subroutine Summary(this, bounds, num_allc, filter_allc) end if end do - ! total cwdn - do fc = 1,num_allc - c = filter_allc(fc) - this%cwdn_col(c) = 0._r8 - end do - do l = 1, ndecomp_pools - if ( decomp_cascade_con%is_cwd(l) ) then - do fc = 1,num_allc - c = filter_allc(fc) - this%cwdn_col(c) = this%cwdn_col(c) + & - this%decomp_npools_col(c,l) - end do - end if - end do - ! total sminn do fc = 1,num_allc c = filter_allc(fc) @@ -993,6 +1030,61 @@ subroutine Summary(this, bounds, num_allc, filter_allc) end do end do + ! total cwdn + do fc = 1,num_allc + c = filter_allc(fc) + this%cwdn_col(c) = 0._r8 + end do + + if(use_fates_bgc)then + num_local = num_bgc_soilc + else + num_local = num_allc + end if + + do fc = 1,num_local + if(use_fates_bgc) then + c = filter_bgc_soilc(fc) + else + c = filter_allc(fc) + end if + + if(col%is_fates(c)) then + totvegn_col = 0._r8 + ecovegn_col = 0._r8 + else + do l = 1, ndecomp_pools + if ( decomp_cascade_con%is_cwd(l) ) then + this%cwdn_col(c) = this%cwdn_col(c) + & + this%decomp_npools_col(c,l) + end if + end do + totvegn_col = cnveg_nitrogenstate_inst%totn_p2c_col(c) + ecovegn_col = cnveg_nitrogenstate_inst%totvegn_col(c) + end if + + ! total ecosystem nitrogen, including veg (TOTECOSYSN) + this%totecosysn_col(c) = & + this%cwdn_col(c) + & + this%totlitn_col(c) + & + this%totmicn_col(c) + & + this%totsomn_col(c) + & + this%sminn_col(c) + & + ecovegn_col + + ! total column nitrogen, including patch (TOTCOLN) + + this%totn_col(c) = & + this%cwdn_col(c) + & + this%totlitn_col(c) + & + this%totmicn_col(c) + & + this%totsomn_col(c) + & + this%sminn_col(c) + & + this%ntrunc_col(c) + & + totvegn_col + + end do + end subroutine Summary !----------------------------------------------------------------------- diff --git a/src/soilbiogeochem/SoilBiogeochemNitrogenUptakeMod.F90 b/src/soilbiogeochem/SoilBiogeochemNitrogenUptakeMod.F90 index 40c6a0bff9..a566a5882a 100644 --- a/src/soilbiogeochem/SoilBiogeochemNitrogenUptakeMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemNitrogenUptakeMod.F90 @@ -24,7 +24,7 @@ module SoilBiogeochemNitrogenUptakeMod contains !----------------------------------------------------------------------- - subroutine SoilBiogeochemNitrogenUptake(bounds, nlevdecomp, num_soilc, filter_soilc, & + subroutine SoilBiogeochemNitrogenUptake(bounds, nlevdecomp, num_bgc_soilc, filter_bgc_soilc, & sminn_vr, dzsoi_decomp, nfixation_prof, nuptake_prof) ! ! DESCRIPTION @@ -33,8 +33,8 @@ subroutine SoilBiogeochemNitrogenUptake(bounds, nlevdecomp, num_soilc, filter_so ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds integer , intent(in) :: nlevdecomp ! number of vertical layers - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns real(r8) , intent(in) :: sminn_vr(bounds%begc: , 1: ) ! soil mineral nitrogen profile real(r8) , intent(in) :: dzsoi_decomp(1: ) ! layer thickness real(r8) , intent(in) :: nfixation_prof(bounds%begc: , 1: ) ! nitrogen fixation profile @@ -51,21 +51,21 @@ subroutine SoilBiogeochemNitrogenUptake(bounds, nlevdecomp, num_soilc, filter_so SHR_ASSERT_ALL_FL((ubound(nuptake_prof) == (/bounds%endc, nlevdecomp/)) , sourcefile, __LINE__) ! init sminn_tot - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_tot(c) = 0. end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) sminn_tot(c) = sminn_tot(c) + sminn_vr(c,j) * dzsoi_decomp(j) end do end do do j = 1, nlevdecomp - do fc=1,num_soilc - c = filter_soilc(fc) + do fc=1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (sminn_tot(c) > 0.) then nuptake_prof(c,j) = sminn_vr(c,j) / sminn_tot(c) else diff --git a/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 b/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 index da46e178b7..deb9bdbf78 100644 --- a/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 @@ -68,7 +68,7 @@ subroutine readParams ( ncid ) end subroutine readParams !----------------------------------------------------------------------- - subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & + subroutine SoilBiogeochemPotential (bounds, num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_state_inst, soilbiogeochem_carbonstate_inst, soilbiogeochem_carbonflux_inst, & soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst, & cn_decomp_pools, p_decomp_cpool_loss, p_decomp_cn_gain, & @@ -80,8 +80,8 @@ subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & ! ! !ARGUMENT: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns type(soilbiogeochem_state_type) , intent(inout) :: soilbiogeochem_state_inst type(soilbiogeochem_carbonstate_type) , intent(in) :: soilbiogeochem_carbonstate_inst type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst @@ -137,8 +137,8 @@ subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & decomp_k => soilbiogeochem_carbonflux_inst%decomp_k_col , & ! Input: [real(r8) (:,:,:) ] decomposition rate coefficient (1./sec) phr_vr => soilbiogeochem_carbonflux_inst%phr_vr_col & ! Output: [real(r8) (:,:) ] potential HR (gC/m3/s) ) - - if ( .not. use_fates ) then + + ! set initial values for potential C and N fluxes p_decomp_cpool_loss(begc:endc, :, :) = 0._r8 pmnf_decomp_cascade(begc:endc, :, :) = 0._r8 @@ -149,8 +149,8 @@ subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & do l = 1, ndecomp_pools if ( floating_cn_ratio_decomp_pools(l) ) then do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if ( decomp_npools_vr(c,j,l) > 0._r8 ) then cn_decomp_pools(c,j,l) = decomp_cpools_vr(c,j,l) / decomp_npools_vr(c,j,l) end if @@ -158,8 +158,8 @@ subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & end do else do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) cn_decomp_pools(c,j,l) = initial_cn_ratio(l) end do end do @@ -173,8 +173,8 @@ subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & do k = 1, ndecomp_cascade_transitions do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (decomp_cpools_vr(c,j,cascade_donor_pool(k)) > 0._r8 .and. & decomp_k(c,j,cascade_donor_pool(k)) > 0._r8 ) then @@ -236,8 +236,8 @@ subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & ! transitions loop). if (decomp_method == mimics_decomp) then do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ! Sum C & N fluxes from all transitions into m1 & m2 pools. ! Had to form a new loop for the summation due to the order ! necessary, ie do k as the innermost loop. @@ -293,15 +293,15 @@ subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & ! Sum up all the potential immobilization fluxes (positive pmnf flux) ! and all the mineralization fluxes (negative pmnf flux) do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) immob(c,j) = 0._r8 end do end do do k = 1, ndecomp_cascade_transitions do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) if (pmnf_decomp_cascade(c,j,k) > 0._r8) then immob(c,j) = immob(c,j) + pmnf_decomp_cascade(c,j,k) else @@ -315,42 +315,29 @@ subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & end do do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) potential_immob_vr(c,j) = immob(c,j) end do end do - else ! use_fates - ! As a first step we are making this a C-only model, so no N downregulation of fluxes. - do k = 1, ndecomp_cascade_transitions - do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) - ! - p_decomp_cpool_loss(c,j,k) = decomp_cpools_vr(c,j,cascade_donor_pool(k)) & - * decomp_k(c,j,cascade_donor_pool(k)) * pathfrac_decomp_cascade(c,j,k) - ! - end do - end do - end do - end if ! Add up potential hr for methane calculations do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) phr_vr(c,j) = 0._r8 end do end do do k = 1, ndecomp_cascade_transitions do j = 1,nlevdecomp - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) phr_vr(c,j) = phr_vr(c,j) + rf_decomp_cascade(c,j,k) * p_decomp_cpool_loss(c,j,k) end do end do end do + end associate end subroutine SoilBiogeochemPotential diff --git a/src/soilbiogeochem/SoilBiogeochemPrecisionControlMod.F90 b/src/soilbiogeochem/SoilBiogeochemPrecisionControlMod.F90 index 3740700ab1..cc349ad8bc 100644 --- a/src/soilbiogeochem/SoilBiogeochemPrecisionControlMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemPrecisionControlMod.F90 @@ -60,7 +60,7 @@ subroutine SoilBiogeochemPrecisionControlInit( soilbiogeochem_carbonstate_inst, end subroutine SoilBiogeochemPrecisionControlInit !----------------------------------------------------------------------- - subroutine SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & + subroutine SoilBiogeochemPrecisionControl(num_bgc_soilc, filter_bgc_soilc, & soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonstate_inst, soilbiogeochem_nitrogenstate_inst) @@ -70,13 +70,13 @@ subroutine SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & ! they get too small. ! ! !USES: - use clm_varctl , only : iulog, use_c13, use_c14, use_nitrif_denitrif, use_cn + use clm_varctl , only : iulog, use_c13, use_c14, use_nitrif_denitrif use clm_varpar , only : nlevdecomp use CNSharedParamsMod, only: use_fun ! ! !ARGUMENTS: - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_soilc ! number of bgc soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for bgc soil columns type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst type(soilbiogeochem_carbonstate_type) , intent(inout) :: c13_soilbiogeochem_carbonstate_inst type(soilbiogeochem_carbonstate_type) , intent(inout) :: c14_soilbiogeochem_carbonstate_inst @@ -106,8 +106,8 @@ subroutine SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & ) ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) do j = 1,nlevdecomp ! initialize the column-level C and N truncation terms @@ -125,13 +125,12 @@ subroutine SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & do k = 1, ndecomp_pools if (abs(cs%decomp_cpools_vr_col(c,j,k)) < ccrit) then + cc = cc + cs%decomp_cpools_vr_col(c,j,k) cs%decomp_cpools_vr_col(c,j,k) = 0._r8 - if (use_cn) then - cn = cn + ns%decomp_npools_vr_col(c,j,k) - ns%decomp_npools_vr_col(c,j,k) = 0._r8 - endif + cn = cn + ns%decomp_npools_vr_col(c,j,k) + ns%decomp_npools_vr_col(c,j,k) = 0._r8 if ( use_c13 ) then cc13 = cc13 + c13cs%decomp_cpools_vr_col(c,j,k) @@ -150,9 +149,8 @@ subroutine SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & cs%ctrunc_vr_col(c,j) = cs%ctrunc_vr_col(c,j) + cc - if (use_cn) then - ns%ntrunc_vr_col(c,j) = ns%ntrunc_vr_col(c,j) + cn - endif + ns%ntrunc_vr_col(c,j) = ns%ntrunc_vr_col(c,j) + cn + if ( use_c13 ) then c13cs%ctrunc_vr_col(c,j) = c13cs%ctrunc_vr_col(c,j) + cc13 endif @@ -167,8 +165,8 @@ subroutine SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & if (use_nitrif_denitrif) then ! remove small negative perturbations for stability purposes, if any should arise. - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) do j = 1,nlevdecomp if (abs(ns%smin_no3_vr_col(c,j)) < ncrit/1e4_r8) then if ( ns%smin_no3_vr_col(c,j) < 0._r8 ) then diff --git a/src/soilbiogeochem/SoilBiogeochemStateType.F90 b/src/soilbiogeochem/SoilBiogeochemStateType.F90 index fcdced386d..69055aec9b 100644 --- a/src/soilbiogeochem/SoilBiogeochemStateType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemStateType.F90 @@ -11,7 +11,7 @@ module SoilBiogeochemStateType use clm_varcon , only : spval, ispval, c14ratio, grlnd use landunit_varcon, only : istsoil, istcrop use clm_varpar , only : nlevsno, nlevgrnd, nlevlak - use clm_varctl , only : use_cn + use clm_varctl , only : use_cn, use_fates_bgc use clm_varctl , only : iulog use LandunitType , only : lun use ColumnType , only : col @@ -60,7 +60,7 @@ subroutine Init(this, bounds) type(bounds_type), intent(in) :: bounds call this%InitAllocate ( bounds ) - if (use_cn) then + if (use_cn .or. use_fates_bgc) then call this%InitHistory ( bounds ) end if call this%InitCold ( bounds ) @@ -103,7 +103,7 @@ subroutine InitAllocate(this, bounds) allocate(this%nue_decomp_cascade_col(1:ndecomp_cascade_transitions)); this%nue_decomp_cascade_col(:) = nan - + end subroutine InitAllocate !------------------------------------------------------------------------ @@ -132,26 +132,30 @@ subroutine InitHistory(this, bounds) begp = bounds%begp; endp= bounds%endp begc = bounds%begc; endc= bounds%endc - this%croot_prof_patch(begp:endp,:) = spval - call hist_addfld_decomp (fname='CROOT_PROF', units='1/m', type2d='levdcmp', & - avgflag='A', long_name='profile for litter C and N inputs from coarse roots', & - ptr_patch=this%croot_prof_patch, default='inactive') - - this%froot_prof_patch(begp:endp,:) = spval - call hist_addfld_decomp (fname='FROOT_PROF', units='1/m', type2d='levdcmp', & - avgflag='A', long_name='profile for litter C and N inputs from fine roots', & - ptr_patch=this%froot_prof_patch, default='inactive') - - this%leaf_prof_patch(begp:endp,:) = spval - call hist_addfld_decomp (fname='LEAF_PROF', units='1/m', type2d='levdcmp', & - avgflag='A', long_name='profile for litter C and N inputs from leaves', & - ptr_patch=this%leaf_prof_patch, default='inactive') - - this%stem_prof_patch(begp:endp,:) = spval - call hist_addfld_decomp (fname='STEM_PROF', units='1/m', type2d='levdcmp', & - avgflag='A', long_name='profile for litter C and N inputs from stems', & - ptr_patch=this%stem_prof_patch, default='inactive') - + if_usecn: if(use_cn) then + this%croot_prof_patch(begp:endp,:) = spval + call hist_addfld_decomp (fname='CROOT_PROF', units='1/m', type2d='levdcmp', & + avgflag='A', long_name='profile for litter C and N inputs from coarse roots', & + ptr_patch=this%croot_prof_patch, default='inactive') + + this%froot_prof_patch(begp:endp,:) = spval + call hist_addfld_decomp (fname='FROOT_PROF', units='1/m', type2d='levdcmp', & + avgflag='A', long_name='profile for litter C and N inputs from fine roots', & + ptr_patch=this%froot_prof_patch, default='inactive') + + this%leaf_prof_patch(begp:endp,:) = spval + call hist_addfld_decomp (fname='LEAF_PROF', units='1/m', type2d='levdcmp', & + avgflag='A', long_name='profile for litter C and N inputs from leaves', & + ptr_patch=this%leaf_prof_patch, default='inactive') + + this%stem_prof_patch(begp:endp,:) = spval + call hist_addfld_decomp (fname='STEM_PROF', units='1/m', type2d='levdcmp', & + avgflag='A', long_name='profile for litter C and N inputs from stems', & + ptr_patch=this%stem_prof_patch, default='inactive') + end if if_usecn + + ! These output variables are valid for both use_cn AND use_fates_bgc + this%nfixation_prof_col(begc:endc,:) = spval call hist_addfld_decomp (fname='NFIXATION_PROF', units='1/m', type2d='levdcmp', & avgflag='A', long_name='profile for biological N fixation', & @@ -161,7 +165,7 @@ subroutine InitHistory(this, bounds) call hist_addfld_decomp (fname='NDEP_PROF', units='1/m', type2d='levdcmp', & avgflag='A', long_name='profile for atmospheric N deposition', & ptr_col=this%ndep_prof_col, default='inactive') - + this%som_adv_coef_col(begc:endc,:) = spval call hist_addfld_decomp (fname='SOM_ADV_COEF', units='m/s', type2d='levdcmp', & avgflag='A', long_name='advection term for vertical SOM translocation', & diff --git a/src/soilbiogeochem/SoilBiogeochemVerticalProfileMod.F90 b/src/soilbiogeochem/SoilBiogeochemVerticalProfileMod.F90 index 7209bd8278..376f18742b 100644 --- a/src/soilbiogeochem/SoilBiogeochemVerticalProfileMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemVerticalProfileMod.F90 @@ -24,7 +24,7 @@ module SoilBiogeochemVerticalProfileMod contains !----------------------------------------------------------------------- - subroutine SoilBiogeochemVerticalProfile(bounds, num_soilc,filter_soilc,num_soilp,filter_soilp, & + subroutine SoilBiogeochemVerticalProfile(bounds, num_bgc_soilc,filter_bgc_soilc,num_bgc_vegp,filter_bgc_vegp, & active_layer_inst, soilstate_inst, soilbiogeochem_state_inst) ! ! !DESCRIPTION: @@ -57,10 +57,10 @@ subroutine SoilBiogeochemVerticalProfile(bounds, num_soilc,filter_soilc,num_soil ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches + integer , intent(in) :: num_bgc_soilc ! number of soil columns in filter + integer , intent(in) :: filter_bgc_soilc(:) ! filter for soil columns + integer , intent(in) :: num_bgc_vegp ! number of soil patches in filter + integer , intent(in) :: filter_bgc_vegp(:) ! filter for soil patches type(active_layer_type) , intent(in) :: active_layer_inst type(soilstate_type) , intent(in) :: soilstate_inst type(soilbiogeochem_state_type) , intent(inout) :: soilbiogeochem_state_inst @@ -71,7 +71,7 @@ subroutine SoilBiogeochemVerticalProfile(bounds, num_soilc,filter_soilc,num_soil real(r8) :: rootfr_tot real(r8) :: cinput_rootfr(bounds%begp:bounds%endp, 1:nlevdecomp_full) ! pft-native root fraction used for calculating inputs real(r8) :: col_cinput_rootfr(bounds%begc:bounds%endc, 1:nlevdecomp_full) ! col-native root fraction used for calculating inputs - integer :: c, j, fc, p, fp, pi + integer :: c, j, fc, p, fp integer :: alt_ind ! debugging temp variables real(r8) :: froot_prof_sum @@ -124,21 +124,20 @@ subroutine SoilBiogeochemVerticalProfile(bounds, num_soilc,filter_soilc,num_soil cinput_rootfr(begp:endp, :) = 0._r8 col_cinput_rootfr(begc:endc, :) = 0._r8 - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) c = patch%column(p) if (patch%itype(p) /= noveg) then do j = 1, nlevdecomp cinput_rootfr(p,j) = crootfr(p,j) / dzsoi_decomp(j) end do - else cinput_rootfr(p,1) = 0. endif end do - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) c = patch%column(p) ! integrate rootfr over active layer of soil column rootfr_tot = 0._r8 @@ -168,7 +167,6 @@ subroutine SoilBiogeochemVerticalProfile(bounds, num_soilc,filter_soilc,num_soil leaf_prof(p,1) = 1./dzsoi_decomp(1) stem_prof(p,1) = 1./dzsoi_decomp(1) endif - end do !! aggregate root profile to column @@ -176,42 +174,57 @@ subroutine SoilBiogeochemVerticalProfile(bounds, num_soilc,filter_soilc,num_soil ! cinput_rootfr(bounds%begp:bounds%endp, :), & ! col_cinput_rootfr(bounds%begc:bounds%endc, :), & ! 'unity') - do pi = 1,maxsoil_patches - do fc = 1,num_soilc - c = filter_soilc(fc) - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - do j = 1,nlevdecomp - col_cinput_rootfr(c,j) = col_cinput_rootfr(c,j) + cinput_rootfr(p,j) * patch%wtcol(p) - end do - end if + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) + c = patch%column(p) + do j = 1,nlevdecomp + col_cinput_rootfr(c,j) = col_cinput_rootfr(c,j) + cinput_rootfr(p,j) * patch%wtcol(p) end do end do + ! repeat for column-native profiles: Ndep and Nfix - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) rootfr_tot = 0._r8 surface_prof_tot = 0._r8 - ! redo column ntegration over active layer for column-native profiles - do j = 1, min(max(altmax_lastyear_indx(c), 1), nlevdecomp) - rootfr_tot = rootfr_tot + col_cinput_rootfr(c,j) * dzsoi_decomp(j) - surface_prof_tot = surface_prof_tot + surface_prof(j) * dzsoi_decomp(j) - end do - if ( (altmax_lastyear_indx(c) > 0) .and. (rootfr_tot > 0._r8) .and. (surface_prof_tot > 0._r8) ) then - do j = 1, min(max(altmax_lastyear_indx(c), 1), nlevdecomp) - nfixation_prof(c,j) = col_cinput_rootfr(c,j) / rootfr_tot - ndep_prof(c,j) = surface_prof(j)/ surface_prof_tot + if_fates: if(col%is_fates(c))then + ! For FATES, we just use the e-folding depth for both fixation and deposition + ! partially because the fixation may be free-living depending on FATES-side + ! fixation choices, and partially for simplicity + do j = 1, min(max(altmax_lastyear_indx(c), 1), nlevdecomp) + surface_prof_tot = surface_prof_tot + surface_prof(j) * dzsoi_decomp(j) end do + if ( (altmax_lastyear_indx(c) > 0) .and. (surface_prof_tot > 0._r8) ) then + do j = 1, min(max(altmax_lastyear_indx(c), 1), nlevdecomp) + nfixation_prof(c,j) = surface_prof(j)/ surface_prof_tot + ndep_prof(c,j) = surface_prof(j)/ surface_prof_tot + end do + else + nfixation_prof(c,1) = 1./dzsoi_decomp(1) + ndep_prof(c,1) = 1./dzsoi_decomp(1) + endif else - nfixation_prof(c,1) = 1./dzsoi_decomp(1) - ndep_prof(c,1) = 1./dzsoi_decomp(1) - endif + ! redo column ntegration over active layer for column-native profiles + do j = 1, min(max(altmax_lastyear_indx(c), 1), nlevdecomp) + rootfr_tot = rootfr_tot + col_cinput_rootfr(c,j) * dzsoi_decomp(j) + surface_prof_tot = surface_prof_tot + surface_prof(j) * dzsoi_decomp(j) + end do + if ( (altmax_lastyear_indx(c) > 0) .and. (rootfr_tot > 0._r8) .and. (surface_prof_tot > 0._r8) ) then + do j = 1, min(max(altmax_lastyear_indx(c), 1), nlevdecomp) + nfixation_prof(c,j) = col_cinput_rootfr(c,j) / rootfr_tot + ndep_prof(c,j) = surface_prof(j)/ surface_prof_tot + end do + else + nfixation_prof(c,1) = 1./dzsoi_decomp(1) + ndep_prof(c,1) = 1./dzsoi_decomp(1) + endif + end if if_fates end do ! check to make sure integral of all profiles = 1. - do fc = 1,num_soilc - c = filter_soilc(fc) + do fc = 1,num_bgc_soilc + c = filter_bgc_soilc(fc) ndep_prof_sum = 0. nfixation_prof_sum = 0. do j = 1, nlevdecomp @@ -237,8 +250,8 @@ subroutine SoilBiogeochemVerticalProfile(bounds, num_soilc,filter_soilc,num_soil endif end do - do fp = 1,num_soilp - p = filter_soilp(fp) + do fp = 1,num_bgc_vegp + p = filter_bgc_vegp(fp) froot_prof_sum = 0. croot_prof_sum = 0. leaf_prof_sum = 0. diff --git a/src/unit_test_shr/unittestWaterTypeFactory.F90 b/src/unit_test_shr/unittestWaterTypeFactory.F90 index cc3510e881..f5f417f9ce 100644 --- a/src/unit_test_shr/unittestWaterTypeFactory.F90 +++ b/src/unit_test_shr/unittestWaterTypeFactory.F90 @@ -161,7 +161,8 @@ subroutine create_water_type(this, water_inst, & h2osno_col = col_array(0._r8), & snow_depth_col = col_array(0._r8), & watsat_col = l_watsat_col, & - t_soisno_col = l_t_soisno_col) + t_soisno_col = l_t_soisno_col, & + NLFilename = ' ') end subroutine create_water_type subroutine teardown(this, water_inst) diff --git a/src/unit_test_stubs/CMakeLists.txt b/src/unit_test_stubs/CMakeLists.txt index 38abfb1633..2d7fe23378 100644 --- a/src/unit_test_stubs/CMakeLists.txt +++ b/src/unit_test_stubs/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(csm_share) add_subdirectory(dyn_subgrid) add_subdirectory(main) +add_subdirectory(share_esmf) add_subdirectory(utils) sourcelist_to_parent(clm_sources) diff --git a/src/unit_test_stubs/share_esmf/CMakeLists.txt b/src/unit_test_stubs/share_esmf/CMakeLists.txt new file mode 100644 index 0000000000..5eb2d42415 --- /dev/null +++ b/src/unit_test_stubs/share_esmf/CMakeLists.txt @@ -0,0 +1,5 @@ +list(APPEND clm_sources + ExcessIceStreamType.F90 + ) + +sourcelist_to_parent(clm_sources) diff --git a/src/unit_test_stubs/share_esmf/ExcessIceStreamType.F90 b/src/unit_test_stubs/share_esmf/ExcessIceStreamType.F90 new file mode 100644 index 0000000000..60bac5ad28 --- /dev/null +++ b/src/unit_test_stubs/share_esmf/ExcessIceStreamType.F90 @@ -0,0 +1,79 @@ +module ExcessIceStreamType + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Stub module for Excess ice streams + ! + ! !USES + use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_cl + use shr_log_mod , only : errMsg => shr_log_errMsg + use abortutils , only : endrun + use decompMod , only : bounds_type + + ! !PUBLIC TYPES: + implicit none + private + + public :: UseExcessIceStreams ! If streams will be used + + type, public :: excessicestream_type + contains + + ! !PUBLIC MEMBER FUNCTIONS: + procedure, public :: Init ! Initialize and read data in + procedure, public :: CalcExcessIce ! Calculate excess ice ammount + end type excessicestream_type + ! ! PRIVATE DATA: + + logical :: namelist_read = .false. + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + +!============================================================================== +contains +!============================================================================== + + subroutine Init(this, bounds, NLFilename) + ! + ! arguments + implicit none + class(excessicestream_type) :: this + type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: NLFilename ! Namelist filename + + namelist_read = .true. + + end subroutine Init + + subroutine CalcExcessIce(this,bounds,exice_bulk_init) + + ! only transfers grid values to columns + implicit none + class(excessicestream_type) :: this + type(bounds_type), intent(in) :: bounds + real(r8) , intent(inout) :: exice_bulk_init(bounds%begc:bounds%endc) + ! + ! !LOCAL VARIABLES: + call endrun(msg=' ERROR CalcExcessIce stub is being called and should NOT be'//errMsg(sourcefile, __LINE__)) + + end subroutine CalcExcessIce + + logical function UseExcessIceStreams() + ! + ! !DESCRIPTION: + ! Return true if + ! + ! !USES: + ! + ! !ARGUMENTS: + implicit none + ! + ! !LOCAL VARIABLES: + if ( .not. namelist_read ) then + call endrun(msg=' ERROR UseExcessIceStreams being called, but namelist has not been read yet'//errMsg(sourcefile, __LINE__)) + end if + UseExcessIceStreams = .false. +end function UseExcessIceStreams + +end module ExcessIceStreamType diff --git a/src/unit_test_stubs/utils/restUtilMod_stub.F90.in b/src/unit_test_stubs/utils/restUtilMod_stub.F90.in index b6e3ba4f19..135c977bf6 100644 --- a/src/unit_test_stubs/utils/restUtilMod_stub.F90.in +++ b/src/unit_test_stubs/utils/restUtilMod_stub.F90.in @@ -21,8 +21,12 @@ module restUtilMod public :: restartvar + public :: RestartExcessIceIssue + public :: set_missing_from_template + public :: CallRestartvarDimOK + contains !----------------------------------------------------------------------- @@ -149,4 +153,57 @@ contains end subroutine set_missing_from_template + !----------------------------------------------------------------------- + subroutine RestartExcessIceIssue(ncid, flag, excess_ice_on_restart) + ! + ! !DESCRIPTION: + ! + ! !USES: + ! + ! !ARGUMENTS: + type(file_desc_t), intent(inout) :: ncid ! netcdf id + character(len=*) , intent(in) :: flag ! 'read' or 'write' + logical, intent(out) :: excess_ice_on_restart ! If excess ice is on the restart file + ! + ! !LOCAL VARIABLES: + integer :: attribute_value + + character(len=*), parameter :: subname = 'RestartExcessIceIssue' + !----------------------------------------------------------------------- + + excess_ice_on_restart = .false. + + end subroutine RestartExcessIceIssue + + + !----------------------------------------------------------------------- + logical function CallRestartvarDimOK (ncid, flag, dimname) + ! + ! !DESCRIPTION: + ! Answer whether to call restartvar(), if necessary checking whether + ! a dimension exists in the restart file + ! + ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2022-02-02) + ! Used in Restart(). Even though restartvar() can safely be called for a + ! non-existent variable, it gives an error for a non-existent dimension, so + ! check whether the dimension exists before trying to read. The need for this + ! function arose because we recently added the mxsowings and mxharvests + ! dimensions to the restart file. + ! + ! !USES: + use ncdio_pio + ! + ! !ARGUMENTS: + type(file_desc_t), intent(inout) :: ncid + character(len=*) , intent(in) :: flag + character(len=*) , intent(in) :: dimname + ! + ! !LOCAL VARIABLES: + !----------------------------------------------------------------------- + + CallRestartvarDimOK = .false. + + end function CallRestartvarDimOK + + end module restUtilMod diff --git a/src/utils/clm_time_manager.F90 b/src/utils/clm_time_manager.F90 index b8d9930b24..5c65f5decd 100644 --- a/src/utils/clm_time_manager.F90 +++ b/src/utils/clm_time_manager.F90 @@ -59,6 +59,8 @@ module clm_time_manager is_beg_curr_year, &! return true on first timestep in current year is_end_curr_year, &! return true on last timestep in current year is_perpetual, &! return true if perpetual calendar is in use + is_doy_in_interval, &! return true if day of year is in the provided interval + is_today_in_doy_interval, &! return true if today's day of year is in the provided interval is_near_local_noon, &! return true if near local noon is_restart, &! return true if this is a restart run update_rad_dtime, &! track radiation interval via nstep @@ -1759,6 +1761,58 @@ end function is_perpetual !========================================================================================= + logical function is_doy_in_interval(start, end, doy) + + ! Return true if day of year is in the provided interval. + ! Does not treat leap years differently from normal years. + ! Arguments + integer, intent(in) :: start ! start of interval (day of year) + integer, intent(in) :: end ! end of interval (day of year) + integer, intent(in) :: doy ! day of year to query + + ! Local variables + logical :: window_crosses_newyear + + character(len=*), parameter :: sub = 'clm::is_doy_in_interval' + + window_crosses_newyear = end < start + + if (window_crosses_newyear .and. & + (doy >= start .or. doy <= end)) then + is_doy_in_interval = .true. + else if (.not. window_crosses_newyear .and. & + (doy >= start .and. doy <= end)) then + is_doy_in_interval = .true. + else + is_doy_in_interval = .false. + end if + + end function is_doy_in_interval + + !========================================================================================= + + logical function is_today_in_doy_interval(start, end) + + ! Return true if today's day of year is in the provided interval. + ! Does not treat leap years differently from normal years. + ! Arguments + integer, intent(in) :: start ! start of interval (day of year) + integer, intent(in) :: end ! end of interval (day of year) + + ! Local variable(s) + integer :: doy_today + + character(len=*), parameter :: sub = 'clm::is_today_in_doy_interval' + + ! Get doy of beginning of current timestep + doy_today = get_prev_calday() + + is_today_in_doy_interval = is_doy_in_interval(start, end, doy_today) + + end function is_today_in_doy_interval + + !========================================================================================= + subroutine timemgr_datediff(ymd1, tod1, ymd2, tod2, days) ! Calculate the difference (ymd2,tod2) - (ymd1,tod1) and return the result in days. diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index b785cdcf46..e33bcd9f83 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -48,6 +48,7 @@ module CLMFatesInterfaceMod use CNProductsMod , only : cn_products_type use clm_varctl , only : iulog use clm_varctl , only : fates_parteh_mode + use PRTGenericMod , only : prt_cnp_flex_allom_hyp use clm_varctl , only : use_fates use clm_varctl , only : fates_spitfire_mode use clm_varctl , only : use_fates_tree_damage @@ -67,6 +68,7 @@ module CLMFatesInterfaceMod use clm_varcon , only : spval use clm_varcon , only : denice use clm_varcon , only : ispval + use clm_varcon , only : sum_to_1_tol use clm_varpar , only : surfpft_lb,surfpft_ub use clm_varpar , only : numrad use clm_varpar , only : ivis @@ -80,6 +82,8 @@ module CLMFatesInterfaceMod use SolarAbsorbedType , only : solarabs_type use SoilBiogeochemCarbonFluxType, only : soilbiogeochem_carbonflux_type use SoilBiogeochemCarbonStateType, only : soilbiogeochem_carbonstate_type + use SoilBiogeochemNitrogenFluxType, only : soilbiogeochem_nitrogenflux_type + use SoilBiogeochemNitrogenStateType, only : soilbiogeochem_nitrogenstate_type use FrictionVelocityMod , only : frictionvel_type use clm_time_manager , only : is_restart, is_first_restart_step use ncdio_pio , only : file_desc_t, ncd_int, ncd_double @@ -126,7 +130,7 @@ module CLMFatesInterfaceMod use FatesHistoryInterfaceMod, only : fates_hist use FatesRestartInterfaceMod, only : fates_restart_interface_type - use EDTypesMod , only : ed_patch_type + use FatesPatchMod , only : fates_patch_type use PRTGenericMod , only : num_elements use FatesInterfaceTypesMod, only : hlm_stepsize use FatesInterfaceTypesMod, only : fates_maxPatchesPerSite @@ -225,7 +229,8 @@ module CLMFatesInterfaceMod procedure, public :: wrap_hydraulics_drive procedure, public :: WrapUpdateFatesRmean procedure, public :: wrap_WoodProducts - + procedure, public :: UpdateCLitterFluxes + procedure, public :: UPdateNLitterFluxes end type hlm_fates_interface_type ! hlm_bounds_to_fates_bounds is not currently called outside the interface. @@ -563,8 +568,6 @@ subroutine init(this, bounds_proc ) use clm_instur , only : wt_nat_patch use FATESFireFactoryMod , only: create_fates_fire_data_method - implicit none - ! Input Arguments class(hlm_fates_interface_type), intent(inout) :: this type(bounds_type),intent(in) :: bounds_proc @@ -713,10 +716,10 @@ subroutine init(this, bounds_proc ) this%fates(nc)%bc_in(s)%pft_areafrac(ft)=wt_nat_patch(g,m) end do - if(abs(sum(this%fates(nc)%bc_in(s)%pft_areafrac(surfpft_lb:surfpft_ub))-1.0_r8).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 + if (abs(sum(this%fates(nc)%bc_in(s)%pft_areafrac(surfpft_lb:surfpft_ub)) - 1.0_r8) > sum_to_1_tol) then + write(iulog,*) 'pft_area error in interfc ', s, sum(this%fates(nc)%bc_in(s)%pft_areafrac(:)) - 1.0_r8 call endrun(msg=errMsg(sourcefile, __LINE__)) - endif + end if end do !site ! Initialize site-level static quantities dictated by the HLM @@ -771,7 +774,6 @@ subroutine check_hlm_active(this, nc, bounds_clump) ! in handy when we have dynamic sites in FATES ! --------------------------------------------------------------------------------- - implicit none class(hlm_fates_interface_type), intent(inout) :: this integer :: nc type(bounds_type),intent(in) :: bounds_clump @@ -822,7 +824,7 @@ subroutine dynamics_driv(this, nc, bounds_clump, & use subgridMod, only : natveg_patch_exists ! !ARGUMENTS: - implicit none + class(hlm_fates_interface_type), intent(inout) :: this type(bounds_type),intent(in) :: bounds_clump type(atm2lnd_type) , intent(in) :: atm2lnd_inst @@ -1053,46 +1055,8 @@ subroutine dynamics_driv(this, nc, bounds_clump, & call ed_update_site(this%fates(nc)%sites(s), & this%fates(nc)%bc_in(s), & this%fates(nc)%bc_out(s)) - enddo - ! --------------------------------------------------------------------------------- - ! Part III: Process FATES output into the dimensions and structures that are part - ! of the HLMs API. (column, depth, and litter fractions) - ! --------------------------------------------------------------------------------- - - if ( decomp_method /= no_soil_decomp )then - do s = 1, this%fates(nc)%nsites - c = this%f2hmap(nc)%fcolumn(s) - - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_lab_c_col(c,1:nlevdecomp) = 0.0_r8 - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_cel_c_col(c,1:nlevdecomp) = 0.0_r8 - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_lig_c_col(c,1:nlevdecomp) = 0.0_r8 - - nld_si = this%fates(nc)%bc_in(s)%nlevdecomp - - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_lab_c_col(c,1:nld_si) = & - this%fates(nc)%bc_out(s)%litt_flux_lab_c_si(1:nld_si) - - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_cel_c_col(c,1:nld_si) = & - this%fates(nc)%bc_out(s)%litt_flux_cel_c_si(1:nld_si) - - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_lig_c_col(c,1:nld_si) = & - this%fates(nc)%bc_out(s)%litt_flux_lig_c_si(1:nld_si) - - ! Copy last 3 variables to an array of litter pools for use in do loops - ! and repeat copy in soilbiogeochem/SoilBiogeochemCarbonFluxType.F90. - ! Keep the three originals to avoid backwards compatibility issues with - ! restart files. - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_c_col(c,1:nld_si,1) = & - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_lab_c_col(c,1:nld_si) - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_c_col(c,1:nld_si,2) = & - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_cel_c_col(c,1:nld_si) - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_c_col(c,1:nld_si,3) = & - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_lig_c_col(c,1:nld_si) - - end do - end if ! --------------------------------------------------------------------------------- @@ -1125,8 +1089,159 @@ subroutine dynamics_driv(this, nc, bounds_clump, & return end subroutine dynamics_driv - ! ------------------------------------------------------------------------------------ + ! =============================================================================== + + subroutine UpdateNLitterFluxes(this,soilbiogeochem_nitrogenflux_inst,ci,c) + + use clm_varpar, only : i_met_lit + + class(hlm_fates_interface_type), intent(inout) :: this + type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst + integer , intent(in) :: ci ! clump index + integer , intent(in) :: c ! column index + + integer :: s ! site index + real(r8) :: dtime + integer :: i_lig_lit, i_cel_lit ! indices for lignan and cellulose + + dtime = get_step_size_real() + s = this%f2hmap(ci)%hsites(c) + + associate(nf_soil => soilbiogeochem_nitrogenflux_inst) + + nf_soil%decomp_npools_sourcesink_col(c,:,:) = 0._r8 + + if ( .not. use_fates_sp ) then + + ! (gC/m3/timestep) + !nf_soil%decomp_npools_sourcesink_col(c,1:nlevdecomp,i_met_lit) = & + ! nf_soil%decomp_npools_sourcesink_col(c,1:nlevdecomp,i_met_lit) + & + ! this%fates(ci)%bc_out(s)%litt_flux_lab_n_si(1:nlevdecomp)*dtime + + ! Used for mass balance checking (gC/m2/s) + !nf_soil%fates_litter_flux(c) = sum(this%fates(ci)%bc_out(s)%litt_flux_lab_n_si(1:nlevdecomp) * & + ! this%fates(ci)%bc_in(s)%dz_decomp_sisl(1:nlevdecomp)) + + i_cel_lit = i_met_lit + 1 + + !nf_soil%decomp_npools_sourcesink_col(c,1:nlevdecomp,i_cel_lit) = & + ! nf_soil%decomp_npools_sourcesink_col(c,1:nlevdecomp,i_cel_lit) + & + ! this%fates(ci)%bc_out(s)%litt_flux_cel_n_si(1:nlevdecomp)*dtime + + !nf_soil%fates_litter_flux(c) = nf_soil%fates_litter_flux(c) + & + ! sum(this%fates(ci)%bc_out(s)%litt_flux_cel_n_si(1:nlevdecomp) * & + ! this%fates(ci)%bc_in(s)%dz_decomp_sisl(1:nlevdecomp)) + + if (decomp_method == mimics_decomp) then + ! Mimics has a structural pool, which is cellulose and lignan + i_lig_lit = i_cel_lit + elseif(decomp_method == century_decomp ) then + ! CENTURY has a separate lignan pool from cellulose + i_lig_lit = i_cel_lit + 1 + end if + + !nf_soil%decomp_npools_sourcesink_col(c,1:nlevdecomp,i_lig_lit) = & + ! nf_soil%decomp_npools_sourcesink_col(c,1:nlevdecomp,i_lig_lit) + & + ! this%fates(ci)%bc_out(s)%litt_flux_lig_n_si(1:nlevdecomp)*dtime + + !nf_soil%fates_litter_flux(c) = nf_soil%fates_litter_flux(c) + & + ! sum(this%fates(ci)%bc_out(s)%litt_flux_lig_n_si(1:nlevdecomp) * & + ! this%fates(ci)%bc_in(s)%dz_decomp_sisl(1:nlevdecomp)) + + nf_soil%fates_litter_flux = 0._r8 + + else + + ! In SP mode their is no mass flux between the two + nf_soil%fates_litter_flux = 0._r8 + + end if + + end associate + + return + end subroutine UpdateNLitterFluxes + + ! =========================================================== + + subroutine UpdateCLitterFluxes(this,soilbiogeochem_carbonflux_inst,ci,c) + + use clm_varpar, only : i_met_lit + + class(hlm_fates_interface_type), intent(inout) :: this + type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst + integer , intent(in) :: ci ! clump index + integer , intent(in) :: c ! column index + + integer :: s ! site index + real(r8) :: dtime + integer :: i_lig_lit, i_cel_lit ! indices for lignan and cellulose + + dtime = get_step_size_real() + s = this%f2hmap(ci)%hsites(c) + + associate(cf_soil => soilbiogeochem_carbonflux_inst) + + ! This is zeroed in CNDriverNoLeaching -> soilbiogeochem_carbonflux_inst%SetValues() + ! Which is called prior to this call, which is later in the CNDriverNoLeaching() + ! routine. + ! cf_soil%decomp_cpools_sourcesink_col(c,:,:) = 0._r8 + + if ( .not. use_fates_sp ) then + + + call FluxIntoLitterPools(this%fates(ci)%sites(s), & + this%fates(ci)%bc_in(s), & + this%fates(ci)%bc_out(s)) + + ! (gC/m3/timestep) + cf_soil%decomp_cpools_sourcesink_col(c,1:nlevdecomp,i_met_lit) = & + cf_soil%decomp_cpools_sourcesink_col(c,1:nlevdecomp,i_met_lit) + & + this%fates(ci)%bc_out(s)%litt_flux_lab_c_si(1:nlevdecomp)*dtime + + ! Used for mass balance checking (gC/m2/s) + cf_soil%fates_litter_flux(c) = sum(this%fates(ci)%bc_out(s)%litt_flux_lab_c_si(1:nlevdecomp) * & + this%fates(ci)%bc_in(s)%dz_decomp_sisl(1:nlevdecomp)) + + i_cel_lit = i_met_lit + 1 + + cf_soil%decomp_cpools_sourcesink_col(c,1:nlevdecomp,i_cel_lit) = & + cf_soil%decomp_cpools_sourcesink_col(c,1:nlevdecomp,i_cel_lit) + & + this%fates(ci)%bc_out(s)%litt_flux_cel_c_si(1:nlevdecomp)*dtime + + cf_soil%fates_litter_flux(c) = cf_soil%fates_litter_flux(c) + & + sum(this%fates(ci)%bc_out(s)%litt_flux_cel_c_si(1:nlevdecomp) * & + this%fates(ci)%bc_in(s)%dz_decomp_sisl(1:nlevdecomp)) + + if (decomp_method == mimics_decomp) then + ! Mimics has a structural pool, which is cellulose and lignan + i_lig_lit = i_cel_lit + elseif(decomp_method == century_decomp ) then + ! CENTURY has a separate lignan pool from cellulose + i_lig_lit = i_cel_lit + 1 + end if + + cf_soil%decomp_cpools_sourcesink_col(c,1:nlevdecomp,i_lig_lit) = & + cf_soil%decomp_cpools_sourcesink_col(c,1:nlevdecomp,i_lig_lit) + & + this%fates(ci)%bc_out(s)%litt_flux_lig_c_si(1:nlevdecomp)*dtime + + cf_soil%fates_litter_flux(c) = cf_soil%fates_litter_flux(c) + & + sum(this%fates(ci)%bc_out(s)%litt_flux_lig_c_si(1:nlevdecomp) * & + this%fates(ci)%bc_in(s)%dz_decomp_sisl(1:nlevdecomp)) + + else + ! In SP mode their is no mass flux between the two + + cf_soil%fates_litter_flux = 0._r8 + end if + + end associate + return + end subroutine UpdateCLitterFluxes + + ! =================================================================================== + subroutine wrap_update_hlmfates_dyn(this, nc, bounds_clump, & waterdiagnosticbulk_inst, canopystate_inst, & soilbiogeochem_carbonflux_inst, is_initing_from_restart) @@ -1137,18 +1252,17 @@ subroutine wrap_update_hlmfates_dyn(this, nc, bounds_clump, & ! provides boundary conditions (such as vegetation fractional coverage) ! --------------------------------------------------------------------------------- - implicit none class(hlm_fates_interface_type), intent(inout) :: this type(bounds_type),intent(in) :: bounds_clump integer , intent(in) :: nc type(waterdiagnosticbulk_type) , intent(inout) :: waterdiagnosticbulk_inst type(canopystate_type) , intent(inout) :: canopystate_inst type(soilbiogeochem_carbonflux_type), intent(inout) :: soilbiogeochem_carbonflux_inst + ! is this being called during a read from restart sequence (if so then use the restarted fates ! snow depth variable rather than the CLM variable). logical , intent(in) :: is_initing_from_restart - integer :: npatch ! number of patches in each site integer :: ifp ! index FATES patch integer :: p ! HLM patch index @@ -1190,7 +1304,7 @@ subroutine wrap_update_hlmfates_dyn(this, nc, bounds_clump, & ! Canopy diagnostics for FATES call canopy_summarization(this%fates(nc)%nsites, & this%fates(nc)%sites, & - this%fates(nc)%bc_in) + this%fates(nc)%bc_in) ! Canopy diagnostic outputs for HLM call update_hlm_dynamics(this%fates(nc)%nsites, & @@ -1357,7 +1471,8 @@ end subroutine wrap_update_hlmfates_dyn subroutine restart( this, bounds_proc, ncid, flag, waterdiagnosticbulk_inst, & waterstatebulk_inst, canopystate_inst, soilstate_inst, & - active_layer_inst, soilbiogeochem_carbonflux_inst) + active_layer_inst, soilbiogeochem_carbonflux_inst, & + soilbiogeochem_nitrogenflux_inst) ! --------------------------------------------------------------------------------- ! The ability to restart the model is handled through three different types of calls @@ -1381,8 +1496,6 @@ subroutine restart( this, bounds_proc, ncid, flag, waterdiagnosticbulk_inst, & use EDMainMod, only : ed_update_site use FatesInterfaceTypesMod, only: fates_maxElementsPerSite - implicit none - ! Arguments class(hlm_fates_interface_type), intent(inout) :: this @@ -1395,7 +1508,8 @@ subroutine restart( this, bounds_proc, ncid, flag, waterdiagnosticbulk_inst, & type(soilstate_type) , intent(inout) :: soilstate_inst type(active_layer_type) , intent(in) :: active_layer_inst type(soilbiogeochem_carbonflux_type), intent(inout) :: soilbiogeochem_carbonflux_inst - + type(soilbiogeochem_nitrogenflux_type), intent(inout) :: soilbiogeochem_nitrogenflux_inst + ! Locals type(bounds_type) :: bounds_clump integer :: nc @@ -1413,7 +1527,6 @@ subroutine restart( this, bounds_proc, ncid, flag, waterdiagnosticbulk_inst, & integer :: nvar integer :: ivar logical :: readvar - logical, save :: initialized = .false. call t_startf('fates_restart') @@ -1605,13 +1718,6 @@ subroutine restart( this, bounds_proc, ncid, flag, waterdiagnosticbulk_inst, & this%fates(nc)%bc_in(s), & this%fates(nc)%bc_out(s) ) - ! This call sends internal fates variables into the - ! output boundary condition structures. Note: this is called - ! internally in fates dynamics as well. - call FluxIntoLitterPools(this%fates(nc)%sites(s), & - this%fates(nc)%bc_in(s), & - this%fates(nc)%bc_out(s)) - end do if(use_fates_sp)then @@ -1836,13 +1942,6 @@ subroutine init_coldstart(this, waterstatebulk_inst, waterdiagnosticbulk_inst, & this%fates(nc)%bc_in(s), & this%fates(nc)%bc_out(s)) - ! This call sends internal fates variables into the - ! output boundary condition structures. Note: this is called - ! internally in fates dynamics as well. - call FluxIntoLitterPools(this%fates(nc)%sites(s), & - this%fates(nc)%bc_in(s), & - this%fates(nc)%bc_out(s)) - end do ! ------------------------------------------------------------------------ @@ -1885,8 +1984,6 @@ subroutine wrap_sunfrac(this,nc,atm2lnd_inst,canopystate_inst) ! of the canopy that is exposed to sun. ! --------------------------------------------------------------------------------- - implicit none - ! Input Arguments class(hlm_fates_interface_type), intent(inout) :: this @@ -1908,7 +2005,7 @@ subroutine wrap_sunfrac(this,nc,atm2lnd_inst,canopystate_inst) ! this is the order increment of patch ! on the site - type(ed_patch_type), pointer :: cpatch ! c"urrent" patch INTERF-TODO: SHOULD + type(fates_patch_type), pointer :: cpatch ! c"urrent" patch INTERF-TODO: SHOULD ! BE HIDDEN AS A FATES PRIVATE call t_startf('fates_wrapsunfrac') @@ -2021,7 +2118,7 @@ subroutine wrap_btran(this,nc,fn,filterc,soilstate_inst, & ! ! --------------------------------------------------------------------------------- - implicit none + use SoilWaterRetentionCurveMod, only : soil_water_retention_curve_type ! Arguments class(hlm_fates_interface_type), intent(inout) :: this @@ -2187,12 +2284,13 @@ subroutine wrap_photosynthesis(this, nc, bounds, fn, filterp, & use shr_log_mod , only : errMsg => shr_log_errMsg use abortutils , only : endrun use decompMod , only : bounds_type - use clm_varcon , only : rgas, tfrz, namep + use clm_varcon , only : tfrz, namep use clm_varctl , only : iulog - use pftconMod , only : pftcon use PatchType , only : patch use quadraticMod , only : quadratic - use EDtypesMod , only : ed_patch_type, ed_cohort_type, ed_site_type + use EDtypesMod , only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type ! ! !ARGUMENTS: @@ -2348,50 +2446,56 @@ end subroutine wrap_accumulatefluxes ! ====================================================================================== - subroutine wrap_WoodProducts(this, bounds_clump, fc, filterc, c_products_inst) + subroutine wrap_WoodProducts(this, bounds_clump, num_soilc, filter_soilc, & + c_products_inst, n_products_inst) ! !ARGUMENTS: class(hlm_fates_interface_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds_clump - integer , intent(in) :: fc ! size of column filter - integer , intent(in) :: filterc(fc) ! column filter + integer , intent(in) :: num_soilc ! size of column filter + integer , intent(in) :: filter_soilc(:) ! column filter type(cn_products_type) , intent(inout) :: c_products_inst + type(cn_products_type) , intent(inout) :: n_products_inst ! Locals - integer :: s,c,icc,g - integer :: nc - - ! This wrapper is not active. This is just place-holder code until - ! harvest-product flux is fully implemented. RGK-05-2022 + integer :: s,c,g,fc + integer :: ci ! Clump index + + ci = bounds_clump%clump_index - !associate( & - ! prod10c => c_products_inst%hrv_deadstem_to_prod10_grc, & - ! prod100c => c_products_inst%hrv_deadstem_to_prod100_grc) + ! Loop over columns + do fc = 1, num_soilc + + c = filter_soilc(fc) + g = col%gridcell(c) + s = this%f2hmap(ci)%hsites(c) - ! nc = bounds_clump%clump_index - ! Loop over columns - do icc = 1,fc - c = filterc(icc) - g = col%gridcell(c) - s = this%f2hmap(nc)%hsites(c) - - ! Shijie: Pass harvested wood products to ELM variable - ! prod10c(g) = prod10c(g) + & - ! this%fates(nc)%bc_out(s)%hrv_deadstemc_to_prod10c - ! prod100c(g) = prod100c(g) + & - ! this%fates(nc)%bc_out(s)%hrv_deadstemc_to_prod100c - - ! RGK: THere is also a patch level variable - !do ifp = 1,this%fates(nc)%sites(s)%youngest_patch%patchno - ! p = ifp+col%patchi(c) - ! hrv_deadstemc_to_prod10c(p) = - ! hrv_deadstemc_to_prod100c(p) - !end do + ! Shijie: Pass harvested wood products to CLM product pools + c_products_inst%hrv_deadstem_to_prod10_grc(g) = & + c_products_inst%hrv_deadstem_to_prod10_grc(g) + & + this%fates(ci)%bc_out(s)%hrv_deadstemc_to_prod10c + + c_products_inst%hrv_deadstem_to_prod100_grc(g) = & + c_products_inst%hrv_deadstem_to_prod100_grc(g) + & + this%fates(ci)%bc_out(s)%hrv_deadstemc_to_prod100c + + ! If N cycling is on + if(fates_parteh_mode .eq. prt_cnp_flex_allom_hyp ) then + + !n_products_inst%hrv_deadstem_to_prod10_grc(g) = & + ! n_products_inst%hrv_deadstem_to_prod10_grc(g) + & + ! this%fates(ci)%bc_out(s)%hrv_deadstemc_to_prod10c + + !n_products_inst%hrv_deadstem_to_prod100_grc(g) = & + ! n_products_inst%hrv_deadstem_to_prod100_grc(g) + & + ! this%fates(ci)%bc_out(s)%hrv_deadstemc_to_prod100c + + end if + - end do + end do - ! end associate - return + return end subroutine wrap_WoodProducts ! ====================================================================================== @@ -3010,35 +3114,6 @@ subroutine ComputeRootSoilFlux(this, bounds_clump, num_filterc, filterc, & end subroutine ComputeRootSoilFlux - ! ====================================================================================== -! -! THIS WAS MOVED TO WRAP_HYDRAULICS_DRIVE() -! -! subroutine TransferPlantWaterStorage(this, bounds_clump, nc, waterstate_inst) -! -! implicit none -! class(hlm_fates_interface_type), intent(inout) :: this -! type(bounds_type),intent(in) :: bounds_clump -! integer,intent(in) :: nc -! type(waterstate_type) , intent(inout) :: waterstate_inst -! -! ! locals -! integer :: s -! integer :: c -! -! if (.not. (use_fates .and. use_fates_planthydro) ) return -! -! do s = 1, this%fates(nc)%nsites -! c = this%f2hmap(nc)%fcolumn(s) -! waterstate_inst%total_plant_stored_h2o_col(c) = & -! this%fates(nc)%bc_out(s)%plant_stored_h2o_si -! end do -! return -!end subroutine TransferPlantWaterStorage - - - - ! ====================================================================================== subroutine wrap_hydraulics_drive(this, bounds_clump, nc, & @@ -3046,7 +3121,6 @@ subroutine wrap_hydraulics_drive(this, bounds_clump, nc, & fn, filterp, solarabs_inst, energyflux_inst) - implicit none class(hlm_fates_interface_type), intent(inout) :: this type(bounds_type),intent(in) :: bounds_clump integer,intent(in) :: nc @@ -3158,18 +3232,16 @@ end subroutine wrap_hydraulics_drive subroutine hlm_bounds_to_fates_bounds(hlm, fates) - use FatesIODimensionsMod, only : fates_bounds_type + use FatesIODimensionsMod, only : fates_bounds_type use FatesInterfaceTypesMod, only : nlevsclass, nlevage, nlevcoage use FatesInterfaceTypesMod, only : nlevheight use FatesInterfaceTypesMod, only : nlevdamage - use EDtypesMod, only : nfsc - use FatesLitterMod, only : ncwd - use EDtypesMod, only : nlevleaf, nclmax + use FatesLitterMod, only : nfsc + use FatesLitterMod, only : ncwd + use EDParamsMod, only : nlevleaf, nclmax use FatesInterfaceTypesMod, only : numpft_fates => numpft - implicit none - type(bounds_type), intent(in) :: hlm type(fates_bounds_type), intent(out) :: fates diff --git a/src/utils/clmfates_paraminterfaceMod.F90 b/src/utils/clmfates_paraminterfaceMod.F90 index 01a3328747..dedd8629cc 100644 --- a/src/utils/clmfates_paraminterfaceMod.F90 +++ b/src/utils/clmfates_paraminterfaceMod.F90 @@ -2,8 +2,13 @@ module CLMFatesParamInterfaceMod ! NOTE(bja, 2017-01) this code can not go into the main clm-fates ! interface module because of circular dependancies with pftvarcon. - use shr_kind_mod, only : r8 => shr_kind_r8 - use FatesGlobals, only : fates_log + use shr_kind_mod, only : r8 => shr_kind_r8, SHR_KIND_CL + use FatesGlobals, only : fates_log + use FatesParametersInterface, only : fates_parameters_type + use EDParamsMod, only : FatesRegisterParams, FatesReceiveParams + use SFParamsMod, only : SpitFireRegisterParams, SpitFireReceiveParams + use PRTInitParamsFATESMod, only : PRTRegisterParams, PRTReceiveParams + use FatesSynchronizedParamsMod, only : FatesSynchronizedParamsInst implicit none @@ -25,49 +30,39 @@ module CLMFatesParamInterfaceMod !----------------------------------------------------------------------- subroutine FatesReadParameters() - - use clm_varctl, only : use_fates, paramfile, fates_paramfile - use spmdMod, only : masterproc - - use FatesParametersInterface, only : fates_parameters_type - - use EDParamsMod, only : FatesRegisterParams, FatesReceiveParams - use SFParamsMod, only : SpitFireRegisterParams, SpitFireReceiveParams - use PRTInitParamsFATESMod, only : PRTRegisterParams, PRTReceiveParams - use FatesSynchronizedParamsMod, only : FatesSynchronizedParamsInst + use clm_varctl, only : use_fates, paramfile, fates_paramfile + use spmdMod, only : masterproc implicit none - + character(len=32) :: subname = 'FatesReadParameters' class(fates_parameters_type), allocatable :: fates_params logical :: is_host_file - if (use_fates) then - if (masterproc) then - write(fates_log(), *) 'clmfates_interfaceMod.F90::'//trim(subname)//' :: CLM reading ED/FATES '//' parameters ' - end if + if (masterproc) then + write(fates_log(), *) 'clmfates_interfaceMod.F90::'//trim(subname)//' :: CLM reading ED/FATES '//' parameters ' + end if - allocate(fates_params) - call fates_params%Init() - call FatesRegisterParams(fates_params) - call SpitFireRegisterParams(fates_params) - call PRTRegisterParams(fates_params) - call FatesSynchronizedParamsInst%RegisterParams(fates_params) + allocate(fates_params) + call fates_params%Init() ! fates_params class, in FatesParameterInterfaceMod + call FatesRegisterParams(fates_params) !EDParamsMod, only operates on fates_params class + call SpitFireRegisterParams(fates_params) !SpitFire Mod, only operates of fates_params class + call PRTRegisterParams(fates_params) ! PRT mod, only operates on fates_params class + call FatesSynchronizedParamsInst%RegisterParams(fates_params) !Synchronized params class in Synchronized params mod, only operates on fates_params class - is_host_file = .false. - call ParametersFromNetCDF(fates_paramfile, is_host_file, fates_params) + is_host_file = .false. + call ParametersFromNetCDF(fates_paramfile, is_host_file, fates_params) - is_host_file = .true. - call ParametersFromNetCDF(paramfile, is_host_file, fates_params) + is_host_file = .true. + call ParametersFromNetCDF(paramfile, is_host_file, fates_params) - call FatesReceiveParams(fates_params) - call SpitFireReceiveParams(fates_params) - call PRTReceiveParams(fates_params) - call FatesSynchronizedParamsInst%ReceiveParams(fates_params) + call FatesReceiveParams(fates_params) + call SpitFireReceiveParams(fates_params) + call PRTReceiveParams(fates_params) + call FatesSynchronizedParamsInst%ReceiveParams(fates_params) - call fates_params%Destroy() - deallocate(fates_params) - end if + call fates_params%Destroy() + deallocate(fates_params) end subroutine FatesReadParameters @@ -211,7 +206,7 @@ subroutine ParametersFromNetCDF(filename, is_host_file, fates_params) call SetParameterDimensions(ncid, is_host_file, fates_params) max_dim_size = fates_params%GetMaxDimensionSize() allocate(data(max_dim_size, max_dim_size)) - + num_params = fates_params%num_params() do i = 1, num_params call fates_params%GetMetaData(i, name, dimension_shape, dimension_sizes, dimension_names, is_host_param) diff --git a/src/utils/restUtilMod.F90.in b/src/utils/restUtilMod.F90.in index 4271271097..1bece885e4 100644 --- a/src/utils/restUtilMod.F90.in +++ b/src/utils/restUtilMod.F90.in @@ -19,6 +19,7 @@ module restUtilMod implicit none save private + integer, parameter, public :: excess_ice_issue = 1787 ! save ! !----------------------------------------------------------------------- @@ -88,9 +89,15 @@ module restUtilMod end interface set_missing_vals_to_constant public :: set_missing_vals_to_constant + public :: RestartExcessIceIssue + private :: missing_field_possibly_abort private :: write_interpinic_flag + ! Answer whether to call restartvar(), if necessary checking whether + ! a dimension exists in the restart file + public :: CallRestartvarDimOK + character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -740,5 +747,78 @@ contains end subroutine write_interpinic_flag + !----------------------------------------------------------------------- + subroutine RestartExcessIceIssue(ncid, flag, excess_ice_on_restart) + ! + ! !DESCRIPTION: + ! Is excess ice on the originating restart file? This is important to have + ! because the init_interp process copies the cold-start values to the + ! interpolated file if they aren't there, and we need to know if good values + ! exist on the originating restart file. + ! + ! !USES: + use ncdio_pio , only : file_desc_t + use IssueFixedMetadataHandler, only : read_issue_fixed_metadata + ! + ! !ARGUMENTS: + type(file_desc_t), intent(inout) :: ncid ! netcdf id + character(len=*) , intent(in) :: flag ! 'read' or 'write' + logical, intent(out) :: excess_ice_on_restart ! If excess ice is on the restart file + ! + ! !LOCAL VARIABLES: + integer :: attribute_value + + + character(len=*), parameter :: subname = 'RestartExcessIceIssue' + !----------------------------------------------------------------------- + + excess_ice_on_restart = .false. + ! The write of the issue metadata is in restFileMod::: restFile_write_issues_fixed + if (flag == 'read' )then + call read_issue_fixed_metadata( & + ncid = ncid, & + issue_num = excess_ice_issue, & + attribute_value = attribute_value) + if (attribute_value == 0) then + excess_ice_on_restart = .false. + else + excess_ice_on_restart = .true. + end if + + end if + + end subroutine RestartExcessIceIssue + !----------------------------------------------------------------------- + logical function CallRestartvarDimOK (ncid, flag, dimname) + ! + ! !DESCRIPTION: + ! Answer whether to call restartvar(), if necessary checking whether + ! a dimension exists in the restart file + ! + ! BACKWARDS_COMPATIBILITY(wjs/ssr, 2022-02-02) + ! Used in Restart(). Even though restartvar() can safely be called for a + ! non-existent variable, it gives an error for a non-existent dimension, so + ! check whether the dimension exists before trying to read. The need for this + ! function arose because we recently added the mxsowings and mxharvests + ! dimensions to the restart file. + ! + ! !USES: + use ncdio_pio + ! + ! !ARGUMENTS: + type(file_desc_t), intent(inout) :: ncid + character(len=*) , intent(in) :: flag + character(len=*) , intent(in) :: dimname + ! + ! !LOCAL VARIABLES: + !----------------------------------------------------------------------- + + if (flag == 'read') then + call check_dim(ncid, dimname, dimexist=CallRestartvarDimOK) + else + CallRestartvarDimOK = .true. + end if + + end function CallRestartvarDimOK end module restUtilMod diff --git a/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf b/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf index 435d795e50..78565fd54d 100644 --- a/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf +++ b/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf @@ -577,4 +577,85 @@ contains end subroutine bad_hilontolocal_time + @Test + subroutine check_is_doy_in_interval_startend(this) + class(TestTimeManager), intent(inout) :: this + + integer, parameter :: start = 100 + integer, parameter :: end = 300 + + @assertTrue(is_doy_in_interval(start, end, start)) + @assertTrue(is_doy_in_interval(start, end, end)) + @assertTrue(is_doy_in_interval(start, end, 200)) + @assertFalse(is_doy_in_interval(start, end, 35)) + @assertFalse(is_doy_in_interval(start, end, 350)) + + end subroutine check_is_doy_in_interval_startend + + @Test + subroutine check_is_doy_in_interval_endstart(this) + class(TestTimeManager), intent(inout) :: this + + integer, parameter :: start = 300 + integer, parameter :: end = 100 + + @assertTrue(is_doy_in_interval(start, end, start)) + @assertTrue(is_doy_in_interval(start, end, end)) + @assertFalse(is_doy_in_interval(start, end, 200)) + @assertTrue(is_doy_in_interval(start, end, 35)) + @assertTrue(is_doy_in_interval(start, end, 350)) + + end subroutine check_is_doy_in_interval_endstart + + @Test + subroutine check_is_doy_in_interval_sameday(this) + class(TestTimeManager), intent(inout) :: this + + integer, parameter :: start = 300 + integer, parameter :: end = 300 + + @assertTrue(is_doy_in_interval(start, end, start)) + @assertTrue(is_doy_in_interval(start, end, end)) + @assertFalse(is_doy_in_interval(start, end, 200)) + @assertFalse(is_doy_in_interval(start, end, 350)) + + end subroutine check_is_doy_in_interval_sameday + + @Test + subroutine check_is_today_in_doy_interval(this) + class(TestTimeManager), intent(inout) :: this + + integer :: start, end + + call unittest_timemgr_setup(dtime=dtime, use_gregorian_calendar=.true.) + + start = 100 ! April 10 + end = 300 ! October 27 + + ! Test well before interval + call set_date(yr=2009, mon=3, day=25, tod=0) + @assertFalse(is_today_in_doy_interval(start, end)) + + ! Test last timestep before interval + call set_date(yr=2009, mon=4, day=10, tod=0) + @assertFalse(is_today_in_doy_interval(start, end)) + + ! Test first timestep of interval + call set_date(yr=2009, mon=4, day=10, tod=dtime) + @assertTrue(is_today_in_doy_interval(start, end)) + + ! Test well within interval + call set_date(yr=2009, mon=7, day=24, tod=0) + @assertTrue(is_today_in_doy_interval(start, end)) + + ! Test last timestep of interval + call set_date(yr=2009, mon=10, day=28, tod=0) + @assertTrue(is_today_in_doy_interval(start, end)) + + ! Test first timestep after interval + call set_date(yr=2009, mon=10, day=28, tod=dtime) + @assertFalse(is_today_in_doy_interval(start, end)) + + end subroutine check_is_today_in_doy_interval + end module test_clm_time_manager diff --git a/tools/mksurfdata_map/modify_1x1_mexicocityMEX.cfg b/tools/mksurfdata_map/modify_1x1_mexicocityMEX.cfg index 5e9de7968b..6eab73a159 100644 --- a/tools/mksurfdata_map/modify_1x1_mexicocityMEX.cfg +++ b/tools/mksurfdata_map/modify_1x1_mexicocityMEX.cfg @@ -36,15 +36,19 @@ lnd_lon_2 = 360 landmask_file = UNSET # PFT/CFT to be set to 100% according to user-defined mask. -# If idealized = True and dom_plant = UNSET, the latter defaults to 0 +# If idealized = True and dom_pft = UNSET, the latter defaults to 0 # (bare soil). Valid values range from 0 to a max value (int) that one can # obtain from the fsurdat_in file using ncdump (or method preferred by user). # The max valid value will equal (lsmpft - 1) and will also equal the last -# value of cft(cft). +# value of cft(cft). Cannot be set with evenly_split_cropland = True. dom_pft = UNSET -# LAI, SAI, HEIGHT_TOP, and HEIGHT_BOT values by month for dom_plant -# If dom_plant = 0, the next four default to 0 (space-delimited list +# If True, evenly split each gridcell's cropland among all crop types (CFTs). +# Can only be True if dom_pft is UNSET. +evenly_split_cropland = False + +# LAI, SAI, HEIGHT_TOP, and HEIGHT_BOT values by month for dom_pft +# If dom_pft = 0, the next four default to 0 (space-delimited list # of floats without brackets). lai = UNSET sai = UNSET diff --git a/tools/mksurfdata_map/modify_1x1_urbanc_alpha.cfg b/tools/mksurfdata_map/modify_1x1_urbanc_alpha.cfg index 38b8ce6372..d704b629bd 100644 --- a/tools/mksurfdata_map/modify_1x1_urbanc_alpha.cfg +++ b/tools/mksurfdata_map/modify_1x1_urbanc_alpha.cfg @@ -36,15 +36,19 @@ lnd_lon_2 = 360 landmask_file = UNSET # PFT/CFT to be set to 100% according to user-defined mask. -# If idealized = True and dom_plant = UNSET, the latter defaults to 0 +# If idealized = True and dom_pft = UNSET, the latter defaults to 0 # (bare soil). Valid values range from 0 to a max value (int) that one can # obtain from the fsurdat_in file using ncdump (or method preferred by user). # The max valid value will equal (lsmpft - 1) and will also equal the last -# value of cft(cft). +# value of cft(cft). Cannot be set with evenly_split_cropland = True. dom_pft = UNSET -# LAI, SAI, HEIGHT_TOP, and HEIGHT_BOT values by month for dom_plant -# If dom_plant = 0, the next four default to 0 (space-delimited list +# If True, evenly split each gridcell's cropland among all crop types (CFTs). +# Can only be True if dom_pft is UNSET. +evenly_split_cropland = False + +# LAI, SAI, HEIGHT_TOP, and HEIGHT_BOT values by month for dom_pft +# If dom_pft = 0, the next four default to 0 (space-delimited list # of floats without brackets). lai = UNSET sai = UNSET diff --git a/tools/mksurfdata_map/modify_1x1_vancouverCAN.cfg b/tools/mksurfdata_map/modify_1x1_vancouverCAN.cfg index abc5df16b1..f46593d653 100644 --- a/tools/mksurfdata_map/modify_1x1_vancouverCAN.cfg +++ b/tools/mksurfdata_map/modify_1x1_vancouverCAN.cfg @@ -36,15 +36,19 @@ lnd_lon_2 = 360 landmask_file = UNSET # PFT/CFT to be set to 100% according to user-defined mask. -# If idealized = True and dom_plant = UNSET, the latter defaults to 0 +# If idealized = True and dom_pft = UNSET, the latter defaults to 0 # (bare soil). Valid values range from 0 to a max value (int) that one can # obtain from the fsurdat_in file using ncdump (or method preferred by user). # The max valid value will equal (lsmpft - 1) and will also equal the last -# value of cft(cft). +# value of cft(cft). Cannot be set with evenly_split_cropland = True. dom_pft = UNSET -# LAI, SAI, HEIGHT_TOP, and HEIGHT_BOT values by month for dom_plant -# If dom_plant = 0, the next four default to 0 (space-delimited list +# If True, evenly split each gridcell's cropland among all crop types (CFTs). +# Can only be True if dom_pft is UNSET. +evenly_split_cropland = False + +# LAI, SAI, HEIGHT_TOP, and HEIGHT_BOT values by month for dom_pft +# If dom_pft = 0, the next four default to 0 (space-delimited list # of floats without brackets). lai = UNSET sai = UNSET diff --git a/tools/modify_input_files/modify_fsurdat_template.cfg b/tools/modify_input_files/modify_fsurdat_template.cfg index 3661784521..1dfb33ce53 100644 --- a/tools/modify_input_files/modify_fsurdat_template.cfg +++ b/tools/modify_input_files/modify_fsurdat_template.cfg @@ -72,9 +72,13 @@ lon_dimname = UNSET # (bare soil). Valid values range from 0 to a max value (int) that one can # obtain from the fsurdat_in file using ncdump (or method preferred by user). # The max valid value will equal (lsmpft - 1) and will also equal the last -# value of cft(cft). +# value of cft(cft). Cannot be set with evenly_split_cropland = True. dom_pft = UNSET +# If True, evenly split each gridcell's cropland among all crop types (CFTs). +# Can only be True if dom_pft is UNSET. +evenly_split_cropland = False + # LAI, SAI, HEIGHT_TOP, and HEIGHT_BOT values by month for dom_pft # If dom_pft = 0, the next four default to 0 (space-delimited list # of floats without brackets).