# 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 < 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 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 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 = "e_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 = "e_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 = "e_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 = "e_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 = "e_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;