#!/usr/bin/env perl
#-----------------------------------------------------------------------------------------------
#
# build-namelist
#
# This script builds the namelists for the MPASO configuration of E3SM
#
# build-namelist uses a config_cache.xml file that current contains the ocean grid information.
# build-namelist reads this file to obtain information it needs to provide
# default values that are consistent with the MPASO XML file.  For example, the grid resolution
# is obtained from the cache file and used to determine appropriate defaults for namelist input
# that is resolution dependent.
#
# 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.
#
#
# Date        Contributor      Modification
# -------------------------------------------------------------------------------------------
# 2015-01-28  djacobsen      Original version
#--------------------------------------------------------------------------------------------
use strict;
use Cwd qw(getcwd abs_path);
use English;
use Getopt::Long;
use IO::File;

#-----------------------------------------------------------------------------------------------

sub usage {
    die <<EOF;
SYNOPSIS
     build-namelist [options]
OPTIONS
     -infile "filepath"    Specify a file containing namelists to read values from.
     -namelist "namelist"  Specify namelist settings directly on the commandline by supplying
                           a string containing FORTRAN namelist syntax, e.g.,
                              -namelist "&mpaso_nml dt=1800 /"
     -help [or -h]         Print usage to STDOUT.
     -test                 Enable checking that input datasets exist on local filesystem.
     -verbose              Turn on verbose echoing of informational messages.
     -caseroot             CASEROOT directory variable
     -casebuild            CASEBUILD directory variable
     -cimeroot             CIMEROOT directory variable
     -ocn_grid             OCN_GRID variable
     -ocn_forcing          variable for defining if the ocn model is forced with an active atm
                           or using CORE forcing.
                           Options are: active_atm, datm_forced, datm_forced_restoring
     -ocn_iceberg          variable for defining if the ocn model is expecting coupling fields
                           for icebergs from the seaice model
                           Options are: false, true
     -ocn_ismf             variable for defining how the ocn model will handle ice shelf melt
                           fluxes
                           Options are: none, data, internal, coupled
     -ocn_sgr              variable for defining how the ocn model will handle subglacial
                           runoff
                           Options are: none, data
     -decomp_prefix        decomp_prefix variable
     -date_stamp           date_stamp variable
     -cfg_grid             Directory containing MPASO configuration scripts.
                           If not defined, location is set as \$ProgDir or \$cwd
                           (Needed to run build-namelist from SourceMods dir)
     -inst_string          inst_string variable
     -ocn_bgc              ocean BGC configuration
     -ocn_wave             ocean wave coupling flag
     -ocn_co2_type         how atm co2 is set within MPASO
     -atm_co2_const_val    value of atm co2 if ocn_co2_type = constant
     -ice_bgc              check for coupling with sea ice BGC
     -ntasks_ocn           NTASKS_OCN for this case
     -ninst_ocn            NINST_OCN for this case
     -ocn_tidal_mixing     variable for defining if to run with parameterized tidal mixing
                           Options are: false, true. Default is false

NOTE: The precedence for setting the values of namelist variables is (highest to lowest):
      1. namelist values set by specific command-line options, i.e. (none right now)
      2. values set on the command-line using the -namelist option,
      3. values read from the file specified by -infile,
      4. values from the namelist defaults file - or values specifically set in build-namelist
EOF
}

#-----------------------------------------------------------------------------------------------
# Set the directory that contains the MPASO configuration scripts.  If the command was
# issued using a relative or absolute path, that path is in $ProgDir.  Otherwise assume the
# command was issued from the current working directory.

(my $ProgName = $0) =~ s!(.*)/!!;      # name of this script
my $ProgDir = $1;                      # name of directory containing this script -- may be a
                                       # relative or absolute path, or null if the script is in
                                       # the user's PATH
my $cwd = getcwd();                    # current working directory
my $cfgdir;                            # absolute pathname of directory that contains this script
if ($ProgDir) {
    $cfgdir = abs_path($ProgDir);
} else {
    $cfgdir = $cwd;
}

#-----------------------------------------------------------------------------------------------

# Process command-line options.

my %opts = ( help          => 0,
             test          => 0,
             verbose       => 0,
             preview       => 0,
             caseroot      => undef,
             casebuild     => undef,
             cimeroot      => undef,
             inst_string   => undef,
             ocn_grid      => undef,
             ocn_forcing   => undef,
             ocn_iceberg   => undef,
             ocn_ismf      => undef,
             ocn_sgr      => undef,
             decomp_prefix => undef,
             date_stamp    => undef,
             ocn_bgc       => undef,
             ocn_wave      => undef,
             ocn_co2_type      => undef,
             atm_co2_const_val => undef,
             ice_bgc       => undef,
             cfg_dir       => $cfgdir,
             ntasks_ocn    => 0,
             ninst_ocn     => 0,
             ocn_tidal_mixing => undef,
           );

GetOptions(
    "h|help"          => \$opts{'help'},
    "infile=s"        => \$opts{'infile'},
    "namelist=s"      => \$opts{'namelist'},
    "v|verbose"       => \$opts{'verbose'},
    "caseroot=s"      => \$opts{'caseroot'},
    "casebuild=s"     => \$opts{'casebuild'},
    "cimeroot=s"      => \$opts{'cimeroot'},
    "inst_string=s"   => \$opts{'inst_string'},
    "ocn_grid=s"      => \$opts{'ocn_grid'},
    "ocn_forcing=s"   => \$opts{'ocn_forcing'},
    "ocn_iceberg=s"   => \$opts{'ocn_iceberg'},
    "ocn_ismf=s"      => \$opts{'ocn_ismf'},
    "ocn_sgr=s"       => \$opts{'ocn_sgr'},
    "decomp_prefix=s" => \$opts{'decomp_prefix'},
    "date_stamp=s"    => \$opts{'date_stamp'},
    "ocn_bgc=s"       => \$opts{'ocn_bgc'},
    "ocn_wave=s"      => \$opts{'ocn_wave'},
    "ocn_co2_type=s"      => \$opts{'ocn_co2_type'},
    "atm_co2_const_val=s" => \$opts{'atm_co2_const_val'},
    "ice_bgc=s"       => \$opts{'ice_bgc'},
    "cfg_dir=s"       => \$opts{'cfg_dir'},
    "ntasks_ocn=i"    => \$opts{'ntasks_ocn'},
    "ninst_ocn=i"     => \$opts{'ninst_ocn'},
    "preview"         => \$opts{'preview'},
    "ocn_tidal_mixing=s"   => \$opts{'ocn_tidal_mixing'},
)  or usage();

# Give usage message.
usage() if $opts{'help'};

# Check for unparsed arguments
if (@ARGV) {
    print "ERROR: unrecognized arguments: @ARGV\n";
    usage();
}

# Define print levels:
# 0 - only issue fatal error messages
# 1 - only informs what files are created (currently not used)
# 2 - verbose
my $print = 0;
my $preview = 0;
if ($opts{'verbose'}) { $print = 2; }
if ($opts{'preview'}) { $preview = 1; }
my $eol = "\n";

if ($print>=2) { print "Setting MPASO configuration script directory to $cfgdir$eol"; }

my $CASEROOT      = $opts{'caseroot'};
my $CASEBUILD     = $opts{'casebuild'};
my $CIMEROOT      = $opts{'cimeroot'};
my $inst_string   = $opts{'inst_string'};
my $OCN_GRID      = $opts{'ocn_grid'};
my $OCN_FORCING   = $opts{'ocn_forcing'};
my $OCN_ICEBERG   = $opts{'ocn_iceberg'};
my $OCN_ISMF      = $opts{'ocn_ismf'};
my $OCN_SGR       = $opts{'ocn_sgr'};
my $decomp_prefix = $opts{'decomp_prefix'};
my $date_stamp    = $opts{'date_stamp'};
my $ocn_bgc       = $opts{'ocn_bgc'};
my $ocn_wave      = $opts{'ocn_wave'};
my $ocn_co2_type      = $opts{'ocn_co2_type'};
my $atm_co2_const_val = $opts{'atm_co2_const_val'};
my $ice_bgc       = $opts{'ice_bgc'};
my $NINST_OCN     = $opts{'ninst_ocn'};
my $NTASKS_OCN    = $opts{'ntasks_ocn'};
my $OCN_TIDAL_MIXING   = $opts{'ocn_tidal_mixing'};
$cfgdir           = $opts{'cfg_dir'};

my $CIMEROOT;
if ( defined $opts{'cimeroot'} ) {
    $CIMEROOT = $opts{'cimeroot'};
}


# Validate some of the commandline option values.
validate_options("commandline", \%opts);

# build config_cache.xml file (needed below)
my $config_cache = "${CASEBUILD}/mpasoconf/config_cache.xml";
my  $fh = new IO::File;
$fh->open(">$config_cache") or die "** can't open file: $config_cache\n";
print $fh  <<"EOF";
<?xml version="1.0"?>
<config_definition>
<entry id="ocn_grid" value="$OCN_GRID">
<entry id="ocn_forcing" value="$OCN_FORCING">
<entry id="ocn_tidal_mixing" value="$OCN_TIDAL_MIXING">
<entry id="decomp_prefix" value="$decomp_prefix">
<entry id="date_stamp" value="$date_stamp">
</config_definition>
EOF
$fh->close;
if ($print>=2) { print "Wrote file $config_cache $eol"; }
(-f "config_cache.xml")  or  die <<"EOF";
** $ProgName - Cannot find configuration cache file: config_cache.xml\" **
EOF

#-----------------------------------------------------------------------------------------------
# Make sure we can find required perl modules, definition, and defaults files.
# Look for them under the directory that contains the configure script.

# The root directory for the input data files must be specified.

my $srcroot = abs_path("$CIMEROOT/../");
if (! -d "$srcroot") {
    die "** Invalid srcroot directory: $srcroot ** ";
}

print "SRCROOT IS: $srcroot\n";

my $perl5lib = "$CIMEROOT/utils/perl5lib";
if (! -d "$perl5lib") {
    die "** Invalid perl5lib root directory: $perl5lib ** ";
}

# The Build::Config module provides utilities to access the configuration information
# in the config_cache.xml file
(-f "$perl5lib/Build/Config.pm")  or  die <<"EOF";
** $ProgName - Cannot find perl module \"Build/Config.pm\" in directory \"$perl5lib\" **
EOF

# The Build::NamelistDefinition module provides utilities to validate that the output
# namelists are consistent with the namelist definition file
(-f "$perl5lib/Build/NamelistDefinition.pm")  or  die <<"EOF";
** $ProgName - Cannot find perl module \"Build/NamelistDefinition.pm\" in directory \"$perl5lib\" **
EOF

# 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/Build/NamelistDefaults.pm")  or  die <<"EOF";
** $ProgName - Cannot find perl module \"Build/NamelistDefaults.pm\" in directory \"$perl5lib\" **
EOF

# The Build::Namelist module provides utilities to parse input namelists, to query and modify
# namelists, and to write output namelists.
(-f "$perl5lib/Build/Namelist.pm")  or  die <<"EOF";
** $ProgName - Cannot find perl module \"Build/Namelist.pm\" in directory \"$perl5lib\" **
EOF


# The namelist definition file contains entries for all namelist variables that
# can be output by build-namelist.  The version of the file that is associate with a
# fixed MPASO tag is $cfgdir/namelist_files/namelist_definition.xml.  To aid developers
# who make use of the SourceMods/src.mpaso directory - we allow the definition file
# to come from that directory
my $nl_definition_file;
if (-f "${CASEROOT}/SourceMods/src.mpaso/namelist_definition_mpaso.xml") {
    $nl_definition_file = "${CASEROOT}/SourceMods/src.mpaso/namelist_definition_mpaso.xml";
}
if (! defined $nl_definition_file) {
    # default location of namelist definition file
    $nl_definition_file = "$cfgdir/namelist_files/namelist_definition_mpaso.xml";
    (-f "$nl_definition_file")  or  die <<"EOF";
    ** $ProgName - ERROR: Cannot find namelist definition file \"$nl_definition_file\" **
EOF
}
if ($print>=2) { print "Using namelist definition file $nl_definition_file$eol"; }

# The namelist defaults file contains default values for all required namelist variables.
my $nl_defaults_file;
if (-f "${CASEROOT}/SourceMods/src.mpaso/namelist_defaults_mpaso.xml") {
    $nl_defaults_file = "${CASEROOT}/SourceMods/src.mpaso/namelist_defaults_mpaso.xml";
}
if (! defined $nl_defaults_file) {
    $nl_defaults_file = "$cfgdir/namelist_files/namelist_defaults_mpaso.xml";
    (-f "$nl_defaults_file")  or  die <<"EOF";
    ** $ProgName - Cannot find namelist defaults file \"$nl_defaults_file\" **
EOF
}
if ($print>=2) { print "Using namelist defaults file $nl_defaults_file$eol"; }

#-----------------------------------------------------------------------------------------------
# Add $perl5lib_dir to the list of paths that Perl searches for modules
unshift @INC, "$perl5lib";
#require XML::Lite;
require Build::Config;
require Build::NamelistDefinition;
require Build::NamelistDefaults;
require Build::Namelist;
require Config::SetupTools;

#-----------------------------------------------------------------------------------------------
# Create a configuration object from the MPASO config_cache.xml file-  created by
# mpaso.cpl7.template in $CASEBUILD/mpasoconf
my $cfg = Build::Config->new('config_cache.xml');

# 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($nl_definition_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 MPASO library for which the namelist is being produced.
my $defaults = Build::NamelistDefaults->new($nl_defaults_file, $cfg);

# Create an empty namelist object.  Add values to it in order of precedence.
my $nl = Build::Namelist->new();

#-----------------------------------------------------------------------------------------------
# Process the user input in 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.

# Process the commandline args that provide specific namelist values.

# Process the -namelist arg.
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 ($@) {
      die "$ProgName - ERROR: Invalid namelist variable in commandline arg '-namelist'.\n $@";
    }

    # Merge input values into namelist.  Previously specified values have higher precedence
    # and are not overwritten.
    $nl->merge_nl($nl_arg_valid);
}

# Process the -infile arg.
if (defined $opts{'infile'}) {
    # Parse namelist input from a file
    my $nl_infile = Build::Namelist->new($opts{'infile'});
    my $nl_infile_valid = Build::Namelist->new();

    # Validate namelist variables (going to do this one variable at a time)
    for my $group ($nl_infile->get_group_names()) {
      for my $var ($nl_infile->get_variable_names($group)) {
        my $var_local; # Name of variable to write to infile
        my $nl_check_var = Build::Namelist->new();
        my $nl_check_valid;
        my $val = $nl_infile->get_variable_value($group, $var);
        my @broken = split(/&/,$var);
        my $check_grp = 0; # If 1, make sure group found in definitions file
                           # matches that specified in user_nl_mpaso

        # if variable has ampersand, truncate it unless it is type derived
        if ($broken[1]) {
          my $nl_check_amp = Build::Namelist->new();
          $nl_check_amp->set_variable_value($group, $var, $val);
          eval { $definition->validate($nl_check_amp) };
          if (not $@) {
            # & is required in variable name
            $var_local = $var;
          } else {
            # & should not be in variable name
            $var_local = $broken[0];
            $check_grp = 1;
          }
        } else {
          $var_local = $var;
        }

        # Make sure variable is defined in namelist_definition_mpaso.xml
        $nl_check_var->set_variable_value($group, $var_local,$val);
        eval { $nl_check_valid = $definition->validate($nl_check_var); };
        (not $@) or die <<"EOF";
** ERROR: either $var_local is not a valid MPASO namelist variable or $var_local = $val is not a valid value; please fix user_nl_mpaso. Note that $var_local may appear in multiple namelists, in which case you need to specify the correct namelist in user_nl_mpaso using the format $var_local\&namelist_nml = $val, where \&namelist_nml is the mpaso_in namelist containing $var_local.**
EOF

        # If group was specified in user_nl_mpaso, make sure it matches
        # the group in the definitions file.
        my @group_valid = $nl_check_valid->get_group_names();
        ((not $check_grp) or ($broken[1] eq $group_valid[0])) or die <<"EOF";
** ERROR: $broken[0] is in $group_valid[0], not $broken[1]! Please fix this in user_nl_mpaso. **
EOF

        # Add variable to validated namelist
        $nl_infile_valid->set_variable_value($group_valid[0], $var_local, $val);
      }
    }

    # If preview is desired and something has been changed in $nl_infile_valid,
    # output everything in $nl_infile_valid
    if (($preview == 1) && ($nl_infile_valid->get_group_names)) {
      print " - The following values have been set in user_nl_mpaso:\n";
      print_nl_to_screen($nl_infile_valid);
    }
    # Merge input values into namelist.  Previously specified values have higher
    # precedence and are not overwritten.
    $nl->merge_nl($nl_infile_valid);
}

#-----------------------------------------------------------------------------------------------
# Determine xml variables
#unshift @INC, "$CASEROOT/Tools";
#require XML::Lite;
#require SetupTools;

my %xmlvars = ();
SetupTools::getxmlvars($CASEROOT, \%xmlvars);
foreach my $attr (keys %xmlvars) {
  $xmlvars{$attr} = SetupTools::expand_xml_var($xmlvars{$attr}, \%xmlvars);
}

my $RUNDIR                 = "$xmlvars{'RUNDIR'}";
my $CODEROOT               = "$xmlvars{'CODEROOT'}";
my $DIN_LOC_ROOT           = "$xmlvars{'DIN_LOC_ROOT'}";
my $CASE                   = "$xmlvars{'CASE'}";
my $CALENDAR               = "$xmlvars{'CALENDAR'}";
my $NCPL_BASE_PERIOD       = "$xmlvars{'NCPL_BASE_PERIOD'}";
my $OCN_NCPL               = "$xmlvars{'OCN_NCPL'}";
my $OCN_COUPLING           = "$xmlvars{'OCN_COUPLING'}";
my $OCN_ICE_FORCING        = "$xmlvars{'OCN_ICE_FORCING'}";
my $INFO_DBUG              = "$xmlvars{'INFO_DBUG'}";
my $RUN_TYPE               = "$xmlvars{'RUN_TYPE'}";
my $RUN_STARTDATE          = "$xmlvars{'RUN_STARTDATE'}";
my $START_TOD              = "$xmlvars{'START_TOD'}";
my $RUN_REFDATE            = "$xmlvars{'RUN_REFDATE'}";
my $CONTINUE_RUN           = "$xmlvars{'CONTINUE_RUN'}";

my $output_r = "./${CASE}.mpaso.r";
my $output_h = "./${CASE}.mpaso.h";
my $output_d = "./${CASE}.mpaso.d";
if ($inst_string) {
    $output_r = "./${CASE}.mpaso${inst_string}.r";
    $output_h = "./${CASE}.mpaso${inst_string}.h";
    $output_d = "./${CASE}.mpaso${inst_string}.d";
}

# Environment variables set in mpaso.buildnml.csh that are not xml variables
my $RESTART_INPUT_TS_FMT = "$ENV{'RESTART_INPUT_TS_FMT'}";
my $LID = $ENV{'LID'};

my $ntasks = $NTASKS_OCN / $NINST_OCN;

print "MPASO build-namelist: ocn_grid is $OCN_GRID \n";
print "MPASO build-namelist: ocn_forcing is $OCN_FORCING \n";
print "MPASO build-namelist: ocn_tidal_mixing is $OCN_TIDAL_MIXING \n";

(-d $DIN_LOC_ROOT)  or mkdir $DIN_LOC_ROOT;
if ($print>=2) { print "CIME inputdata root directory: $DIN_LOC_ROOT$eol"; }

#-----------------------------------------------------------------------------------------------
# Determine namelist
#-----------------------------------------------------------------------------------------------


#############################
# Namelist group: run_modes #
#############################

add_default($nl, 'config_ocean_run_mode');

###################################
# Namelist group: time_management #
###################################

if ($CONTINUE_RUN eq 'TRUE') {
	add_default($nl, 'config_do_restart', 'val'=>".true.");
} else {
	add_default($nl, 'config_do_restart', 'val'=>".false.");
}
add_default($nl, 'config_restart_timestamp_name');
add_default($nl, 'config_calendar_type', 'calendar'=>"$CALENDAR");
if ($CONTINUE_RUN eq 'TRUE') {
	add_default($nl, 'config_start_time', 'val'=>"'file'");
} else {
	add_default($nl, 'config_start_time', 'val'=>"'${RUN_STARTDATE}_${START_TOD}'");
}
add_default($nl, 'config_output_reference_time');

######################
# Namelist group: io #
######################

add_default($nl, 'config_write_output_on_startup');
add_default($nl, 'config_pio_num_iotasks');
add_default($nl, 'config_pio_stride');

#################################
# Namelist group: decomposition #
#################################

add_default($nl, 'config_num_halos');
add_default($nl, 'config_block_decomp_file_prefix', 'val'=>"'${DIN_LOC_ROOT}/ocn/mpas-o/${OCN_GRID}/${decomp_prefix}${date_stamp}.part.'");
add_default($nl, 'config_number_of_blocks');
add_default($nl, 'config_explicit_proc_decomp');
add_default($nl, 'config_proc_decomp_file_prefix');

####################################
# Namelist group: time_integration #
####################################

add_default($nl, 'config_dt');
add_default($nl, 'config_time_integrator');
add_default($nl, 'config_number_of_time_levels');

########################
# Namelist group: hmix #
########################

add_default($nl, 'config_hmix_scaleWithMesh');
add_default($nl, 'config_maxMeshDensity');
add_default($nl, 'config_hmix_use_ref_cell_width');
add_default($nl, 'config_hmix_ref_cell_width');
add_default($nl, 'config_apvm_scale_factor');

#############################
# Namelist group: hmix_del2 #
#############################

add_default($nl, 'config_use_mom_del2');
add_default($nl, 'config_mom_del2');
add_default($nl, 'config_use_tracer_del2');
add_default($nl, 'config_tracer_del2');

#############################
# Namelist group: hmix_del4 #
#############################

add_default($nl, 'config_use_mom_del4');
add_default($nl, 'config_mom_del4');
add_default($nl, 'config_mom_del4_div_factor');
add_default($nl, 'config_use_tracer_del4');
add_default($nl, 'config_tracer_del4');

##############################
# Namelist group: hmix_Leith #
##############################

add_default($nl, 'config_use_Leith_del2');
add_default($nl, 'config_Leith_parameter');
add_default($nl, 'config_Leith_dx');
add_default($nl, 'config_Leith_visc2_max');

#########################################
# Namelist group: Redi_isopycnal_mixing #
#########################################

add_default($nl, 'config_use_Redi');
add_default($nl, 'config_Redi_closure');
add_default($nl, 'config_Redi_constant_kappa');
add_default($nl, 'config_Redi_maximum_slope');
add_default($nl, 'config_Redi_use_slope_taper');
add_default($nl, 'config_Redi_use_surface_taper');
add_default($nl, 'config_Redi_limit_term1');
add_default($nl, 'config_Redi_use_quasi_monotone_limiter');
add_default($nl, 'config_Redi_quasi_monotone_safety_factor');
add_default($nl, 'config_Redi_min_layers_diag_terms');
add_default($nl, 'config_Redi_horizontal_taper');
add_default($nl, 'config_Redi_horizontal_ramp_min');
add_default($nl, 'config_Redi_horizontal_ramp_max');

######################################################
# Namelist group: submesoscale_eddy_parameterization #
######################################################

add_default($nl, 'config_submesoscale_enable');
add_default($nl, 'config_submesoscale_tau');
add_default($nl, 'config_submesoscale_Ce');
add_default($nl, 'config_submesoscale_Lfmin');
add_default($nl, 'config_submesoscale_ds_max');

############################################
# Namelist group: GM_eddy_parameterization #
############################################

add_default($nl, 'config_use_GM');
add_default($nl, 'config_GM_closure');
add_default($nl, 'config_GM_constant_kappa');
add_default($nl, 'config_GM_constant_bclModeSpeed');
add_default($nl, 'config_GM_minBclModeSpeed_method');
add_default($nl, 'config_GM_spatially_variable_min_kappa');
add_default($nl, 'config_GM_spatially_variable_max_kappa');
add_default($nl, 'config_GM_spatially_variable_baroclinic_mode');
add_default($nl, 'config_GM_Visbeck_alpha');
add_default($nl, 'config_GM_Visbeck_max_depth');
add_default($nl, 'config_GM_EG_riMin');
add_default($nl, 'config_GM_EG_kappa_factor');
add_default($nl, 'config_GM_EG_Rossby_factor');
add_default($nl, 'config_GM_EG_Rhines_factor');
add_default($nl, 'config_GM_horizontal_taper');
add_default($nl, 'config_GM_horizontal_ramp_min');
add_default($nl, 'config_GM_horizontal_ramp_max');
add_default($nl, 'config_GMRedi_Rossby_ramp_min');
add_default($nl, 'config_GMRedi_Rossby_ramp_max');

#########################################
# Namelist group: eddy_parameterization #
#########################################

add_default($nl, 'config_eddyMLD_dens_threshold');
add_default($nl, 'config_eddyMLD_reference_depth');
add_default($nl, 'config_eddyMLD_reference_pressure');
add_default($nl, 'config_eddyMLD_use_old');

#########################
# Namelist group: cvmix #
#########################

add_default($nl, 'config_use_cvmix');
add_default($nl, 'config_cvmix_prandtl_number');
add_default($nl, 'config_cvmix_background_scheme');
add_default($nl, 'config_cvmix_background_diffusion');
add_default($nl, 'config_cvmix_background_diffusion_passive');
add_default($nl, 'config_cvmix_background_diffusion_passive_enable');
add_default($nl, 'config_cvmix_background_viscosity');
add_default($nl, 'config_cvmix_BryanLewis_bl1');
add_default($nl, 'config_cvmix_BryanLewis_bl2');
add_default($nl, 'config_cvmix_BryanLewis_transitionDepth');
add_default($nl, 'config_cvmix_BryanLewis_transitionWidth');
add_default($nl, 'config_use_cvmix_convection');
add_default($nl, 'config_cvmix_convective_diffusion');
add_default($nl, 'config_cvmix_convective_viscosity');
add_default($nl, 'config_cvmix_convective_basedOnBVF');
add_default($nl, 'config_cvmix_convective_triggerBVF');
add_default($nl, 'config_use_cvmix_shear');
add_default($nl, 'config_cvmix_num_ri_smooth_loops');
add_default($nl, 'config_cvmix_use_BLD_smoothing');
add_default($nl, 'config_cvmix_shear_mixing_scheme');
add_default($nl, 'config_cvmix_shear_PP_nu_zero');
add_default($nl, 'config_cvmix_shear_PP_alpha');
add_default($nl, 'config_cvmix_shear_PP_exp');
add_default($nl, 'config_cvmix_shear_KPP_nu_zero');
add_default($nl, 'config_cvmix_shear_KPP_Ri_zero');
add_default($nl, 'config_cvmix_shear_KPP_exp');
add_default($nl, 'config_use_cvmix_tidal_mixing');
add_default($nl, 'config_use_cvmix_double_diffusion');
add_default($nl, 'config_use_cvmix_kpp');
add_default($nl, 'config_use_cvmix_fixed_boundary_layer');
add_default($nl, 'config_cvmix_kpp_boundary_layer_depth');
add_default($nl, 'config_cvmix_kpp_criticalBulkRichardsonNumber');
add_default($nl, 'config_cvmix_kpp_matching');
add_default($nl, 'config_cvmix_kpp_EkmanOBL');
add_default($nl, 'config_cvmix_kpp_MonObOBL');
add_default($nl, 'config_cvmix_kpp_interpolationOMLType');
add_default($nl, 'config_cvmix_kpp_surface_layer_extent');
add_default($nl, 'config_cvmix_kpp_surface_layer_averaging');
add_default($nl, 'configure_cvmix_kpp_minimum_OBL_under_sea_ice');
add_default($nl, 'config_cvmix_kpp_stop_OBL_search');
add_default($nl, 'config_cvmix_kpp_use_enhanced_diff');
add_default($nl, 'config_cvmix_kpp_nonlocal_with_implicit_mix');
if ($ocn_wave eq 'true' ) {
	add_default($nl, 'config_cvmix_kpp_use_theory_wave', 'val'=>'.false.');
	add_default($nl, 'config_cvmix_kpp_use_active_wave', 'val'=>'.true.');
	add_default($nl, 'config_cvmix_kpp_langmuir_mixing_opt', 'val'=>'LWF16');
	add_default($nl, 'config_cvmix_kpp_langmuir_entrainment_opt', 'val'=>'LWF16');
} else {
	add_default($nl, 'config_cvmix_kpp_use_theory_wave');
	add_default($nl, 'config_cvmix_kpp_langmuir_mixing_opt');
	add_default($nl, 'config_cvmix_kpp_langmuir_entrainment_opt');
}

#################################
# Namelist group: wave_coupling #
#################################

if ($ocn_wave eq 'true' ) {
	add_default($nl, 'config_use_active_wave', 'val'=>'.true.');
} else {
	add_default($nl, 'config_use_active_wave', 'val'=>'.false.');
}
add_default($nl, 'config_n_stokes_drift_wavenumber_partitions');

########################
# Namelist group: gotm #
########################

add_default($nl, 'config_use_gotm');
add_default($nl, 'config_gotm_namelist_file');
add_default($nl, 'config_gotm_constant_surface_roughness_length');
add_default($nl, 'config_gotm_constant_bottom_roughness_length');
add_default($nl, 'config_gotm_constant_bottom_drag_coeff');

###########################
# Namelist group: forcing #
###########################

add_default($nl, 'config_use_variable_drag');
add_default($nl, 'config_use_bulk_wind_stress');
add_default($nl, 'config_use_bulk_thickness_flux');
add_default($nl, 'config_flux_attenuation_coefficient');
add_default($nl, 'config_flux_attenuation_coefficient_runoff');
if ($OCN_SGR eq 'data') {
	add_default($nl, 'config_subglacial_runoff_mode', 'val'=>"data");
} else {
	add_default($nl, 'config_subglacial_runoff_mode');
}
add_default($nl, 'config_flux_attenuation_coefficient_subglacial_runoff');
add_default($nl, 'config_sgr_flux_vertical_location');
add_default($nl, 'config_use_sgr_opt_kpp');
add_default($nl, 'config_use_sgr_opt_temp_prescribed');
add_default($nl, 'config_use_sgr_opt_salt_prescribed');
add_default($nl, 'config_sgr_temperature_prescribed');
add_default($nl, 'config_sgr_salinity_prescribed');

############################
# Namelist group: coupling #
############################

add_default($nl, 'config_remove_ais_river_runoff');
if (($OCN_ICEBERG eq 'true') && ($OCN_FORCING eq 'active_atm')) {
	add_default($nl, 'config_remove_ais_ice_runoff', 'val'=>".true.");
} else {
	add_default($nl, 'config_remove_ais_ice_runoff', 'val'=>".false.");
}

######################################
# Namelist group: shortwaveRadiation #
######################################

add_default($nl, 'config_sw_absorption_type');
add_default($nl, 'config_jerlov_water_type');
add_default($nl, 'config_surface_buoyancy_depth');
add_default($nl, 'config_enable_shortwave_energy_fixer');

###########################################
# Namelist group: self_attraction_loading #
###########################################

add_default($nl, 'config_use_self_attraction_loading');
add_default($nl, 'config_self_attraction_loading_depth_cutoff');
add_default($nl, 'config_mpas_to_grid_weights_file');
add_default($nl, 'config_grid_to_mpas_weights_file');
add_default($nl, 'config_self_attraction_loading_compute_interval');
add_default($nl, 'config_nLatitude');
add_default($nl, 'config_nLongitude');
add_default($nl, 'config_use_parallel_self_attraction_loading');
add_default($nl, 'config_parallel_self_attraction_loading_order');
add_default($nl, 'config_parallel_self_attraction_loading_n_cells_per_block');
add_default($nl, 'config_parallel_self_attraction_loading_bfb');

###########################################
# Namelist group: tidal_potential_forcing #
###########################################

add_default($nl, 'config_use_tidal_potential_forcing');
add_default($nl, 'config_tidal_potential_reference_time');
add_default($nl, 'config_use_tidal_potential_forcing_M2');
add_default($nl, 'config_use_tidal_potential_forcing_S2');
add_default($nl, 'config_use_tidal_potential_forcing_N2');
add_default($nl, 'config_use_tidal_potential_forcing_K2');
add_default($nl, 'config_use_tidal_potential_forcing_K1');
add_default($nl, 'config_use_tidal_potential_forcing_O1');
add_default($nl, 'config_use_tidal_potential_forcing_Q1');
add_default($nl, 'config_use_tidal_potential_forcing_P1');
add_default($nl, 'config_tidal_potential_ramp');
add_default($nl, 'config_self_attraction_and_loading_beta');

##############################
# Namelist group: frazil_ice #
##############################

add_default($nl, 'config_use_frazil_ice_formation');
add_default($nl, 'config_frazil_in_open_ocean');
add_default($nl, 'config_frazil_under_land_ice');
add_default($nl, 'config_frazil_heat_of_fusion');
add_default($nl, 'config_frazil_ice_density');
add_default($nl, 'config_frazil_fractional_thickness_limit');
add_default($nl, 'config_specific_heat_sea_water');
add_default($nl, 'config_frazil_maximum_depth');
add_default($nl, 'config_frazil_sea_ice_reference_salinity');
add_default($nl, 'config_frazil_maximum_freezing_temperature');
add_default($nl, 'config_frazil_use_surface_pressure');

###################################
# Namelist group: land_ice_fluxes #
###################################

if ($OCN_ISMF eq 'coupled') {
	add_default($nl, 'config_land_ice_flux_mode', 'val'=>"coupled");
} elsif ($OCN_ISMF eq 'internal') {
	add_default($nl, 'config_land_ice_flux_mode', 'val'=>"standalone");
} elsif ($OCN_ISMF eq 'data') {
	add_default($nl, 'config_land_ice_flux_mode', 'val'=>"data");
} else {
	add_default($nl, 'config_land_ice_flux_mode');
}
if ($OCN_TIDAL_MIXING eq 'true') {
	add_default($nl, 'config_land_ice_flux_tidal_Jourdain_alpha', 'val'=>"0.777");
	add_default($nl, 'config_land_ice_flux_tidal_Jourdain_A0', 'val'=>"0.656");
	add_default($nl, 'config_land_ice_flux_tidal_Jourdain_U0', 'val'=>"0.003");
} else {
	add_default($nl, 'config_land_ice_flux_tidal_Jourdain_alpha');
	add_default($nl, 'config_land_ice_flux_tidal_Jourdain_A0');
	add_default($nl, 'config_land_ice_flux_tidal_Jourdain_U0');
}
add_default($nl, 'config_land_ice_flux_formulation');
add_default($nl, 'config_land_ice_flux_useHollandJenkinsAdvDiff');
add_default($nl, 'config_land_ice_flux_attenuation_coefficient');
add_default($nl, 'config_land_ice_flux_boundaryLayerThickness');
add_default($nl, 'config_land_ice_flux_boundaryLayerNeighborWeight');
add_default($nl, 'config_land_ice_flux_cp_ice');
add_default($nl, 'config_land_ice_flux_rho_ice');
add_default($nl, 'config_land_ice_flux_explicit_topDragCoeff');
add_default($nl, 'config_land_ice_flux_ISOMIP_gammaT');
add_default($nl, 'config_land_ice_flux_jenkins_heat_transfer_coefficient');
add_default($nl, 'config_land_ice_flux_jenkins_salt_transfer_coefficient');

#############################
# Namelist group: advection #
#############################

add_default($nl, 'config_vert_advection_method');
add_default($nl, 'config_vert_remap_order');
add_default($nl, 'config_vert_remap_interval');
add_default($nl, 'config_vert_tracer_adv_flux_order');
add_default($nl, 'config_horiz_tracer_adv_order');
add_default($nl, 'config_coef_3rd_order');
add_default($nl, 'config_flux_limiter');
add_default($nl, 'config_remap_limiter');
add_default($nl, 'config_thickness_flux_type');

###############################
# Namelist group: bottom_drag #
###############################

add_default($nl, 'config_bottom_drag_mode');
add_default($nl, 'config_implicit_bottom_drag_type');
add_default($nl, 'config_implicit_constant_bottom_drag_coeff');
add_default($nl, 'config_use_implicit_top_drag');
add_default($nl, 'config_implicit_top_drag_coeff');
add_default($nl, 'config_loglaw_bottom_roughness');
add_default($nl, 'config_loglaw_layer_depth_max');
add_default($nl, 'config_loglaw_bottom_drag_min');
add_default($nl, 'config_loglaw_bottom_drag_max');
add_default($nl, 'config_explicit_bottom_drag_coeff');
add_default($nl, 'config_use_topographic_wave_drag');
add_default($nl, 'config_topographic_wave_drag_scheme');
add_default($nl, 'config_topographic_wave_drag_coeff');
add_default($nl, 'config_thickness_drag_type');
add_default($nl, 'config_topographic_wave_drag_cutoff_depth');
add_default($nl, 'config_topographic_wave_drag_cutoff_width');

####################################
# Namelist group: Rayleigh_damping #
####################################

add_default($nl, 'config_Rayleigh_damping_coeff');
add_default($nl, 'config_Rayleigh_damping_depth_variable');
add_default($nl, 'config_Rayleigh_bottom_friction');
add_default($nl, 'config_Rayleigh_bottom_damping_coeff');

###################################
# Namelist group: vegetation_drag #
###################################

add_default($nl, 'config_use_vegetation_drag');
add_default($nl, 'config_vegetation_drag_coefficient');

###################################
# Namelist group: ocean_constants #
###################################

add_default($nl, 'config_density0');

#####################################
# Namelist group: pressure_gradient #
#####################################

add_default($nl, 'config_pressure_gradient_type');
add_default($nl, 'config_common_level_weight');
add_default($nl, 'config_zonal_ssh_grad');
add_default($nl, 'config_meridional_ssh_grad');

#######################
# Namelist group: eos #
#######################

add_default($nl, 'config_eos_type');
add_default($nl, 'config_open_ocean_freezing_temperature_coeff_0');
add_default($nl, 'config_open_ocean_freezing_temperature_coeff_S');
add_default($nl, 'config_open_ocean_freezing_temperature_coeff_p');
add_default($nl, 'config_open_ocean_freezing_temperature_coeff_pS');
add_default($nl, 'config_open_ocean_freezing_temperature_coeff_mushy_az1_liq');
add_default($nl, 'config_land_ice_cavity_freezing_temperature_coeff_0');
add_default($nl, 'config_land_ice_cavity_freezing_temperature_coeff_S');
add_default($nl, 'config_land_ice_cavity_freezing_temperature_coeff_p');
add_default($nl, 'config_land_ice_cavity_freezing_temperature_coeff_pS');

##############################
# Namelist group: eos_linear #
##############################

add_default($nl, 'config_eos_linear_alpha');
add_default($nl, 'config_eos_linear_beta');
add_default($nl, 'config_eos_linear_Tref');
add_default($nl, 'config_eos_linear_Sref');
add_default($nl, 'config_eos_linear_densityref');

##############################
# Namelist group: eos_wright #
##############################

add_default($nl, 'config_eos_wright_ref_pressure');

########################################
# Namelist group: split_timestep_share #
########################################

add_default($nl, 'config_n_ts_iter');
add_default($nl, 'config_n_bcl_iter_beg');
add_default($nl, 'config_n_bcl_iter_mid');
add_default($nl, 'config_n_bcl_iter_end');

#####################################
# Namelist group: split_explicit_ts #
#####################################

add_default($nl, 'config_btr_dt');
add_default($nl, 'config_n_btr_cor_iter');
add_default($nl, 'config_vel_correction');
add_default($nl, 'config_btr_subcycle_loop_factor');
add_default($nl, 'config_btr_gam1_velWt1');
add_default($nl, 'config_btr_gam2_SSHWt1');
add_default($nl, 'config_btr_gam3_velWt2');
add_default($nl, 'config_btr_solve_SSH2');

#####################################
# Namelist group: split_implicit_ts #
#####################################

add_default($nl, 'config_btr_si_preconditioner');
add_default($nl, 'config_btr_si_tolerance');
add_default($nl, 'config_n_btr_si_large_iter');
add_default($nl, 'config_btr_si_partition_match_mode');

#####################################
# Namelist group: ALE_vertical_grid #
#####################################

add_default($nl, 'config_vert_coord_movement');
add_default($nl, 'config_ALE_thickness_proportionality');
add_default($nl, 'config_vert_taper_weight_depth_1');
add_default($nl, 'config_vert_taper_weight_depth_2');
add_default($nl, 'config_use_min_max_thickness');
add_default($nl, 'config_min_thickness');
add_default($nl, 'config_max_thickness_factor');
add_default($nl, 'config_dzdk_positive');

####################################################
# Namelist group: ALE_frequency_filtered_thickness #
#####################################################

add_default($nl, 'config_use_freq_filtered_thickness');
add_default($nl, 'config_thickness_filter_timescale');
add_default($nl, 'config_use_highFreqThick_restore');
add_default($nl, 'config_highFreqThick_restore_time');
add_default($nl, 'config_use_highFreqThick_del2');
add_default($nl, 'config_highFreqThick_del2');

#########################
# Namelist group: debug #
#########################

add_default($nl, 'config_check_zlevel_consistency');
add_default($nl, 'config_check_ssh_consistency');
add_default($nl, 'config_filter_btr_mode');
add_default($nl, 'config_prescribe_velocity');
add_default($nl, 'config_prescribe_thickness');
add_default($nl, 'config_include_KE_vertex');
add_default($nl, 'config_check_tracer_monotonicity');
add_default($nl, 'config_compute_active_tracer_budgets');
add_default($nl, 'config_disable_thick_all_tend');
add_default($nl, 'config_disable_thick_hadv');
add_default($nl, 'config_disable_thick_vadv');
add_default($nl, 'config_disable_thick_sflux');
add_default($nl, 'config_disable_vel_all_tend');
add_default($nl, 'config_disable_vel_hadv');
add_default($nl, 'config_disable_vel_coriolis');
add_default($nl, 'config_disable_vel_pgrad');
add_default($nl, 'config_disable_vel_hmix');
add_default($nl, 'config_disable_vel_surface_stress');
add_default($nl, 'config_disable_vel_topographic_wave_drag');
add_default($nl, 'config_disable_vel_explicit_bottom_drag');
add_default($nl, 'config_disable_vel_vmix');
add_default($nl, 'config_disable_vel_vadv');
add_default($nl, 'config_disable_tr_all_tend');
add_default($nl, 'config_disable_tr_adv');
add_default($nl, 'config_disable_tr_hmix');
add_default($nl, 'config_disable_tr_vmix');
add_default($nl, 'config_disable_tr_sflux');
add_default($nl, 'config_disable_tr_nonlocalflux');
add_default($nl, 'config_disable_redi_k33');
add_default($nl, 'config_read_nearest_restart');

###########################
# Namelist group: testing #
###########################

add_default($nl, 'config_conduct_tests');
add_default($nl, 'config_test_tensors');
add_default($nl, 'config_tensor_test_function');

###################################
# Namelist group: transport_tests #
###################################

add_default($nl, 'config_transport_tests_vert_levels');
add_default($nl, 'config_transport_tests_temperature');
add_default($nl, 'config_transport_tests_salinity');
add_default($nl, 'config_transport_tests_flow_id');

#########################################
# Namelist group: init_mode_vert_levels #
#########################################

add_default($nl, 'config_vert_levels');

#########################################
# Namelist group: manufactured_solution #
#########################################

add_default($nl, 'config_use_manufactured_solution');
add_default($nl, 'config_manufactured_solution_wavelength_x');
add_default($nl, 'config_manufactured_solution_wavelength_y');
add_default($nl, 'config_manufactured_solution_amplitude');

#####################################
# Namelist group: init_mode_subgrid #
#####################################

add_default($nl, 'config_subgrid_table_levels');

################################################
# Namelist group: tracer_forcing_activeTracers #
################################################

add_default($nl, 'config_use_activeTracers');
add_default($nl, 'config_use_activeTracers_surface_bulk_forcing');
if ($OCN_FORCING eq 'datm_forced_restoring') {
	add_default($nl, 'config_use_activeTracers_surface_restoring', 'val'=>".true.");
	add_default($nl, 'config_use_surface_salinity_monthly_restoring', 'val'=>".true.");
	add_default($nl, 'config_salinity_restoring_constant_piston_velocity', 'val'=>"1.585e-6");
	add_default($nl, 'config_salinity_restoring_max_difference', 'val'=>"100.");
	add_default($nl, 'config_salinity_restoring_under_sea_ice', 'val'=>".true.");
} else {
	add_default($nl, 'config_use_activeTracers_surface_restoring');
	add_default($nl, 'config_use_surface_salinity_monthly_restoring');
	add_default($nl, 'config_salinity_restoring_constant_piston_velocity');
	add_default($nl, 'config_salinity_restoring_max_difference');
	add_default($nl, 'config_salinity_restoring_under_sea_ice');
}
add_default($nl, 'config_surface_salinity_monthly_restoring_compute_interval');
add_default($nl, 'config_use_activeTracers_interior_restoring');
add_default($nl, 'config_use_activeTracers_exponential_decay');
add_default($nl, 'config_use_activeTracers_idealAge_forcing');
add_default($nl, 'config_use_activeTracers_ttd_forcing');

###############################################
# Namelist group: tracer_forcing_debugTracers #
###############################################

add_default($nl, 'config_use_debugTracers');
add_default($nl, 'config_reset_debugTracers_near_surface');
add_default($nl, 'config_reset_debugTracers_top_nLayers');
add_default($nl, 'config_use_debugTracers_surface_bulk_forcing');
add_default($nl, 'config_use_debugTracers_surface_restoring');
add_default($nl, 'config_use_debugTracers_interior_restoring');
add_default($nl, 'config_use_debugTracers_exponential_decay');
add_default($nl, 'config_use_debugTracers_idealAge_forcing');
add_default($nl, 'config_use_debugTracers_ttd_forcing');

################################################
# Namelist group: tracer_forcing_ecosysTracers #
################################################

if ($ocn_bgc eq 'eco_only' || $ocn_bgc eq 'eco_and_dms' || $ocn_bgc eq 'eco_and_macromolecules' || $ocn_bgc eq 'eco_and_dms_and_macromolecules' ) {
        add_default($nl, 'config_use_ecosysTracers', 'val'=>".true.");
        add_default($nl, 'config_ecosysTracers_diagnostic_fields_level1', 'val'=>".true.");
        add_default($nl, 'config_ecosysTracers_diagnostic_fields_level2', 'val'=>".true.");
        add_default($nl, 'config_ecosysTracers_diagnostic_fields_level3', 'val'=>".true.");
        add_default($nl, 'config_ecosysTracers_diagnostic_fields_level4', 'val'=>".true.");
        add_default($nl, 'config_ecosysTracers_diagnostic_fields_level5', 'val'=>".false.");
} else {
        add_default($nl, 'config_use_ecosysTracers', 'val'=>".false.");
        add_default($nl, 'config_ecosysTracers_diagnostic_fields_level1', 'val'=>".false.");
        add_default($nl, 'config_ecosysTracers_diagnostic_fields_level2', 'val'=>".false.");
        add_default($nl, 'config_ecosysTracers_diagnostic_fields_level3', 'val'=>".false.");
        add_default($nl, 'config_ecosysTracers_diagnostic_fields_level4', 'val'=>".false.");
        add_default($nl, 'config_ecosysTracers_diagnostic_fields_level5', 'val'=>".false.");
}
if ($ocn_co2_type eq 'constant' ) {
        add_default($nl, 'config_ecosys_atm_co2_option', 'val'=>"constant");
        add_default($nl, 'config_ecosys_atm_alt_co2_option', 'val'=>"constant");
        add_default($nl, 'config_ecosys_atm_alt_co2_use_eco', 'val'=>".false.");
        add_default($nl, 'config_ecosys_atm_co2_constant_value', 'val'=>$atm_co2_const_val);
} elsif ($ocn_co2_type eq 'bcrc' ) {
        add_default($nl, 'config_ecosys_atm_co2_option', 'val'=>"constant");
        add_default($nl, 'config_ecosys_atm_alt_co2_option', 'val'=>"constant");
        add_default($nl, 'config_ecosys_atm_alt_co2_use_eco', 'val'=>".false.");
        add_default($nl, 'config_ecosys_atm_co2_constant_value', 'val'=>$atm_co2_const_val);
} elsif ($ocn_co2_type eq 'bcrd' ) {
        add_default($nl, 'config_ecosys_atm_co2_option', 'val'=>"constant");
        add_default($nl, 'config_ecosys_atm_alt_co2_option', 'val'=>"diagnostic");
        add_default($nl, 'config_ecosys_atm_alt_co2_use_eco', 'val'=>".false.");
        add_default($nl, 'config_ecosys_atm_co2_constant_value', 'val'=>$atm_co2_const_val);
} elsif ($ocn_co2_type eq 'bdrc' ) {
        add_default($nl, 'config_ecosys_atm_co2_option', 'val'=>"diagnostic");
        add_default($nl, 'config_ecosys_atm_alt_co2_option', 'val'=>"constant");
        add_default($nl, 'config_ecosys_atm_alt_co2_use_eco', 'val'=>".false.");
        add_default($nl, 'config_ecosys_atm_co2_constant_value', 'val'=>$atm_co2_const_val);
} elsif ($ocn_co2_type eq 'bdrd' ) {
        add_default($nl, 'config_ecosys_atm_co2_option', 'val'=>"diagnostic");
        add_default($nl, 'config_ecosys_atm_alt_co2_option', 'val'=>"diagnostic");
        add_default($nl, 'config_ecosys_atm_alt_co2_use_eco', 'val'=>".false.");
        add_default($nl, 'config_ecosys_atm_co2_constant_value', 'val'=>$atm_co2_const_val);
} elsif ($ocn_co2_type eq 'prognostic' ) {
        add_default($nl, 'config_ecosys_atm_co2_option', 'val'=>"prognostic");
        add_default($nl, 'config_ecosys_atm_alt_co2_option', 'val'=>"prognostic");
        add_default($nl, 'config_ecosys_atm_alt_co2_use_eco', 'val'=>".false.");
        add_default($nl, 'config_ecosys_atm_co2_constant_value', 'val'=>$atm_co2_const_val);
} else {
        add_default($nl, 'config_ecosys_atm_co2_option', 'val'=>"diagnostic");
        add_default($nl, 'config_ecosys_atm_alt_co2_option', 'val'=>"diagnostic");
        add_default($nl, 'config_ecosys_atm_alt_co2_use_eco', 'val'=>".true.");
        add_default($nl, 'config_ecosys_atm_co2_constant_value', 'val'=>$atm_co2_const_val);
}
add_default($nl, 'config_use_ecosysTracers_surface_bulk_forcing');
add_default($nl, 'config_use_ecosysTracers_surface_restoring');
add_default($nl, 'config_use_ecosysTracers_interior_restoring');
add_default($nl, 'config_use_ecosysTracers_exponential_decay');
add_default($nl, 'config_use_ecosysTracers_idealAge_forcing');
add_default($nl, 'config_use_ecosysTracers_ttd_forcing');
add_default($nl, 'config_use_ecosysTracers_surface_value');
if ($ice_bgc eq 'ice_bgc' ) {
        add_default($nl, 'config_use_ecosysTracers_sea_ice_coupling', 'val'=>".true.");
} else {
        add_default($nl, 'config_use_ecosysTracers_sea_ice_coupling', 'val'=>".false.");
}
add_default($nl, 'config_use_ecosysTracers_river_inputs_from_coupler');

#############################################
# Namelist group: tracer_forcing_DMSTracers #
#############################################

if ($ocn_bgc eq 'eco_and_dms' || $ocn_bgc eq 'eco_and_dms_and_macromolecules' ) {
        add_default($nl, 'config_use_DMSTracers', 'val'=>".true.");
} else {
        add_default($nl, 'config_use_DMSTracers', 'val'=>".false.");
}
add_default($nl, 'config_use_DMSTracers_surface_bulk_forcing');
add_default($nl, 'config_use_DMSTracers_surface_restoring');
add_default($nl, 'config_use_DMSTracers_interior_restoring');
add_default($nl, 'config_use_DMSTracers_exponential_decay');
add_default($nl, 'config_use_DMSTracers_idealAge_forcing');
add_default($nl, 'config_use_DMSTracers_ttd_forcing');
add_default($nl, 'config_use_DMSTracers_surface_value');
add_default($nl, 'config_use_DMSTracers_sea_ice_coupling');

########################################################
# Namelist group: tracer_forcing_MacroMoleculesTracers #
########################################################

if ($ocn_bgc eq 'eco_and_macromolecules' || $ocn_bgc eq 'eco_and_dms_and_macromolecules' ) {
        add_default($nl, 'config_use_MacroMoleculesTracers', 'val'=>".true.");
} else {
        add_default($nl, 'config_use_MacroMoleculesTracers', 'val'=>".false.");
}
add_default($nl, 'config_use_MacroMoleculesTracers_surface_bulk_forcing');
add_default($nl, 'config_use_MacroMoleculesTracers_surface_restoring');
add_default($nl, 'config_use_MacroMoleculesTracers_interior_restoring');
add_default($nl, 'config_use_MacroMoleculesTracers_exponential_decay');
add_default($nl, 'config_use_MacroMoleculesTracers_idealAge_forcing');
add_default($nl, 'config_use_MacroMoleculesTracers_ttd_forcing');
add_default($nl, 'config_use_MacroMoleculesTracers_surface_value');
add_default($nl, 'config_use_MacroMoleculesTracers_sea_ice_coupling');

##################################################
# Namelist group: tracer_forcing_idealAgeTracers #
##################################################

add_default($nl, 'config_use_idealAgeTracers');
add_default($nl, 'config_use_idealAgeTracers_surface_bulk_forcing');
add_default($nl, 'config_use_idealAgeTracers_surface_restoring');
add_default($nl, 'config_use_idealAgeTracers_interior_restoring');
add_default($nl, 'config_use_idealAgeTracers_exponential_decay');
add_default($nl, 'config_use_idealAgeTracers_idealAge_forcing');
add_default($nl, 'config_use_idealAgeTracers_ttd_forcing');

#############################################
# Namelist group: tracer_forcing_CFCTracers #
#############################################

add_default($nl, 'config_use_CFCTracers');
add_default($nl, 'config_use_CFCTracers_surface_bulk_forcing');
add_default($nl, 'config_use_CFCTracers_surface_restoring');
add_default($nl, 'config_use_CFCTracers_interior_restoring');
add_default($nl, 'config_use_CFCTracers_exponential_decay');
add_default($nl, 'config_use_CFCTracers_idealAge_forcing');
add_default($nl, 'config_use_CFCTracers_ttd_forcing');
add_default($nl, 'config_use_CFC11');
add_default($nl, 'config_use_CFC12');

##################################
# Namelist group: AM_globalStats #
##################################

add_default($nl, 'config_AM_globalStats_enable');
add_default($nl, 'config_AM_globalStats_compute_interval');
add_default($nl, 'config_AM_globalStats_compute_on_startup');
add_default($nl, 'config_AM_globalStats_write_on_startup');
add_default($nl, 'config_AM_globalStats_text_file');
add_default($nl, 'config_AM_globalStats_directory');
add_default($nl, 'config_AM_globalStats_output_stream');

##################################################
# Namelist group: AM_surfaceAreaWeightedAverages #
##################################################

add_default($nl, 'config_AM_surfaceAreaWeightedAverages_enable');
add_default($nl, 'config_AM_surfaceAreaWeightedAverages_compute_on_startup');
add_default($nl, 'config_AM_surfaceAreaWeightedAverages_write_on_startup');
add_default($nl, 'config_AM_surfaceAreaWeightedAverages_compute_interval');
add_default($nl, 'config_AM_surfaceAreaWeightedAverages_output_stream');

######################################
# Namelist group: AM_waterMassCensus #
######################################

add_default($nl, 'config_AM_waterMassCensus_enable');
add_default($nl, 'config_AM_waterMassCensus_compute_interval');
add_default($nl, 'config_AM_waterMassCensus_output_stream');
add_default($nl, 'config_AM_waterMassCensus_compute_on_startup');
add_default($nl, 'config_AM_waterMassCensus_write_on_startup');
add_default($nl, 'config_AM_waterMassCensus_minTemperature');
add_default($nl, 'config_AM_waterMassCensus_maxTemperature');
add_default($nl, 'config_AM_waterMassCensus_minSalinity');
add_default($nl, 'config_AM_waterMassCensus_maxSalinity');
add_default($nl, 'config_AM_waterMassCensus_compute_predefined_regions');
add_default($nl, 'config_AM_waterMassCensus_region_group');

#################################################
# Namelist group: AM_layerVolumeWeightedAverage #
#################################################

add_default($nl, 'config_AM_layerVolumeWeightedAverage_enable');
add_default($nl, 'config_AM_layerVolumeWeightedAverage_compute_interval');
add_default($nl, 'config_AM_layerVolumeWeightedAverage_compute_on_startup');
add_default($nl, 'config_AM_layerVolumeWeightedAverage_write_on_startup');
add_default($nl, 'config_AM_layerVolumeWeightedAverage_output_stream');

################################
# Namelist group: AM_zonalMean #
################################

add_default($nl, 'config_AM_zonalMean_enable');
add_default($nl, 'config_AM_zonalMean_compute_on_startup');
add_default($nl, 'config_AM_zonalMean_write_on_startup');
add_default($nl, 'config_AM_zonalMean_compute_interval');
add_default($nl, 'config_AM_zonalMean_output_stream');
add_default($nl, 'config_AM_zonalMean_num_bins');
add_default($nl, 'config_AM_zonalMean_min_bin');
add_default($nl, 'config_AM_zonalMean_max_bin');

#################################
# Namelist group: AM_okuboWeiss #
#################################

add_default($nl, 'config_AM_okuboWeiss_enable');
add_default($nl, 'config_AM_okuboWeiss_compute_on_startup');
add_default($nl, 'config_AM_okuboWeiss_write_on_startup');
add_default($nl, 'config_AM_okuboWeiss_compute_interval');
add_default($nl, 'config_AM_okuboWeiss_output_stream');
add_default($nl, 'config_AM_okuboWeiss_directory');
add_default($nl, 'config_AM_okuboWeiss_threshold_value');
add_default($nl, 'config_AM_okuboWeiss_normalization');
add_default($nl, 'config_AM_okuboWeiss_lambda2_normalization');
add_default($nl, 'config_AM_okuboWeiss_use_lat_lon_coords');
add_default($nl, 'config_AM_okuboWeiss_compute_eddy_census');
add_default($nl, 'config_AM_okuboWeiss_eddy_min_cells');

##############################################
# Namelist group: AM_meridionalHeatTransport #
##############################################

add_default($nl, 'config_AM_meridionalHeatTransport_enable');
add_default($nl, 'config_AM_meridionalHeatTransport_compute_interval');
add_default($nl, 'config_AM_meridionalHeatTransport_compute_on_startup');
add_default($nl, 'config_AM_meridionalHeatTransport_write_on_startup');
add_default($nl, 'config_AM_meridionalHeatTransport_output_stream');
add_default($nl, 'config_AM_meridionalHeatTransport_num_bins');
add_default($nl, 'config_AM_meridionalHeatTransport_min_bin');
add_default($nl, 'config_AM_meridionalHeatTransport_max_bin');
add_default($nl, 'config_AM_meridionalHeatTransport_region_group');

##########################################
# Namelist group: AM_testComputeInterval #
##########################################

add_default($nl, 'config_AM_testComputeInterval_enable');
add_default($nl, 'config_AM_testComputeInterval_compute_interval');
add_default($nl, 'config_AM_testComputeInterval_compute_on_startup');
add_default($nl, 'config_AM_testComputeInterval_write_on_startup');
add_default($nl, 'config_AM_testComputeInterval_output_stream');

##########################################
# Namelist group: AM_highFrequencyOutput #
##########################################

add_default($nl, 'config_AM_highFrequencyOutput_enable');
add_default($nl, 'config_AM_highFrequencyOutput_compute_interval');
add_default($nl, 'config_AM_highFrequencyOutput_output_stream');
add_default($nl, 'config_AM_highFrequencyOutput_compute_on_startup');
add_default($nl, 'config_AM_highFrequencyOutput_write_on_startup');

##################################
# Namelist group: AM_timeFilters #
##################################

add_default($nl, 'config_AM_timeFilters_enable');
add_default($nl, 'config_AM_timeFilters_compute_interval');
add_default($nl, 'config_AM_timeFilters_output_stream');
add_default($nl, 'config_AM_timeFilters_restart_stream');
add_default($nl, 'config_AM_timeFilters_compute_on_startup');
add_default($nl, 'config_AM_timeFilters_write_on_startup');
add_default($nl, 'config_AM_timeFilters_initialize_filters');
add_default($nl, 'config_AM_timeFilters_tau');
add_default($nl, 'config_AM_timeFilters_compute_cell_centered_values');

####################################
# Namelist group: AM_lagrPartTrack #
####################################

add_default($nl, 'config_AM_lagrPartTrack_enable');
add_default($nl, 'config_AM_lagrPartTrack_compute_interval');
add_default($nl, 'config_AM_lagrPartTrack_compute_on_startup');
add_default($nl, 'config_AM_lagrPartTrack_output_stream');
add_default($nl, 'config_AM_lagrPartTrack_restart_stream');
add_default($nl, 'config_AM_lagrPartTrack_input_stream');
add_default($nl, 'config_AM_lagrPartTrack_write_on_startup');
add_default($nl, 'config_AM_lagrPartTrack_filter_number');
add_default($nl, 'config_AM_lagrPartTrack_timeIntegration');
add_default($nl, 'config_AM_lagrPartTrack_reset_criteria');
add_default($nl, 'config_AM_lagrPartTrack_reset_global_timestamp');
add_default($nl, 'config_AM_lagrPartTrack_region_stream');
add_default($nl, 'config_AM_lagrPartTrack_reset_if_outside_region');
add_default($nl, 'config_AM_lagrPartTrack_reset_if_inside_region');
add_default($nl, 'config_AM_lagrPartTrack_sample_horizontal_interp');
add_default($nl, 'config_AM_lagrPartTrack_sample_temperature');
add_default($nl, 'config_AM_lagrPartTrack_sample_salinity');
add_default($nl, 'config_AM_lagrPartTrack_sample_DIC');
add_default($nl, 'config_AM_lagrPartTrack_sample_ALK');
add_default($nl, 'config_AM_lagrPartTrack_sample_PO4');
add_default($nl, 'config_AM_lagrPartTrack_sample_NO3');
add_default($nl, 'config_AM_lagrPartTrack_sample_SiO3');
add_default($nl, 'config_AM_lagrPartTrack_sample_NH4');
add_default($nl, 'config_AM_lagrPartTrack_sample_Fe');
add_default($nl, 'config_AM_lagrPartTrack_sample_O2');

###################################
# Namelist group: AM_eliassenPalm #
###################################

add_default($nl, 'config_AM_eliassenPalm_enable');
add_default($nl, 'config_AM_eliassenPalm_compute_interval');
add_default($nl, 'config_AM_eliassenPalm_output_stream');
add_default($nl, 'config_AM_eliassenPalm_restart_stream');
add_default($nl, 'config_AM_eliassenPalm_compute_on_startup');
add_default($nl, 'config_AM_eliassenPalm_write_on_startup');
add_default($nl, 'config_AM_eliassenPalm_debug');
add_default($nl, 'config_AM_eliassenPalm_nBuoyancyLayers');
add_default($nl, 'config_AM_eliassenPalm_rhomin_buoycoor');
add_default($nl, 'config_AM_eliassenPalm_rhomax_buoycoor');

#######################################
# Namelist group: AM_mixedLayerDepths #
#######################################

add_default($nl, 'config_AM_mixedLayerDepths_enable');
add_default($nl, 'config_AM_mixedLayerDepths_compute_interval');
add_default($nl, 'config_AM_mixedLayerDepths_output_stream');
add_default($nl, 'config_AM_mixedLayerDepths_write_on_startup');
add_default($nl, 'config_AM_mixedLayerDepths_compute_on_startup');
add_default($nl, 'config_AM_mixedLayerDepths_Tthreshold');
add_default($nl, 'config_AM_mixedLayerDepths_crit_temp_threshold');
add_default($nl, 'config_AM_mixedLayerDepths_reference_pressure');
add_default($nl, 'config_AM_mixedLayerDepths_Tgradient');
add_default($nl, 'config_AM_mixedLayerDepths_Dgradient');
add_default($nl, 'config_AM_mixedLayerDepths_temp_gradient_threshold');
add_default($nl, 'config_AM_mixedLayerDepths_den_gradient_threshold');
add_default($nl, 'config_AM_mixedLayerDepths_interp_method');

#########################################
# Namelist group: AM_regionalStatsDaily #
#########################################

add_default($nl, 'config_AM_regionalStatsDaily_enable');
add_default($nl, 'config_AM_regionalStatsDaily_compute_on_startup');
add_default($nl, 'config_AM_regionalStatsDaily_write_on_startup');
add_default($nl, 'config_AM_regionalStatsDaily_compute_interval');
add_default($nl, 'config_AM_regionalStatsDaily_output_stream');
add_default($nl, 'config_AM_regionalStatsDaily_restart_stream');
add_default($nl, 'config_AM_regionalStatsDaily_input_stream');
add_default($nl, 'config_AM_regionalStatsDaily_operation');
add_default($nl, 'config_AM_regionalStatsDaily_region_type');
add_default($nl, 'config_AM_regionalStatsDaily_region_group');
add_default($nl, 'config_AM_regionalStatsDaily_1d_weighting_function');
add_default($nl, 'config_AM_regionalStatsDaily_2d_weighting_function');
add_default($nl, 'config_AM_regionalStatsDaily_1d_weighting_field');
add_default($nl, 'config_AM_regionalStatsDaily_2d_weighting_field');
add_default($nl, 'config_AM_regionalStatsDaily_vertical_mask');
add_default($nl, 'config_AM_regionalStatsDaily_vertical_dimension');

##########################################
# Namelist group: AM_regionalStatsWeekly #
##########################################

add_default($nl, 'config_AM_regionalStatsWeekly_enable');
add_default($nl, 'config_AM_regionalStatsWeekly_compute_on_startup');
add_default($nl, 'config_AM_regionalStatsWeekly_write_on_startup');
add_default($nl, 'config_AM_regionalStatsWeekly_compute_interval');
add_default($nl, 'config_AM_regionalStatsWeekly_output_stream');
add_default($nl, 'config_AM_regionalStatsWeekly_restart_stream');
add_default($nl, 'config_AM_regionalStatsWeekly_input_stream');
add_default($nl, 'config_AM_regionalStatsWeekly_operation');
add_default($nl, 'config_AM_regionalStatsWeekly_region_type');
add_default($nl, 'config_AM_regionalStatsWeekly_region_group');
add_default($nl, 'config_AM_regionalStatsWeekly_1d_weighting_function');
add_default($nl, 'config_AM_regionalStatsWeekly_2d_weighting_function');
add_default($nl, 'config_AM_regionalStatsWeekly_1d_weighting_field');
add_default($nl, 'config_AM_regionalStatsWeekly_2d_weighting_field');
add_default($nl, 'config_AM_regionalStatsWeekly_vertical_mask');
add_default($nl, 'config_AM_regionalStatsWeekly_vertical_dimension');

###########################################
# Namelist group: AM_regionalStatsMonthly #
###########################################

add_default($nl, 'config_AM_regionalStatsMonthly_enable');
add_default($nl, 'config_AM_regionalStatsMonthly_compute_on_startup');
add_default($nl, 'config_AM_regionalStatsMonthly_write_on_startup');
add_default($nl, 'config_AM_regionalStatsMonthly_compute_interval');
add_default($nl, 'config_AM_regionalStatsMonthly_output_stream');
add_default($nl, 'config_AM_regionalStatsMonthly_restart_stream');
add_default($nl, 'config_AM_regionalStatsMonthly_input_stream');
add_default($nl, 'config_AM_regionalStatsMonthly_operation');
add_default($nl, 'config_AM_regionalStatsMonthly_region_type');
add_default($nl, 'config_AM_regionalStatsMonthly_region_group');
add_default($nl, 'config_AM_regionalStatsMonthly_1d_weighting_function');
add_default($nl, 'config_AM_regionalStatsMonthly_2d_weighting_function');
add_default($nl, 'config_AM_regionalStatsMonthly_1d_weighting_field');
add_default($nl, 'config_AM_regionalStatsMonthly_2d_weighting_field');
add_default($nl, 'config_AM_regionalStatsMonthly_vertical_mask');
add_default($nl, 'config_AM_regionalStatsMonthly_vertical_dimension');

##########################################
# Namelist group: AM_regionalStatsCustom #
##########################################

add_default($nl, 'config_AM_regionalStatsCustom_enable');
add_default($nl, 'config_AM_regionalStatsCustom_compute_on_startup');
add_default($nl, 'config_AM_regionalStatsCustom_write_on_startup');
add_default($nl, 'config_AM_regionalStatsCustom_compute_interval');
add_default($nl, 'config_AM_regionalStatsCustom_output_stream');
add_default($nl, 'config_AM_regionalStatsCustom_restart_stream');
add_default($nl, 'config_AM_regionalStatsCustom_input_stream');
add_default($nl, 'config_AM_regionalStatsCustom_operation');
add_default($nl, 'config_AM_regionalStatsCustom_region_type');
add_default($nl, 'config_AM_regionalStatsCustom_region_group');
add_default($nl, 'config_AM_regionalStatsCustom_1d_weighting_function');
add_default($nl, 'config_AM_regionalStatsCustom_2d_weighting_function');
add_default($nl, 'config_AM_regionalStatsCustom_1d_weighting_field');
add_default($nl, 'config_AM_regionalStatsCustom_2d_weighting_field');
add_default($nl, 'config_AM_regionalStatsCustom_vertical_mask');
add_default($nl, 'config_AM_regionalStatsCustom_vertical_dimension');

###########################################
# Namelist group: AM_timeSeriesStatsDaily #
###########################################

add_default($nl, 'config_AM_timeSeriesStatsDaily_enable');
add_default($nl, 'config_AM_timeSeriesStatsDaily_compute_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsDaily_write_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsDaily_compute_interval');
add_default($nl, 'config_AM_timeSeriesStatsDaily_output_stream');
add_default($nl, 'config_AM_timeSeriesStatsDaily_restart_stream');
add_default($nl, 'config_AM_timeSeriesStatsDaily_operation');
add_default($nl, 'config_AM_timeSeriesStatsDaily_reference_times');
add_default($nl, 'config_AM_timeSeriesStatsDaily_duration_intervals');
add_default($nl, 'config_AM_timeSeriesStatsDaily_repeat_intervals');
add_default($nl, 'config_AM_timeSeriesStatsDaily_reset_intervals');
add_default($nl, 'config_AM_timeSeriesStatsDaily_backward_output_offset');

#############################################
# Namelist group: AM_timeSeriesStatsMonthly #
#############################################

add_default($nl, 'config_AM_timeSeriesStatsMonthly_enable');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_compute_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_write_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_compute_interval');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_output_stream');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_restart_stream');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_operation');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_reference_times');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_duration_intervals');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_repeat_intervals');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_reset_intervals');
add_default($nl, 'config_AM_timeSeriesStatsMonthly_backward_output_offset');

#################################################
# Namelist group: AM_timeSeriesStatsClimatology #
#################################################

add_default($nl, 'config_AM_timeSeriesStatsClimatology_enable');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_compute_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_write_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_compute_interval');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_output_stream');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_restart_stream');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_operation');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_reference_times');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_duration_intervals');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_repeat_intervals');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_reset_intervals');
add_default($nl, 'config_AM_timeSeriesStatsClimatology_backward_output_offset');

################################################
# Namelist group: AM_timeSeriesStatsMonthlyMax #
################################################

add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_enable');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_compute_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_write_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_compute_interval');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_output_stream');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_restart_stream');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_operation');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_reference_times');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_duration_intervals');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_repeat_intervals');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_reset_intervals');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMax_backward_output_offset');

################################################
# Namelist group: AM_timeSeriesStatsMonthlyMin #
################################################

add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_enable');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_compute_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_write_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_compute_interval');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_output_stream');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_restart_stream');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_operation');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_reference_times');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_duration_intervals');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_repeat_intervals');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_reset_intervals');
add_default($nl, 'config_AM_timeSeriesStatsMonthlyMin_backward_output_offset');

############################################
# Namelist group: AM_timeSeriesStatsCustom #
############################################

add_default($nl, 'config_AM_timeSeriesStatsCustom_enable');
add_default($nl, 'config_AM_timeSeriesStatsCustom_compute_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsCustom_write_on_startup');
add_default($nl, 'config_AM_timeSeriesStatsCustom_compute_interval');
add_default($nl, 'config_AM_timeSeriesStatsCustom_output_stream');
add_default($nl, 'config_AM_timeSeriesStatsCustom_restart_stream');
add_default($nl, 'config_AM_timeSeriesStatsCustom_operation');
add_default($nl, 'config_AM_timeSeriesStatsCustom_reference_times');
add_default($nl, 'config_AM_timeSeriesStatsCustom_duration_intervals');
add_default($nl, 'config_AM_timeSeriesStatsCustom_repeat_intervals');
add_default($nl, 'config_AM_timeSeriesStatsCustom_reset_intervals');
add_default($nl, 'config_AM_timeSeriesStatsCustom_backward_output_offset');

#####################################
# Namelist group: AM_pointwiseStats #
#####################################

add_default($nl, 'config_AM_pointwiseStats_enable');
add_default($nl, 'config_AM_pointwiseStats_compute_interval');
add_default($nl, 'config_AM_pointwiseStats_output_stream');
add_default($nl, 'config_AM_pointwiseStats_compute_on_startup');
add_default($nl, 'config_AM_pointwiseStats_write_on_startup');

#######################################
# Namelist group: AM_debugDiagnostics #
#######################################

add_default($nl, 'config_AM_debugDiagnostics_enable');
add_default($nl, 'config_AM_debugDiagnostics_compute_interval');
add_default($nl, 'config_AM_debugDiagnostics_output_stream');
add_default($nl, 'config_AM_debugDiagnostics_compute_on_startup');
add_default($nl, 'config_AM_debugDiagnostics_write_on_startup');
add_default($nl, 'config_AM_debugDiagnostics_check_state');

####################################
# Namelist group: AM_rpnCalculator #
####################################

add_default($nl, 'config_AM_rpnCalculator_enable');
add_default($nl, 'config_AM_rpnCalculator_compute_on_startup');
add_default($nl, 'config_AM_rpnCalculator_write_on_startup');
add_default($nl, 'config_AM_rpnCalculator_compute_interval');
add_default($nl, 'config_AM_rpnCalculator_output_stream');
add_default($nl, 'config_AM_rpnCalculator_variable_a');
add_default($nl, 'config_AM_rpnCalculator_variable_b');
add_default($nl, 'config_AM_rpnCalculator_variable_c');
add_default($nl, 'config_AM_rpnCalculator_variable_d');
add_default($nl, 'config_AM_rpnCalculator_variable_e');
add_default($nl, 'config_AM_rpnCalculator_variable_f');
add_default($nl, 'config_AM_rpnCalculator_variable_g');
add_default($nl, 'config_AM_rpnCalculator_variable_h');
add_default($nl, 'config_AM_rpnCalculator_expression_1');
add_default($nl, 'config_AM_rpnCalculator_expression_2');
add_default($nl, 'config_AM_rpnCalculator_expression_3');
add_default($nl, 'config_AM_rpnCalculator_expression_4');
add_default($nl, 'config_AM_rpnCalculator_output_name_1');
add_default($nl, 'config_AM_rpnCalculator_output_name_2');
add_default($nl, 'config_AM_rpnCalculator_output_name_3');
add_default($nl, 'config_AM_rpnCalculator_output_name_4');

########################################
# Namelist group: AM_transectTransport #
########################################

add_default($nl, 'config_AM_transectTransport_enable');
add_default($nl, 'config_AM_transectTransport_compute_interval');
add_default($nl, 'config_AM_transectTransport_output_stream');
add_default($nl, 'config_AM_transectTransport_compute_on_startup');
add_default($nl, 'config_AM_transectTransport_write_on_startup');
add_default($nl, 'config_AM_transectTransport_transect_group');

###########################################
# Namelist group: AM_eddyProductVariables #
###########################################

add_default($nl, 'config_AM_eddyProductVariables_enable');
add_default($nl, 'config_AM_eddyProductVariables_compute_interval');
add_default($nl, 'config_AM_eddyProductVariables_output_stream');
add_default($nl, 'config_AM_eddyProductVariables_compute_on_startup');
add_default($nl, 'config_AM_eddyProductVariables_write_on_startup');

########################################
# Namelist group: AM_mocStreamfunction #
########################################

add_default($nl, 'config_AM_mocStreamfunction_enable');
add_default($nl, 'config_AM_mocStreamfunction_compute_interval');
add_default($nl, 'config_AM_mocStreamfunction_output_stream');
add_default($nl, 'config_AM_mocStreamfunction_compute_on_startup');
add_default($nl, 'config_AM_mocStreamfunction_write_on_startup');
add_default($nl, 'config_AM_mocStreamfunction_min_bin');
add_default($nl, 'config_AM_mocStreamfunction_max_bin');
add_default($nl, 'config_AM_mocStreamfunction_num_bins');
add_default($nl, 'config_AM_mocStreamfunction_region_group');
add_default($nl, 'config_AM_mocStreamfunction_transect_group');

#######################################
# Namelist group: AM_oceanHeatContent #
#######################################

add_default($nl, 'config_AM_oceanHeatContent_enable');
add_default($nl, 'config_AM_oceanHeatContent_compute_interval');
add_default($nl, 'config_AM_oceanHeatContent_output_stream');
add_default($nl, 'config_AM_oceanHeatContent_compute_on_startup');
add_default($nl, 'config_AM_oceanHeatContent_write_on_startup');

###########################################
# Namelist group: AM_mixedLayerHeatBudget #
###########################################

add_default($nl, 'config_AM_mixedLayerHeatBudget_enable');
add_default($nl, 'config_AM_mixedLayerHeatBudget_compute_interval');
add_default($nl, 'config_AM_mixedLayerHeatBudget_output_stream');
add_default($nl, 'config_AM_mixedLayerHeatBudget_compute_on_startup');
add_default($nl, 'config_AM_mixedLayerHeatBudget_write_on_startup');

########################################
# Namelist group: AM_sedimentFluxIndex #
########################################

add_default($nl, 'config_AM_sedimentFluxIndex_enable');
add_default($nl, 'config_AM_sedimentFluxIndex_compute_on_startup');
add_default($nl, 'config_AM_sedimentFluxIndex_write_on_startup');
add_default($nl, 'config_AM_sedimentFluxIndex_compute_interval');
add_default($nl, 'config_AM_sedimentFluxIndex_output_stream');
add_default($nl, 'config_AM_sedimentFluxIndex_directory');
add_default($nl, 'config_AM_sedimentFluxIndex_use_lat_lon_coords');

########################################
# Namelist group: AM_sedimentTransport #
########################################

add_default($nl, 'config_AM_sedimentTransport_enable');
add_default($nl, 'config_AM_sedimentTransport_compute_on_startup');
add_default($nl, 'config_AM_sedimentTransport_write_on_startup');
add_default($nl, 'config_AM_sedimentTransport_compute_interval');
add_default($nl, 'config_AM_sedimentTransport_output_stream');
add_default($nl, 'config_AM_sedimentTransport_directory');
add_default($nl, 'config_AM_sedimentTransport_grain_size');
add_default($nl, 'config_AM_sedimentTransport_ws_formula');
add_default($nl, 'config_AM_sedimentTransport_bedld_formula');
add_default($nl, 'config_AM_sedimentTransport_SSC_ref_formula');
add_default($nl, 'config_AM_sedimentTransport_drag_coefficient');
add_default($nl, 'config_AM_sedimentTransport_erate');
add_default($nl, 'config_AM_sedimentTransport_tau_ce');
add_default($nl, 'config_AM_sedimentTransport_tau_cd');
add_default($nl, 'config_AM_sedimentTransport_Manning_coef');
add_default($nl, 'config_AM_sedimentTransport_grain_porosity');
add_default($nl, 'config_AM_sedimentTransport_water_density');
add_default($nl, 'config_AM_sedimentTransport_grain_density');
add_default($nl, 'config_AM_sedimentTransport_alpha');
add_default($nl, 'config_AM_sedimentTransport_kinematic_viscosity');
add_default($nl, 'config_AM_sedimentTransport_vertical_diffusion_coefficient');
add_default($nl, 'config_AM_sedimentTransport_bedload');
add_default($nl, 'config_AM_sedimentTransport_suspended');
add_default($nl, 'config_AM_sedimentTransport_use_lat_lon_coords');

#######################################
# Namelist group: AM_harmonicAnalysis #
#######################################

add_default($nl, 'config_AM_harmonicAnalysis_enable');
add_default($nl, 'config_AM_harmonicAnalysis_compute_interval');
add_default($nl, 'config_AM_harmonicAnalysis_start_delay');
add_default($nl, 'config_AM_harmonicAnalysis_duration');
add_default($nl, 'config_AM_harmonicAnalysis_output_stream');
add_default($nl, 'config_AM_harmonicAnalysis_restart_stream');
add_default($nl, 'config_AM_harmonicAnalysis_compute_on_startup');
add_default($nl, 'config_AM_harmonicAnalysis_write_on_startup');
add_default($nl, 'config_AM_harmonicAnalysis_use_M2');
add_default($nl, 'config_AM_harmonicAnalysis_use_S2');
add_default($nl, 'config_AM_harmonicAnalysis_use_N2');
add_default($nl, 'config_AM_harmonicAnalysis_use_K2');
add_default($nl, 'config_AM_harmonicAnalysis_use_K1');
add_default($nl, 'config_AM_harmonicAnalysis_use_O1');
add_default($nl, 'config_AM_harmonicAnalysis_use_Q1');
add_default($nl, 'config_AM_harmonicAnalysis_use_P1');

########################################
# Namelist group: AM_conservationCheck #
########################################

add_default($nl, 'config_AM_conservationCheck_enable');
add_default($nl, 'config_AM_conservationCheck_compute_interval');
add_default($nl, 'config_AM_conservationCheck_output_stream');
add_default($nl, 'config_AM_conservationCheck_compute_on_startup');
add_default($nl, 'config_AM_conservationCheck_write_on_startup');
add_default($nl, 'config_AM_conservationCheck_write_to_logfile');
add_default($nl, 'config_AM_conservationCheck_restart_stream');

#-----------------------------------------------------------------------------------------------
# *** Write output namelist file (mpaso_in) and input dataset list (mpaso.input_data_list) ***
#-----------------------------------------------------------------------------------------------
# Set namelist groups to be written out


my @groups = qw(run_modes
                time_management
                io
                decomposition
                time_integration
                hmix
                hmix_del2
                hmix_del4
                hmix_leith
                redi_isopycnal_mixing
                submesoscale_eddy_parameterization
                gm_eddy_parameterization
                eddy_parameterization
                cvmix
                wave_coupling
                gotm
                forcing
                coupling
                shortwaveradiation
                self_attraction_loading
                tidal_potential_forcing
                frazil_ice
                land_ice_fluxes
                advection
                bottom_drag
                rayleigh_damping
                vegetation_drag
                ocean_constants
                pressure_gradient
                eos
                eos_linear
                eos_wright
                split_timestep_share
                split_explicit_ts
                split_implicit_ts
                ale_vertical_grid
                ale_frequency_filtered_thickness
                debug
                testing
                transport_tests
                init_mode_vert_levels
                manufactured_solution
                init_mode_subgrid
                tracer_forcing_activetracers
                tracer_forcing_debugtracers
                tracer_forcing_ecosystracers
                tracer_forcing_dmstracers
                tracer_forcing_macromoleculestracers
                tracer_forcing_idealagetracers
                tracer_forcing_cfctracers
                am_globalstats
                am_surfaceareaweightedaverages
                am_watermasscensus
                am_layervolumeweightedaverage
                am_zonalmean
                am_okuboweiss
                am_meridionalheattransport
                am_testcomputeinterval
                am_highfrequencyoutput
                am_timefilters
                am_lagrparttrack
                am_eliassenpalm
                am_mixedlayerdepths
                am_regionalstatsdaily
                am_regionalstatsweekly
                am_regionalstatsmonthly
                am_regionalstatscustom
                am_timeseriesstatsdaily
                am_timeseriesstatsmonthly
                am_timeseriesstatsclimatology
                am_timeseriesstatsmonthlymax
                am_timeseriesstatsmonthlymin
                am_timeseriesstatscustom
                am_pointwisestats
                am_debugdiagnostics
                am_rpncalculator
                am_transecttransport
                am_eddyproductvariables
                am_mocstreamfunction
                am_oceanheatcontent
                am_mixedlayerheatbudget
                am_sedimentfluxindex
                am_sedimenttransport
                am_harmonicanalysis
                am_conservationcheck
                );

# Check for variables in the "derived" group, add them to appropriate group
for my $var ($nl->get_variable_names('derived')) {
  my @broken = split(/&/,$var);
  my $val = $nl->get_variable_value('derived', $var);
  $nl->set_variable_value($broken[1], $broken[0], $val);
}

# Write out all groups to mpaso_in
my $outfile = "./mpaso_in";
$nl->write($outfile, 'groups'=>\@groups);
if ($print>=2) { print "Writing mpaso ocean component namelist to $outfile $eol"; }

#--------------------------------------------------------------------
# Append namelist specified files to input data file
#     currently just the graph file -- which is complicated because the prefix
#     is set in the namelist and the suffix comes from the number of tasks
#--------------------------------------------------------------------

open(my $input_list, ">>", "$CASEBUILD/mpaso.input_data_list") or
     die "** can't open filepath file: mpaso.input_data_list\n";
my $block_decomp_file_prefix = $nl->get_value( 'config_block_decomp_file_prefix' );
# remove quotes for concatenation
$block_decomp_file_prefix =~ s/['"]//g;
my $block_decomp_file = $block_decomp_file_prefix . $NTASKS_OCN;
print $input_list "graph$NTASKS_OCN = $block_decomp_file\n";
$input_list->close;

# Write input dataset list.
check_input_files($DIN_LOC_ROOT, "$CASEBUILD/mpaso.input_data_list");

#-----------------------------------------------------------------------------------------------
# END OF MAIN SCRIPT
#===============================================================================================

#===============================================================================================
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.
#
# Additional optional keyword=>value pairs may be specified.  If the keyword 'val' is
# not present, then any other keyword=>value pairs that are specified will be used to
# match attributes in the defaults file.
#
# Example 1: Specify the default value $val for the namelist variable $var in namelist
#            object $nl:
#
#  add_default($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($nl, $var, 'nofail'=>1)
#
#
# ***** N.B. ***** This routine assumes the following variables are in package main::
#  $definition        -- the namelist definition object
#  $DIN_LOC_ROOT -- CCSM inputdata root directory

    my $nl = shift;     # namelist object
    my $var = shift;    # name of namelist variable
    my %opts = @_;      # options

    my $val = undef;

    # 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();
      die "$ProgName - ERROR: variable \"$var\" not found in namelist definition file $fname.\n";
    }

    # check whether the variable has a value in the namelist object -- if so then return
    $val = $nl->get_variable_value($group, $var);
    if (defined $val) { return; }

    # Look for a specified value in the options hash
    if (defined $opts{'val'}) {
      $val = $opts{'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 %opts to the get_value method to be used as attributes that are matched
    # when looking for default values.
    else {
      $val = get_default_value($var, \%opts);
    }

    # if no value is found then exit w/ error (unless 'nofail' option set)
    unless (defined $val) {
      unless ($opts{'nofail'}) {
        print "$ProgName - ERROR: No default value found for $var\n".
              "user defined attributes:\n";
        foreach my $key (keys(%opts)) {
          if ($key ne 'nofail' and $key ne 'val') {
            print "key=$key  val=$opts{$key}\n";
          }
        }
        die;
      } else {
        return;
      }
    }

    # 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 CCSM inputdata root directory.
    # TODO: unless ignore_abs is passed as argument
    if ($is_input_pathname eq 'abs') {
      unless ($opts{'noprepend'}){
        $val = set_abs_filepath($val, $DIN_LOC_ROOT);
      }
    }

    # 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);
}

#-----------------------------------------------------------------------------------------------

sub get_default_value {

# Return a default value for the requested variable.
# Return undef if no default found.
#
# ***** N.B. ***** This routine assumes the following variables are in package main::
#  $defaults          -- the namelist defaults object
#  $uc_defaults       -- the use CASE defaults object

    my $var_name    = lc(shift);   # name of namelist variable (CASE insensitive interface)
    my $usr_att_ref = shift;       # reference to hash containing user supplied attributes

    # Check in the namelist defaults
    return $defaults->get_value($var_name, $usr_att_ref);

}

#-----------------------------------------------------------------------------------------------

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

    my $inputdata_rootdir = shift;    # if false prints test, else creates inputdata file
    my $data_file_list = shift;
    open(my $fh, "<:encoding(UTF-8)", $data_file_list) or die "Couldn't open data file list $data_file_list";

	while (my $row = <$fh>) {
		chomp $row;
		my @split = split(' = ', $row);
		#my $input_path = $split[2]

		if (-e $split[1] ) {
			print "OK -- found $split[1]\n"
		} else {
			print "NOT FOUND: $split[1]\n"
		}
	}
    close $fh;
    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
    $filepath =~ s/^\s+//;
    $filepath =~ s/\s+$//;
    $rootdir  =~ s/^\s+//;
    $rootdir  =~ s/\s+$//;

    # strip any leading/trailing quotes
    $filepath =~ s/^['"]+//;
    $filepath =~ s/["']+$//;
    $rootdir =~ s/^['"]+//;
    $rootdir =~ s/["']+$//;

    my $out = $filepath;
    unless ( $filepath =~ /^\// ) {  # unless $filepath starts with a /
      $out = "$rootdir/$filepath"; # prepend the root directory
    }
    return $out;
}

#-----------------------------------------------------------------------------------------------


sub absolute_path {
#
# Convert a pathname into an absolute pathname, expanding any . or .. characters.
# Assumes pathnames refer to a local filesystem.
# Assumes the directory separator is "/".
#
  my $path = shift;
  my $cwd = getcwd();  # current working directory
  my $abspath;         # resulting absolute pathname

# Strip off any leading or trailing whitespace.  (This pattern won't match if
# there's embedded whitespace.
  $path =~ s!^\s*(\S*)\s*$!$1!;

# Convert relative to absolute path.

  if ($path =~ m!^\.$!) {          # path is "."
      return $cwd;
  } elsif ($path =~ m!^\./!) {     # path starts with "./"
      $path =~ s!^\.!$cwd!;
  } elsif ($path =~ m!^\.\.$!) {   # path is ".."
      $path = "$cwd/..";
  } elsif ($path =~ m!^\.\./!) {   # path starts with "../"
      $path = "$cwd/$path";
  } elsif ($path =~ m!^[^/]!) {    # path starts with non-slash character
      $path = "$cwd/$path";
  }

  my ($dir, @dirs2);
  my @dirs = split "/", $path, -1;   # The -1 prevents split from stripping trailing nulls
                                     # This enables correct processing of the input "/".

  # Remove any "" that are not leading.
  for (my $i=0; $i<=$#dirs; ++$i) {
      if ($i == 0 or $dirs[$i] ne "") {
        push @dirs2, $dirs[$i];
      }
  }
  @dirs = ();

  # Remove any "."
  foreach $dir (@dirs2) {
      unless ($dir eq ".") {
        push @dirs, $dir;
      }
  }
  @dirs2 = ();

  # Remove the "subdir/.." parts.
  foreach $dir (@dirs) {
    if ( $dir !~ /\.\./ ) {
        push @dirs2, $dir;
    } else {
        pop @dirs2;   # remove previous dir when current dir is ..
    }
  }
  if ($#dirs2 == 0 and $dirs2[0] eq "") { return "/"; }
  $abspath = join '/', @dirs2;
  return( $abspath );
}

#-------------------------------------------------------------------------------

sub valid_option {

    my ($val, @expect) = @_;
    my ($expect);

    $val =~ s/^\s+//;
    $val =~ s/\s+$//;
    foreach $expect (@expect) {
      if ($val =~ /^$expect$/i) { return $expect; }
    }
    return undef;
}

#-------------------------------------------------------------------------------

sub validate_options {

    my $source = shift;   # text string declaring the source of the options being validated
    my $opts   = shift;   # reference to hash that contains the options

    my ($opt, $old, @expect);

}

#-------------------------------------------------------------------------------

sub quote_string {
    my $str = shift;
    $str =~ s/^\s+//;
    $str =~ s/\s+$//;
    unless ($str =~ /^['"]/) {        #"'
        $str = "\'$str\'";
    }
    return $str;
}

#-------------------------------------------------------------------------------

sub expand_env_xml {

    my $value = shift;

    if ($value =~ /\$([\w_]+)(.*)$/) {
	my $subst = $xmlvars{$1};
	$value =~ s/\$${1}/$subst/g;
    }
    return $value;
}

#-------------------------------------------------------------------------------

sub print_nl_to_screen {

  my $namelist = $_[0];
  # Loop through every group in the namelist
  for my $group ($namelist->get_group_names()) {
    # Loop through every variable in group
    for my $var ($namelist->get_variable_names($group)) {
      my $val = $namelist->get_variable_value($group, $var);
      # For derived type, $var contains variable name and group name
      if ($group eq "derived") {
        my @broken = split(/&/,$var);
        print "   * ", $broken[0], " = ", $val, " in \&", $broken[1], "\n";
      }
      else {
        print "   * ", $var, " = ", $val, " in \&", $group, "\n";
      }
    }
  }
}

#-------------------------------------------------------------------------------

sub valid_date {
# return 1 if given date ($$month/$$day/$$year) exists in calendar $cal
# otherwise subtract number of days in $$month from $$day, and increment
# $$month by 1 (also incrementing $$year if going from Dec to Jan) and
# then return 0.

  my $day = shift;
  my $month = shift;
  my $year = shift;
  my $cal = shift;

  my $maxday = -1;
  if ($$month == 1) { $maxday = 31; }
  if ($$month == 2) {
       if (($cal eq 'NO_LEAP') || (not leap($$year))) {
         $maxday = 28;
       } else {
         $maxday = 29;
       }
     }
  if ($$month == 3) { $maxday = 31; }
  if ($$month == 4) { $maxday = 30; }
  if ($$month == 5) { $maxday = 31; }
  if ($$month == 6) { $maxday = 30; }
  if ($$month == 7) { $maxday = 31; }
  if ($$month == 8) { $maxday = 31; }
  if ($$month == 9) { $maxday = 30; }
  if ($$month == 10) { $maxday = 31; }
  if ($$month == 11) { $maxday = 30; }
  if ($$month == 12) { $maxday = 31; }

  if ($maxday == -1) {
    die "ERROR: can not figure out what month $$month is";
  }
  if ($$day > $maxday) {
    $$month++;
    if ($$month == 13) {
      $$year++;
      $$month = 1;
    }
    $$day = $$day - $maxday;
    return 0;
  }
  return 1;
}

#-------------------------------------------------------------------------------

sub leap() {
# return 1 if given year is a leap year, 0 otherwise

  my $year = shift;

  if (($year%4 == 0) && (($year%400 == 0) || ($year%100 != 0))) {
    return 1;
  }
  return 0;
}


#-------------------------------------------------------------------------------

sub any() {
# return 1 if array (arg 0) contains val (arg 1). Note that this uses "eq"
# instead of "==" because it's meant for strings

  my $array_ref = shift;
  my @array = @$array_ref;
  my $val = shift;

  foreach (@array) {
    if ($_ eq $val) {
      return 1;
    }
  }
  return 0;
}
