clm5/bld/CLMBuildNamelist.pm
2024-05-09 15:14:01 +08:00

5412 lines
242 KiB
Perl

# build-namelist
#
# This script builds the namelists for CLM
#
# The simplest use of build-namelist is to execute it from the build directory where configure
# was run. By default it will use the config_cache.xml file that was written by configure to
# determine the build time properties of the executable, and will write the files that contain
# the output namelists in that same directory. But if multiple runs are to made using the
# same executable, successive invocations of build-namelist will overwrite previously generated
# namelist files. So generally the best strategy is to invoke build-namelist from the run
# directory and use the -config option to provide the filepath of the config_cache.xml file.
#
#
# Date Contributor Modification
# -------------------------------------------------------------------------------------------
# 2009-01-20 Vertenstein Original version
# 2010-04-27 Kluzek Add ndep streams capability
# 2011-07-25 Kluzek Add multiple ensemble's of namelists
# 2012-03-23 Kluzek Add megan namelist and do checking on it
# 2012-07-01 Kluzek Add some common CESM namelist options
# 2013-12 Andre Refactor everything into subroutines
# 2013-12 Muszala Add Ecosystem Demography functionality
#--------------------------------------------------------------------------------------------
package CLMBuildNamelist;
require 5;
use strict;
#use warnings;
#use diagnostics;
use Cwd qw(getcwd abs_path);
use File::Basename qw(dirname);
use English;
use Getopt::Long;
use IO::File;
use File::Glob ':bsd_glob';
#-------------------------------------------------------------------------------
#
# Define a small number of global variables
#
#-------------------------------------------------------------------------------
(my $ProgName = $0) =~ s!(.*)/!!; # name of this script
my $ProgDir = $1;
$ProgName = "CLM " . "$ProgName";
my $cwd = abs_path(getcwd()); # absolute path of the current working directory
my $log; # Log messages object -- will be set in main, declaring it global here means it can be used everywhere
#-------------------------------------------------------------------------------
sub usage {
die <<EOF;
SYNOPSIS
build-namelist [options]
Create the namelist for CLM
REQUIRED OPTIONS
-cimeroot "directory" Path to cime directory
-config "filepath" Read the given CLM configuration cache file.
Default: "config_cache.xml".
-configuration "cfg" The overall configuration being used [ clm | nwp ]
clm = Climate configuration
nwp = Numerical Weather Prediction configuration
-d "directory" Directory where output namelist file will be written
Default: current working directory.
-envxml_dir "directory" Directory name of env_*.xml case files to read in.
(if read they allow user_nl_clm and CLM_BLDNML_OPTS to expand
variables [for example to use \$DIN_LOC_ROOT])
(default current directory)
-lnd_frac "domainfile" Land fraction file (the input domain file) (needed for MCT driver and LILAC)
-res "resolution" Specify horizontal grid. Use nlatxnlon for spectral grids;
dlatxdlon for fv grids (dlat and dlon are the grid cell size
in degrees for latitude and longitude respectively)
"-res list" to list valid resolutions.
(default: 0.9x1.25)
-sim_year "year" Year to simulate for input datasets
(i.e. PtVg, 1850, 2000, 2010, 1850-2000, 1850-2100)
"-sim_year list" to list valid simulation years
(default 2000)
-structure "structure" The overall structure being used [ standard | fast ]
OPTIONS
-driver "value" CESM driver type you will run with [ mct | nuopc ]
-bgc "value" Build CLM with BGC package [ sp | bgc | fates ]
(default is sp).
CLM Biogeochemistry mode
sp = Satellite Phenology (SP)
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:
use_cn, use_lch4, use_nitrif_denitrif
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.
-clm_accelerated_spinup "on|off" Setup in a configuration to run as fast as possible for doing a throw-away
simulation in order to get the model to a spun-up state. So do things like
turn off expensive options and setup for a low level of history output.
If CLM4.5/CLM5.0 and bgc it also includes a prognostic Carbon model (cn or bgc)
, also by default turn on Accelerated Decomposition mode which
is controlled by the namelist variable spinup_state.
Turn on given spinup mode for BGC setting of CN
on : Turn on Accelerated Decomposition (spinup_state = 1 or 2)
off : run in normal mode (spinup_state = 0)
Default is set by clm_accelerated_spinup mode.
Spinup is now a two step procedure. First, run the model
with clm_accelerated_spinup = "on". Then run the model for a while with
spinup_state = 0. The exit spinup step happens automatically
on the first timestep when using a restart file from spinup
mode.
The spinup state is saved to the restart file.
If the values match between the model and the restart
file it proceeds as directed.
If the restart file is in spinup mode and the model is in
normal mode, then it performs the exit spinup step
and proceeds in normal mode after that.
If the restart file has normal mode and the model is in
spinup, then it enters spinup. This is useful if you change
a parameter and want to rapidly re-equilibrate without doing
a cold start.
-clm_demand "list" List of variables to require on clm namelist besides the usuals.
"-clm_demand list" to list valid options.
(can include a list member "null" which does nothing)
-clm_start_type "type" Start type of simulation
(default, cold, arb_ic, startup, continue, or branch)
(default=do the default type for this configuration)
(cold=always start with arbitrary initial conditions)
(arb_ic=start with arbitrary initial conditions if
initial conditions do not exist)
(startup=ensure that initial conditions are being used)
-clm_usr_name "name" Dataset resolution/descriptor for personal datasets.
Default: not used
Example: 1x1pt_boulderCO_c090722 to describe location,
number of pts, and date files created
-co2_type "value" Set CO2 the type of CO2 variation to use.
-co2_ppmv "value" Set CO2 concentration to use when co2_type is constant (ppmv).
-crop Toggle for prognostic crop model. (default is off)
(can ONLY be turned on when BGC type is CN or BGC)
This turns on the namelist variable: use_crop
-csmdata "dir" Root directory of CESM input data.
Can also be set by using the CSMDATA environment variable.
-drydep Produce a drydep_inparm namelist that will go into the
"drv_flds_in" file for the driver to pass dry-deposition to the atm.
Default: -no-drydep
(Note: buildnml copies the file for use by the driver)
-dynamic_vegetation Toggle for dynamic vegetation model. (default is off)
(can ONLY be turned on when BGC type is 'bgc')
This turns on the namelist variable: use_cndv
(Deprecated, this will be removed)
-fire_emis Produce a fire_emis_nl namelist that will go into the
"drv_flds_in" file for the driver to pass fire emissions to the atm.
(Note: buildnml copies the file for use by the driver)
-glc_nec <name> Glacier number of elevation classes [0 | 3 | 5 | 10 | 36]
(default is 0) (standard option with land-ice model is 10)
-glc_use_antarctica Set defaults appropriate for runs that include Antarctica
-help [or -h] Print usage to STDOUT.
-light_res <value> Resolution of lightning dataset to use for CN or FATES fire (360x720, 106x174, or 94x192)
106x174 can only be used for NEON sites
-lilac If CTSM is being run through LILAC (normally not used)
(LILAC is the Lightweight Infrastructure for Land-Atmosphere Coupling)
-ignore_ic_date Ignore the date on the initial condition files
when determining what input initial condition file to use.
-ignore_ic_year Ignore just the year part of the date on the initial condition files
when determining what input initial condition file to use.
-ignore_warnings Allow build-namelist to continue, rather than stopping on
warnings
-infile "filepath" Specify a file (or list of files) containing namelists to
read values from.
If used with a CLM build with multiple ensembles (ninst_lnd>1)
and the filename entered is a directory to files of the
form filepath/filepath and filepath/filepath_\$n where \$n
is the ensemble member number. the "filepath/filepath"
input namelist file is the master input namelist file
that is applied to ALL ensemble members.
(by default for CESM this is setup for files of the
form \$CASEDIR/user_nl_clm/user_nl_clm_????)
-inputdata "filepath" Writes out a list containing pathnames for required input datasets in
file specified.
-lnd_tuning_mode "value" Use the parameters tuned for the given configuration (CLM version and atmospheric forcing)
-mask "landmask" Type of land-mask (default, navy, gx3v5, gx1v5 etc.)
"-mask list" to list valid land masks.
-namelist "namelist" Specify namelist settings directly on the commandline by supplying
a string containing FORTRAN namelist syntax, e.g.,
-namelist "&clm_inparm dt=1800 /"
-no-megan DO NOT PRODUCE a megan_emis_nl namelist that will go into the
"drv_flds_in" file for the driver to pass VOCs to the atm.
MEGAN (Model of Emissions of Gases and Aerosols from Nature)
(Note: buildnml copies the file for use by the driver)
-[no-]note Add note to output namelist [do NOT add note] about the
arguments to build-namelist.
-output_reals <file> Output real parameters to the given output file.
-ssp_rcp "value" Shared Socioeconomic Pathway (SSP) and
Representative Concentration Pathway (RCP) combination to use for
future scenarios.
"-ssp_rcp list" to list valid ssp_rcp settings.
-s Turns on silent mode - only fatal messages issued.
-test Enable checking that input datasets exist on local filesystem.
-use_case "case" Specify a use case which will provide default values.
"-use_case list" to list valid use-cases.
-verbose [or -v] Turn on verbose echoing of informational messages.
-version Echo the SVN tag name used to check out this CLM distribution.
-vichydro Toggle to turn on VIC hydrologic parameterizations (default is off)
This turns on the namelist variable: use_vichydro
Note: The precedence for setting the values of namelist variables is (highest to lowest):
0. namelist values set by specific command-line options, like, -d, -sim_year
(i.e. compset choice and CLM_BLDNML_OPTS, CLM_ACCELERATED_SPINUP, LND_TUNING_MODE env_run variables)
(NOTE: If you try to contradict these settings by methods below, an error will be triggered)
1. values set on the command-line using the -namelist option,
(i.e. CLM_NAMELIST_OPTS env_run variable)
2. values read from the file(s) specified by -infile,
(i.e. user_nl_clm files)
3. datasets from the -clm_usr_name option,
(i.e. CLM_USRDAT_NAME env_run variable)
4. values set from a use-case scenario, e.g., -use_case
(i.e. CLM_NML_USE_CASE env_run variable)
5. values from the namelist defaults file.
EOF
}
#-------------------------------------------------------------------------------
sub process_commandline {
# Process command-line options and return the hash
my ($nl_flags) = @_;
# Save the command line arguments to the script. NOTE: this must be
# before GetOptions() is called because items are removed from from
# the array!
$nl_flags->{'cmdline'} = "@ARGV\n";
my %opts = ( cimeroot => undef,
config => "config_cache.xml",
configuration => undef,
csmdata => undef,
clm_usr_name => undef,
co2_type => undef,
co2_ppmv => undef,
clm_demand => "null",
driver => "nuopc",
help => 0,
glc_nec => "default",
glc_use_antarctica => 0,
light_res => "default",
lnd_tuning_mode => "default",
lnd_frac => undef,
dir => "$cwd",
ssp_rcp => "default",
sim_year => "default",
structure => undef,
clm_accelerated_spinup=> "default",
chk_res => undef,
note => undef,
drydep => 0,
lilac => 0,
output_reals_filename => undef,
fire_emis => 0,
megan => "default",
res => "default",
silent => 0,
ignore_warnings => 0,
mask => "default",
test => 0,
bgc => "default",
crop => 0,
dynamic_vegetation => 0,
envxml_dir => ".",
vichydro => 0,
maxpft => "default",
);
GetOptions(
"cimeroot=s" => \$opts{'cimeroot'},
"driver=s" => \$opts{'driver'},
"clm_demand=s" => \$opts{'clm_demand'},
"co2_ppmv=f" => \$opts{'co2_ppmv'},
"co2_type=s" => \$opts{'co2_type'},
"config=s" => \$opts{'config'},
"configuration=s" => \$opts{'configuration'},
"csmdata=s" => \$opts{'csmdata'},
"clm_usr_name=s" => \$opts{'clm_usr_name'},
"envxml_dir=s" => \$opts{'envxml_dir'},
"drydep!" => \$opts{'drydep'},
"lilac!" => \$opts{'lilac'},
"fire_emis!" => \$opts{'fire_emis'},
"ignore_warnings!" => \$opts{'ignore_warnings'},
"chk_res!" => \$opts{'chk_res'},
"note!" => \$opts{'note'},
"megan!" => \$opts{'megan'},
"glc_nec=i" => \$opts{'glc_nec'},
"glc_use_antarctica!" => \$opts{'glc_use_antarctica'},
"light_res=s" => \$opts{'light_res'},
"d:s" => \$opts{'dir'},
"h|help" => \$opts{'help'},
"ignore_ic_date" => \$opts{'ignore_ic_date'},
"ignore_ic_year" => \$opts{'ignore_ic_year'},
"infile=s" => \$opts{'infile'},
"lnd_frac=s" => \$opts{'lnd_frac'},
"lnd_tuning_mode=s" => \$opts{'lnd_tuning_mode'},
"inputdata=s" => \$opts{'inputdata'},
"mask=s" => \$opts{'mask'},
"namelist=s" => \$opts{'namelist'},
"res=s" => \$opts{'res'},
"ssp_rcp=s" => \$opts{'ssp_rcp'},
"s|silent" => \$opts{'silent'},
"sim_year=s" => \$opts{'sim_year'},
"structure=s" => \$opts{'structure'},
"output_reals=s" => \$opts{'output_reals_filename'},
"clm_accelerated_spinup=s" => \$opts{'clm_accelerated_spinup'},
"clm_start_type=s" => \$opts{'clm_start_type'},
"test" => \$opts{'test'},
"use_case=s" => \$opts{'use_case'},
"bgc=s" => \$opts{'bgc'},
"crop!" => \$opts{'crop'},
"dynamic_vegetation" => \$opts{'dynamic_vegetation'},
"vichydro" => \$opts{'vichydro'},
"maxpft=i" => \$opts{'maxpft'},
"v|verbose" => \$opts{'verbose'},
"version" => \$opts{'version'},
) or usage();
# Give usage message.
usage() if $opts{'help'};
# Check for unparsed arguments
if (@ARGV) {
print "ERROR: unrecognized arguments: @ARGV\n";
usage();
}
return %opts;
}
#-------------------------------------------------------------------------------
sub check_for_perl_utils {
my $cfgdir = shift;
my $opts_ref = shift;
# Determine CIME root directory and perl5lib root directory
my $cimeroot = $opts_ref->{'cimeroot'};
if ( ! defined($cimeroot) ) {
$cimeroot = "$cfgdir/../cime";
if ( -d $cimeroot ) {
} elsif ( -d "$cfgdir/../../../cime" ) {
$cimeroot = "$cfgdir/../../../cime";
} else {
die <<"EOF";
** Cannot find the root of the cime directory enter it using the -cimeroot option
Did you run the checkout_externals scripts?
EOF
}
}
my $perl5lib_dir = "$cimeroot/utils/perl5lib";
#-----------------------------------------------------------------------------
# Add $perl5lib_dir to the list of paths that Perl searches for modules
my @dirs = ( $ProgDir, $cfgdir, "$perl5lib_dir");
unshift @INC, @dirs;
require config_files::clm_phys_vers;
require namelist_files::LogMessages;
my $locallog = namelist_files::LogMessages->new( $ProgName, $opts_ref );
# The XML::Lite module is required to parse the XML files.
(-f "$perl5lib_dir/XML/Lite.pm") or
$locallog->fatal_error("Cannot find perl module \"XML/Lite.pm\" in directory\n" .
"\"$perl5lib_dir\"");
# The Build::Config module provides utilities to access the configuration information
# in the config_cache.xml file
(-f "$perl5lib_dir/Build/Config.pm") or
$locallog->fatal_error("Cannot find perl module \"Build/Config.pm\" in directory\n" .
"\"$perl5lib_dir\"");
# The Build::NamelistDefinition module provides utilities to validate that the output
# namelists are consistent with the namelist definition file
(-f "$perl5lib_dir/Build/NamelistDefinition.pm") or
$locallog->fatal_error("Cannot find perl module \"Build/NamelistDefinition.pm\" in directory\n" .
"\"$perl5lib_dir\"");
# The Build::NamelistDefaults module provides a utility to obtain default values of namelist
# variables based on finding a best fit with the attributes specified in the defaults file.
(-f "$perl5lib_dir/Build/NamelistDefaults.pm") or
$locallog->fatal_error("Cannot find perl module \"Build/NamelistDefaults.pm\" in directory\n" .
"\"$perl5lib_dir\"");
# The Build::Namelist module provides utilities to parse input namelists, to query and modify
# namelists, and to write output namelists.
(-f "$perl5lib_dir/Build/Namelist.pm") or
$locallog->fatal_error("Cannot find perl module \"Build/Namelist.pm\" in directory\n" .
"\"$perl5lib_dir\"");
# required cesm perl modules
require XML::Lite;
require Build::Config;
require Build::NamelistDefinition;
require Build::NamelistDefaults;
require Build::Namelist;
require Config::SetupTools;
}
#-------------------------------------------------------------------------------
sub read_configure_definition {
# Read the configure definition and specific config_cache file for this case
# configure are the build-time settings for CLM
my ($cfgdir, $opts) = @_;
$log->verbose_message("Setting CLM configuration script directory to $cfgdir");
# Create a configuration object from the default config_definition file
my $configfile;
if ( -f $opts->{'config'} ) {
$configfile = $opts->{'config'};
} else {
$configfile = "$cfgdir/config_files/config_definition_ctsm.xml";
}
# Check that configuration cache file exists.
$log->verbose_message("Using CLM configuration cache file $opts->{'config'}");
if ( $configfile ne $opts->{'config'} ) {
$log->fatal_error("Cannot find configuration cache file: \"$opts->{'config'}\"");
}
my $cfg = Build::Config->new("$configfile");
return $cfg;
}
#-----------------------------------------------------------------------------------------------
sub read_namelist_definition {
my ($cfgdir, $opts, $nl_flags) = @_;
# The namelist definition file contains entries for all namelist
# variables that can be output by build-namelist.
my @nl_definition_files = ( "$cfgdir/namelist_files/namelist_definition_drv.xml",
"$cfgdir/namelist_files/namelist_definition_drv_flds.xml",
"$cfgdir/namelist_files/namelist_definition_ctsm.xml" );
foreach my $nl_defin_file ( @nl_definition_files ) {
(-f "$nl_defin_file") or $log->fatal_error("Cannot find namelist definition file \"$nl_defin_file\"");
$log->verbose_message("Using namelist definition file $nl_defin_file");
}
# Create a namelist definition object. This object provides a
# method for verifying that the output namelist variables are in the
# definition file, and are output in the correct namelist groups.
my $definition = Build::NamelistDefinition->new( shift(@nl_definition_files) );
foreach my $nl_defin_file ( @nl_definition_files ) {
$definition->add( "$nl_defin_file" );
}
return $definition;
}
#-----------------------------------------------------------------------------------------------
sub read_envxml_case_files {
# read the contents of the env*.xml files in the case directory
my ($opts) = @_;
my %envxml = ();
if ( defined($opts->{'envxml_dir'}) ) {
(-d $opts->{'envxml_dir'}) or $log->fatal_error( "envxml_dir is not a directory" );
my @files = bsd_glob( $opts->{'envxml_dir'}."/env_*xml" );
($#files >= 0) or $log->fatal_error( "there are no env_*xml files in the envxml_dir" );
foreach my $file (@files) {
$log->verbose_message( "Open env.xml file: $file" );
my $xml = XML::Lite->new( "$file" );
my @e = $xml->elements_by_name('entry');
while ( my $e = shift @e ) {
my %a = $e->get_attributes();
$envxml{$a{'id'}} = $a{'value'};
}
}
foreach my $attr (keys %envxml) {
if ( $envxml{$attr} =~ m/\$/ ) {
$envxml{$attr} = SetupTools::expand_xml_var( $envxml{$attr}, \%envxml );
}
}
} else {
$log->fatal_error( "The -envxml_dir option was NOT given and it is a REQUIRED option" );
}
return( %envxml );
}
#-----------------------------------------------------------------------------------------------
sub read_namelist_defaults {
my ($cfgdir, $opts, $nl_flags, $cfg) = @_;
# The namelist defaults file contains default values for all required namelist variables.
my @nl_defaults_files = ( "$cfgdir/namelist_files/namelist_defaults_overall.xml",
"$cfgdir/namelist_files/namelist_defaults_ctsm.xml",
"$cfgdir/namelist_files/namelist_defaults_drv.xml",
"$cfgdir/namelist_files/namelist_defaults_fire_emis.xml",
"$cfgdir/namelist_files/namelist_defaults_drydep.xml" );
# Add the location of the use case defaults files to the options hash
$opts->{'use_case_dir'} = "$cfgdir/namelist_files/use_cases";
if (defined $opts->{'use_case'}) {
if ( $opts->{'use_case'} ne "list" ) {
unshift( @nl_defaults_files, "$opts->{'use_case_dir'}/$opts->{'use_case'}.xml" );
}
}
foreach my $nl_defaults_file ( @nl_defaults_files ) {
(-f "$nl_defaults_file") or $log->fatal_error("Cannot find namelist defaults file \"$nl_defaults_file\"");
$log->verbose_message("Using namelist defaults file $nl_defaults_file");
}
# Create a namelist defaults object. This object provides default
# values for variables contained in the input defaults file. The
# configuration object provides attribute values that are relevent
# for the CLM executable for which the namelist is being produced.
my $defaults = Build::NamelistDefaults->new( shift( @nl_defaults_files ), $cfg);
foreach my $nl_defaults_file ( @nl_defaults_files ) {
$defaults->add( "$nl_defaults_file" );
}
return $defaults;
}
#-------------------------------------------------------------------------------
sub check_cesm_inputdata {
# Check that the CESM inputdata root directory has been specified. This must be
# a local or nfs mounted directory.
my ($opts, $nl_flags) = @_;
$nl_flags->{'inputdata_rootdir'} = undef;
if (defined($opts->{'csmdata'})) {
$nl_flags->{'inputdata_rootdir'} = $opts->{'csmdata'};
}
elsif (defined $ENV{'CSMDATA'}) {
$nl_flags->{'inputdata_rootdir'} = $ENV{'CSMDATA'};
}
else {
$log->fatal_error("CESM inputdata root directory must be specified by either -csmdata\n" .
"argument or by the CSMDATA environment variable.");
}
if ( ! defined($ENV{'DIN_LOC_ROOT'}) ) {
$ENV{'DIN_LOC_ROOT'} = $nl_flags->{'inputdata_rootdir'};
}
if ($opts->{'test'}) {
(-d $nl_flags->{'inputdata_rootdir'}) or $log->fatal_error("CESM inputdata root is not a directory: \"$nl_flags->{'inputdata_rootdir'}\"");
}
$log->verbose_message("CESM inputdata root directory: $nl_flags->{'inputdata_rootdir'}");
}
#-------------------------------------------------------------------------------
sub process_namelist_user_input {
# Process the user input in general by order of precedence. At each point
# we'll only add new values to the namelist and not overwrite
# previously specified specified values which have higher
# precedence. The one exception to this rule are the specifc command-line
# options which are done last as if the user contradicts these settings
# CLM build-namelist will abort with an error.
#
# 1. values set on the command-line using the -namelist option,
# (i.e. CLM_NAMELIST_OPTS env_run variable)
# 2. values read from the file(s) specified by -infile,
# (i.e. user_nl_clm files)
# After the above are done the command line options are processed and they
# are made sure the user hasn't contradicted any of their settings with
# anything above. Because of this they are condsidered to have the highest
# precedence.
# 0. namelist values set by specific command-line options, like, -d, -sim_year
# (i.e. CLM_BLDNML_OPTS env_run variable)
# The results of these are needed for the final two user input
# 3. datasets from the -clm_usr_name option,
# (i.e. CLM_USRDAT_NAME env_run variable)
# 4. values set from a use-case scenario, e.g., -use_case
# (i.e. CLM_NML_USE_CASE env_run variable)
#
# Finally after all the above is done, the defaults are found from the
# namelist defaults file (outside of this routine).
#
my ($opts, $nl_flags, $definition, $defaults, $nl, $cfg, $envxml_ref, $physv) = @_;
# Get the inputs that will be coming from the user...
process_namelist_commandline_namelist($opts, $definition, $nl, $envxml_ref);
process_namelist_commandline_infile($opts, $definition, $nl, $envxml_ref);
# Apply the commandline options and make sure the user didn't change it above
process_namelist_commandline_options($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref, $physv);
# The last two process command line arguments for usr_name and use_case
# They require that process_namelist_commandline_options was called before this
process_namelist_commandline_clm_usr_name($opts, $nl_flags, $definition, $defaults, $nl, $cfg, $envxml_ref);
process_namelist_commandline_use_case($opts, $nl_flags, $definition, $defaults, $nl, $cfg, $envxml_ref);
# Set the start_type by the command line setting for clm_start_type
process_namelist_commandline_clm_start_type($opts, $nl_flags, $definition, $defaults, $nl);
}
#-------------------------------------------------------------------------------
sub process_namelist_commandline_options {
# First process the commandline args that provide specific namelist values.
#
# First get the command-line specified overall values or their defaults
# Obtain default values for the following build-namelist input arguments
# : res, mask, ssp_rcp, sim_year, sim_year_range, and clm_accelerated_spinup.
my ($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref, $physv) = @_;
setup_cmdl_chk_res($opts, $defaults);
setup_cmdl_resolution($opts, $nl_flags, $definition, $defaults, $envxml_ref);
setup_cmdl_mask($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_configuration_and_structure($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_bgc($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_fire_light_res($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_spinup($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_crop($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_maxpft($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_glc_nec($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_ssp_rcp($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_simulation_year($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_dynamic_vegetation($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_fates_mode($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_vichydro($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_lnd_tuning($opts, $nl_flags, $definition, $defaults, $nl, $physv);
setup_cmdl_run_type($opts, $nl_flags, $definition, $defaults, $nl);
setup_cmdl_output_reals($opts, $nl_flags, $definition, $defaults, $nl);
}
#-------------------------------------------------------------------------------
sub setup_cmdl_chk_res {
my ($opts, $defaults) = @_;
my $var = "chk_res";
if ( ! defined($opts->{$var}) ) {
$opts->{$var} = $defaults->get_value($var);
}
}
sub setup_cmdl_resolution {
my ($opts, $nl_flags, $definition, $defaults, $envxml_ref) = @_;
my $var = "res";
my $val;
if ( $opts->{$var} ne "default" ) {
$val = $opts->{$var};
} else {
$val= $defaults->get_value($var);
}
$nl_flags->{'res'} = $val;
$log->verbose_message("CLM atm resolution is $nl_flags->{'res'}");
$opts->{$var} = $val;
if ( $opts->{'chk_res'} ) {
$val = &quote_string( $nl_flags->{'res'} );
if ( ! $definition->is_valid_value( $var, $val ) ) {
my @valid_values = $definition->get_valid_values( $var );
if ( $nl_flags->{'res'} ne "CLM_USRDAT" ) {
$log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values");
}
}
}
if ( $nl_flags->{'res'} eq "CLM_USRDAT" ) {
if ( ! defined($opts->{'clm_usr_name'}) ) {
$log->fatal_error("Resolution is CLM_USRDAT, but --clm_usr_name option is NOT set, and it is required for CLM_USRDAT resolutions");
}
}
#
# For NEON sites
#
$nl_flags->{'neon'} = ".false.";
$nl_flags->{'neonsite'} = "";
if ( $nl_flags->{'res'} eq "CLM_USRDAT" ) {
if ( $opts->{'clm_usr_name'} eq "NEON" ) {
$nl_flags->{'neon'} = ".true.";
$nl_flags->{'neonsite'} = $envxml_ref->{'NEONSITE'};
$log->verbose_message( "This is a NEON site with NEONSITE = " . $nl_flags->{'neonsite'} );
}
}
if ( ! &value_is_true( $nl_flags->{'neon'} ) ) {
$log->verbose_message( "This is NOT a NEON site" );
}
}
#-------------------------------------------------------------------------------
sub setup_cmdl_mask {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = "mask";
my $val;
if ( $opts->{$var} ne "default" ) {
$val = $opts->{$var};
} else {
my %tmp = ( 'hgrid'=>$nl_flags->{'res'} );
$val = $defaults->get_value($var, \%tmp );
}
$nl_flags->{'mask'} = $val;
$opts->{'mask'} = $nl_flags->{'mask'};
if ( $opts->{'chk_res'} ) {
$val = &quote_string( $val );
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");
}
}
$log->verbose_message("CLM land mask is $nl_flags->{'mask'}");
}
#-------------------------------------------------------------------------------
sub setup_cmdl_fates_mode {
#
# call this at least after crop check is called
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $val;
my $var = "bgc_mode";
if ( $nl_flags->{'crop'} eq "on" ) {
if ( $nl_flags->{$var} eq "fates" ) {
# FATES should not be used with crop
$log->fatal_error("** Cannot turn fates mode on with crop." );
}
} elsif ($nl_flags->{"bgc_mode"} eq "fates" && ! &value_is_true($nl_flags->{"use_fates"}) ) {
$log->fatal_error("DEV_ERROR: internal logic error: bgc_mode = fates and use_fates = false.");
} else {
$var = "use_fates";
if ( &value_is_true($nl_flags->{$var}) ) {
# This section is a place-holder to test for modules that are not allowed with FATES
# the defaults which are set in the logic section of the namelist builder will
# automatically set these correctly (well that is the assumption), but here we
# want to set a catch to fail and warn users if they explicitly set incompatible user namelist
# options
my $var = "use_crop";
$val = $nl_flags->{$var};
if ( defined($nl->get_value($var)) ) {
if ( &value_is_true($nl->get_value($var)) ) {
$log->fatal_error("$var was set to .true., which is incompatible when -bgc fates option is used.");
}
}
} 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","fates_history_dimlevel","fates_seeddisp_cadence",
"use_fates_luh","fluh_timeseries" );
# dis-allow fates specific namelist items with non-fates runs
foreach my $var ( @list ) {
if ( defined($nl->get_value($var)) ) {
$log->fatal_error("$var is being set, but can ONLY be set when -bgc fates option is used.\n");
}
}
}
}
}
#-------------------------------------------------------------------------------
sub setup_cmdl_configuration_and_structure {
# Error-check and set the 'configuration' and 'structure' namelist flags
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $val;
my $var = "configuration";
$val = $opts->{$var};
if (defined($val) && ($val eq "clm" || $val eq "nwp")) {
$nl_flags->{$var} = $val;
} else {
$log->fatal_error("$var has a value (".$val.") that is NOT valid. Valid values are: clm, nwp.");
}
$var = "structure";
$val = $opts->{$var};
if (defined($val) && ($val eq "standard" || $val eq "fast")) {
$nl_flags->{$var} = $val;
} else {
$log->fatal_error("$var has a value (".$val.") that is NOT valid. Valid values are: standard, fast.");
}
}
#-------------------------------------------------------------------------------
sub setup_cmdl_bgc {
# BGC - alias for group of biogeochemistry related use_XXX namelists
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $val;
my $var = "bgc";
$val = $opts->{$var};
$nl_flags->{'bgc_mode'} = $val;
my $var = "bgc_mode";
if ( $nl_flags->{$var} eq "default" ) {
$nl_flags->{$var} = $defaults->get_value($var);
}
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, quote_string( $nl_flags->{$var} ) );
if ( ! $definition->is_valid_value( $var, quote_string( $nl_flags->{$var}) ) ) {
my @valid_values = $definition->get_valid_values( $var );
$log->fatal_error("$var has a value (".$nl_flags->{$var}.") that is NOT valid. Valid values are: @valid_values");
}
$log->verbose_message("Using $nl_flags->{$var} for bgc.");
# now set the actual name list variables based on the bgc alias
if ($nl_flags->{$var} eq "bgc" ) {
$nl_flags->{'use_cn'} = ".true.";
$nl_flags->{'use_fates'} = ".false.";
} elsif ($nl_flags->{$var} eq "fates" ) {
$nl_flags->{'use_cn'} = ".false.";
$nl_flags->{'use_fates'} = ".true.";
} else {
$nl_flags->{'use_cn'} = ".false.";
$nl_flags->{'use_fates'} = ".false.";
}
if ( defined($nl->get_value("use_cn")) && ($nl_flags->{'use_cn'} ne $nl->get_value("use_cn")) ) {
$log->fatal_error("The namelist variable use_cn is inconsistent with the -bgc option");
}
if ( defined($nl->get_value("use_fates")) && ($nl_flags->{'use_fates'} ne $nl->get_value("use_fates")) ) {
$log->fatal_error("The namelist variable use_fates is inconsistent with the -bgc option");
}
# Now set use_cn and use_fates
foreach $var ( "use_cn", "use_fates" ) {
$val = $nl_flags->{$var};
$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");
}
}
#
# Set FATES-SP mode
#
if ( &value_is_true( $nl_flags->{'use_fates'} ) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_sp', 'use_fates'=>$nl_flags->{'use_fates'} );
if ( &value_is_true($nl->get_value('use_fates_sp')) ) {
$nl_flags->{'use_fates_sp'} = ".true.";
} else {
$nl_flags->{'use_fates_sp'} = ".false.";
}
} else {
$nl_flags->{'use_fates_sp'} = ".false.";
}
#
# Determine Soil decomposition method
#
my $var = "soil_decomp_method";
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, 'use_fates'=>$nl_flags->{'use_fates'},
'use_fates_sp'=>$nl_flags->{'use_fates_sp'} );
my $soil_decomp_method = remove_leading_and_trailing_quotes( $nl->get_value( $var ) );
if ( &value_is_true($nl_flags->{'use_cn'}) ) {
if ( $soil_decomp_method eq "None" ) {
$log->fatal_error("$var must NOT be None if use_cn is on");
}
} elsif ( &value_is_true($nl_flags->{'use_fates'}) && (not &value_is_true($nl_flags->{'use_fates_sp'})) ) {
if ( $soil_decomp_method eq "None" ) {
$log->fatal_error("$var must NOT be None if use_fates is on and use_fates_sp is not TRUE");
}
} elsif ( $soil_decomp_method ne "None" ) {
$log->fatal_error("$var must be None if use_cn and use_fates are off");
}
#
# Soil decomposition control variables, methane and Nitrification-Denitrification
#
my @list = ( "use_lch4", "use_nitrif_denitrif" );
my %settings = ( 'bgc_mode'=>$nl_flags->{'bgc_mode'} );
foreach my $var ( @list ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'phys'=>$nl_flags->{'phys'}, 'soil_decomp_method'=>$soil_decomp_method );
$nl_flags->{$var} = $nl->get_value($var);
}
if ( $soil_decomp_method eq "None" ) {
foreach my $var ( @list ) {
if ( &value_is_true($nl_flags->{$var}) ) {
$log->fatal_error("When soil_decomp_method is None $var can NOT be TRUE");
}
}
} else {
# nitrif_denitrif can only be .false. if fates is on
if ( (! &value_is_true($nl_flags->{'use_fates'})) && &value_is_true($nl_flags->{'use_cn'}) ) {
$var = "use_nitrif_denitrif";
if ( ! &value_is_true($nl_flags->{$var}) ) {
$log->warning("$var normally use_nitrif_denitrif should only be FALSE if FATES is on, it has NOT been validated for being off for BGC mode" );
}
}
# if MIMICS is on and use_fates = .true. then use_lch4 must = .true.
if ( (! &value_is_true($nl_flags->{'use_lch4'})) && &value_is_true($nl_flags->{'use_fates'}) ) {
if ( $soil_decomp_method eq "MIMICSWieder2015" ) {
$log->warning("If MIMICS is on and use_fates = .true. then use_lch4 must be .true. and currently it's not" );
}
}
}
#
# Set FUN for BGC
#
my $var = "use_fun";
if ( ! defined($nl->get_value($var)) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'},
'use_nitrif_denitrif'=>$nl_flags->{'use_nitrif_denitrif'} );
}
if ( (! &value_is_true($nl_flags->{'use_cn'}) ) && &value_is_true($nl->get_value('use_fun')) ) {
$log->fatal_error("When FUN is on, use_cn MUST also be on!");
}
if ( (! &value_is_true($nl_flags->{'use_nitrif_denitrif'}) ) && &value_is_true($nl->get_value('use_fun')) ) {
$log->fatal_error("When FUN is on, use_nitrif_denitrif MUST also be on!");
}
} # end bgc
#-------------------------------------------------------------------------------
sub setup_cmdl_fire_light_res {
# light_res - alias for lightning resolution
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = "light_res";
my $val = $opts->{$var};
if ( &value_is_true($nl->get_value('use_cn')) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fire_method');
}
my $fire_method = remove_leading_and_trailing_quotes( $nl->get_value('fire_method') );
if ( $val eq "default" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'},
'neon'=>$nl_flags->{'neon'},
'fates_spitfire_mode'=>$nl->get_value('fates_spitfire_mode'),
'use_fates'=>$nl_flags->{'use_fates'}, fire_method=>$fire_method );
$val = remove_leading_and_trailing_quotes( $nl->get_value($var) );
$nl_flags->{$var} = $val;
} else {
if ( defined($fire_method) && $val ne "none" ) {
if ( $fire_method eq "nofire" ) {
$log->fatal_error("-$var option used with fire_method='nofire'. -$var can ONLY be used without the nofire option");
}
}
my $stream_fldfilename_lightng = remove_leading_and_trailing_quotes( $nl->get_value('stream_fldfilename_lightng') );
if ( defined($stream_fldfilename_lightng) && $val ne "none" ) {
$log->fatal_error("-$var option used while also explicitly setting stream_fldfilename_lightng filename which is a contradiction. Use one or the other not both.");
}
if ( ! &value_is_true($nl->get_value('use_cn')) ) {
if ( &value_is_true($nl_flags->{'use_fates'}) ) {
if ( $nl->get_value('fates_spitfire_mode') < 2) {
if ( $val ne "none" ) {
$log->fatal_error("-$var option used when FATES is on, but fates_spitfire_mode does NOT use lightning data");
}
} else {
if ( $val eq "none" ) {
$log->fatal_error("-$var option is set to none, but FATES is on and fates_spitfire_mode requires lightning data");
}
}
} else {
$log->fatal_error("-$var option used when FATES off and CN is NOT on. -$var can only be used when BGC is set to bgc or fates");
}
} else {
if ( $val eq "none" and $fire_method ne "nofire" ) {
$log->fatal_error("-$var option is set to none, but CN is on (with bgc: cn or bgc) which is a contradiction");
}
}
$nl_flags->{$var} = $val;
}
# Check that NEON data is only used for NEON sites
if ( $val eq "106x174" ) {
if ( ! &value_is_true($nl_flags->{'neon'}) ) {
if ( defined($opts->{'clm_usr_name'}) ) {
$log->warning("The NEON lightning dataset does NOT cover the entire globe, make sure it covers the region for your grid");
} else {
$log->fatal_error("The NEON lightning dataset can NOT be used for global grids or regions or points outside of its area as it does NOT cover the entire globe.");
}
}
}
# check for valid values...
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, quote_string($nl_flags->{$var}) );
if ( ! $definition->is_valid_value( $var, $nl_flags->{$var}, 'noquotes'=>1 ) ) {
my @valid_values = $definition->get_valid_values( $var );
$log->fatal_error("$var has a value (".$nl_flags->{$var}.") that is NOT valid. Valid values are: @valid_values");
}
$log->verbose_message("Using $nl_flags->{$var} for $var.");
#
# Set flag if cn-fires are on or not, only for BGC (not FATES)
#
$var = "cnfireson";
my $fire_method = remove_leading_and_trailing_quotes( $nl->get_value('fire_method') );
if ( defined($fire_method) && ! &value_is_true($nl_flags->{'use_cn'}) && ! &value_is_true($nl_flags->{'use_fates'}) ) {
$log->fatal_error("fire_method is being set while use_cn and use_fates are both false.");
}
if ( defined($fire_method) && $fire_method eq "nofire" ) {
$nl_flags->{$var} = ".false.";
# } elsif ( &value_is_true($nl->get_value('use_cn')) || $nl_flags->{'fates_spitfire_mode'} > 1 ) {
} elsif ( &value_is_true($nl->get_value('use_cn')) || &value_is_true($nl->get_value('use_fates')) ) {
$nl_flags->{$var} = ".true.";
} else {
$nl_flags->{$var} = ".false.";
}
}
#-------------------------------------------------------------------------------
sub setup_cmdl_crop {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
$nl_flags->{'use_crop'} = ".false.";
my $val;
my $var = "crop";
$val = $opts->{$var};
$nl_flags->{'crop'} = $val;
if ( $nl_flags->{'crop'} eq 1 ) {
$nl_flags->{'use_crop'} = ".true.";
}
if ( defined($nl->get_value("use_crop")) && ($nl_flags->{'use_crop'} ne $nl->get_value("use_crop")) ) {
$log->fatal_error("Namelist item use_crop contradicts the command-line option -crop, use the command line option");
}
if ( ($nl_flags->{'crop'} eq 1 ) && ($nl_flags->{'bgc_mode'} eq "sp") ) {
$log->fatal_error("** Cannot turn crop mode on mode bgc=sp\n" .
"**\n" .
"** Set the bgc mode to 'bgc' by the following means from highest to lowest precedence:\n" .
"** * by the command-line options -bgc bgc\n" .
"** * by a default configuration file, specified by -defaults");
}
$var = "use_crop";
$val = ".false.";
if ($nl_flags->{'crop'} eq 1) {
$val = ".true.";
}
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");
}
}
#-------------------------------------------------------------------------------
sub setup_cmdl_maxpft {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $val;
my $var = "maxpft";
my %maxpatchpft;
$maxpatchpft{'.true.'} = 79;
$maxpatchpft{'.false.'} = 17;
if ( $opts->{$var} ne "default") {
$val = $opts->{$var};
} else {
$val = $maxpatchpft{$nl_flags->{'use_crop'}};
}
$nl_flags->{'maxpft'} = $val;
}
#-------------------------------------------------------------------------------
sub setup_cmdl_glc_nec {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $val;
my $var = "glc_nec";
if ( $opts->{$var} ne "default" ) {
$val = $opts->{$var};
} else {
$val = $defaults->get_value($var);
}
$nl_flags->{'glc_nec'} = $val;
$opts->{'glc_nec'} = $val;
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");
}
$log->verbose_message("Glacier number of elevation classes is $val");
}
#-------------------------------------------------------------------------------
sub setup_cmdl_ssp_rcp {
# shared socioeconmic pathway and representative concentration pathway combination
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $val;
my $var = "ssp_rcp";
if ( $opts->{$var} ne "default" ) {
$val = $opts->{$var};
} else {
$val = remove_leading_and_trailing_quotes( $defaults->get_value($var) );
}
$nl_flags->{'ssp_rcp'} = $val;
$opts->{'ssp_rcp'} = $nl_flags->{'ssp_rcp'};
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, quote_string($val) );
if ( ! $definition->is_valid_value( $var, $val, 'noquotes'=>1 ) ) {
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");
}
$log->verbose_message("CLM future scenario SSP-RCP combination is $nl_flags->{'ssp_rcp'}");
}
#-------------------------------------------------------------------------------
sub setup_cmdl_spinup {
# BGC spinup mode controlled from "clm_accelerated_spinup" in build-namelist
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $val;
my $var;
$nl_flags->{'spinup'} = undef;
$var = "clm_accelerated_spinup";
if ( $opts->{$var} ne "default" ) {
$val = $opts->{$var};
} else {
$val = $defaults->get_value($var);
}
$nl_flags->{$var} = $val;
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, quote_string($val) );
if ( ! $definition->is_valid_value( $var, $val , 'noquotes' => 1) ) {
my @valid_values = $definition->get_valid_values( $var );
$log->fatal_error("$var has an invalid value ($val). Valid values are: @valid_values");
}
$log->verbose_message("CLM accelerated spinup mode is $val");
if ( &value_is_true($nl_flags->{'use_cn'}) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition,
$defaults, $nl, "spinup_state", clm_accelerated_spinup=>$nl_flags->{$var},
use_cn=>$nl_flags->{'use_cn'}, use_fates=>$nl_flags->{'use_fates'} );
if ( $nl->get_value("spinup_state") ne 0 ) {
$nl_flags->{'bgc_spinup'} = "on";
if ( $nl_flags->{'clm_accelerated_spinup'} eq "off" ) {
$log->fatal_error("spinup_state is accelerated, but clm_accelerated_spinup is off, change one or the other");
}
} else {
$nl_flags->{'bgc_spinup'} = "off";
$val = $defaults->get_value($var);
}
# For AD spinup mode by default reseed dead plants
if ( $nl_flags->{$var} ne "off" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition,
$defaults, $nl, "reseed_dead_plants", clm_accelerated_spinup=>$nl_flags->{$var},
use_cn=>$nl_flags->{'use_cn'} );
}
} else {
if ( defined($nl->get_value("spinup_state")) ) {
$log->fatal_error("spinup_state is accelerated (=1 or 2) which is for a BGC mode of CN or BGC," .
" but the BGC mode is Satellite Phenology, change one or the other");
}
}
$nl_flags->{$var} = $val;
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, quote_string($val) );
if ( ! $definition->is_valid_value( $var, $val , 'noquotes' => 1) ) {
my @valid_values = $definition->get_valid_values( $var );
$log->fatal_error("$var has an invalid value ($val). Valid values are: @valid_values");
}
if ( $nl_flags->{'bgc_spinup'} eq "on" && (not &value_is_true( $nl_flags->{'use_cn'} )) && (not &value_is_true($nl_flags->{'use_fates'})) ) {
$log->fatal_error("$var can not be '$nl_flags->{'bgc_spinup'}' if neither CN nor FATES is turned on (use_cn=$nl_flags->{'use_cn'}, use_fates=$nl_flags->{'use_fates'}).");
}
if ( $nl->get_value("spinup_state") eq 0 && $nl_flags->{'bgc_spinup'} eq "on" ) {
$log->fatal_error("Namelist spinup_state contradicts the command line option bgc_spinup" );
}
if ( $nl->get_value("spinup_state") eq 1 && $nl_flags->{'bgc_spinup'} eq "off" ) {
$log->fatal_error("Namelist spinup_state contradicts the command line option bgc_spinup" );
}
$val = $nl_flags->{'bgc_spinup'};
$log->verbose_message("CLM CN bgc_spinup mode is $val");
}
#-------------------------------------------------------------------------------
sub setup_cmdl_simulation_year {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $val;
my $var = "sim_year";
if ( $opts->{$var} ne "default" ) {
$val = $opts->{$var};
} else {
$val = $defaults->get_value($var);
}
$nl_flags->{'sim_year_range'} = $defaults->get_value("sim_year_range");
$nl_flags->{'sim_year'} = &remove_leading_and_trailing_quotes($val);
if ( $val =~ /([0-9]+)-([0-9]+)/ ) {
$nl_flags->{'sim_year'} = $1;
$nl_flags->{'sim_year_range'} = $val;
}
$val = $nl_flags->{'sim_year'};
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, "'$val'" );
if ( ! $definition->is_valid_value( $var, $val, 'noquotes'=>1 ) ) {
my @valid_values = $definition->get_valid_values( $var );
$log->fatal_error("$var of $val is NOT valid. Valid values are: @valid_values");
}
$nl->set_variable_value($group, $var, "'$val'" );
$log->verbose_message("CLM sim_year is $nl_flags->{'sim_year'}");
$var = "sim_year_range";
$val = $nl_flags->{'sim_year_range'};
if ( $val ne "constant" ) {
$opts->{$var} = $val;
$group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, $val );
if ( ! $definition->is_valid_value( $var, $val, 'noquotes'=>1 ) ) {
my @valid_values = $definition->get_valid_values( $var );
$log->fatal_error("$var of $val is NOT valid. Valid values are: @valid_values");
}
$val = "'".$defaults->get_value($var)."'";
$nl->set_variable_value($group, $var, $val );
$log->verbose_message("CLM sim_year_range is $nl_flags->{'sim_year_range'}");
}
}
#-------------------------------------------------------------------------------
sub setup_cmdl_run_type {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
# Set the clm_start_type and the st_year, start year
# This MUST be done after lnd_tuning_mode is set
my $val;
my $var = "clm_start_type";
my $ic_date = $nl->get_value('start_ymd');
my $st_year;
if ( defined($ic_date) ) {
$st_year = int( $ic_date / 10000);
} else {
$st_year = $nl_flags->{'sim_year'};
$ic_date = $st_year *10000 + 101;
my $date = 'start_ymd';
my $group = $definition->get_group_name($date);
$nl->set_variable_value($group, $date, $ic_date );
}
my $set = undef;
if (defined $opts->{$var}) {
if ($opts->{$var} ne "default" ) {
$set = 1;
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, quote_string( $opts->{$var} ) );
}
}
if ( ! defined $set ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'use_cndv'=>$nl_flags->{'use_cndv'}, 'use_fates'=>$nl_flags->{'use_fates'},
'sim_year'=>$st_year, 'sim_year_range'=>$nl_flags->{'sim_year_range'},
'bgc_spinup'=>$nl_flags->{'bgc_spinup'}, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'} );
}
$nl_flags->{'clm_start_type'} = $nl->get_value($var);
$nl_flags->{'st_year'} = $st_year;
}
#-------------------------------------------------------------------------------
sub setup_cmdl_dynamic_vegetation {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $val;
my $var = "dynamic_vegetation";
$val = $opts->{$var};
$nl_flags->{'dynamic_vegetation'} = $val;
if ( ($nl_flags->{'dynamic_vegetation'} eq 1 ) && ($nl_flags->{'bgc_mode'} eq "sp") ) {
$log->fatal_error("** Cannot turn dynamic_vegetation mode on with bgc=sp.\n" .
"**\n" .
"** Set the bgc mode to 'bgc' by the following means from highest to lowest precedence:" .
"** * by the command-line options -bgc bgc\n");
}
$var = "use_cndv";
$nl_flags->{$var} = ".false.";
if ($nl_flags->{'dynamic_vegetation'} eq 1) {
$val = ".true.";
$nl_flags->{$var} = $val;
}
if ( defined($nl->get_value($var)) && $nl->get_value($var) ne $val ) {
$log->fatal_error("$var is inconsistent with the commandline setting of -dynamic_vegetation");
}
if ( &value_is_true($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");
}
$log->warning("The use_cndv=T option is deprecated. We do NOT recommend using it." .
" It's known to have issues and it's not calibrated.");
}
}
#-------------------------------------------------------------------------------
sub setup_cmdl_output_reals {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = "output_reals_filename";
my $file = $opts->{$var};
if ( defined($file) ) {
# Make sure can open file and if not die with an error
my $fh = IO::File->new($file, '>') or $log->fatal_error("can't create real parameter filename: $file");
$fh->close();
}
}
#-------------------------------------------------------------------------------
sub setup_cmdl_vichydro {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $val;
my $var = "vichydro";
$val = $opts->{$var};
$nl_flags->{'vichydro'} = $val;
if ($nl_flags->{'vichydro'} eq 1) {
$log->verbose_message("Using VIC hydrology for runoff calculations.");
}
$var = "use_vichydro";
$val = $nl->get_value($var);
my $set = undef;
if ($nl_flags->{'vichydro'} eq 1) {
my $group = $definition->get_group_name($var);
$set = ".true.";
if ( defined($val) && $set ne $val ) {
$log->fatal_error("$var contradicts the command-line -vichydro option" );
}
$nl->set_variable_value($group, $var, $set);
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 {
$set = ".false.";
}
$nl_flags->{$var} = $set;
}
#-------------------------------------------------------------------------------
sub process_namelist_commandline_namelist {
# Process the commandline '-namelist' arg.
my ($opts, $definition, $nl, $envxml_ref) = @_;
if (defined $opts->{'namelist'}) {
# Parse commandline namelist
my $nl_arg = Build::Namelist->new($opts->{'namelist'});
# Validate input namelist -- trap exceptions
my $nl_arg_valid;
eval { $nl_arg_valid = $definition->validate($nl_arg); };
if ($@) {
$log->fatal_error("Invalid namelist variable in commandline arg '-namelist'.\n $@");
}
# Go through all variables and expand any XML env settings in them
expand_xml_variables_in_namelist( $nl_arg_valid, $envxml_ref );
# Merge input values into namelist. Previously specified values have higher precedence
# and are not overwritten.
$nl->merge_nl($nl_arg_valid);
}
}
#-------------------------------------------------------------------------------
sub process_namelist_commandline_infile {
# Process the commandline '-infile' arg.
my ($opts, $definition, $nl, $envxml_ref) = @_;
if (defined $opts->{'infile'}) {
my @infiles = split( /,/, $opts->{'infile'} );
foreach my $infile ( @infiles ) {
# Make sure a valid file was found
if ( -f "$infile" ) {
# Otherwise abort as a valid file doesn't exist
} else {
$log->fatal_error("input namelist file does NOT exist $infile.\n $@");
}
# Parse namelist input from the next file
my $nl_infile = Build::Namelist->new($infile);
# Validate input namelist -- trap exceptions
my $nl_infile_valid;
eval { $nl_infile_valid = $definition->validate($nl_infile); };
if ($@) {
$log->fatal_error("Invalid namelist variable in '-infile' $infile.\n $@");
}
# Go through all variables and expand any XML env settings in them
expand_xml_variables_in_namelist( $nl_infile_valid, $envxml_ref );
# Merge input values into namelist. Previously specified values have higher precedence
# and are not overwritten.
$nl->merge_nl($nl_infile_valid);
}
}
}
#-------------------------------------------------------------------------------
sub process_namelist_commandline_clm_usr_name {
# Process the -clm_usr_name argument
my ($opts, $nl_flags, $definition, $defaults, $nl, $cfg, $envxml_ref) = @_;
if (defined $opts->{'clm_usr_name'}) {
# The user files definition is contained in an xml file with the same format as the defaults file.
# The one difference is that variables are expanded.
# Create a new NamelistDefaults object.
my $nl_defaults_file = "$nl_flags->{'cfgdir'}/namelist_files/namelist_defaults_usr_files.xml";
my $uf_defaults = Build::NamelistDefaults->new("$nl_defaults_file", $cfg );
# Loop over the variables specified in the user files
# Add each one to the namelist.
my @vars = $uf_defaults->get_variable_names();
my %settings;
$settings{'mask'} = $nl_flags->{'mask'};
$settings{'sim_year'} = $nl_flags->{'sim_year'};
$settings{'ssp_rcp'} = $nl_flags->{'ssp_rcp'};
$settings{'sim_year_range'} = $nl_flags->{'sim_year_range'};
$settings{'clm_accelerated_spinup'} = $nl_flags->{'clm_accelerated_spinup'};
$settings{'clm_usr_name'} = $opts->{'clm_usr_name'};
if ( $nl_flags->{'inputdata_rootdir'} eq "\$DIN_LOC_ROOT" ) {
$settings{'csmdata'} = $ENV{'DIN_LOC_ROOT'};
} else {
$settings{'csmdata'} = $nl_flags->{'inputdata_rootdir'};
}
my $nvars = 0;
my $nl_usrfile = Build::Namelist->new();
foreach my $var (@vars) {
my $val = $uf_defaults->get_usr_file($var, $definition, \%settings);
if ($val) {
$log->message("adding clm user file defaults for var $var with val $val");
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl_usrfile, $var, 'val'=>$val);
$nvars++;
}
}
# Go through all variables and expand any XML env settings in them
expand_xml_variables_in_namelist( $nl_usrfile, $envxml_ref );
# Merge input values into namelist. Previously specified values have higher precedence
# and are not overwritten.
$nl->merge_nl($nl_usrfile);
}
}
#-------------------------------------------------------------------------------
sub process_namelist_commandline_use_case {
# Now process the -use_case arg.
my ($opts, $nl_flags, $definition, $defaults, $nl, $cfg, $envxml_ref) = @_;
if (defined $opts->{'use_case'}) {
# The use case definition is contained in an xml file with the same format as the defaults file.
# Create a new NamelistDefaults object.
my $uc_defaults = Build::NamelistDefaults->new("$opts->{'use_case_dir'}/$opts->{'use_case'}.xml", $cfg);
my %settings;
$settings{'res'} = $nl_flags->{'res'};
$settings{'ssp_rcp'} = $nl_flags->{'ssp_rcp'};
$settings{'mask'} = $nl_flags->{'mask'};
$settings{'sim_year'} = $nl_flags->{'sim_year'};
$settings{'sim_year_range'} = $nl_flags->{'sim_year_range'};
$settings{'phys'} = $nl_flags->{'phys'};
$settings{'lnd_tuning_mode'}= $nl_flags->{'lnd_tuning_mode'};
$settings{'use_cn'} = $nl_flags->{'use_cn'};
$settings{'use_cndv'} = $nl_flags->{'use_cndv'};
$settings{'use_crop'} = $nl_flags->{'use_crop'};
$settings{'cnfireson'} = $nl_flags->{'cnfireson'};
# Loop over the variables specified in the use case.
# Add each one to the namelist.
my @vars = $uc_defaults->get_variable_names();
my $nl_usecase = Build::Namelist->new();
foreach my $var (@vars) {
my $val = $uc_defaults->get_value($var, \%settings );
if ( defined($val) ) {
$log->verbose_message("CLM adding use_case $opts->{'use_case'} defaults for var '$var' with val '$val'");
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl_usecase, $var, 'val'=>$val);
}
}
# Go through all variables and expand any XML env settings in them
expand_xml_variables_in_namelist( $nl_usecase, $envxml_ref );
# Merge input values into namelist. Previously specified values have higher precedence
# and are not overwritten.
$nl->merge_nl($nl_usecase);
}
}
#-------------------------------------------------------------------------------
sub process_namelist_commandline_clm_start_type {
# Set the start_type according to the command line clm_start_type option
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
# Run type for driver namelist - note that arb_ic implies that the run is startup
my $var = "start_type";
if ($nl_flags->{'clm_start_type'} eq "'cold'" || $nl_flags->{'clm_start_type'} eq "'arb_ic'") {
# Add default is used here, but the value is explicitly set
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>'startup' );
} else {
# Add default is used here, but the value is explicitly set
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>$nl_flags->{'clm_start_type'} );
}
}
#-------------------------------------------------------------------------------
sub process_namelist_inline_logic {
# Use the namelist default object to add default values for required
# namelist variables that have not been previously set.
my ($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref, $physv) = @_;
##############################
# namelist group: clm_inparm #
##############################
setup_logic_site_specific($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_lnd_frac($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref);
setup_logic_co2_type($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_irrigate($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_start_type($opts, $nl_flags, $nl);
setup_logic_decomp_performance($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_roughness_methods($opts, $nl_flags, $definition, $defaults, $nl, $physv);
setup_logic_snicar_methods($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_snow($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_glacier($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref);
setup_logic_dynamic_plant_nitrogen_alloc($opts, $nl_flags, $definition, $defaults, $nl, $physv);
setup_logic_luna($opts, $nl_flags, $definition, $defaults, $nl, $physv);
setup_logic_hillslope($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_o3_veg_stress_method($opts, $nl_flags, $definition, $defaults, $nl,$physv);
setup_logic_hydrstress($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_dynamic_roots($opts, $nl_flags, $definition, $defaults, $nl, $physv);
setup_logic_params_file($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_create_crop_landunit($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_subgrid($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_fertilizer($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_grainproduct($opts, $nl_flags, $definition, $defaults, $nl, $physv);
setup_logic_soilstate($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_demand($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_surface_dataset($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref);
setup_logic_dynamic_subgrid($opts, $nl_flags, $definition, $defaults, $nl);
if ( remove_leading_and_trailing_quotes($nl_flags->{'clm_start_type'}) ne "branch" ) {
setup_logic_initial_conditions($opts, $nl_flags, $definition, $defaults, $nl, $physv);
}
setup_logic_spinup($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_supplemental_nitrogen($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_snowpack($opts, $nl_flags, $definition, $defaults, $nl);
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);
#########################################
# namelist group: atm2lnd_inparm
#########################################
setup_logic_atm_forcing($opts, $nl_flags, $definition, $defaults, $nl);
#########################################
# namelist group: lnd2atm_inparm
#########################################
setup_logic_lnd2atm($opts, $nl_flags, $definition, $defaults, $nl);
#########################################
# namelist group: clm_humanindex_inparm #
#########################################
setup_logic_humanindex($opts, $nl_flags, $definition, $defaults, $nl);
#################################
# namelist group: cnfire_inparm #
#################################
setup_logic_cnfire($opts, $nl_flags, $definition, $defaults, $nl);
######################################
# namelist group: cnprecision_inparm #
######################################
setup_logic_cnprec($opts, $nl_flags, $definition, $defaults, $nl);
###############################
# namelist group: clmu_inparm #
###############################
setup_logic_urban($opts, $nl_flags, $definition, $defaults, $nl);
###############################
# namelist group: crop_inparm #
###############################
setup_logic_crop_inparm($opts, $nl_flags, $definition, $defaults, $nl);
###############################
# namelist group: tillage #
###############################
setup_logic_tillage($opts, $nl_flags, $definition, $defaults, $nl, $physv);
###############################
# namelist group: ch4par_in #
###############################
setup_logic_methane($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_c_isotope($opts, $nl_flags, $definition, $defaults, $nl);
###############################
# namelist group: ndepdyn_nml #
###############################
setup_logic_nitrogen_deposition($opts, $nl_flags, $definition, $defaults, $nl);
##################################
# namelist group: cnmresp_inparm #
##################################
setup_logic_cnmresp($opts, $nl_flags, $definition, $defaults, $nl);
#################################
# namelist group: nitrif_inparm #
#################################
setup_logic_nitrif_params( $nl_flags, $definition, $defaults, $nl );
#############################################
# namelist group: mineral_nitrogen_dynamics #
#############################################
setup_logic_mineral_nitrogen_dynamics( $opts, $nl_flags, $definition, $defaults, $nl );
####################################
# namelist group: photosyns_inparm #
####################################
setup_logic_photosyns($opts, $nl_flags, $definition, $defaults, $nl);
#################################
# namelist group: popd_streams #
#################################
setup_logic_popd_streams($opts, $nl_flags, $definition, $defaults, $nl);
####################################
# namelist group: urbantv_streams #
####################################
setup_logic_urbantv_streams($opts, $nl_flags, $definition, $defaults, $nl);
##################################
# namelist group: light_streams #
##################################
setup_logic_lightning_streams($opts, $nl_flags, $definition, $defaults, $nl);
#################################
# namelist group: drydep_inparm #
#################################
setup_logic_dry_deposition($opts, $nl_flags, $definition, $defaults, $nl);
#################################
# namelist group: fire_emis_nl #
#################################
setup_logic_fire_emis($opts, $nl_flags, $definition, $defaults, $nl);
######################################
# namelist options for dust emissions
######################################
setup_logic_dust_emis($opts, $nl_flags, $definition, $defaults, $nl);
#################################
# namelist group: megan_emis_nl #
#################################
setup_logic_megan($opts, $nl_flags, $definition, $defaults, $nl);
##################################
# namelist group: lai_streams #
##################################
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 #
##########################################
setup_logic_soilm_streams($opts, $nl_flags, $definition, $defaults, $nl, $physv);
##################################
# namelist group: bgc_shared
##################################
setup_logic_bgc_shared($opts, $nl_flags, $definition, $defaults, $nl, $physv);
##################################
# namelist group: cnphenology
##################################
setup_logic_cnphenology($opts, $nl_flags, $definition, $defaults, $nl, $physv);
#############################################
# namelist group: soilwater_movement_inparm #
#############################################
setup_logic_soilwater_movement($opts, $nl_flags, $definition, $defaults, $nl);
#############################################
# namelist group: rooting_profile_inparm #
#############################################
setup_logic_rooting_profile($opts, $nl_flags, $definition, $defaults, $nl);
#############################
# namelist group: cngeneral #
#############################
setup_logic_cngeneral($opts, $nl_flags, $definition, $defaults, $nl);
####################################
# namelist group: cnvegcarbonstate #
####################################
setup_logic_cnvegcarbonstate($opts, $nl_flags, $definition, $defaults, $nl);
#############################################
# namelist group: soil_resis_inparm #
#############################################
setup_logic_soil_resis($opts, $nl_flags, $definition, $defaults, $nl);
#############################################
# namelist group: canopyfluxes_inparm #
#############################################
setup_logic_canopyfluxes($opts, $nl_flags, $definition, $defaults, $nl);
##########################################################
# namelist group: friction_velocity (after canopyfluxes) #
##########################################################
setup_logic_friction_vel($opts, $nl_flags, $definition, $defaults, $nl);
#############################################
# namelist group: canopyhydrology_inparm #
#############################################
setup_logic_canopyhydrology($opts, $nl_flags, $definition, $defaults, $nl);
#####################################
# namelist group: clm_canopy_inparm #
#####################################
setup_logic_canopy($opts, $nl_flags, $definition, $defaults, $nl);
########################################
# namelist group: soilhydrology_inparm #
########################################
setup_logic_hydrology_params($opts, $nl_flags, $definition, $defaults, $nl);
#####################################
# namelist group: irrigation_inparm #
#####################################
setup_logic_irrigation_parameters($opts, $nl_flags, $definition, $defaults, $nl);
########################################
# namelist group: surfacealbedo_inparm #
########################################
setup_logic_surfacealbedo($opts, $nl_flags, $definition, $defaults, $nl);
########################################
# namelist group: water_tracers_inparm #
########################################
setup_logic_water_tracers($opts, $nl_flags, $definition, $defaults, $nl);
#######################################################################
# namelist groups: clm_hydrology1_inparm and clm_soilhydrology_inparm #
#######################################################################
setup_logic_hydrology_switches($opts, $nl_flags, $definition, $defaults, $nl);
#######################################################################
# namelist group: scf_swenson_lawrence_2012_inparm #
#######################################################################
setup_logic_scf_SwensonLawrence2012($opts, $nl_flags, $definition, $defaults, $nl);
#########################################
# 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);
}
#-------------------------------------------------------------------------------
sub setup_logic_site_specific {
# site specific requirements
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
# res check prevents polluting the namelist with an unnecessary
# false variable for every run
if ($nl_flags->{'res'} eq "1x1_vancouverCAN") {
my $var = "use_vancouver";
my $val = ".true.";
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, $val);
}
# res check prevents polluting the namelist with an unnecessary
# false variable for every run
if ($nl_flags->{'res'} eq "1x1_mexicocityMEX") {
my $var = "use_mexicocity";
my $val = ".true.";
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, $val);
}
if ($nl_flags->{'res'} eq "1x1_smallvilleIA") {
if (! &value_is_true($nl_flags->{'use_cn'}) || ! &value_is_true($nl_flags->{'use_crop'})) {
$log->fatal_error("1x1_smallvilleIA grids must use a compset with CN and CROP turned on.");
}
}
if ($nl_flags->{'res'} eq "1x1_numaIA") {
if (! &value_is_true($nl_flags->{'use_cn'}) || ! &value_is_true($nl_flags->{'use_crop'})) {
$log->fatal_error("1x1_numaIA grids must use a compset with CN and CROP turned on.");
}
}
# Set compname
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'compname',
'phys'=>$nl_flags->{'phys'} );
}
#-------------------------------------------------------------------------------
sub setup_logic_lnd_tuning {
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
my $var = "lnd_tuning_mode";
if ( $opts->{$var} eq "default" ) {
my %settings;
$settings{'phys'} = $nl_flags->{'phys'};
$nl_flags->{$var} = $defaults->get_value($var, \%settings );
} else {
$nl_flags->{$var} = $opts->{$var};
}
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, quote_string( $nl_flags->{$var} ) );
if ( ! $definition->is_valid_value( $var, quote_string( $nl_flags->{$var}) ) ) {
my @valid_values = $definition->get_valid_values( $var );
$log->fatal_error("$var has a value (".$nl_flags->{$var}.") that is NOT valid. Valid values are: @valid_values");
}
$log->verbose_message("Using $nl_flags->{$var} for lnd_tuning_mode");
my $phys = $physv->as_string();
if ( $nl_flags->{$var} !~ /^${phys}_/ ) {
$log->fatal_error("First part of lnd_tuning_mode MUST match the CLM version you are using.");
}
}
#-------------------------------------------------------------------------------
sub setup_logic_lnd_frac {
my ($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref) = @_;
#
# fatmlndfrc is required for the MCT driver (or LILAC), but uneeded for NUOPC
#
my $var = "lnd_frac";
if ( ($opts->{'driver'} eq "mct") || $opts->{'lilac'} ) {
if ( defined($opts->{$var}) ) {
if ( defined($nl->get_value('fatmlndfrc')) ) {
$log->fatal_error("Can NOT set both -lnd_frac option (set via LND_DOMAIN_PATH/LND_DOMAIN_FILE " .
"env variables) AND fatmlndfrac on namelist");
}
if ( $opts->{$var} =~ /UNSET/ ) {
$log->fatal_error("-lnd_frac was set as UNSET in the CTSM build-namelist set it with the env variables: LND_DOMAIN_PATH/LND_DOMAIN_FILE.");
}
my $lnd_frac = SetupTools::expand_xml_var( $opts->{$var}, $envxml_ref);
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fatmlndfrc','val'=>$lnd_frac );
}
# Get the fraction file
if (defined $nl->get_value('fatmlndfrc')) {
# do nothing - use value provided by config_grid.xml and clm.cpl7.template
} else {
$log->fatal_error("fatmlndfrc was NOT sent into CLM build-namelist.");
}
#
# For the NUOPC driver neither lnd_frac nor fatmlndfrc need to be set
#
} else {
if ( defined($opts->{$var}) ) {
if ( $opts->{$var} !~ /UNSET/ ) {
$log->fatal_error("$var should NOT be set for the NUOPC driver as it is unused" );
}
}
if ( defined($nl->get_value('fatmlndfrc')) ) {
$log->fatal_error("fatmlndfrac should NOT be set in the namelist for the NUOPC driver as it is unused" );
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_co2_type {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = "co2_type";
if ( defined($opts->{$var}) ) {
if ( ! defined($nl->get_value($var)) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'co2_type','val'=>"$opts->{'co2_type'}");
} else {
$log->fatal_error("co2_type set on namelist as well as -co2_type option.");
}
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'co2_type');
if ( $nl->get_value('co2_type') =~ /constant/ ) {
my $var = 'co2_ppmv';
if ( defined($opts->{$var}) ) {
if ( $opts->{$var} <= 0.0 ) {
$log->fatal_error("co2_ppmv can NOT be less than or equal to zero.");
}
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, $opts->{$var});
} else {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'sim_year'=>$nl_flags->{'sim_year'},
'ssp_rcp'=>$nl_flags->{'ssp_rcp'} );
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_irrigate {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'irrigate',
'use_crop'=>$nl_flags->{'use_crop'}, 'use_cndv'=>$nl_flags->{'use_cndv'},
'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, );
if ( &value_is_true($nl->get_value('irrigate') ) ) {
$nl_flags->{'irrigate'} = ".true.";
if ( $nl_flags->{'sim_year'} eq "PtVg" ) {
$log->fatal_error("irrigate=TRUE does NOT make sense with the Potential Vegetation dataset, leave irrigate=FALSE");
}
} else {
$nl_flags->{'irrigate'} = ".false.";
}
}
#-------------------------------------------------------------------------------
sub setup_logic_start_type {
my ($opts, $nl_flags, $nl) = @_;
my $var = "start_type";
my $drv_start_type = $nl->get_value($var);
my $my_start_type = $nl_flags->{'clm_start_type'};
if ( $my_start_type =~ /branch/ ) {
if (not defined $nl->get_value('nrevsn')) {
$log->fatal_error("nrevsn is required for a branch type.");
}
if (defined $nl->get_value('use_init_interp')) {
if ( &value_is_true($nl->get_value('use_init_interp') ) ) {
# Always print this warning, but don't stop if it happens
print "\nWARNING: use_init_interp will NOT happen for a branch case.\n\n";
}
}
} else {
if (defined $nl->get_value('nrevsn')) {
$log->fatal_error("nrevsn should ONLY be set for a branch type.");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_decomp_performance {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
# Set the number of segments per clump
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'nsegspc', 'hgrid'=>$nl_flags->{'res'});
}
#-------------------------------------------------------------------------------
sub setup_logic_roughness_methods {
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'z0param_method',
'phys'=>$nl_flags->{'phys'} );
my $var = remove_leading_and_trailing_quotes( $nl->get_value("z0param_method") );
if ( $var ne "Meier2022" && $var ne "ZengWang2007" ) {
$log->fatal_error("$var is incorrect entry for the namelist variable z0param_method; expected Meier2022 or ZengWang2007");
}
my $phys = $physv->as_string();
if ( $phys eq "clm4_5" || $phys eq "clm5_0" ) {
if ( $var eq "Meier2022" ) {
$log->fatal_error("z0param_method = $var and phys = $phys, but this method has been tested only with clm5_1 and later versions; to use with earlier versions, disable this error, and add Meier2022 parameters to the corresponding params file");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_snicar_methods {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snicar_snw_shape' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snicar_solarspec' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snicar_dust_optics' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snicar_numrad_snw' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snicar_snobc_intmix' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snicar_snodst_intmix' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snicar_use_aerosol' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_snicar_frc' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'do_sno_oc' );
# Error checking in loop
my %supportedSettings = ( 'snicar_solarspec' => "'mid_latitude_winter'", 'snicar_dust_optics' => "'sahara'", 'snicar_numrad_snw' => '5', 'snicar_snodst_intmix' => '.false.', 'snicar_use_aerosol' => '.true.', 'do_sno_oc' => '.false.' );
keys %supportedSettings;
while ( my ($key, $val) = each %supportedSettings ) {
my $var = $nl->get_value($key);
if ( $var ne $val ) {
$log->warning("$key=$val is the supported option; $var is EXPERIMENTAL, UNSUPPORTED, and UNTESTED!");
}
}
# Error checking not in loop
my $key1 = 'snicar_snw_shape';
my $var1 = $nl->get_value($key1);
my $val1a = "'sphere'"; # supported value for this option
my $val1b = "'hexagonal_plate'"; # supported value for this option
if (($var1 ne $val1a) && ($var1 ne $val1b)) {
$log->warning("$key1=$val1a and $val1b are supported; $var1 is EXPERIMENTAL, UNSUPPORTED, and UNTESTED!");
}
# snicar_snobc_intmix and snicar_snodst_intmix cannot both be true, however, they can both be false
my $key1 = 'snicar_snobc_intmix';
my $key2 = 'snicar_snodst_intmix';
my $var1 = $nl->get_value($key1);
my $var2 = $nl->get_value($key2);
my $val2 = $supportedSettings{$key2}; # supported value for this option
if (($var1 eq $var2) && ($var2 ne $val2)) {
$log->warning("$key1 = $var1 and $key2 = $var2 do not work together!");
}
}
#-------------------------------------------------------------------------------
sub setup_logic_snow {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_thermal_cond_method' );
my $var = $nl->get_value('snow_thermal_cond_method');
if ( $var ne "'Jordan1991'" && $var ne "'Sturm1997'" ) {
$log->fatal_error("$var is incorrect entry for the namelist variable snow_thermal_cond_method; expected Jordan1991 or Sturm1997");
}
my $numrad_snw = $nl->get_value('snicar_numrad_snw');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fsnowoptics',
'snicar_numrad_snw' => $numrad_snw);
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fsnowaging' );
}
#-------------------------------------------------------------------------------
sub setup_logic_glacier {
#
# Glacier multiple elevation class options
#
my ($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref) = @_;
my $clm_upvar = "GLC_TWO_WAY_COUPLING";
# glc_do_dynglacier is set via GLC_TWO_WAY_COUPLING; it cannot be set via
# user_nl_clm (this is because we might eventually want the coupler and glc
# to also respond to GLC_TWO_WAY_COUPLING, by not bothering to send / map
# these fields - so we want to ensure that CLM is truly listening to this
# shared xml variable and not overriding it)
my $var = "glc_do_dynglacier";
my $val = logical_to_fortran($envxml_ref->{$clm_upvar});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>$val);
if (lc($nl->get_value($var)) ne lc($val)) {
$log->fatal_error("glc_do_dynglacier can only be set via the env variable $clm_upvar: it can NOT be set in user_nl_clm");
}
my $var = "maxpatch_glc";
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>$nl_flags->{'glc_nec'} );
my $val = $nl->get_value($var);
if ( $val != $nl_flags->{'glc_nec'} ) {
$log->fatal_error("$var set to $val does NOT agree with -glc_nec argument of $nl_flags->{'glc_nec'} (set with GLC_NEC env variable)");
}
if ( $nl_flags->{'glc_nec'} < 1 ) {
$log->fatal_error("GLC_NEC must be at least 1.");
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glc_snow_persistence_max_days');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'albice');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_behavior',
'glc_use_antarctica'=>$opts->{'glc_use_antarctica'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_melt_behavior');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_ice_runoff_behavior');
}
#-------------------------------------------------------------------------------
sub setup_logic_params_file {
# get param data
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'paramfile',
'phys'=>$nl_flags->{'phys'},
'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} );
}
#-------------------------------------------------------------------------------
sub setup_logic_create_crop_landunit {
# Create crop land unit
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = 'create_crop_landunit';
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'use_fates'=>$nl_flags->{'use_fates'} );
if ( &value_is_true($nl_flags->{'use_fates'}) && &value_is_true($nl->get_value($var)) ) {
$log->fatal_error( "$var is true and yet use_fates is being set, which contradicts that (use_fates requires $var to be .false." );
}
if ( (! &value_is_true($nl_flags->{'use_fates'})) && (! &value_is_true($nl->get_value($var))) ) {
$log->fatal_error( "$var is false which is ONLY allowed when FATES is being used" );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_subgrid {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = 'run_zero_weight_urban';
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var);
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'convert_ocean_to_land');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'collapse_urban',
'structure'=>$nl_flags->{'structure'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'n_dom_landunits',
'structure'=>$nl_flags->{'structure'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'n_dom_pfts',
'structure'=>$nl_flags->{'structure'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'toosmall_soil');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'toosmall_crop');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'toosmall_glacier');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'toosmall_lake');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'toosmall_wetland');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'toosmall_urban');
if ( &value_is_true($nl_flags->{'use_fates'}) && $nl->get_value('n_dom_pfts') != 0 ) {
$log->fatal_error( "FATES and n_dom_pfts can NOT be set at the same time" );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_cnfire {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my @fire_consts = ( "rh_low", "rh_hgh", "bt_min", "bt_max", "cli_scale", "boreal_peatfire_c", "non_boreal_peatfire_c",
"pot_hmn_ign_counts_alpha", "cropfire_a1", "occur_hi_gdp_tree", "lfuel", "ufuel",
"cmb_cmplt_fact_litter", "cmb_cmplt_fact_cwd" );
if ( &value_is_true($nl->get_value('use_cn')) ) {
foreach my $item ( @fire_consts ) {
if ( ! &value_is_true($nl_flags->{'cnfireson'} ) ) {
if ( defined($nl->get_value($item)) ) {
$log->fatal_error( "fire_method is no_fire and yet $item is being set, which contradicts that" );
}
} else {
my $fire_method = remove_leading_and_trailing_quotes( $nl->get_value('fire_method') );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $item,
'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'},
'fire_method'=>$fire_method );
}
}
} else {
foreach my $item ( @fire_consts ) {
if ( defined($nl->get_value($item)) ) {
$log->fatal_error( "CN is off which implies that cnfire is off and yet a fire constant ($item) is being set, which contradicts that" );
}
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_cnprec {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ( &value_is_true($nl_flags->{'use_cn'}) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults,
$nl, 'ncrit', 'use_cn'=>$nl_flags->{'use_cn'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults,
$nl, 'cnegcrit', 'use_cn'=>$nl_flags->{'use_cn'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults,
$nl, 'nnegcrit', 'use_cn'=>$nl_flags->{'use_cn'});
}
}
#-------------------------------------------------------------------------------
sub setup_logic_humanindex {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'calc_human_stress_indices');
}
#-------------------------------------------------------------------------------
sub setup_logic_urban {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'building_temp_method');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'urban_hac');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'urban_traffic');
}
#-------------------------------------------------------------------------------
sub setup_logic_crop_inparm {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ( &value_is_true($nl->get_value('use_crop')) ) {
my $maptype = 'baset_mapping';
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $maptype,
'use_crop'=>$nl->get_value('use_crop') );
my $baset_mapping = remove_leading_and_trailing_quotes( $nl->get_value($maptype) );
if ( $baset_mapping eq "varytropicsbylat" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "baset_latvary_slope",
'use_crop'=>$nl->get_value('use_crop'), $maptype=>$baset_mapping );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "baset_latvary_intercept",
'use_crop'=>$nl->get_value('use_crop'), $maptype=>$baset_mapping );
} else {
error_if_set( $nl, "Can only be set if $maptype == varytropicsbylat", "baset_latvary_slope", "baset_latvary_intercept" );
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "initial_seed_at_planting",
'use_crop'=>$nl->get_value('use_crop') );
my $crop_residue_removal_frac = $nl->get_value('crop_residue_removal_frac');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'crop_residue_removal_frac' );
if ( $crop_residue_removal_frac < 0.0 or $crop_residue_removal_frac > 1.0 ) {
$log->fatal_error("crop_residue_removal_frac must be in range [0, 1]");
}
} else {
error_if_set( $nl, "Can NOT be set without crop on", "baset_mapping", "baset_latvary_slope", "baset_latvary_intercept", "crop_residue_removal_frac" );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'crop_fsat_equals_zero' );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_tillage {
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'tillage_mode',
'use_crop'=>$nl_flags->{'use_crop'}, 'phys'=>$physv->as_string() );
my $tillage_mode = remove_leading_and_trailing_quotes( $nl->get_value( "tillage_mode" ) );
if ( $tillage_mode ne "off" && $tillage_mode ne "" && not &value_is_true($nl_flags->{'use_crop'}) ) {
$log->fatal_error( "Tillage only works on crop columns, so use_crop must be true if tillage is enabled." );
}
}
#-------------------------------------------------------------------------------
sub error_if_set {
# do a fatal_error and exit if any of the input variable names are set
my ($nl, $error, @list) = @_;
foreach my $var ( @list ) {
if ( defined($nl->get_value($var)) ) {
$log->fatal_error( "$var $error" );
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_soilstate {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
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";
my $var3 = "soil_layerstruct_userdefined_nlevsoi";
my $soil_layerstruct_predefined = $nl->get_value($var1);
my $soil_layerstruct_userdefined = $nl->get_value($var2);
my $soil_layerstruct_userdefined_nlevsoi = $nl->get_value($var3);
if (defined($soil_layerstruct_userdefined)) {
if (defined($soil_layerstruct_predefined)) {
$log->fatal_error("You have set both soil_layerstruct_userdefined and soil_layerstruct_predefined in your namelist; model cannot determine which to use");
}
if (not defined($soil_layerstruct_userdefined_nlevsoi)) {
$log->fatal_error("You have set soil_layerstruct_userdefined and NOT set soil_layerstruct_userdefined_nlevsoi in your namelist; both MUST be set");
}
} else {
if (defined($soil_layerstruct_userdefined_nlevsoi)) {
$log->fatal_error("You have set soil_layerstruct_userdefined_nlevsoi and NOT set soil_layerstruct_userdefined in your namelist; EITHER set both OR neither; in the latter case soil_layerstruct_predefined will be assigned a default value");
} else {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soil_layerstruct_predefined',
'structure'=>$nl_flags->{'structure'});
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_demand {
#
# Deal with options that the user has said are required...
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my %settings;
$settings{'hgrid'} = $nl_flags->{'res'};
$settings{'sim_year'} = $nl_flags->{'sim_year'};
$settings{'sim_year_range'} = $nl_flags->{'sim_year_range'};
$settings{'use_vichydro'} = $nl_flags->{'use_vichydro'};
$settings{'mask'} = $nl_flags->{'mask'};
$settings{'crop'} = $nl_flags->{'crop'};
$settings{'ssp_rcp'} = $nl_flags->{'ssp_rcp'};
$settings{'glc_nec'} = $nl_flags->{'glc_nec'};
# necessary for demand to be set correctly (flanduse_timeseries requires
# use_crop, maybe other options require other flags?)!
$settings{'irrigate'} = $nl_flags->{'irrigate'};
$settings{'use_cn'} = $nl_flags->{'use_cn'};
$settings{'use_cndv'} = $nl_flags->{'use_cndv'};
$settings{'use_lch4'} = $nl_flags->{'use_lch4'};
$settings{'use_nitrif_denitrif'} = $nl_flags->{'use_nitrif_denitrif'};
$settings{'use_crop'} = $nl_flags->{'use_crop'};
$settings{'neon'} = $nl_flags->{'neon'};
my $demand = $nl->get_value('clm_demand');
if (defined($demand)) {
$demand =~ s/\'//g; # Remove quotes
if ( $demand =~ /.+/ ) {
$opts->{'clm_demand'} .= ",$demand";
}
}
$demand = $defaults->get_value('clm_demand', \%settings);
if (defined($demand)) {
$demand =~ s/\'//g; # Remove quotes
if ( $demand =~ /.+/ ) {
$opts->{'clm_demand'} .= ",$demand";
}
}
my @demandlist = split( ",", $opts->{'clm_demand'} );
foreach my $item ( @demandlist ) {
if ( $item eq "null" ) {
next;
}
if ( $item eq "finidat" ) {
$log->fatal_error( "Do NOT put findat in the clm_demand list, set the clm_start_type=startup so initial conditions are required");
}
# For landuse.timeseries try with crop on first eise try with exact settings
# Logic for this is identical for fsurdat
if ( $item eq "flanduse_timeseries" ) {
$settings{'use_crop'} = ".true.";
$settings{'nofail'} = 1;
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $item, %settings );
if ( $item eq "flanduse_timeseries" ) {
$settings{'nofail'} = 0;
$settings{'use_crop'} = $nl_flags->{'use_crop'};
if ( ! defined($nl->get_value( $item )) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $item, %settings );
}
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_surface_dataset {
#
# Get surface dataset after flanduse_timeseries so that we can get surface data
# consistent with it
# MUST BE AFTER: setup_logic_demand which is where flanduse_timeseries is set
#
my ($opts, $nl_flags, $definition, $defaults, $nl, $xmlvar_ref) = @_;
$nl_flags->{'flanduse_timeseries'} = "null";
my $flanduse_timeseries = $nl->get_value('flanduse_timeseries');
if (defined($flanduse_timeseries)) {
$flanduse_timeseries =~ s!(.*)/!!;
$flanduse_timeseries =~ s/\'//;
$flanduse_timeseries =~ s/\"//;
if ( $flanduse_timeseries ne "" ) {
$nl_flags->{'flanduse_timeseries'} = $flanduse_timeseries;
}
}
$flanduse_timeseries = $nl_flags->{'flanduse_timeseries'};
if ($flanduse_timeseries ne "null" && &value_is_true($nl_flags->{'use_cndv'}) ) {
$log->fatal_error( "dynamic PFT's (setting flanduse_timeseries) are incompatible with dynamic vegetation (use_cndv=.true)." );
}
#
# Always get the crop version of the datasets now and let the code turn it into the form desired
# Provided this isn't with FATES on
#
my $var = "fsurdat";
if ( ! &value_is_true($nl_flags->{'use_fates'}) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'hgrid'=>$nl_flags->{'res'}, 'ssp_rcp'=>$nl_flags->{'ssp_rcp'},
'neon'=>$nl_flags->{'neon'}, 'neonsite'=>$nl_flags->{'neonsite'},
'sim_year'=>$nl_flags->{'sim_year'}, 'use_vichydro'=>$nl_flags->{'use_vichydro'},
'use_crop'=>".true.", 'use_fates'=>$nl_flags->{'use_fates'}, 'nofail'=>1);
}
# If didn't find the crop version check for the exact match
my $fsurdat = $nl->get_value($var);
if ( ! defined($fsurdat) ) {
if ( ! &value_is_true($nl_flags->{'use_fates'}) ) {
$log->verbose_message( "Crop version of $var NOT found, searching for an exact match" );
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'hgrid'=>$nl_flags->{'res'}, 'ssp_rcp'=>$nl_flags->{'ssp_rcp'}, 'use_vichydro'=>$nl_flags->{'use_vichydro'},
'sim_year'=>$nl_flags->{'sim_year'}, 'use_fates'=>$nl_flags->{'use_fates'},
'neon'=>$nl_flags->{'neon'}, 'neonsite'=>$nl_flags->{'neonsite'},
'use_crop'=>$nl_flags->{'use_crop'} );
}
#
# Expand the XML variables for NEON cases so that NEONSITE will be used
#
if ( &value_is_true($nl_flags->{'neon'}) ) {
my $fsurdat = $nl->get_value($var);
my $newval = SetupTools::expand_xml_var( $fsurdat, $xmlvar_ref );
if ( $newval ne $fsurdat ) {
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, $newval);
$log->verbose_message( "This is a NEON site and the fsurdat file selected is: $newval" );
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_initial_conditions {
# Initial conditions
# The initial date is an attribute in the defaults file which should be matched unless
# the user explicitly requests to ignore the initial date via the -ignore_ic_date option,
# or just ignore the year of the initial date via the -ignore_ic_year option.
#
# MUST BE AFTER: setup_logic_demand which is where flanduse_timeseries is set
# AFTER: setup_logic_irrigate which is where irrigate is set
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
my $var = "finidat";
my $finidat = $nl->get_value($var);
if ( $nl_flags->{'clm_start_type'} =~ /cold/ ) {
if (defined $finidat ) {
$log->warning("setting $var (either explicitly in your user_nl_clm or by doing a hybrid or branch RUN_TYPE)\n is incomptable with using a cold start" .
" (by setting CLM_FORCE_COLDSTART=on)." );
$log->warning("Overridding input $var file with one specifying that this is a cold start from arbitrary initial conditions." );
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, "' '" );
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl,
$var, 'val'=>"' '", 'no_abspath'=>1);
$finidat = $nl->get_value($var);
} elsif ( defined $finidat ) {
if ( string_is_undef_or_empty($finidat) ) {
print "You are setting $var to blank which signals arbitrary initial conditions.\n";
print "But, CLM_FORCE_COLDSTART is off which is a contradiction. For arbitrary initial conditions just use the CLM_FORCE_COLDSTART option\n";
$log->fatal_error("To do a cold-start set ./xmlchange CLM_FORCE_COLDSTART=on, and remove the setting of $var in the user_nl_clm file");
}
}
my $useinitvar = "use_init_interp";
my %settings;
my $use_init_interp_default = $nl->get_value($useinitvar);
$settings{$useinitvar} = $use_init_interp_default;
if ( string_is_undef_or_empty( $use_init_interp_default ) ) {
$use_init_interp_default = $defaults->get_value($useinitvar, \%settings);
$settings{$useinitvar} = ".false.";
}
if (not defined $finidat ) {
my $ic_date = $nl->get_value('start_ymd');
my $st_year = $nl_flags->{'st_year'};
my $nofail = 1;
$settings{'hgrid'} = $nl_flags->{'res'};
$settings{'phys'} = $physv->as_string();
$settings{'nofail'} = $nofail;
my $fsurdat = $nl->get_value('fsurdat');
$fsurdat =~ s!(.*)/!!;
$settings{'fsurdat'} = $fsurdat;
$settings{'do_transient_pfts'} = $nl->get_value('do_transient_pfts');
#
# If not transient use sim_year, otherwise use date
#
if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) {
$settings{'sim_year'} = $nl_flags->{'sim_year'};
$opts->{'ignore_ic_year'} = 1;
} else {
$settings{'sim_year'} = $st_year;
}
foreach my $item ( "mask", "maxpft", "irrigate", "glc_nec", "use_crop", "use_cn", "use_cndv",
"use_fates",
"lnd_tuning_mode",
) {
$settings{$item} = $nl_flags->{$item};
}
if ($opts->{'ignore_ic_date'}) {
if ( &value_is_true($nl_flags->{'use_crop'}) ) {
$log->warning("using ignore_ic_date is incompatable with crop! If you choose to ignore this error, " .
"the counters since planting for crops will be messed up. \nSo you should ignore at " .
"least the first season for crops. And since it will impact the 20 year means, ideally the " .
"first 20 years should be ignored.");
}
} elsif ($opts->{'ignore_ic_year'}) {
$settings{'ic_md'} = $ic_date;
} else {
$settings{'ic_ymd'} = $ic_date;
}
my $try = 0;
my $done = 2;
do {
$try++;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, %settings );
# If couldn't find a matching finidat file, check if can turn on interpolation and try to find one again
$finidat = $nl->get_value($var);
if (not defined $finidat) {
# Delete any date settings, except for crop
delete( $settings{'ic_ymd'} );
delete( $settings{'ic_md'} );
#if ( &value_is_true($nl_flags->{'use_crop'}) ) {
#$settings{'ic_md'} = $ic_date;
#}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "init_interp_sim_years" );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "init_interp_how_close" );
#
# Figure out which sim_year has a usable finidat file that is closest to the desired one
#
my $close = $nl->get_value("init_interp_how_close");
my $closest_sim_year = undef;
my @sim_years = split( /,/, $nl->get_value("init_interp_sim_years") );
SIMYR: foreach my $sim_yr ( @sim_years ) {
my $how_close = undef;
if ( $nl_flags->{'sim_year'} eq "PtVg" ) {
$how_close = abs(1850 - $sim_yr);
} elsif ( $nl_flags->{'flanduse_timeseries'} eq "null" ) {
$how_close = abs($nl_flags->{'sim_year'} - $sim_yr);
} else {
$how_close = abs($st_year - $sim_yr);
}
if ( ($sim_yr == $sim_years[-1]) || (($how_close < $nl->get_value("init_interp_how_close")) && ($how_close < $close)) ) {
my $group = $definition->get_group_name($useinitvar);
$settings{'sim_year'} = $sim_yr;
$settings{$useinitvar} = $defaults->get_value($useinitvar, \%settings);
if ( ! defined($settings{$useinitvar}) ) {
$settings{$useinitvar} = $use_init_interp_default;
}
if ( &value_is_true($settings{$useinitvar}) ) {
if ( ($how_close < $nl->get_value("init_interp_how_close")) && ($how_close < $close) ) {
$close = $how_close;
$closest_sim_year = $sim_yr;
}
}
}
} # SIMYR:
$settings{'sim_year'} = $closest_sim_year;
# Add options set here to the "$set" variable below...
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $useinitvar,
'use_cndv'=>$nl_flags->{'use_cndv'}, 'phys'=>$physv->as_string(), 'hgrid'=>$nl_flags->{'res'},
'sim_year'=>$settings{'sim_year'}, 'nofail'=>1, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'},
'use_fates'=>$nl_flags->{'use_fates'} );
$settings{$useinitvar} = $nl->get_value($useinitvar);
if ( ! &value_is_true($nl->get_value($useinitvar) ) ) {
if ( $nl_flags->{'clm_start_type'} =~ /startup/ ) {
my $err_msg = "clm_start_type is startup so an initial conditions ($var) file is required,";
if ( defined($use_init_interp_default) ) {
$log->fatal_error($err_msg." but can't find one without $useinitvar being set to true, change it to true in your user_nl_clm file in your case");
} else {
my $set = "Relevent settings: use_cndv = ". $nl_flags->{'use_cndv'} . " phys = " .
$physv->as_string() . " hgrid = " . $nl_flags->{'res'} . " sim_year = " .
$settings{'sim_year'} . " lnd_tuning_mode = " . $nl_flags->{'lnd_tuning_mode'} .
"use_fates = " . $nl_flags->{'use_fates'};
$log->fatal_error($err_msg." but the default setting of $useinitvar is false, so set both $var to a startup file and $useinitvar==TRUE, or developers should modify the namelist_defaults file".$set);
}
}
} else {
my $stat = add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "init_interp_attributes",
'sim_year'=>$settings{'sim_year'}, 'use_cndv'=>$nl_flags->{'use_cndv'},
'glc_nec'=>$nl_flags->{'glc_nec'}, 'use_fates'=>$nl_flags->{'use_fates'},
'hgrid'=>$nl_flags->{'res'},
'use_cn'=>$nl_flags->{'use_cn'}, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'}, 'nofail'=>1 );
if ( $stat ) {
$log->fatal_error("$useinitvar is NOT synchronized with init_interp_attributes in the namelist_defaults file, this should be corrected there");
}
my $attributes = $nl->get_value("init_interp_attributes");
my $attributes_string = remove_leading_and_trailing_quotes($attributes);
foreach my $pair ( split( /\s/, $attributes_string) ) {
if ( $pair =~ /^([a-z_]+)=([a-zA-Z._0-9]+)$/ ) {
$settings{$1} = $2;
} else {
$log->fatal_error("Problem interpreting init_interp_attributes from the namelist_defaults file: $pair");
}
}
}
} else {
$try = $done
}
} while( ($try < $done) && (not defined $finidat ) );
if ( not defined $finidat ) {
my $group = $definition->get_group_name($var);
$nl->set_variable_value($group, $var, "' '" );
}
}
$finidat = $nl->get_value($var);
if ( &value_is_true($nl->get_value($useinitvar) ) && string_is_undef_or_empty($finidat) ) {
if ( ! defined($use_init_interp_default) ) {
$log->fatal_error("You set $useinitvar but a $var file could not be found for this case, try setting $var explicitly, and/or removing the setting for $useinitvar" );
} else {
$log->fatal_error("$useinitvar is being set for you but a $var was not found, so $useinitvar, init_interp_attributes, and finidat must not be set correctly for this configuration in the namelist_default file" );
}
}
} # end initial conditions
#-------------------------------------------------------------------------------
sub setup_logic_dynamic_subgrid {
#
# Options controlling which parts of flanduse_timeseries to use
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
setup_logic_do_transient_pfts($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_do_transient_crops($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_do_transient_lakes($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_do_transient_urban($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_do_harvest($opts, $nl_flags, $definition, $defaults, $nl);
setup_logic_do_grossunrep($opts, $nl_flags, $definition, $defaults, $nl);
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reset_dynbal_baselines');
if ( &value_is_true($nl->get_value('reset_dynbal_baselines')) &&
&remove_leading_and_trailing_quotes($nl_flags->{'clm_start_type'}) eq "branch") {
$log->fatal_error("reset_dynbal_baselines has no effect in a branch run");
}
}
sub setup_logic_do_transient_pfts {
#
# Set do_transient_pfts default value, and perform error checking on do_transient_pfts
#
# Assumes the following are already set in the namelist (although it's okay
# for them to be unset if that will be their final state):
# - flanduse_timeseries
# - use_cndv
# - use_fates
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = 'do_transient_pfts';
# Start by assuming a default value of '.true.'. Then check a number of
# conditions under which do_transient_pfts cannot be true. Under these
# conditions: (1) set default value to '.false.'; (2) make sure that the
# value is indeed false (e.g., that the user didn't try to set it to true).
my $default_val = ".true.";
# cannot_be_true will be set to a non-empty string in any case where
# do_transient_pfts should not be true; if it turns out that
# do_transient_pfts IS true in any of these cases, a fatal error will be
# generated
my $cannot_be_true = "";
my $n_dom_pfts = $nl->get_value( 'n_dom_pfts' );
my $n_dom_landunits = $nl->get_value( 'n_dom_landunits' );
my $toosmall_soil = $nl->get_value( 'toosmall_soil' );
my $toosmall_crop = $nl->get_value( 'toosmall_crop' );
my $toosmall_glacier = $nl->get_value( 'toosmall_glacier' );
my $toosmall_lake = $nl->get_value( 'toosmall_lake' );
my $toosmall_wetland = $nl->get_value( 'toosmall_wetland' );
my $toosmall_urban = $nl->get_value( 'toosmall_urban' );
if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) {
$cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)";
} elsif (&value_is_true($nl->get_value('use_cndv'))) {
$cannot_be_true = "$var cannot be combined with use_cndv";
} elsif (&value_is_true($nl->get_value('use_fates'))) {
$cannot_be_true = "$var cannot be combined with use_fates";
} elsif (&value_is_true($nl->get_value('use_hillslope'))) {
$cannot_be_true = "$var cannot be combined with use_hillslope";
}
if ($cannot_be_true) {
$default_val = ".false.";
}
if (!$cannot_be_true) {
# Note that, if the variable cannot be true, we don't call add_default
# - so that we don't clutter up the namelist with variables that don't
# matter for this case
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val);
}
# Make sure the value is false when it needs to be false - i.e., that the
# user hasn't tried to set a true value at an inappropriate time.
if (&value_is_true($nl->get_value($var)) && $cannot_be_true) {
$log->fatal_error($cannot_be_true);
}
# if do_transient_pfts is .true. and any of these (n_dom_* or toosmall_*)
# are > 0 or collapse_urban = .true., then give fatal error
if (&value_is_true($nl->get_value($var))) {
if (&value_is_true($nl->get_value('collapse_urban'))) {
$log->fatal_error("$var cannot be combined with collapse_urban");
}
if ($n_dom_pfts > 0 || $n_dom_landunits > 0 || $toosmall_soil > 0 || $toosmall_crop > 0 || $toosmall_glacier > 0 || $toosmall_lake > 0 || $toosmall_wetland > 0 || $toosmall_urban > 0) {
$log->fatal_error("$var cannot be combined with any of the of the following > 0: n_dom_pfts > 0, n_dom_landunit > 0, toosmall_soi > 0._r8, toosmall_crop > 0._r8, toosmall_glacier > 0._r8, toosmall_lake > 0._r8, toosmall_wetland > 0._r8, toosmall_urban > 0._r8");
}
}
}
sub setup_logic_do_transient_crops {
#
# Set do_transient_crops default value, and perform error checking on do_transient_crops
#
# Assumes the following are already set in the namelist (although it's okay
# for them to be unset if that will be their final state):
# - flanduse_timeseries
# - use_crop
# - use_fates
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = 'do_transient_crops';
# Start by assuming a default value of '.true.'. Then check a number of
# conditions under which do_transient_crops cannot be true. Under these
# conditions: (1) set default value to '.false.'; (2) make sure that the
# value is indeed false (e.g., that the user didn't try to set it to true).
my $default_val = ".true.";
# cannot_be_true will be set to a non-empty string in any case where
# do_transient_crops should not be true; if it turns out that
# do_transient_crops IS true in any of these cases, a fatal error will be
# generated
my $cannot_be_true = "";
my $n_dom_pfts = $nl->get_value( 'n_dom_pfts' );
my $n_dom_landunits = $nl->get_value( 'n_dom_landunits' );
my $toosmall_soil = $nl->get_value( 'toosmall_soil' );
my $toosmall_crop = $nl->get_value( 'toosmall_crop' );
my $toosmall_glacier = $nl->get_value( 'toosmall_glacier' );
my $toosmall_lake = $nl->get_value( 'toosmall_lake' );
my $toosmall_wetland = $nl->get_value( 'toosmall_wetland' );
my $toosmall_urban = $nl->get_value( 'toosmall_urban' );
if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) {
$cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)";
} elsif (&value_is_true($nl->get_value('use_fates'))) {
# In principle, use_fates should be compatible with
# do_transient_crops. However, this hasn't been tested, so to be safe,
# we are not allowing this combination for now.
$cannot_be_true = "$var has not been tested with FATES, so for now these two options cannot be combined";
} elsif (&value_is_true($nl->get_value('use_hillslope'))) {
$cannot_be_true = "$var cannot be combined with use_hillslope";
}
if ($cannot_be_true) {
$default_val = ".false.";
}
if (!$cannot_be_true) {
# Note that, if the variable cannot be true, we don't call add_default
# - so that we don't clutter up the namelist with variables that don't
# matter for this case
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val);
}
# Make sure the value is false when it needs to be false - i.e., that the
# user hasn't tried to set a true value at an inappropriate time.
if (&value_is_true($nl->get_value($var)) && $cannot_be_true) {
$log->fatal_error($cannot_be_true);
}
# if do_transient_crops is .true. and any of these (n_dom_* or toosmall_*)
# are > 0 or collapse_urban = .true., then give fatal error
if (&value_is_true($nl->get_value($var))) {
if (&value_is_true($nl->get_value('collapse_urban'))) {
$log->fatal_error("$var cannot be combined with collapse_urban");
}
if ($n_dom_pfts > 0 || $n_dom_landunits > 0 || $toosmall_soil > 0 || $toosmall_crop > 0 || $toosmall_glacier > 0 || $toosmall_lake > 0 || $toosmall_wetland > 0 || $toosmall_urban > 0) {
$log->fatal_error("$var cannot be combined with any of the of the following > 0: n_dom_pfts > 0, n_dom_landunit > 0, toosmall_soil > 0._r8, toosmall_crop > 0._r8, toosmall_glacier > 0._r8, toosmall_lake > 0._r8, toosmall_wetland > 0._r8, toosmall_urban > 0._r8");
}
}
my $dopft = "do_transient_pfts";
# Make sure the value agrees with the do_transient_pft flag
if ( ( &value_is_true($nl->get_value($var))) && (! &value_is_true($nl->get_value($dopft))) ||
(! &value_is_true($nl->get_value($var))) && ( &value_is_true($nl->get_value($dopft))) ) {
$log->fatal_error("$var and $dopft do NOT agree and need to");
}
}
sub setup_logic_do_transient_lakes {
#
# Set do_transient_lakes default value, and perform error checking on do_transient_lakes
#
# Assumes the following are already set in the namelist (although it's okay
# for them to be unset if that will be their final state):
# - flanduse_timeseries
#
# NOTE(wjs, 2020-08-23) I based this function on setup_logic_do_transient_crops. I'm
# not sure if all of the checks here are truly important for transient lakes (in
# particular, my guess is that collapse_urban could probably be done with transient
# lakes - as well as transient pfts and transient crops for that matter), but some of
# the checks probably are needed, and it seems best to keep transient lakes consistent
# with other transient areas in this respect.
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = 'do_transient_lakes';
# Start by assuming a default value of '.true.'. Then check a number of
# conditions under which do_transient_lakes cannot be true. Under these
# conditions: (1) set default value to '.false.'; (2) make sure that the
# value is indeed false (e.g., that the user didn't try to set it to true).
my $default_val = ".true.";
# cannot_be_true will be set to a non-empty string in any case where
# do_transient_lakes should not be true; if it turns out that
# do_transient_lakes IS true in any of these cases, a fatal error will be
# generated
my $cannot_be_true = "";
my $n_dom_pfts = $nl->get_value( 'n_dom_pfts' );
my $n_dom_landunits = $nl->get_value( 'n_dom_landunits' );
my $toosmall_soil = $nl->get_value( 'toosmall_soil' );
my $toosmall_crop = $nl->get_value( 'toosmall_crop' );
my $toosmall_glacier = $nl->get_value( 'toosmall_glacier' );
my $toosmall_lake = $nl->get_value( 'toosmall_lake' );
my $toosmall_wetland = $nl->get_value( 'toosmall_wetland' );
my $toosmall_urban = $nl->get_value( 'toosmall_urban' );
if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) {
$cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)";
}
if (!$cannot_be_true) {
# Note that, if the variable cannot be true, we don't call add_default
# - so that we don't clutter up the namelist with variables that don't
# matter for this case
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val);
}
# Make sure the value is false when it needs to be false - i.e., that the
# user hasn't tried to set a true value at an inappropriate time.
if (&value_is_true($nl->get_value($var)) && $cannot_be_true) {
$log->fatal_error($cannot_be_true);
}
# if do_transient_lakes is .true. and any of these (n_dom_* or toosmall_*)
# are > 0 or collapse_urban = .true., then give fatal error
if (&value_is_true($nl->get_value($var))) {
if (&value_is_true($nl->get_value('collapse_urban'))) {
$log->fatal_error("$var cannot be combined with collapse_urban");
} elsif (&value_is_true($nl->get_value('use_hillslope'))) {
$log->fatal_error("$var cannot be combined with use_hillslope");
}
if ($n_dom_pfts > 0 || $n_dom_landunits > 0 || $toosmall_soil > 0 || $toosmall_crop > 0 || $toosmall_glacier > 0 || $toosmall_lake > 0 || $toosmall_wetland > 0 || $toosmall_urban > 0) {
$log->fatal_error("$var cannot be combined with any of the of the following > 0: n_dom_pfts > 0, n_dom_landunit > 0, toosmall_soil > 0._r8, toosmall_crop > 0._r8, toosmall_glacier > 0._r8, toosmall_lake > 0._r8, toosmall_wetland > 0._r8, toosmall_urban > 0._r8");
}
}
}
sub setup_logic_do_transient_urban {
#
# Set do_transient_urban default value, and perform error checking on do_transient_urban
#
# Assumes the following are already set in the namelist (although it's okay
# for them to be unset if that will be their final state):
# - flanduse_timeseries
#
# NOTE(kwo, 2021-08-11) I based this function on setup_logic_do_transient_lakes.
# As in NOTE(wjs, 2020-08-23) I'm not sure if all of the checks here are truly important
# for transient urban (in particular, my guess is that collapse_urban could probably be done with transient
# urban - as well as transient pfts and transient crops for that matter), but some of
# the checks probably are needed, and it seems best to keep transient urban consistent
# with other transient areas in this respect.
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = 'do_transient_urban';
# Start by assuming a default value of '.true.'. Then check a number of
# conditions under which do_transient_urban cannot be true. Under these
# conditions: (1) set default value to '.false.'; (2) make sure that the
# value is indeed false (e.g., that the user didn't try to set it to true).
my $default_val = ".true.";
# cannot_be_true will be set to a non-empty string in any case where
# do_transient_urban should not be true; if it turns out that
# do_transient_urban IS true in any of these cases, a fatal error will be
# generated
my $cannot_be_true = "";
my $n_dom_pfts = $nl->get_value( 'n_dom_pfts' );
my $n_dom_landunits = $nl->get_value( 'n_dom_landunits' );
my $toosmall_soil = $nl->get_value( 'toosmall_soil' );
my $toosmall_crop = $nl->get_value( 'toosmall_crop' );
my $toosmall_glacier = $nl->get_value( 'toosmall_glacier' );
my $toosmall_lake = $nl->get_value( 'toosmall_lake' );
my $toosmall_wetland = $nl->get_value( 'toosmall_wetland' );
my $toosmall_urban = $nl->get_value( 'toosmall_urban' );
if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) {
$cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)";
}
if (!$cannot_be_true) {
# Note that, if the variable cannot be true, we don't call add_default
# - so that we don't clutter up the namelist with variables that don't
# matter for this case
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val);
}
# Make sure the value is false when it needs to be false - i.e., that the
# user hasn't tried to set a true value at an inappropriate time.
if (&value_is_true($nl->get_value($var)) && $cannot_be_true) {
$log->fatal_error($cannot_be_true);
}
# if do_transient_urban is .true. and any of these (n_dom_* or toosmall_*)
# are > 0 or collapse_urban = .true., then give fatal error
if (&value_is_true($nl->get_value($var))) {
if (&value_is_true($nl->get_value('collapse_urban'))) {
$log->fatal_error("$var cannot be combined with collapse_urban");
} elsif (&value_is_true($nl->get_value('use_hillslope'))) {
$log->fatal_error("$var cannot be combined with use_hillslope");
}
if ($n_dom_pfts > 0 || $n_dom_landunits > 0 || $toosmall_soil > 0 || $toosmall_crop > 0 || $toosmall_glacier > 0 || $toosmall_lake > 0 || $toosmall_wetland > 0 || $toosmall_urban > 0) {
$log->fatal_error("$var cannot be combined with any of the of the following > 0: n_dom_pfts > 0, n_dom_landunit > 0, toosmall_soil > 0._r8, toosmall_crop > 0._r8, toosmall_glacier > 0._r8, toosmall_lake > 0._r8, toosmall_wetland > 0._r8, toosmall_urban > 0._r8");
}
}
}
sub setup_logic_do_harvest {
#
# Set do_harvest default value, and perform error checking on do_harvest
#
# Assumes the following are already set in the namelist (although it's okay
# for them to be unset if that will be their final state):
# - flanduse_timeseries
# - use_cn
# - use_fates
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = 'do_harvest';
# Start by assuming a default value of '.true.'. Then check a number of
# conditions under which do_harvest cannot be true. Under these
# conditions: (1) set default value to '.false.'; (2) make sure that the
# value is indeed false (e.g., that the user didn't try to set it to true).
my $default_val = ".true.";
# cannot_be_true will be set to a non-empty string in any case where
# do_harvest should not be true; if it turns out that do_harvest IS true
# in any of these cases, a fatal error will be generated
my $cannot_be_true = "";
if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) {
$cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)";
}
elsif (!&value_is_true($nl->get_value('use_cn')) && !&value_is_true($nl->get_value('use_fates'))) {
$cannot_be_true = "$var can only be set to true when running with either CN or FATES";
}
if ($cannot_be_true) {
$default_val = ".false.";
}
if (!$cannot_be_true) {
# Note that, if the variable cannot be true, we don't call add_default
# - so that we don't clutter up the namelist with variables that don't
# matter for this case
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val);
}
# Make sure the value is false when it needs to be false - i.e., that the
# user hasn't tried to set a true value at an inappropriate time.
if (&value_is_true($nl->get_value($var)) && $cannot_be_true) {
$log->fatal_error($cannot_be_true);
}
}
#-------------------------------------------------------------------------------
sub setup_logic_do_grossunrep {
#
# Set do_grossunrep default value, and perform error checking on do_grossunrep
#
# Assumes the following are already set in the namelist (although it's okay
# for them to be unset if that will be their final state):
# - flanduse_timeseries
# - use_cn
# - use_fates
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = 'do_grossunrep';
# Start by assuming a default value of '.true.'. Then check a number of
# conditions under which do_grossunrep cannot be true. Under these
# conditions: (1) set default value to '.false.'; (2) make sure that the
# value is indeed false (e.g., that the user didn't try to set it to true).
my $default_val = ".false.";
# cannot_be_true will be set to a non-empty string in any case where
# do_grossunrep should not be true; if it turns out that do_grossunrep IS true
# in any of these cases, a fatal error will be generated
my $cannot_be_true = "";
if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) {
$cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)";
}
elsif (&value_is_true($nl->get_value('use_fates'))) {
$cannot_be_true = "$var currently doesn't work with FATES";
}
elsif (!&value_is_true($nl->get_value('use_cn'))) {
$cannot_be_true = "$var can only be set to true when running with CN (use_cn = true)";
}
if ($cannot_be_true) {
$default_val = ".false.";
}
if (!$cannot_be_true) {
# Note that, if the variable cannot be true, we don't call add_default
# - so that we don't clutter up the namelist with variables that don't
# matter for this case
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val);
}
# Make sure the value is false when it needs to be false - i.e., that the
# user hasn't tried to set a true value at an inappropriate time.
if (&value_is_true($nl->get_value($var)) && $cannot_be_true) {
$log->fatal_error($cannot_be_true);
}
}
#-------------------------------------------------------------------------------
sub setup_logic_spinup {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ( $nl_flags->{'bgc_mode'} eq "sp" && defined($nl->get_value('override_bgc_restart_mismatch_dump'))) {
$log->fatal_error("CN must be on if override_bgc_restart_mismatch_dump is set.");
}
if ( $nl_flags->{'clm_accelerated_spinup'} eq "on" ) {
foreach my $var ( "hist_nhtfrq", "hist_fincl1", "hist_empty_htapes", "hist_mfilt" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl,
$var, use_cn=>$nl_flags->{'use_cn'}, use_fates=>$nl_flags->{'use_fates'},
use_cndv=>$nl_flags->{'use_cndv'} );
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_bgc_shared {
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
if ( $nl_flags->{'bgc_mode'} ne "sp" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'constrain_stress_deciduous_onset', 'phys'=>$physv->as_string() );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_cnphenology {
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
my @list = ( "onset_thresh_depends_on_veg", "min_critical_dayl_method" );
foreach my $var ( @list ) {
if ( &value_is_true($nl_flags->{'use_cn'}) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'phys'=>$physv->as_string(), 'use_cn'=>$nl_flags->{'use_cn'} );
} else {
if ( defined($nl->get_value($var)) ) {
$log->fatal_error("$var should only be set if use_cn is on");
}
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_supplemental_nitrogen {
#
# Supplemental Nitrogen for prognostic crop cases
#
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'}) ) {
# 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 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" && $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" );
}
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_hydrology_params {
#
# Logic for hydrology parameters
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $lower = $nl->get_value( 'lower_boundary_condition' );
my $var = "baseflow_scalar";
if ( $lower == 1 || $lower == 2 ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl,
$var, 'lower_boundary_condition' => $lower );
}
my $val = $nl->get_value( $var );
if ( defined($val) ) {
if ( $lower != 1 && $lower != 2 ) {
$log->fatal_error("baseflow_scalar is only used for lower_boundary_condition of flux or zero-flux");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_irrigation_parameters {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var;
foreach $var ("irrig_min_lai", "irrig_start_time", "irrig_length",
"irrig_target_smp", "irrig_depth", "irrig_threshold_fraction",
"limit_irrigation_if_rof_enabled","use_groundwater_irrigation",
"irrig_method_default") {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var);
}
if ( &value_is_true($nl->get_value('use_groundwater_irrigation')) &&
! &value_is_true($nl->get_value('limit_irrigation_if_rof_enabled'))) {
$log->fatal_error("use_groundwater_irrigation only makes sense if limit_irrigation_if_rof_enabled is set. (If limit_irrigation_if_rof_enabled is .false., then groundwater extraction will never be invoked.)")
}
my $lower = $nl->get_value( 'lower_boundary_condition' );
if ( ($lower == 3 || $lower == 4) && (&value_is_true($nl->get_value( 'use_groundwater_irrigation' ))) ) {
$log->fatal_error("use_groundwater_irrigation can only be used when lower_boundary_condition is NOT 3 or 4");
}
$var = "irrig_river_volume_threshold";
if ( &value_is_true($nl->get_value("limit_irrigation_if_rof_enabled")) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var);
} else {
if (defined($nl->get_value($var))) {
$log->fatal_error("$var can only be set if limit_irrigation_if_rof_enabled is true");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_surfacealbedo {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snowveg_affects_radiation' );
}
#-------------------------------------------------------------------------------
sub setup_logic_water_tracers {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var;
foreach $var ("enable_water_tracer_consistency_checks",
"enable_water_isotopes") {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var);
}
}
#-------------------------------------------------------------------------------
sub setup_logic_nitrif_params {
#
# Logic for nitrification parameters
#
my ($nl_flags, $definition, $defaults, $nl) = @_;
if ( ! &value_is_true($nl_flags->{'use_nitrif_denitrif'}) ) {
my @vars = ( "k_nitr_max", "denitrif_respiration_coefficient", "denitrif_respiration_exponent");
foreach my $var ( @vars ) {
if ( defined($nl->get_value( $var ) ) ) {
$log->fatal_error("$var is only used when use_nitrif_denitrif is turned on");
}
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_mineral_nitrogen_dynamics {
#
# Logic for mineral_nitrogen_dynamics
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my @vars = ( "freelivfix_slope_wet", "freelivfix_intercept" );
if ( &value_is_true($nl_flags->{'use_cn'}) && &value_is_true($nl->get_value('use_fun')) ) {
foreach my $var ( @vars ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'use_cn'=>$nl_flags->{'use_cn'}, 'use_fun'=>$nl->get_value('use_fun') );
}
} else {
foreach my $var ( @vars ) {
if ( defined($nl->get_value( $var ) ) ) {
$log->fatal_error("$var is only used when use_cn and use_fun are both turned on");
}
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_hydrology_switches {
#
# Check on Switches for hydrology
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_subgrid_fluxes');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_cover_fraction_method');
my $subgrid = $nl->get_value('use_subgrid_fluxes' );
my $h2osfcflag = $nl->get_value('h2osfcflag' );
my $scf_method = $nl->get_value('snow_cover_fraction_method');
if ( $h2osfcflag == 1 && ! &value_is_true($subgrid) ) {
$log->fatal_error("if h2osfcflag is ON, use_subgrid_fluxes can NOT be off!");
}
if ( remove_leading_and_trailing_quotes($scf_method) eq 'NiuYang2007' && &value_is_true($subgrid) ) {
$log->fatal_error("snow_cover_fraction_method NiuYang2007 is incompatible with use_subgrid_fluxes");
}
# Test bad configurations
my $lower = $nl->get_value( 'lower_boundary_condition' );
my $use_vic = $nl_flags->{'use_vichydro'};
my $use_bed = $nl->get_value( 'use_bedrock' );
my $soilmtd = $nl->get_value( 'soilwater_movement_method' );
if ( defined($soilmtd) && defined($lower) && $soilmtd == 0 && $lower != 4 ) {
$log->fatal_error( "If soil water movement method is zeng-decker -- lower_boundary_condition can only be aquifer" );
}
if ( defined($soilmtd) && defined($lower) && $soilmtd == 1 && $lower == 4 ) {
$log->fatal_error( "If soil water movement method is adaptive -- lower_boundary_condition can NOT be aquifer" );
}
if ( defined($use_bed) && defined($lower) && (&value_is_true($use_bed)) && $lower != 2 ) {
$log->fatal_error( "If use_bedrock is on -- lower_boundary_condition can only be flux" );
}
if ( defined($use_vic) && defined($lower) && (&value_is_true($use_vic)) && $lower != 3 && $lower != 4) {
$log->fatal_error( "If use_vichydro is on -- lower_boundary_condition can only be table or aquifer" );
}
if ( defined($h2osfcflag) && defined($lower) && $h2osfcflag == 0 && $lower != 4 ) {
$log->fatal_error( "If h2osfcflag is 0 lower_boundary_condition can only be aquifer" );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_methane {
#
# CH4 model if bgc=CN or CNDV
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ( &value_is_true($nl_flags->{'use_lch4'}) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'finundation_method',
'use_cn'=>$nl_flags->{'use_cn'}, 'use_fates'=>$nl_flags->{'use_fates'} );
my $finundation_method = remove_leading_and_trailing_quotes($nl->get_value('finundation_method' ));
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_ch4finundated',
'finundation_method'=>$finundation_method);
if ($opts->{'driver'} eq "nuopc" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_ch4finundated',
'finundation_method'=>$finundation_method);
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_aereoxid_prog',
'use_cn'=>$nl_flags->{'use_cn'}, 'use_fates'=>$nl_flags->{'use_fates'} );
#
# Check if use_aereoxid_prog is set. If no, then read value of aereoxid from
# parameters file
#
my $use_aereoxid_prog = $nl->get_value('use_aereoxid_prog');
if ( defined($use_aereoxid_prog) && ! &value_is_true($use_aereoxid_prog) ) {
$log->warning("Using aereoxid value from parameters file." );
}
} else {
my @vars = $nl->get_variable_names('ch4par_in');
if ( $#vars >= 0 ) {
$log->fatal_error("ch4par_in namelist variables were set, but Methane model NOT defined in the configuration (use_lch4)");
}
}
#
# Ch4 namelist checking
#
if ( &value_is_true($nl_flags->{'use_lch4'}) ) {
my $allowlakeprod = $nl->get_value('allowlakeprod');
if ( ! defined($allowlakeprod) ||
(defined($allowlakeprod) && ! &value_is_true($allowlakeprod)) ) {
if ( defined($nl->get_value('lake_decomp_fact')) ) {
$log->fatal_error("lake_decomp_fact set without allowlakeprod=.true.");
}
}
my $pftspec_rootprof = $nl->get_value('pftspecific_rootingprofile');
if ( ! defined($pftspec_rootprof) ||
(defined($pftspec_rootprof) && &value_is_true($pftspec_rootprof) ) ) {
if ( defined($nl->get_value('rootprof_exp')) ) {
$log->fatal_error("rootprof_exp set without pftspecific_rootingprofile=.false.");
}
}
} else {
my @vars = ( "allowlakeprod", "anoxia", "pftspecific_rootingprofile" );
foreach my $var ( @vars ) {
if ( defined($nl->get_value($var)) ) {
$log->fatal_error("$var set without methane model configuration on (use_lch4)");
}
}
my $var = "use_nitrif_denitrif";
if ( (! &value_is_true( $nl_flags->{'use_fates'} ) ) && &value_is_true($nl->get_value($var)) ) {
$log->warning("methane is off (use_lch4=FALSE), but $var is TRUE, both need to be on, unless FATES is also on" );
}
}
} # end methane
#-------------------------------------------------------------------------------
sub setup_logic_dynamic_plant_nitrogen_alloc {
#
# dynamic plant nitrogen allocation model, bgc=bgc
#
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
if ( &value_is_true($nl_flags->{'use_cn'}) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_flexibleCN',
'phys'=>$physv->as_string(), 'use_cn'=>$nl_flags->{'use_cn'} );
$nl_flags->{'use_flexibleCN'} = $nl->get_value('use_flexibleCN');
if ( &value_is_true($nl->get_value('use_fun') ) && not &value_is_true( $nl_flags->{'use_flexibleCN'}) ) {
$log->warning("FUN has NOT been extensively tested without use_flexibleCN on, so could result in failures or unexpected results" );
}
if ( &value_is_true($nl_flags->{'use_flexibleCN'}) ) {
# TODO(bja, 2015-04) make this depend on > clm 5.0 and bgc mode at some point.
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'MM_Nuptake_opt',
'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'CNratio_floating',
'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reduce_dayl_factor',
'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'vcmax_opt',
'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'CN_evergreen_phenology_opt',
'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'carbon_resp_opt',
'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'}, 'use_fun'=>$nl->get_value('use_fun') );
if ( $nl->get_value('carbon_resp_opt') == 1 && &value_is_true($nl->get_value('use_fun')) ) {
$log->fatal_error("carbon_resp_opt should NOT be set to 1 when FUN is also on");
}
}
} else {
if ( &value_is_true($nl->get_value('use_flexibleCN')) ) {
$log->fatal_error("use_flexibleCN can ONLY be set if CN is on");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_o3_veg_stress_method {
#
# Ozone vegetation stress method
#
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
my $var = 'o3_veg_stress_method';
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var );
my $val = $nl->get_value($var);
if (remove_leading_and_trailing_quotes($val) eq "stress_falk" && not (&value_is_true($nl_flags->{'use_luna'})) ) {
$log->fatal_error(" use_luna=.true. is required for $var='stress_falk'.");
}
}
#-------------------------------------------------------------------------------
sub setup_logic_luna {
#
# LUNA model to calculate photosynthetic capacities based on environmental conditions
#
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_luna',
'phys'=>$physv->as_string(), 'use_cn'=>$nl_flags->{'use_cn'}, 'use_fates'=>$nl_flags->{'use_fates'},
'use_nitrif_denitrif'=>$nl_flags->{'use_nitrif_denitrif'} );
if ( &value_is_true( $nl_flags->{'use_cn'} ) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_nguardrail',
'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 ) {
# lnc_opt can be set for both CN on and off
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lnc_opt',
'use_cn'=>$nl_flags->{'use_cn'} );
}
if ( &value_is_true($nl->get_value('lnc_opt') ) && not &value_is_true( $nl_flags->{'use_cn'}) ) {
$log->fatal_error("Cannot turn lnc_opt to true when bgc=sp" );
}
my $var = "jmaxb1";
if ( &value_is_true( $nl_flags->{'use_luna'} ) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var,
'use_luna'=>$nl_flags->{'use_luna'} );
}
my $val = $nl->get_value($var);
if ( ! &value_is_true( $nl_flags->{'use_luna'} ) ) {
if ( defined($val) ) {
$log->fatal_error("Cannot set $var when use_luna is NOT on" );
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_hillslope {
#
# Hillslope model
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'downscale_hillslope_meteorology' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_head_gradient_method' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_transmissivity_method' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_pft_distribution_method' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_soil_profile_method' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope_routing', 'use_hillslope'=>$nl_flags->{'use_hillslope'} );
my $use_hillslope = $nl->get_value('use_hillslope');
my $use_hillslope_routing = $nl->get_value('use_hillslope_routing');
if ( (! &value_is_true($use_hillslope)) && &value_is_true($use_hillslope_routing) ) {
$log->fatal_error("Cannot turn on use_hillslope_routing when use_hillslope is off\n" );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_hydrstress {
#
# Plant hydraulic stress model
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hydrstress',
'configuration'=>$nl_flags->{'configuration'}, 'use_fates'=>$nl_flags->{'use_fates'} );
$nl_flags->{'use_hydrstress'} = $nl->get_value('use_hydrstress');
if ( &value_is_true( $nl_flags->{'use_fates'} ) && &value_is_true( $nl_flags->{'use_hydrstress'} ) ) {
$log->fatal_error("Cannot turn use_hydrstress on when use_fates is on" );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_fertilizer {
#
# Flags to control fertilizer application
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fertilizer',
'use_crop'=>$nl_flags->{'use_crop'} );
my $use_fert = $nl->get_value('use_fertilizer');
if ( (! &value_is_true($nl_flags->{'use_crop'})) && &value_is_true($use_fert) ) {
$log->fatal_error("use_ferilizer can NOT be on without prognostic crop\n" );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_grainproduct {
#
# Flags to control 1-year grain product pool
#
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_grainproduct',
'use_crop'=>$nl_flags->{'use_crop'}, 'phys'=>$physv->as_string() );
if ( (! &value_is_true($nl_flags->{'use_crop'})) && &value_is_true($nl->get_value('use_grainproduct') ) ) {
$log->fatal_error("use_grainproduct can NOT be on without prognostic crop\n" );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_dynamic_roots {
#
# dynamic root model
#
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_dynroot', 'phys'=>$physv->as_string(), 'bgc_mode'=>$nl_flags->{'bgc_mode'});
my $use_dynroot = $nl->get_value('use_dynroot');
if ( &value_is_true($use_dynroot) && ($nl_flags->{'bgc_mode'} eq "sp") ) {
$log->fatal_error("Cannot turn dynroot mode on mode bgc=sp\n" .
"Set the bgc mode to 'bgc'.");
}
if ( &value_is_true( $use_dynroot ) && &value_is_true( $nl_flags->{'use_hydrstress'} ) ) {
$log->fatal_error("Cannot turn use_dynroot on when use_hydrstress is on" );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_c_isotope {
#
# Error checking for C-isotope options
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $use_c13 = $nl->get_value('use_c13');
my $use_c14 = $nl->get_value('use_c14');
if ( $nl_flags->{'bgc_mode'} ne "sp" && $nl_flags->{'bgc_mode'} ne "fates" ) {
if ( $nl_flags->{'bgc_mode'} ne "bgc" ) {
if ( defined($use_c13) && &value_is_true($use_c13) ) {
$log->warning("use_c13 is ONLY scientifically validated with the bgc=BGC configuration" );
}
if ( defined($use_c14) && &value_is_true($use_c14) ) {
$log->warning("use_c14 is ONLY scientifically validated with the bgc=BGC configuration" );
}
}
if ( defined($use_c14) ) {
if ( &value_is_true($use_c14) ) {
my $use_c14_bombspike = $nl->get_value('use_c14_bombspike');
if ( defined($use_c14_bombspike) && &value_is_true($use_c14_bombspike) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'atm_c14_filename',
'use_c14'=>$use_c14, 'use_cn'=>$nl_flags->{'use_cn'}, 'use_c14_bombspike'=>$nl->get_value('use_c14_bombspike'),
'ssp_rcp'=>$nl_flags->{'ssp_rcp'} );
}
} else {
if ( defined($nl->get_value('use_c14_bombspike')) ||
defined($nl->get_value('atm_c14_filename')) ) {
$log->fatal_error("use_c14 is FALSE and use_c14_bombspike or atm_c14_filename set");
}
}
} else {
if ( defined($nl->get_value('use_c14_bombspike')) ||
defined($nl->get_value('atm_c14_filename')) ) {
$log->fatal_error("use_c14 NOT set to .true., but use_c14_bompspike/atm_c14_filename defined.");
}
}
if ( defined($use_c13) ) {
if ( &value_is_true($use_c13) ) {
my $use_c13_timeseries = $nl->get_value('use_c13_timeseries');
if ( defined($use_c13_timeseries) && &value_is_true($use_c13_timeseries) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'atm_c13_filename',
'use_c13'=>$use_c13, 'use_cn'=>$nl_flags->{'use_cn'}, 'use_c13_timeseries'=>$nl->get_value('use_c13_timeseries'),
'ssp_rcp'=>$nl_flags->{'ssp_rcp'} );
}
} else {
if ( defined($nl->get_value('use_c13_timeseries')) ||
defined($nl->get_value('atm_c13_filename')) ) {
$log->fatal_error("use_c13 is FALSE and use_c13_timeseries or atm_c13_filename set");
}
}
} else {
if ( defined($nl->get_value('use_c13_timeseries')) ||
defined($nl->get_value('atm_c13_filename')) ) {
$log->fatal_error("use_c13 NOT set to .true., but use_c13_bompspike/atm_c13_filename defined.");
}
}
} else {
if ( defined($use_c13) ||
defined($use_c14) ||
defined($nl->get_value('use_c14_bombspike')) ||
defined($nl->get_value('atm_c14_filename')) ||
defined($nl->get_value('use_c13_timeseries')) ||
defined($nl->get_value('atm_c13_filename')) ) {
$log->fatal_error("bgc=sp and C isotope namelist variables were set, both can't be used at the same time");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_nitrogen_deposition {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
#
# Nitrogen deposition for bgc=CN or fates
#
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'} );
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'} );
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'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_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'});
# Set align year, if first and last years are different
if ( $nl->get_value('stream_year_first_ndep') != $nl->get_value('stream_year_last_ndep') ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_ndep', '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_fldfilename_ndep', 'phys'=>$nl_flags->{'phys'},
'use_cn'=>$nl_flags->{'use_cn'}, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'},
'hgrid'=>"0.9x1.25", 'ssp_rcp'=>$nl_flags->{'ssp_rcp'}, 'nofail'=>1 );
if ( ! defined($nl->get_value('stream_fldfilename_ndep') ) ) {
# Also check at f19 resolution
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_ndep', 'phys'=>$nl_flags->{'phys'},
'use_cn'=>$nl_flags->{'use_cn'}, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'},
'hgrid'=>"1.9x2.5", 'ssp_rcp'=>$nl_flags->{'ssp_rcp'}, 'nofail'=>1 );
# If not found report an error
if ( ! defined($nl->get_value('stream_fldfilename_ndep') ) ) {
$log->warning("Did NOT find the Nitrogen-deposition forcing file (stream_fldfilename_ndep) for this ssp_rcp\n" .
"One way to get around this is to point to a file for another existing ssp_rcp in your user_nl_clm file.\n" .
"If you are running with CAM and WACCM chemistry Nitrogen deposition will come through the coupler.\n" .
"This file won't be used, so it doesn't matter what it points to -- but it's required to point to something.\n" )
}
}
if ($opts->{'driver'} eq "nuopc" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_ndep', 'phys'=>$nl_flags->{'phys'},
'use_cn'=>$nl_flags->{'use_cn'}, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'},
'hgrid'=>"0.9x1.25", 'ssp_rcp'=>$nl_flags->{'ssp_rcp'}, 'nofail'=>1 );
if ( ! defined($nl->get_value('stream_fldfilename_ndep') ) ) {
# Also check at f19 resolution
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_ndep', 'phys'=>$nl_flags->{'phys'},
'use_cn'=>$nl_flags->{'use_cn'}, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'},
'hgrid'=>"1.9x2.5", 'ssp_rcp'=>$nl_flags->{'ssp_rcp'}, 'nofail'=>1 );
# If not found report an error
if ( ! defined($nl->get_value('stream_meshfile_ndep') ) ) {
$log->warning("Did NOT find the Nitrogen-deposition meshfile file (stream_meshfilee_ndep) for this ssp_rcp. \n")
}
}
}
} else {
# If bgc is NOT CN/CNDV then make sure none of the ndep settings are set!
if ( defined($nl->get_value('stream_year_first_ndep')) ||
defined($nl->get_value('stream_year_last_ndep')) ||
defined($nl->get_value('model_year_align_ndep')) ||
defined($nl->get_value('ndep_taxmode' )) ||
defined($nl->get_value('ndep_varlist' )) ||
defined($nl->get_value('stream_fldfilename_ndep'))
) {
$log->fatal_error("When bgc is NOT CN or CNDV none of: stream_year_first_ndep," .
"stream_year_last_ndep, model_year_align_ndep, ndep_taxmod, " .
"ndep_varlist, nor stream_fldfilename_ndep" .
" can be set!");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_cnmresp {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
#
# CN Maintence respiration for bgc=CN
#
if ( $nl_flags->{'bgc_mode'} ne "sp" ) {
# When FUN is on get a default value
if ( &value_is_true( $nl->get_value('use_fun') ) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults,
$nl, 'br_root', 'phys'=>$nl_flags->{'phys'},
'use_fun'=>$nl->get_value('use_fun'),
'use_cn'=>$nl_flags->{'use_cn'} );
}
} else {
# If bgc is NOT CN/CNDV then make sure not set
if ( defined($nl->get_value('br_root'))) {
$log->fatal_error("br_root can NOT be set when bgc_mode==sp!");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_photosyns {
# MUST be after use_hydrstress is set
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
#
# Photosynthesis
#
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults,
$nl, 'rootstem_acc', 'phys'=>$nl_flags->{'phys'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults,
$nl, 'light_inhibit', 'phys'=>$nl_flags->{'phys'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults,
$nl, 'leafresp_method', 'phys'=>$nl_flags->{'phys'},
'use_cn'=>$nl_flags->{'use_cn'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults,
$nl, 'modifyphoto_and_lmr_forcrop', 'phys'=>$nl_flags->{'phys'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults,
$nl, 'stomatalcond_method', 'phys'=>$nl_flags->{'phys'},
'use_hydrstress'=>$nl_flags->{'use_hydrstress'} );
# When CN on, must NOT be scaled by vcmax25top
if ( &value_is_true( $nl_flags->{'use_cn'} ) ) {
if ( $nl->get_value('leafresp_method') == 0 ) {
$log->fatal_error("leafresp_method can NOT be set to scaled to vcmax (0) when CN is on!");
}
# And when CN off, must NOT be anything besides scaled by vxmac25top
} else {
if ( $nl->get_value('leafresp_method') != 0 ) {
$log->fatal_error("leafresp_method can NOT be set to anything besides scaled to vcmax (0) when bgc_mode==sp!");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_canopy {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
#
# Canopy state
#
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults,
$nl, 'leaf_mr_vcm', 'phys'=>$nl_flags->{'phys'} )
}
#-------------------------------------------------------------------------------
sub setup_logic_popd_streams {
# population density streams require CN/BGC
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ( &value_is_true($nl_flags->{'cnfireson'}) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'popdensmapalgo', 'hgrid'=>$nl_flags->{'res'},
'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'}, 'cnfireson'=>$nl_flags->{'cnfireson'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_popdens', 'phys'=>$nl_flags->{'phys'},
'cnfireson'=>$nl_flags->{'cnfireson'}, '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_popdens', 'phys'=>$nl_flags->{'phys'},
'cnfireson'=>$nl_flags->{'cnfireson'}, '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_popdens') !=
$nl->get_value('stream_year_last_popdens') ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_popdens', 'sim_year'=>$nl_flags->{'sim_year'},
'sim_year_range'=>$nl_flags->{'sim_year_range'}, 'cnfireson'=>$nl_flags->{'cnfireson'});
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_popdens', 'phys'=>$nl_flags->{'phys'},
'cnfireson'=>$nl_flags->{'cnfireson'}, 'hgrid'=>"0.5x0.5", 'ssp_rcp'=>$nl_flags->{'ssp_rcp'} );
#
# TODO (mvertens, 2021-06-22) the following is needed for MCT since a use case enforces this - so for now stream_meshfile_popdens will be added to the mct
# stream namelist but simply not used
if ($opts->{'driver'} eq "nuopc" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_popdens', 'hgrid'=>"0.5x0.5");
my $inputdata_rootdir = $nl_flags->{'inputdata_rootdir'};
my $default_value = $nl->get_value('stream_meshfile_popdens');
my $none_filename = $inputdata_rootdir . '/none';
my $none_filename = &quote_string($none_filename);
if ($default_value eq $none_filename) {
my $var = 'stream_meshfile_popdens';
my $group = $definition->get_group_name($var);
my $val = "none";
$val = &quote_string( $val );
$nl->set_variable_value($group, $var, $val);
}
} else {
my $var = 'stream_meshfile_popdens';
my $group = $definition->get_group_name($var);
my $val = "none";
$val = &quote_string( $val );
$nl->set_variable_value($group, $var, $val);
}
} else {
# If bgc is NOT CN/CNDV or fire_method==nofire then make sure none of the popdens settings are set
if ( defined($nl->get_value('stream_year_first_popdens')) ||
defined($nl->get_value('stream_year_last_popdens')) ||
defined($nl->get_value('model_year_align_popdens')) ||
defined($nl->get_value('popdens_tintalgo' )) ||
defined($nl->get_value('stream_fldfilename_popdens')) ) {
$log->fatal_error("When bgc is SP (NOT CN or BGC) or fire_method==nofire none of: stream_year_first_popdens,\n" .
"stream_year_last_popdens, model_year_align_popdens, popdens_tintalgo nor\n" .
"stream_fldfilename_popdens can be set!");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_urbantv_streams {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'urbantvmapalgo',
'hgrid'=>$nl_flags->{'res'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_urbantv', 'phys'=>$nl_flags->{'phys'},
'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_urbantv', 'phys'=>$nl_flags->{'phys'},
'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_urbantv') !=
$nl->get_value('stream_year_last_urbantv') ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl,
'model_year_align_urbantv', '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_fldfilename_urbantv', 'phys'=>$nl_flags->{'phys'},
'hgrid'=>"0.9x1.25" );
if ($opts->{'driver'} eq "nuopc" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_urbantv', 'phys'=>$nl_flags->{'phys'},
'hgrid'=>"0.9x1.25" );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_lightning_streams {
# lightning streams require CN/BGC
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ( $nl_flags->{'light_res'} ne "none" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lightngmapalgo',
'hgrid'=>$nl_flags->{'res'},
'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_lightng',
'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_lightng',
'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_lightng') !=
$nl->get_value('stream_year_last_lightng') ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_lightng', '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_fldfilename_lightng',
'hgrid'=>$nl_flags->{'light_res'} );
if ($opts->{'driver'} eq "nuopc" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_lightng',
'hgrid'=>$nl_flags->{'light_res'} );
}
} else {
# If bgc is NOT CN/CNDV then make sure none of the Lightng settings are set
if ( defined($nl->get_value('stream_year_first_lightng')) ||
defined($nl->get_value('stream_year_last_lightng')) ||
defined($nl->get_value('model_year_align_lightng')) ||
defined($nl->get_value('lightng_tintalgo' )) ||
defined($nl->get_value('stream_fldfilename_lightng')) ) {
$log->fatal_error("When bgc is SP (NOT CN or BGC or FATES) or fire is turned off none of: stream_year_first_lightng,\n" .
"stream_year_last_lightng, model_year_align_lightng, lightng_tintalgo nor\n" .
"stream_fldfilename_lightng can be set!");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_dry_deposition {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ($opts->{'drydep'} ) {
if ( &value_is_true( $nl_flags->{'use_fates'}) && not &value_is_true( $nl_flags->{'use_fates_sp'}) ) {
$log->warning("DryDeposition can NOT be on when FATES is also on unless FATES-SP mode is on.\n" .
" Use the '--no-drydep' option when '-bgc fates' is activated");
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'drydep_list');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'dep_data_file');
} else {
if ( defined($nl->get_value('drydep_list')) ) {
$log->fatal_error("drydep_list defined, but drydep option NOT set");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_fire_emis {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ($opts->{'fire_emis'} ) {
if ( &value_is_true( $nl_flags->{'use_fates'} ) ) {
$log->warning("Fire emission can NOT be on when FATES is also on.\n" .
" DON'T use the '-fire_emis' option when '-bgc fates' is activated");
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fire_emis_factors_file');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fire_emis_specifier');
} else {
if ( defined($nl->get_value('fire_emis_elevated')) ||
defined($nl->get_value('fire_emis_factors_file')) ||
defined($nl->get_value('fire_emis_specifier')) ) {
$log->fatal_error("fire_emission setting defined: fire_emis_elevated, fire_emis_factors_file, or fire_emis_specifier, but fire_emis option NOT set");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_dust_emis {
# Logic to handle the dust emissions
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
# First get the dust emission method
my $var = "dust_emis_method";
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var );
my $dust_emis_method = remove_leading_and_trailing_quotes( $nl->get_value($var) );
my @zender_files_in_lnd_opts = ( "stream_fldfilename_zendersoilerod", "stream_meshfile_zendersoilerod",
"zendersoilerod_mapalgo" );
if ( $dust_emis_method eq "Zender_2003" ) {
# get the zender_soil_erod_source
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl,
"zender_soil_erod_source", 'dust_emis_method'=>$dust_emis_method );
my $zender_source = remove_leading_and_trailing_quotes( $nl->get_value('zender_soil_erod_source') );
if ( $zender_source eq "lnd" ) {
foreach my $option ( @zender_files_in_lnd_opts ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $option,
'dust_emis_method'=>$dust_emis_method, 'zender_soil_erod_source'=>$zender_source,
'hgrid'=>$nl_flags->{'res'}, 'lnd_tuning_mod'=>$nl_flags->{'lnd_tuning_mode'} );
}
} else {
foreach my $option ( @zender_files_in_lnd_opts ) {
if ( defined($nl->get_value($option)) ) {
$log->fatal_error("zender_soil_erod_source is NOT lnd, but the file option $option is being set" .
" and should NOT be unless you want it handled here in the LAND model, " .
"otherwise the equivalent option is set in CAM" );
}
}
}
} else {
# Verify that NONE of the Zender options are being set if Zender is NOT being used
push @zender_files_in_lnd_opts, "zender_soil_erod_source";
foreach my $option ( @zender_files_in_lnd_opts ) {
if ( defined($nl->get_value($option)) ) {
$log->fatal_error("dust_emis_method is NOT set to Zender_2003, but one of it's options " .
"$option is being set, need to change one or the other" );
}
}
if ( $dust_emis_method eq "Leung_2023" ) {
$log->warning("dust_emis_method is Leung_2023 and that option has NOT been brought into CTSM yet");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_megan {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = "megan";
if ( $opts->{$var} eq "default" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'megan',
'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'},
'configuration'=>$nl_flags->{'configuration'} );
$nl_flags->{$var} = $nl->get_value($var);
} else {
$nl_flags->{$var} = $opts->{$var};
}
if ($nl_flags->{'megan'} ) {
if ( &value_is_true( $nl_flags->{'use_fates'} ) ) {
$log->warning("MEGAN can NOT be on when FATES is also on.\n" .
" Use the '-no-megan' option when '-bgc fates' is activated");
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'megan_specifier');
check_megan_spec( $opts, $nl, $definition );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'megan_factors_file');
} else {
if ( defined($nl->get_value('megan_specifier')) ||
defined($nl->get_value('megan_factors_file')) ) {
$log->fatal_error("megan_specifier or megan_factors_file defined, but megan option NOT set");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_soilm_streams {
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_soil_moisture_streams');
if ( &value_is_true( $nl->get_value('use_soil_moisture_streams') ) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soilm_tintalgo',
'hgrid'=>$nl_flags->{'res'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soilm_offset',
'hgrid'=>$nl_flags->{'res'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_soilm', 'phys'=>$nl_flags->{'phys'},
'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_soilm', 'phys'=>$nl_flags->{'phys'},
'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_soilm') !=
$nl->get_value('stream_year_last_soilm') ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl,
'model_year_align_soilm', '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_fldfilename_soilm', 'phys'=>$nl_flags->{'phys'},
'hgrid'=>$nl_flags->{'res'} );
if ( ($opts->{'use_case'} =~ /_transient$/) &&
(remove_leading_and_trailing_quotes($nl->get_value("soilm_tintalgo")) eq "linear") ) {
$log->warning("For a transient case, soil moisture streams, should NOT use soilm_tintalgo='linear'" .
" since vegetated areas could go from missing to not missing or vice versa" );
}
} else {
if ( defined($nl->get_value('stream_year_first_soilm')) ||
defined($nl->get_value('model_year_align_soilm')) ||
defined($nl->get_value('stream_fldfilename_soilm')) ||
defined($nl->get_value('soilm_tintalgo')) ||
defined($nl->get_value('soilm_offset')) ||
defined($nl->get_value('stream_year_last_soilm')) ) {
$log->fatal_error("One of the soilm streams namelist items (stream_year_first_soilm, " .
" model_year_align_soilm, stream_fldfilename_soilm, stream_fldfilename_soilm)" .
" soilm_tintalgo soilm_offset" .
" is defined, but use_soil_moisture_streams option NOT set to true");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_lai_streams {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_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" || ($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',
'hgrid'=>$nl_flags->{'res'} );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_lai',
'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_lai',
'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_lai') !=
$nl->get_value('stream_year_last_lai') ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl,
'model_year_align_lai', '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_fldfilename_lai',
'hgrid'=>"360x720cru" );
if ($opts->{'driver'} eq "nuopc" ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_lai',
'hgrid'=>"360x720cru" );
}
}
} else {
# 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 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 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 $swindow_start_file = $nl->get_value('stream_fldFileName_swindow_start') ;
my $swindow_end_file = $nl->get_value('stream_fldFileName_swindow_end') ;
my $gdd_file = $nl->get_value('stream_fldFileName_cultivar_gdds') ;
my $mesh_file = $nl->get_value('stream_meshfile_cropcal') ;
if ( ($swindow_start_file eq '' and $swindow_start_file ne '') or ($swindow_start_file ne '' and $swindow_start_file eq '') ) {
$log->fatal_error("When specifying sowing window dates, you must provide both swindow_start_file and swindow_end_file. To specify exact sowing dates, use the same file." );
}
if ( $generate_crop_gdds eq '.true.' ) {
if ( $use_mxmat eq '.true.' ) {
$log->fatal_error("If generate_crop_gdds is true, you must also set use_mxmat to false" );
}
if ( $swindow_start_file eq '' or $swindow_end_file eq '' ) {
$log->fatal_error("If generate_crop_gdds is true, you must specify stream_fldFileName_swindow_start and stream_fldFileName_swindow_end")
}
if ( $swindow_start_file ne $swindow_end_file ) {
$log->fatal_error("If generate_crop_gdds is true, you must specify exact sowing dates by setting stream_fldFileName_swindow_start and stream_fldFileName_swindow_end to the same file")
}
if ( $gdd_file ne '' ) {
$log->fatal_error("If generate_crop_gdds is true, do not specify stream_fldFileName_cultivar_gdds")
}
}
if ( $mesh_file eq '' and ( $swindow_start_file ne '' or $gdd_file ne '' ) ) {
$log->fatal_error("If prescribing crop sowing dates and/or maturity requirements, you must specify stream_meshfile_cropcal")
}
}
#-------------------------------------------------------------------------------
sub setup_logic_soilwater_movement {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soilwater_movement_method' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'upper_boundary_condition' );
my $soilmtd = $nl->get_value("soilwater_movement_method");
my $use_bed = $nl->get_value('use_bedrock' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl,
'lower_boundary_condition', 'vichydro'=>$nl_flags->{'vichydro'},
'soilwater_movement_method'=>$soilmtd, 'use_bedrock'=>$use_bed
);
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'dtmin' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'verySmall' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'xTolerUpper' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'xTolerLower' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'expensive' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'inexpensive' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'flux_calculation' );
}
#-------------------------------------------------------------------------------
sub setup_logic_cnvegcarbonstate {
# MUST be AFTER: setup_logic_dynamic_plant_nitrogen_alloc as depends on mm_nuptake_opt which is set there
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ( &value_is_true($nl->get_value('use_cn')) ) {
my $mmnuptake = $nl->get_value('mm_nuptake_opt');
if ( ! defined($mmnuptake) ) { $mmnuptake = ".false."; }
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'initial_vegC',
'use_cn' => $nl->get_value('use_cn'), 'mm_nuptake_opt' => $mmnuptake );
}
}
#-------------------------------------------------------------------------------
sub setup_logic_cngeneral {
# Must be set after setup_logic_co2_type
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ( &value_is_true($nl->get_value('use_cn')) ) {
if ( &value_is_true($nl->get_value('use_crop')) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'dribble_crophrv_xsmrpool_2atm',
'co2_type' => remove_leading_and_trailing_quotes($nl->get_value('co2_type')),
'use_crop' => $nl->get_value('use_crop') );
} else {
if ( defined($nl->get_value('dribble_crophrv_xsmrpool_2atm')) ) {
$log->fatal_error("When CROP is NOT on dribble_crophrv_xsmrpool_2atm can NOT be set\n" );
}
}
} else {
if ( defined($nl->get_value('reseed_dead_plants')) ||
defined($nl->get_value('dribble_crophrv_xsmrpool_2atm')) ) {
$log->fatal_error("When CN is not on none of the following can be set: ,\n" .
"dribble_crophrv_xsmrpool_2atm nor reseed_dead_plantsr\n" .
"(eg. don't use these options with SP mode).");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_rooting_profile {
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'rooting_profile_method_water' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'rooting_profile_method_carbon' );
}
#-------------------------------------------------------------------------------
sub setup_logic_friction_vel {
# Must be after canopyfluxes so that use_biomass_heat_storage will be set
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'zetamaxstable',
'use_biomass_heat_storage'=>$nl_flags->{'use_biomass_heat_storage'}, 'phys'=>$nl_flags->{'phys'} );
}
#-------------------------------------------------------------------------------
sub setup_logic_soil_resis {
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soil_resis_method' );
}
sub setup_logic_canopyfluxes {
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_undercanopy_stability' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'itmax_canopy_fluxes',
'structure'=>$nl_flags->{'structure'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_biomass_heat_storage',
'use_fates'=>$nl_flags->{'use_fates'}, 'phys'=>$nl_flags->{'phys'} );
if ( &value_is_true($nl->get_value('use_biomass_heat_storage') ) && &value_is_true( $nl_flags->{'use_fates'}) ) {
$log->fatal_error('use_biomass_heat_storage can NOT be set to true when fates is on');
}
if ( &value_is_true($nl->get_value('use_biomass_heat_storage')) ) {
$nl_flags->{'use_biomass_heat_storage'} = ".true.";
} else {
$nl_flags->{'use_biomass_heat_storage'} = ".false.";
}
}
#-------------------------------------------------------------------------------
sub setup_logic_canopyhydrology {
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'interception_fraction' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'maximum_leaf_wetted_fraction' );
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_clm5_fpi' );
}
#-------------------------------------------------------------------------------
sub setup_logic_snowpack {
#
# Snowpack related options
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'nlevsno',
'structure'=>$nl_flags->{'structure'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'h2osno_max',
'structure'=>$nl_flags->{'structure'});
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'wind_dependent_snow_density');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_overburden_compaction_method');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lotmp_snowdensity_method');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'upplim_destruct_metamorph');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reset_snow');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reset_snow_glc');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reset_snow_glc_ela');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_dzmin_1');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_dzmin_2');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_dzmax_l_1');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_dzmax_l_2');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_dzmax_u_1');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_dzmax_u_2');
my $dzmin1 = $nl->get_value('snow_dzmin_1');
my $dzmin2 = $nl->get_value('snow_dzmin_2');
my $dzmax_l1 = $nl->get_value('snow_dzmax_l_1');
my $dzmax_l2 = $nl->get_value('snow_dzmax_l_2');
my $dzmax_u1 = $nl->get_value('snow_dzmax_u_1');
my $dzmax_u2 = $nl->get_value('snow_dzmax_u_2');
if ($dzmin1 != 0.01 || $dzmin2 != 0.015 || $dzmax_u1 != 0.02 || $dzmax_u2 != 0.05 || $dzmax_l1 != 0.03 || $dzmax_l2 != 0.07) {
$log->warning("Setting any of the following namelist variables to NON DEFAULT values remains untested as of Sep 6, 2019: snow_dzmin_1 & 2, snow_dzmax_u_1 & 2, snow_dzmax_l_1 & 2." );
$log->warning("Leave these variables unspecified in user_nl_clm in order to use the default values." );
}
if ($dzmin1 <= 0.0 || $dzmin2 <= 0.0 || $dzmax_u1 <= 0.0 || $dzmax_u2 <= 0.0 || $dzmax_l1 <= 0.0 || $dzmax_l2 <= 0.0) {
$log->fatal_error('One or more of the snow_dzmin_* and/or snow_dzmax_* were set incorrectly to be <= 0');
}
if ($dzmin2 <= $dzmin1) {
$log->fatal_error('snow_dzmin_2 was set incorrectly to be <= snow_dzmin_1');
}
if ($dzmax_l2 <= $dzmax_l1) {
$log->fatal_error('snow_dzmax_l_2 was set incorrectly to be <= snow_dzmax_l_1');
}
if ($dzmax_u2 <= $dzmax_u1) {
$log->fatal_error('snow_dzmax_u_2 was set incorrectly to be <= snow_dzmax_u_1');
}
if ($dzmin1 >= $dzmax_u1) {
$log->fatal_error('snow_dzmin_1 was set incorrectly to be >= snow_dzmax_u_1');
}
if ($dzmin2 >= $dzmax_u2) {
$log->fatal_error('snow_dzmin_2 was set incorrectly to be >= snow_dzmax_u_2');
}
if ($dzmax_u1 >= $dzmax_l1) {
$log->fatal_error('snow_dzmax_u_1 was set incorrectly to be >= snow_dzmax_l_1');
}
if ($dzmax_u2 >= $dzmax_l2) {
$log->fatal_error('snow_dzmax_u_2 was set incorrectly to be >= snow_dzmax_l_2');
}
if (remove_leading_and_trailing_quotes($nl->get_value('snow_overburden_compaction_method')) eq 'Vionnet2012') {
# overburden_compress_tfactor isn't used if we're using the Vionnet2012
# snow overburden compaction method, so make sure the user hasn't tried
# to set it
if (defined($nl->get_value('overburden_compress_tfactor'))) {
$log->fatal_error('overburden_compress_tfactor is set, but does not apply when using snow_overburden_compaction_method=Vionnet2012');
}
} else {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'overburden_compress_tfactor');
}
}
#-------------------------------------------------------------------------------
sub setup_logic_scf_SwensonLawrence2012 {
# Options related to the SwensonLawrence2012 snow cover fraction method
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if (remove_leading_and_trailing_quotes($nl->get_value('snow_cover_fraction_method')) eq 'SwensonLawrence2012') {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'int_snow_max');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'n_melt_glcmec');
}
else {
if (defined($nl->get_value('int_snow_max'))) {
$log->fatal_error('int_snow_max is set, but only applies for snow_cover_fraction_method=SwensonLawrence2012');
}
if (defined($nl->get_value('n_melt_glcmec'))) {
$log->fatal_error('n_melt_glcmec is set, but only applies for snow_cover_fraction_method=SwensonLawrence2012');
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_atm_forcing {
#
# Options related to atmospheric forcings
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glcmec_downscale_longwave');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'repartition_rain_snow');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lapse_rate');
my $var;
foreach $var ("lapse_rate_longwave",
"longwave_downscaling_limit") {
if ( &value_is_true($nl->get_value("glcmec_downscale_longwave")) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var);
} else {
if (defined($nl->get_value($var))) {
$log->fatal_error("$var can only be set if glcmec_downscale_longwave is true");
}
}
}
foreach $var ("precip_repartition_glc_all_snow_t",
"precip_repartition_glc_all_rain_t",
"precip_repartition_nonglc_all_snow_t",
"precip_repartition_nonglc_all_rain_t") {
if ( &value_is_true($nl->get_value("repartition_rain_snow")) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var);
} else {
if (defined($nl->get_value($var))) {
$log->fatal_error("$var can only be set if repartition_rain_snow is true");
}
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_lnd2atm {
#
# Options related to fields sent to atmosphere
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'melt_non_icesheet_ice_runoff');
}
#-------------------------------------------------------------------------------
sub setup_logic_initinterp {
#
# Options related to init_interp
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
my $var = 'init_interp_method';
if ( &value_is_true($nl->get_value("use_init_interp"))) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var);
} else {
if (defined($nl->get_value($var))) {
$log->fatal_error("$var can only be set if use_init_interp is true");
}
}
}
#-------------------------------------------------------------------------------
sub setup_logic_fates {
#
# Set some default options related to Ecosystem Demography
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if (&value_is_true( $nl_flags->{'use_fates'}) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_paramfile', 'phys'=>$nl_flags->{'phys'});
my @list = ( "fates_spitfire_mode", "use_fates_planthydro", "use_fates_ed_st3", "use_fates_ed_prescribed_phys",
"use_fates_inventory_init","use_fates_fixed_biogeog","use_fates_nocomp","fates_seeddisp_cadence",
"use_fates_logging","fates_parteh_mode", "use_fates_cohort_age_tracking","use_fates_tree_damage",
"use_fates_luh","fates_history_dimlevel" );
foreach my $var ( @list ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_fates'=>$nl_flags->{'use_fates'},
'use_fates_sp'=>$nl_flags->{'use_fates_sp'} );
}
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
#
my $var = "use_fates_sp";
if ( defined($nl->get_value($var)) ) {
if ( &value_is_true($nl->get_value($var)) ) {
my @list = ( "use_fates_nocomp", "use_fates_fixed_biogeog" );
foreach my $var ( @list ) {
if ( ! &value_is_true($nl->get_value($var)) ) {
$log->fatal_error("$var is required when FATES SP is on (use_fates_sp)" );
}
}
# spit-fire can't be on with FATES SP mode is active
if ( $nl->get_value('fates_spitfire_mode') > 0 ) {
$log->fatal_error('fates_spitfire_mode can NOT be set to greater than 0 when use_fates_sp is true');
}
# hydro isn't currently supported to work when FATES SP mode is active
if (&value_is_true( $nl->get_value('use_fates_planthydro') )) {
$log->fatal_error('fates sp mode is currently not supported to work with fates hydro');
}
}
}
my $var = "use_fates_inventory_init";
if ( defined($nl->get_value($var)) ) {
if ( &value_is_true($nl->get_value($var)) ) {
$var = "fates_inventory_ctrl_filename";
my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) );
if ( ! defined($nl->get_value($var)) ) {
$log->fatal_error("$var is required when use_fates_inventory_init is set" );
} elsif ( ! -f "$fname" ) {
$log->fatal_error("$fname does NOT point to a valid filename" );
}
}
}
my $var = "use_fates_luh";
if ( defined($nl->get_value($var)) ) {
if ( &value_is_true($nl->get_value($var)) ) {
$var = "fluh_timeseries";
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>$nl_flags->{'res'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, nofail=>1 );
my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) );
if ( ! defined($nl->get_value($var)) ) {
$log->fatal_error("$var is required when use_fates_luh is set" );
} elsif ( ! -f "$fname" ) {
$log->fatal_error("$fname does NOT point to a valid filename" );
}
}
}
}
}
#-------------------------------------------------------------------------------
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 {
#
# Set some misc options
#
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
if ( $opts->{'driver'} ne "nuopc" ) {
my $var = "force_send_to_atm";
my $val = $nl->get_value($var);
if ( defined($val) ) {
$log->fatal_error( "$var can only be set for the nuopc driver" );
}
}
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'for_testing_run_ncdiopio_tests');
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_fields_list_file');
}
#-------------------------------------------------------------------------------
sub write_output_files {
my ($opts, $nl_flags, $defaults, $nl) = @_;
my $note = "";
my $var = "note";
if ( ! defined($opts->{$var}) ) {
$opts->{$var} = $defaults->get_value($var);
}
if ( $opts->{$var} ) {
$note = "Comment:\n" .
"This namelist was created using the following command-line:\n" .
" $nl_flags->{'cfgdir'}/$ProgName $nl_flags->{'cmdline'}\n" .
"For help on options use: $nl_flags->{'cfgdir'}/$ProgName -help";
}
# CLM component
my @groups;
@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
soilhydrology_inparm luna friction_velocity mineral_nitrogen_dynamics
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_inparm irrigation_inparm
surfacealbedo_inparm water_tracers_inparm tillage_inparm);
#@groups = qw(clm_inparm clm_canopyhydrology_inparm clm_soilhydrology_inparm
# finidat_consistency_checks dynpft_consistency_checks);
# Eventually only list namelists that are actually used when CN on
if ( &value_is_true($nl_flags->{'use_lch4'}) ) {
push @groups, "ch4par_in";
}
if ( $opts->{'driver'} eq "nuopc" ) {
push @groups, "ctsm_nuopc_cap";
}
push @groups, "clm_humanindex_inparm";
push @groups, "cnmresp_inparm";
push @groups, "photosyns_inparm";
push @groups, "cnfire_inparm";
push @groups, "cn_general";
push @groups, "nitrif_inparm";
push @groups, "lifire_inparm";
push @groups, "ch4finundated";
push @groups, "exice_streams";
push @groups, "soilbgc_decomp";
push @groups, "clm_canopy_inparm";
push @groups, "zendersoilerod";
if (remove_leading_and_trailing_quotes($nl->get_value('snow_cover_fraction_method')) eq 'SwensonLawrence2012') {
push @groups, "scf_swenson_lawrence_2012_inparm";
}
my $outfile;
$outfile = "$opts->{'dir'}/lnd_in";
$nl->write($outfile, 'groups'=>\@groups, 'note'=>"$note" );
$log->verbose_message("Writing clm namelist to $outfile");
# Drydep, fire-emission or MEGAN namelist for driver
@groups = qw(drydep_inparm megan_emis_nl fire_emis_nl carma_inparm);
$outfile = "$opts->{'dir'}/drv_flds_in";
$nl->write($outfile, 'groups'=>\@groups, 'note'=>"$note" );
$log->verbose_message("Writing @groups namelists to $outfile");
}
sub write_output_real_parameter_file {
my ($opts, $nl_flags, $definition, $defaults, $nl) = @_;
# Output real parameters
if ( defined($opts->{'output_reals_filename'}) ) {
my $file = $opts->{'output_reals_filename'};
my $fh = IO::File->new($file, '>>') or $log->fatal_error("can't create real parameter filename: $file");
foreach my $var ( $definition->get_var_names() ) {
my $type = $definition->get_var_type($var);
my $doc = $definition->get_var_doc($var);
$doc =~ s/\n//g;
if ( $type =~ /real/ ) {
my $val = $nl->get_value($var);
if ( ! defined($val) ) { $val = "?.??"; }
print $fh "\! $doc\n$var = $val\n";
}
}
$fh->close();
}
}
#-------------------------------------------------------------------------------
sub add_default {
# Add a value for the specified variable to the specified namelist object. The variables
# already in the object have the higher precedence, so if the specified variable is already
# defined in the object then don't overwrite it, just return.
#
# This method checks the definition file and adds the variable to the correct
# namelist group.
#
# The value can be provided by using the optional argument key 'val' in the
# calling list. Otherwise a default value is obtained from the namelist
# defaults object. If no default value is found this method throws an exception
# unless the 'nofail' option is set true.
#
# Example 1: Specify the default value $val for the namelist variable $var in namelist
# object $nl:
#
# add_default($inputdata_rootdir, $definition, $defaults, $nl, $var, 'val'=>$val)
#
# Example 2: Add a default for variable $var if an appropriate value is found. Otherwise
# don't add the variable
#
# add_default($inputdata_rootdir, $definition, $defaults, $nl, $var, 'nofail'=>1)
#
#
# ***** N.B. ***** This routine assumes the following variables are in package main::
# $definition -- the namelist definition object
# $defaults -- the namelist defaults object
# $inputdata_rootdir -- CESM inputdata root directory
my $opts = shift;
my $inputdata_rootdir = shift;
my $definition = shift;
my $defaults = shift;
my $nl = shift;
my $var = shift;
my %settings = @_;
my $test_files = $opts->{'test'};
#my $nl = shift; # namelist object
#my $var = shift; # name of namelist variable
#my %settings = @_; # options
# If variable has quotes around it
if ( $var =~ /'(.+)'/ ) {
$var = $1;
}
# Query the definition to find which group the variable belongs to. Exit if not found.
my $group = $definition->get_group_name($var);
unless ($group) {
my $fname = $definition->get_file_name();
$log->fatal_error("variable \"$var\" not found in namelist definition file $fname.");
}
# check whether the variable has a value in the namelist object -- if so then skip to end
my $val = $nl->get_variable_value($group, $var);
if (! defined $val) {
# Look for a specified value in the options hash
if (defined $settings{'val'}) {
$val = $settings{'val'};
}
# or else get a value from namelist defaults object.
# Note that if the 'val' key isn't in the hash, then just pass anything else
# in %settings to the get_value method to be used as attributes that are matched
# when looking for default values.
else {
$val = $defaults->get_value($var, \%settings);
# Truncate model_version appropriately
if ( $var eq "model_version" ) {
$val =~ /(URL: https:\/\/[a-zA-Z0-9._-]+\/)([a-zA-Z0-9\/._-]+)(\/bld\/.+)/;
$val = $2;
}
}
# if no value is found then exit w/ error (unless 'nofail' option set)
unless ( defined($val) ) {
unless ($settings{'nofail'}) {
if ($var eq 'finidat') {
$log->message("No default value found for $var.\n" .
" Are defaults provided for this resolution and land mask?" );
} else {
$log->fatal_error("No default value found for $var.\n" .
" Are defaults provided for this resolution and land mask?");
}
}
else {
return( 1 );
}
}
# query the definition to find out if the variable is an input pathname
my $is_input_pathname = $definition->is_input_pathname($var);
# The default values for input pathnames are relative. If the namelist
# variable is defined to be an absolute pathname, then prepend
# the CESM inputdata root directory.
if (not defined $settings{'no_abspath'}) {
if (defined $settings{'set_abspath'}) {
$val = set_abs_filepath($val, $settings{'set_abspath'});
} else {
if ($is_input_pathname eq 'abs') {
$val = set_abs_filepath($val, $inputdata_rootdir);
if ( $test_files and ($val !~ /null|none/) and (! -f "$val") ) {
$log->fatal_error("file not found: $var = $val");
}
}
}
}
# query the definition to find out if the variable takes a string value.
# The returned string length will be >0 if $var is a string, and 0 if not.
my $str_len = $definition->get_str_len($var);
# If the variable is a string, then add quotes if they're missing
if ($str_len > 0) {
$val = quote_string($val);
}
# set the value in the namelist
$nl->set_variable_value($group, $var, $val);
}
return( 0 );
}
#-------------------------------------------------------------------------------
sub expand_xml_variables_in_namelist {
# Go through all variables in the namelist and expand any XML env settings in them
my ($nl, $xmlvar_ref) = @_;
foreach my $group ( $nl->get_group_names() ) {
foreach my $var ( $nl->get_variable_names($group) ) {
my $val = $nl->get_variable_value($group, $var);
my $newval = SetupTools::expand_xml_var( $val, $xmlvar_ref );
if ( $newval ne $val ) {
$nl->set_variable_value($group, $var, $newval);
}
}
}
}
#-------------------------------------------------------------------------------
sub check_input_files {
# For each variable in the namelist which is an input dataset, check to see if it
# exists locally.
#
# ***** N.B. ***** This routine assumes the following variables are in package main::
# $definition -- the namelist definition object
# $nl -- namelist object
# $inputdata_rootdir -- if false prints test, else creates inputdata file
my ($nl, $inputdata_rootdir, $outfile, $definition) = @_;
open(OUTFILE, ">>$outfile") if defined $inputdata_rootdir;
# Look through all namelist groups
my @groups = $nl->get_group_names();
foreach my $group (@groups) {
# Look through all variables in each group
my @vars = $nl->get_variable_names($group);
foreach my $var (@vars) {
# Is the variable an input dataset?
my $input_pathname_type = $definition->is_input_pathname($var);
# If it is, check whether it exists locally and print status
if ($input_pathname_type) {
# Get pathname of input dataset
my $pathname = $nl->get_variable_value($group, $var);
# Need to strip the quotes
$pathname =~ s/['"]//g;
next if ($pathname =~ /UNSET$/);
if ($input_pathname_type eq 'abs') {
if ($inputdata_rootdir) {
if ( $pathname !~ /^\s*$/ ) { # If pathname isn't blank or null
print OUTFILE "$var = $pathname\n";
}
}
else {
if (-e $pathname) { # use -e rather than -f since the absolute pathname
# might be a directory
print "OK -- found $var = $pathname\n";
}
else {
print "NOT FOUND: $var = $pathname\n";
}
}
}
elsif ($input_pathname_type =~ m/rel:(.+)/o) {
# The match provides the namelist variable that contains the
# root directory for a relative filename
my $rootdir_var = $1;
my $rootdir = $nl->get_variable_value($group, $rootdir_var);
$rootdir =~ s/['"]//g;
if ($inputdata_rootdir) {
$pathname = "$rootdir/$pathname";
#MV $pathname =~ s:$inputdata_rootdir::;
if ( $pathname !~ /^\s*$/ ) { # If pathname isn't blank or null
print OUTFILE "$var = $pathname\n";
}
}
else {
if (-f "$rootdir/$pathname") {
print "OK -- found $var = $rootdir/$pathname\n";
}
else {
print "NOT FOUND: $var = $rootdir/$pathname\n";
}
}
}
}
}
}
close OUTFILE if defined $inputdata_rootdir;
return 0 if defined $inputdata_rootdir;
}
#-------------------------------------------------------------------------------
sub set_abs_filepath {
# check whether the input filepath is an absolute path, and if it isn't then
# prepend a root directory
my ($filepath, $rootdir) = @_;
# strip any leading/trailing whitespace and quotes
$filepath = trim($filepath);
$filepath = remove_leading_and_trailing_quotes($filepath);
$rootdir = trim($rootdir);
$rootdir = remove_leading_and_trailing_quotes($rootdir);
my $out = $filepath;
unless ( $filepath =~ /^\// ) { # unless $filepath starts with a /
$out = "$rootdir/$filepath"; # prepend the root directory
}
return $out;
}
#-------------------------------------------------------------------------------
sub valid_option {
my ($val, @expect) = @_;
my $expect;
$val = trim($val);
foreach $expect (@expect) {
if ($val =~ /^$expect$/i) { return $expect; }
}
return undef;
}
#-------------------------------------------------------------------------------
sub check_use_case_name {
#
# Check the use-case name and ensure it follows the naming convention.
#
my ($use_case) = @_;
my $diestring = "bad use_case name $use_case, follow the conventions " .
"in namelist_files/use_cases/README\n";
my $desc = "[a-zA-Z0-9]*";
my $ssp_rcp = "SSP[0-9]-[0-9\.]+";
if ( $use_case =~ /^[0-9]+-[0-9]+([a-zA-Z0-9_\.-]*)_transient$/ ) {
my $string = $1;
if ( $string =~ /^_($ssp_rcp)_*($desc)$/ ) {
# valid name
} elsif ( $string =~ /^_*($desc)$/ ) {
# valid name
} else {
$log->fatal_error($diestring);
}
} elsif ( $use_case =~ /^20thC([a-zA-Z0-9_\.]*)_transient$/ ) {
my $string = $1;
if ( $string =~ /^_($ssp_rcp)_*($desc)$/ ) {
# valid name
} elsif ( $string =~ /^_*($desc)$/ ) {
# valid name
} else {
$log->fatal_error($diestring);
}
} elsif ( $use_case =~ /^([0-9]+|PI)-PD_*($desc)_transient$/ ) {
# valid name
} elsif ( $use_case =~ /^([0-9]+)_*($desc)_control$/ ) {
# valid name
} elsif ( $use_case =~ /^($desc)_pd$/ ) {
# valid name
} else {
$log->fatal_error($diestring);
}
}
#-------------------------------------------------------------------------------
sub validate_options {
# $source -- text string declaring the source of the options being validated
# $cfg -- configure object
# $opts -- reference to hash that contains the options
my ($source, $cfg, $opts) = @_;
my ($opt, $old, @expect);
# use_case
$opt = 'use_case';
if (defined $opts->{$opt}) {
if ( $opts->{$opt} ne "list" ) {
# create the @expect array by listing the files in $use_case_dir
# and strip off the ".xml" part of the filename
@expect = ();
my @files = bsd_glob("$opts->{'use_case_dir'}/*.xml");
foreach my $file (@files) {
$file =~ m{.*/(.*)\.xml};
&check_use_case_name( $1 );
push @expect, $1;
}
$old = $opts->{$opt};
$opts->{$opt} = valid_option($old, @expect)
or $log->fatal_error("invalid value of $opt ($old) specified in $source\n" .
"expected one of: @expect");
} else {
print "Use cases are:...\n\n";
my @ucases;
foreach my $file( sort( bsd_glob($opts->{'use_case_dir'}."/*.xml") ) ) {
my $use_case;
if ( $file =~ /\/([^\/]+)\.xml$/ ) {
&check_use_case_name( $1 );
$use_case = $1;
} else {
$log->fatal_error("Bad name for use case file = $file");
}
my $uc_defaults = Build::NamelistDefaults->new("$file", $cfg);
printf "%15s = %s\n", $use_case, $uc_defaults->get_value("use_case_desc");
push @ucases, $use_case;
}
$log->exit_message("use cases : @ucases");
}
}
}
#-------------------------------------------------------------------------------
sub list_options {
#
# List the options for different command line values if asked for
#
my ($opts_cmdl, $definition, $defaults) = @_;
# options to list values that are in the defaults files
my @opts_list = ( "res", "mask", "sim_year", "ssp_rcp" );
my %opts_local;
foreach my $var ( "res", "mask", "sim_year", "ssp_rcp" ) {
my $val;
if ( $opts_cmdl->{$var} eq "list" ) {
$val = "default";
} elsif ( $opts_cmdl->{$var} eq "default" ) {
$val = $defaults->get_value($var, \%opts_local );
} else {
$val = $opts_cmdl->{$var};
}
my $vname = $var;
if ( $vname eq "res" ) { $vname = "hgrid"; }
$opts_local{$vname} = $val;
}
foreach my $var ( @opts_list ) {
if (defined $opts_cmdl->{$var}) {
if ( $opts_cmdl->{$var} eq "list" ) {
my @valid_values = $definition->get_valid_values( $var );
if ( $var eq "sim_year" ) {
unshift( @valid_values,
$definition->get_valid_values( "sim_year_range" ) );
}
unshift( @valid_values, "default" );
# Strip out quotes and the constant value
for( my $i = 0; $i <= $#valid_values; $i++ ) {
$valid_values[$i] =~ s/('|')//g;
if ( $valid_values[$i] eq "constant" ) { $valid_values[$i] = undef; }
}
my $val= $defaults->get_value($var, \%opts_local);
my $doc = $definition->get_var_doc( $var );
$doc =~ s/\n//;
chomp( $doc );
$log->exit_message("valid values for $var ($doc) :\n" .
" Values: @valid_values\n" .
" Default = $val\n" .
" (NOTE: resolution and mask and other settings may influence what the default is)");
}
}
}
# clm_demand
my $var = 'clm_demand';
if (defined $opts_cmdl->{$var}) {
if ( $opts_cmdl->{$var} eq "list" ) {
my @vars = $definition->get_var_names( );
my @demands = ( "null" );
foreach my $var ( @vars ) {
if ( $definition->get_group_name( $var ) ne "clm_inparm" ) { next; }
if ( defined($defaults->get_value($var, $opts_cmdl ) ) ) {
push( @demands, $var );
}
}
my $doc = $definition->get_var_doc( 'clm_demand' );
$doc =~ s/\n//;
chomp( $doc );
$log->exit_message("valid values for $var ($doc) :\n" .
"Namelist options to require: @demands\n" .
"any valid namelist item for clm_inparm can be set. However, not all are\n" .
"available in the clm defaults file. The defaults are also dependent on\n" .
"resolution and landmask, as well as other settings. Hence, the list above\n" .
"will vary depending on what you set for resolution and landmask.");
}
}
}
#-------------------------------------------------------------------------------
sub check_megan_spec {
#
# Check the megan specifier setting
#
my ($opts, $nl, $definition) = @_;
my $megan_spec = $nl->get_value('megan_specifier');
my @megan_spec_list = split( /\s*,\s*/, $megan_spec );
foreach $megan_spec ( @megan_spec_list ) {
if ( $megan_spec =~ /^['"]+[A-Za-z0-9]+\s*\=\s*([\sA-Za-z0-9+_-]+)["']+$/ ) {
my $megan_list = $1;
my @megan_cmpds = split( /\s*\+\s*/, $megan_list );
my $var = "megan_cmpds";
my $warn = 0;
foreach my $megan_cmpd ( @megan_cmpds ) {
if ( ! $definition->is_valid_value( $var, $megan_cmpd, 'noquotes'=>1 ) ) {
$log->warning("megan_compound $megan_cmpd NOT found in list" );
$warn++;
}
}
if ( $warn > 0 ) {
my @valid_values = $definition->get_valid_values( $var, 'noquotes'=>1 );
$log->warning("list of megan compounds includes:\n" .
"@valid_values\n" .
"Does your megan_factors_file include more compounds?\n" .
"If NOT your simulation will fail." );
}
} else {
$log->fatal_error("Bad format for megan_specifier = $megan_spec");
}
}
}
#-------------------------------------------------------------------------------
sub trim {
# remove leading and trailing whitespace from a string.
my ($str) = @_;
$str =~ s/^\s+//;
$str =~ s/\s+$//;
return $str;
}
#-------------------------------------------------------------------------------
sub quote_string {
# Add quotes around a string, unless they are already there
my ($str) = @_;
$str = trim($str);
unless ($str =~ /^['"]/) { #"'
$str = "\'$str\'";
}
return $str;
}
#-------------------------------------------------------------------------------
sub remove_leading_and_trailing_quotes {
# Remove leading and trailing single and double quotes from a string. Also
# removes leading spaces before the leading quotes, and trailing spaces after
# the trailing quotes.
my ($str) = @_;
$str = trim($str);
# strip any leading/trailing quotes
$str =~ s/^['"]+//;
$str =~ s/["']+$//;
return $str;
}
#-------------------------------------------------------------------------------
sub logical_to_fortran {
# Given a logical variable ('true' / 'false'), convert it to a fortran-style logical ('.true.' / '.false.')
# The result will be lowercase, regardless of the case of the input.
my ($var) = @_;
my $result;
if (lc($var) eq 'true') {
$result = ".true.";
}
elsif (lc($var) eq 'false') {
$result = ".false.";
}
else {
$log->fatal_error("Unexpected value in logical_to_fortran: $var");
}
return $result;
}
#-------------------------------------------------------------------------------
sub string_is_undef_or_empty {
# Return true if the given string is undefined or only spaces, false otherwise.
# A quoted empty string (' ' or " ") is treated as being empty.
my ($str) = @_;
if (!defined($str)) {
return 1;
}
else {
$str = remove_leading_and_trailing_quotes($str);
if ($str =~ /^\s*$/) {
return 1;
}
else {
return 0;
}
}
}
#-------------------------------------------------------------------------------
sub value_is_true {
# Return true if the given namelist value is .true.
# An undefined value is treated as false (with the assumption that false is the default in the code)
my ($val) = @_;
# Some regular expressions...
###my $TRUE = qr/\.true\./i;
###my $FALSE = qr/\.false\./i;
# **N.B.** the use of qr// for precompiling regexps isn't supported until perl 5.005.
my $TRUE = '\.?true\.?|[t]';
my $FALSE = '\.?false\.?|[f]';
my $is_true = 0;
if (defined($val)) {
if ($val =~ /$TRUE/i) {
$is_true = 1;
}
}
return $is_true;
}
#-------------------------------------------------------------------------------
sub version {
# The version is found in CLM ChangeLog file.
# $cfgdir is set by the configure script to the name of its directory.
my ($cfgdir) = @_;
my $logfile = "$cfgdir/../doc/ChangeLog";
my $fh = IO::File->new($logfile, '<') or $log->fatal_error("can't open ChangeLog file: $logfile");
while (my $line = <$fh>) {
if ($line =~ /^Tag name:\s*([a-zA-Z0-9_. -]*[clmcesm0-9_.-]+)$/ ) {
$log->exit_message("$1");
}
}
}
#-------------------------------------------------------------------------------
sub main {
my %nl_flags;
$nl_flags{'cfgdir'} = dirname(abs_path($0));
my %opts = process_commandline(\%nl_flags);
my $cfgdir = $nl_flags{'cfgdir'};
check_for_perl_utils($cfgdir, \%opts);
$log = namelist_files::LogMessages->new( $ProgName, \%opts ); # global
version($cfgdir) if $opts{'version'};
my $cfg = read_configure_definition($cfgdir, \%opts);
my $physv = config_files::clm_phys_vers->new( $cfg->get('phys') );
my $definition = read_namelist_definition($cfgdir, \%opts, \%nl_flags);
my $defaults = read_namelist_defaults($cfgdir, \%opts, \%nl_flags, $cfg);
# List valid values if asked for
list_options(\%opts, $definition, $defaults);
# Validate some of the commandline option values.
validate_options("commandline", $cfg, \%opts);
# Create an empty namelist object.
my $nl = Build::Namelist->new();
check_cesm_inputdata(\%opts, \%nl_flags);
# Read in the env_*.xml files
my %env_xml = read_envxml_case_files( \%opts );
# Process the user inputs
process_namelist_user_input(\%opts, \%nl_flags, $definition, $defaults, $nl, $cfg, \%env_xml, $physv );
# Get any other defaults needed from the namelist defaults file
process_namelist_inline_logic(\%opts, \%nl_flags, $definition, $defaults, $nl, \%env_xml, $physv);
# Validate that the entire resultant namelist is valid
$definition->validate($nl);
write_output_files(\%opts, \%nl_flags, $defaults, $nl);
write_output_real_parameter_file(\%opts, \%nl_flags, $definition, $defaults, $nl);
if ($opts{'inputdata'}) {
check_input_files($nl, $nl_flags{'inputdata_rootdir'}, $opts{'inputdata'}, $definition);
}
$log->final_exit("Successfully made CLM namelist file");
}
#-------------------------------------------------------------------------------
1;