clm5.0/bld/queryDefaultNamelist.pl
2025-01-12 20:48:10 +08:00

318 lines
12 KiB
Perl
Executable File

#!/usr/bin/env perl
#=======================================================================
#
# This is a script to read the CLM namelist XML file
#
# Usage:
#
# queryDefaultNamelist.pl [options]
#
# To get help on options and usage:
#
# queryDefaultNamelist.pl -help
#
#=======================================================================
use Cwd;
use strict;
#use diagnostics;
use Getopt::Long;
use English;
#-----------------------------------------------------------------------------------------------
#Figure out where configure directory is and where can use the XML/Lite module from
my $ProgName;
($ProgName = $PROGRAM_NAME) =~ s!(.*)/!!; # name of program
my $ProgDir = $1; # name of directory where program lives
my $cwd = getcwd(); # current working directory
my $cfgdir;
if ($ProgDir) { $cfgdir = $ProgDir; }
else { $cfgdir = $cwd; }
#-----------------------------------------------------------------------------------------------
# Add $cfgdir to the list of paths that Perl searches for modules
my @dirs = ( "$cfgdir",
"$cfgdir/../cime/utils/perl5lib",
"$cfgdir/../../../cime/utils/perl5lib" );
unshift @INC, @dirs;
my $result = eval "require XML::Lite";
if ( ! defined($result) ) {
die <<"EOF";
** Cannot find perl module \"XML/Lite.pm\" from directories: @dirs **
EOF
}
require Build::Config;
require Build::NamelistDefinition;
require queryDefaultXML;
# Defaults
my $namelist = "clm_inparm";
my $config = "config_cache.xml";
sub usage {
die <<EOF;
SYNOPSIS
$ProgName [options]
query default namelist values.
OPTIONS
-config "file" CLM build configuration file created by configure.
-cesm CESM mode set csmdata to \$DIN_LOC_ROOT.
-usrname "name" Dataset resolution/descriptor for personal datasets.
Default : not used
Example: 1x1pt_boulderCO to describe location,
number of pts
-csmdata "dir" Directory for head of csm inputdata.
-demand Demand that something is returned.
-filenameonly Only return the filename -- not the full path to it.
-help [or -h] Display this help.
-justvalue Just display the values (NOT key = value).
-var "varname" Variable name to match. Use "-var list" to
list valid variable names from all namelists.
-namelist "namelistname" Namelist name to read in (by default $namelist).
-onlyfiles Only output filenames.
-options "item=value,item2=value2" Set options to query for when matching.
(comma delimited, with equality to set value).
-phys "CLM-version" [or -p] CLM version to use (clm4_0 or clm4_5)
-res "resolution" Resolution to use for files. Use "-res list" to
list all valid resolutions. Use "-res any" to
use any valid resolution.
-silent [or -s] Do not do any extra printing.
-test [or -t] Test that files exists.
EXAMPLES
To list all fsurdat files that match the resolution: 10x15:
$ProgName -var "fsurdat" -res 10x15
To only list files that match T42 resolution (or are for all resolutions)
$ProgName -onlyfiles -res 64x128
To test that all of the files exist on disk under a different default inputdata
$ProgName -onlyfiles -test -csmdata /spin/proj/ccsm/inputdata
To query for namelist items that match particular configurations
$ProgName -namelist seq_infodata_inparm -options sim_year=2000,bgc=cn
Only lists namelist items in the seqinfodata_inparm namelist with options for
sim_year=2000 and BGC=cn.
EOF
}
#-----------------------------------------------------------------------------------------------
my %opts = (
namelist => $namelist,
model => "clm4_5",
var => undef,
hgrid => undef,
config => undef,
cesm => undef,
csmdata => undef,
demand => undef,
test => undef,
onlyfiles => undef,
fileonly => undef,
silent => undef,
usrname => undef,
help => undef,
options => undef,
);
my $cmdline = "@ARGV";
GetOptions(
"f|file=s" => \$opts{'file'},
"n|namelist=s" => \$opts{'namelist'},
"v|var=s" => \$opts{'var'},
"p|phys=s" => \$opts{'model'},
"r|res=s" => \$opts{'hgrid'},
"config=s" => \$opts{'config'},
"cesm" => \$opts{'cesm'},
"csmdata=s" => \$opts{'csmdata'},
"demand" => \$opts{'demand'},
"options=s" => \$opts{'options'},
"t|test" => \$opts{'test'},
"onlyfiles" => \$opts{'onlyfiles'},
"filenameonly" => \$opts{'fileonly'},
"justvalues" => \$opts{'justvalues'},
"usrname=s" => \$opts{'usrname'},
"s|silent" => \$opts{'silent'},
"h|elp" => \$opts{'help'},
) or usage();
# Check for unparsed arguments
if (@ARGV) {
print "ERROR: unrecognized arguments: @ARGV\n";
usage();
}
if ( $opts{'help'} ) {
usage();
}
# Set if should do extra printing or not (if silent mode is not set)
my $printing = 1;
if ( defined($opts{'silent'}) ) {
$printing = 0;
}
# Get list of options from command-line into the settings hash
my %settings;
if ( defined($opts{'options'}) ) {
$opts{'options'} =~ s/\s//g; # Remove all white-space in options
my @optionlist = split( ",", $opts{'options'} );
foreach my $item ( @optionlist ) {
my ($key,$value) = split( "=", $item );
$settings{$key} = $value;
}
}
my $csmdata = "";
if ( defined($opts{'fileonly'}) ) {
if ( ! defined($opts{'justvalues'}) ) { print "When -filenameonly option used, -justvalues is set as well\n" if $printing; }
if ( ! defined($opts{'onlyfiles'}) ) { print "When -filenameonly option used, -onlyfiles is set as well\n" if $printing; }
$opts{'justvalues'} = 1;
$opts{'onlyfiles'} = 1;
}
# List of input options
my %inputopts;
# This namelist files under the cime directories are in version 2 format and can't be read by perl code EBK 11/15/2016
my $model = $opts{'model'};
my @nl_definition_files = ("$cfgdir/namelist_files/namelist_definition_drv.xml",
"$cfgdir/namelist_files/namelist_definition_$model.xml"
);
$inputopts{empty_cfg_file} = "$cfgdir/config_files/config_definition_$model.xml";
$inputopts{nldef_files} = \@nl_definition_files;
$inputopts{namelist} = $opts{namelist};
$inputopts{printing} = $printing;
$inputopts{cfgdir} = $cfgdir;
$inputopts{ProgName} = $ProgName;
$inputopts{cmdline} = $cmdline;
my $exitearly = 0;
my $definition = Build::NamelistDefinition->new( $nl_definition_files[0] );
foreach my $nl_defin_file ( @nl_definition_files ) {
if ( ! -f "$nl_defin_file" ) {
die "($ProgName $cmdline) ERROR:: bad namelist definition filename: $nl_defin_file.\n";
}
$definition->add( "$nl_defin_file" );
}
if ( ! defined($opts{csmdata}) ) {
$inputopts{csmdata} = "default";
} else {
$inputopts{csmdata} = $opts{csmdata};
}
if ( defined($opts{cesm}) ) {
$inputopts{csmdata} = '$DIN_LOC_ROOT';
}
if ( ! defined($opts{config}) ) {
$inputopts{config} = "noconfig";
} else {
$inputopts{config} = $opts{config};
}
if ( ! defined($opts{var}) ) {
$settings{'var'} = undef;
} elsif ( $opts{var} eq "list" ) {
print "Valid variables: " if $printing;
my @vars = $definition->get_var_names( );
print "@vars\n";
$exitearly = 1;
} else {
$settings{'var'} = $opts{'var'};
}
if ( ! defined($opts{hgrid}) ) {
$inputopts{hgrid} = "any";
} elsif ( $opts{hgrid} eq "list" ) {
print "Valid resolutions: " if $printing;
my @hgrids = $definition->get_valid_values( "res", 'noquotes'=>1 );
print "@hgrids\n";
$exitearly = 1;
} else {
if ( ! $definition->is_valid_value( "res", $opts{hgrid}, 'noquotes'=>1 ) ) {
if ( $opts{'hgrid'} ne $opts{'usrname'} ) {
die "($ProgName $cmdline) ERROR:: invalid resolution entered.\n";
}
}
$inputopts{hgrid} = $opts{hgrid};
}
# The namelist defaults file contains default values for all required namelist variables.
my @nl_defaults_files = ( "$cfgdir/namelist_files/namelist_defaults_overall.xml" );
if ( defined($opts{'usrname'}) ) {
my $nl_defaults_file = "$cfgdir/namelist_files/namelist_defaults_usr_files.xml";
push( @nl_defaults_files, $nl_defaults_file );
$settings{'clm_usr_name'} = $opts{'usrname'};
$settings{'notest'} = ! $opts{'test'};
$settings{'csmdata'} = $inputopts{csmdata};
} else {
my @files = ( "$cfgdir/namelist_files/namelist_defaults_${model}.xml",
"$cfgdir/namelist_files/namelist_defaults_drydep.xml",
);
push( @nl_defaults_files, @files );
}
if ( ! $exitearly ) {
$inputopts{files} = \@nl_defaults_files;
my $defaults_ref = &queryDefaultXML::ReadDefaultXMLFile( \%inputopts, \%settings );
my %defaults = %$defaults_ref;
my @keys = keys(%defaults);
if ( defined($opts{'demand'}) && ($#keys == -1) ) {
die "($ProgName $cmdline) ERROR:: demand option is set and nothing was found.\n";
}
my $print;
foreach my $var ( @keys ) {
$print = 1;
my $value = $defaults{$var}{value};
my $isadir = $defaults{$var}{isdir};
my $isafile = $defaults{$var}{isfile};
my $isastr = $defaults{$var}{isstr};
# If onlyfiles option set do NOT print if is NOT a file
if ( defined($opts{'onlyfiles'}) && (! $isafile) ) {
$print = undef;
}
# If is a directory
if ( $isadir ) {
# Test that this directory exists
if ( defined($opts{'test'}) && defined($print) ) {
print "Test that directory $value exists\n" if $printing;
if ( ! -d "$value" ) {
die "($ProgName) ERROR:: directory $value does NOT exist!\n";
}
}
}
# If is a file
if ( $isafile ) {
# Test that this file exists
if ( defined($opts{'test'}) && defined($print) ) {
chomp( $value );
print "Test that file $value exists\n" if $printing;
if ( ! -f "$value" ) {
die "($ProgName) ERROR:: file $value does NOT exist!\n";
}
}
}
# If a string
if ( (! defined($opts{'justvalues'}) ) && ($isastr) ) {
$value = "\'$value\'";
}
# if you just want the filename -- not the full path with the directory
if ( defined($opts{'fileonly'}) ) {
$value =~ s!(.*)/!!;
}
if ( defined($print) ) {
if ( ! defined($opts{'justvalues'}) ) {
print "$var = ";
}
print "$value\n";
}
}
}
if ( $printing && defined($opts{'test'}) ) {
print "\n\nTesting was successful\n\n"
}