#!/usr/bin/env perl #----------------------------------------------------------------------------------------------- # # create_newcase # # This utility allows the users to specify configuration # options via a commandline interface. # #----------------------------------------------------------------------------------------------- use strict; use Cwd; use English; use Getopt::Long; use IO::File; use IO::Handle; #----------------------------------------------------------------------------------------------- # Setting autoflush (an IO::Handle method) on STDOUT helps in debugging. It forces the test # descriptions to be printed to STDOUT before the error messages start. *STDOUT->autoflush(); #----------------------------------------------------------------------------------------------- # Set the directory that contains the CESM configuration scripts. If the create_newcase 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 = absolute_path($ProgDir); } else { $cfgdir = $cwd; } my $ccsmroot = absolute_path("$cfgdir/.."); (-d "$ccsmroot") or die <<"EOF"; ** Cannot find ccsmroot directory \"$ccsmroot\" ** EOF #----------------------------------------------------------------------------------------------- if ($#ARGV == -1) { usage(); } my $machdir="$cfgdir/ccsm_utils/Machines"; #----------------------------------------------------------------------------------------------- sub usage { die <). Any value that contains white-space must be quoted. Long option names may be supplied with either single or double leading dashes. A consequence of this is that single letter options may NOT be bundled. -case Specifies the case name (required). -compset Specify a CESM compset (required). -res Specify a CESM grid resolution (required). -mach Specify a CESM machine (required). -compiler Specify a compiler for the target machine (optional) default: default compiler for the target machine -mpilib Specify a mpi library for the target machine (optional) default: default mpi library for the target machine allowed: openmpi, mpich, ibm, mpi-serial, etc redundant with _M confopts setting -mach_dir Specify the locations of the Machines directory (optional). default: $machdir -confopts Specify some addition configuration options (optional) _AOA = aoflux on atm grid _AOE = aoflux on exch grid _CG = gregorian calendar _D = debug _E = esmf interfaces _IOP*= PnetCDF IO test where * is A(atm), C(cpl), G(glc) , I(ice), L(clm), O(ocn) or blank (all components) _L* = set run length y, m, d, h, s, n(nsteps) plus integer (ie _Lm6 for 6 months) _M* = set the mpilib where * is default, mpi-serial, mpich, etc _N* = set NINST_ env value to * where * is an integer _P* = set pecount to specific values include T,S,M,L,X,1,1x1,16,16x1,4x4, etc _R* = PTS_MODE test case, valid values are LA, LB, OA, OB -pecount Value of S,M,L,X1,X2 (optional). default: M, partially redundant with confopts _P -pes_file Full pathname of pes file to use (will overwrite default settings) (optional). See sample_pes_file.xml for an example. -compset_file Full pathname of compset file to use. (optional) See sample_compset_file.xml for an example. -grid_file Full pathname of grid file to use (optional) See sample_grid_file.xml for an example. Note that compset components must support the new grid. -help [or -h] Print usage to STDOUT (optional). -list Only list valid values for compset, grid settings and machines (optional). -testlist List valid values for tests [normally only invoked by create_test] (optional). -silent [or -s] Turns on silent mode - only fatal messages issued (optional). -verbose [or -v] Turn on verbose echoing of settings made by create_newcase (optional). -xmlmode Sets format of xml files; normal or expert (optional). (default is normal) -nowarning Turns off checking of the known_problems repository. (default is on) The following two arguments turn on single point mode. If one is given -- both MUST be given. -pts_lat Latitude of single point to operate on (optional) -pts_lon Longitude of single point to operate on (optional) EXAMPLES ./create_newcase -case mycase1 -res f19_g16 -compset B1850CN -mach bluefire ./create_newcase -case mycase2 -res f19_g16 -compset B1850CN -mach bluefire -confopts _D_P16 ./create_newcase -case mycase3 -res f19_g16 -compset B1850CN -mach bluefire -pts_lon -160 -pts_lat 40 ./create_newcase -case mycase4 -res f19_g16 -compset MYCOMP -compset_file mycompset_file -mach bluefire ./create_newcase -case mycase5 -res f19_g16 -compset B1850CN -mach bluefire -confopts _CG_E -pes_file mypes_file / EOF } #----------------------------------------------------------------------------------------------- # Save commandline my $commandline = "create_newcase @ARGV"; #----------------------------------------------------------------------------------------------- # Parse command-line options. my %opts = ( pts_lat => undef, pts_lon => undef, mach_dir => $machdir, ); GetOptions( "case=s" => \$opts{'case'}, "compset=s" => \$opts{'compset'}, "confopts=s" => \$opts{'confopts'}, "compiler=s" => \$opts{'compiler'}, "mpilib=s" => \$opts{'mpilib'}, "res=s" => \$opts{'res'}, "h|help" => \$opts{'help'}, "list" => \$opts{'list'}, "mach=s" => \$opts{'mach'}, "mach_dir=s" => \$opts{'mach_dir'}, "pecount=s" => \$opts{'pecount'}, "pes_file=s" => \$opts{'pes_file'}, "compset_file=s" => \$opts{'compset_file'}, "grid_file=s" => \$opts{'grid_file'}, "s|silent" => \$opts{'silent'}, "testname=s" => \$opts{'testname'}, "testlist" => \$opts{'testlist'}, "v|verbose" => \$opts{'verbose'}, "xmlmode=s" => \$opts{'xmlmode'}, "pts_lat=s" => \$opts{'pts_lat'}, "pts_lon=s" => \$opts{'pts_lon'}, "nowarning" => \$opts{'nowarning'}, ) or usage(); # Give usage message. usage() if $opts{'help'}; # Check for unparsed argumentss if (@ARGV) { print "ERROR: unrecognized arguments: @ARGV\n"; usage(); } # Check that points mode is set correctly if ( defined($opts{'pts_lat'}) && ! defined(($opts{'pts_lon'}) ) ) { print "ERROR: if pts_lat set -- pts_lon must also be set: @ARGV\n"; usage(); } if ( defined($opts{'pts_lon'}) && ! defined(($opts{'pts_lat'}) ) ) { print "ERROR: if pts_lon set -- pts_lat must also be set: @ARGV\n"; usage(); } # Check for manditory case input if not just listing valid values my $case; my $caseroot; my $compset; my $confopts; my $grid; my $mach; my $testname; my $pecount; my $xmlmode; my $compiler; my $mpilib; if (!$opts{'list'} && !$opts{'testlist'}) { # Check for manditory case input if ($opts{'case'}) { $case = $opts{'case'}; } else { die "ERROR: create_newcase must include the input argument, -case \n"; } $caseroot = absolute_path("$case"); if (-d $caseroot) { die "Caseroot directory $caseroot already exists \n"; } my @dirs = split "/", $caseroot, -1; # The -1 prevents split from stripping trailing nulls my $num = scalar @dirs; $case = $dirs[$num-1]; # Check for manditory compset input if ($opts{'compset'}) { $compset = $opts{'compset'}; } else { die "ERROR: create_newcase must include the input argument, -compset\n"; } # Check for manditory grid input if ($opts{'res'}) { $grid = $opts{'res'}; } else { die "ERROR: create_newcase must include the input argument, -res\n"; } # Check for manditory machine input if ($opts{'mach'}) { $mach = $opts{'mach'}; } else { die "ERROR: create_newcase must include the input argument, -mach \n"; } # Check if machine compiler option is given if ($opts{'compiler'}) { $compiler = $opts{'compiler'}; } # Check if machine mpilib option is given $mpilib = 'unset'; if ($opts{'mpilib'}) { $mpilib = $opts{'mpilib'}; } # Check for pecount setting $pecount = 'M'; if ($opts{'pecount'}) { $pecount = $opts{'pecount'}; } # Check for xmlmode setting $xmlmode = 'normal'; if ($opts{'xmlmode'}) { $xmlmode = $opts{'xmlmode'}; } } # Set machdir to default or value sent in on command line $machdir=$opts{'mach_dir'}; # Define 3 print levels: # 0 - only issue fatal error messages # 1 - only informs what files are created (default) # 2 - verbose my $print = 1; if ($opts{'silent'}) { $print = 0; } if ($opts{'verbose'}) { $print = 2; } my $eol = "\n"; my %cfg = (); # build configuration # # Make sure we can find the Machines directory # (-d "$machdir") or die <<"EOF"; ** Cannot find ccsm Machines directory \"$machdir\" ** EOF #----------------------------------------------------------------------------------------------- # Make sure we can find required perl modules and configuration files. # Look for them in the directory that contains the create_newcase script. # Check for the configuration definition file. my $config_def_file = "config_definition.xml"; (-f "$cfgdir/ccsm_utils/Case.template/$config_def_file") or die <<"EOF"; ** Cannot find configuration definition file \"$config_def_file\" in directory \"$cfgdir/ccsm_utils/Case.template/$config_def_file\" ** EOF # Grid definition file. my $grid_file = ""; if (defined $opts{'grid_file'}){ $grid_file = $opts{'grid_file'}; (-f $grid_file) or die <<"EOF"; ** Cannot find user specified grid definition file \"$grid_file\" ** EOF } else { $grid_file = "$cfgdir/ccsm_utils/Case.template/config_grid.xml"; (-f $grid_file) or die <<"EOF"; ** Cannot find default grid definition file \"$grid_file\" ** EOF } # Compset definition file. my $compset_file=""; if (defined $opts{'compset_file'}){ $compset_file = $opts{'compset_file'}; (-f $compset_file) or die <<"EOF"; ** Cannot find user specified compset parameters file \"$compset_file\" ** EOF } else { $compset_file = "$cfgdir/ccsm_utils/Case.template/config_compsets.xml"; (-f $compset_file) or die <<"EOF"; ** Cannot find default compset parameters file \"$compset_file\" ** EOF } # Machines definition file. my $machine_file = 'config_machines.xml'; (-f "$machdir/$machine_file") or die <<"EOF"; ** Cannot find machine parameters file \"$machine_file\" in directory \"$machdir\" ** EOF # Machines definition file. my $compiler_file = 'config_compilers.xml'; (-f "$machdir/$compiler_file") or die <<"EOF"; ** Cannot find compiler parameters file \"$compiler_file\" in directory \"$machdir\" ** EOF # Tests file my $tests_file = 'config_tests.xml'; (-f "$cfgdir/ccsm_utils/Testcases/$tests_file") or die <<"EOF"; ** Cannot find test parameters file \"$tests_file\" in directory \"$cfgdir/ccsm_utils/Testcases\" ** EOF # The XML::Lite module is required to parse the XML configuration files. (-f "$cfgdir/ccsm_utils/Tools/perl5lib/XML/Lite.pm") or die <<"EOF"; ** Cannot find perl module \"XML/Lite.pm\" in directory \"$cfgdir/ccsm_utils/Tools/perl5lib\" ** EOF # The ConfigCase module provides utilities to store and manipulate the configuration. (-f "$cfgdir/ccsm_utils/Case.template/ConfigCase.pm") or die <<"EOF"; ** Cannot find perl module \"ConfigCase.pm\" in directory \"$cfgdir/ccsm_utils/Case.template\" ** EOF if ($print>=2) { print "Setting configuration directory to $cfgdir$eol"; } #----------------------------------------------------------------------------------------------- # Add $cfgdir/perl5lib to the list of paths that Perl searches for modules my @dirs = ($cfgdir, "$cfgdir/ccsm_utils/Case.template", "$cfgdir/ccsm_utils/Tools", "$cfgdir/ccsm_utils/Tools/perl5lib"); unshift @INC, @dirs; require XML::Lite; require ConfigCase; #----------------------------------------------------------------------------------------------- # If just listing valid values then exit after completion of lists if ($opts{'testlist'}) { print_tests("$cfgdir/ccsm_utils/Testcases/config_tests.xml"); } if ($opts{'list'}) { print_grids("$cfgdir/ccsm_utils/Case.template/config_grid.xml"); print_compsets($compset_file); ConfigCase::print_machines("$machdir/$machine_file"); &check_known_problems(); if ($print>=2) { print "finished listing valid values, now exiting $eol"; } exit; } #----------------------------------------------------------------------------------------------- # jshollen: Check the repository for known problems that match the tag name. If we find a matching file, # print the known problems file, and exit. We want this done before the case root is made. # Broken, commented out for now. #----------------------------------------------------------------------------------------------- if(! defined ($opts{'nowarning'})) { &check_known_problems; } #----------------------------------------------------------------------------------------------- # Create new config object if not just listing valid values my $cfg_ref = ConfigCase->new("$cfgdir/ccsm_utils/Case.template/$config_def_file"); #if ($print>=2) { print "A new config reference object was created$eol";} #----------------------------------------------------------------------------------------------- # (1) Grid parameters my ($grid_longname, $grid_shortname) = set_grid($grid_file, $grid, $cfg_ref); if ($print>=2) { print "Horizontal grid specifier: $grid.$eol"; } #----------------------------------------------------------------------------------------------- # (2) Compset parameters my $sysmod = "mkdir -p $caseroot"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; my $file = "$caseroot/README.case"; my $fh = IO::File->new($file, '>' ) or die "can't open file: $file\n"; print $fh "$commandline\n\n\n"; $fh->close; my ($compset_longname, $compset_shortname) = set_compset($compset_file, $compset, $grid_longname, $grid_shortname, $cfg_ref, $caseroot); if ($print>=2) { print "Compset specifier: $compset.$eol"; } # print README/disclaimer file in scripts dir my $sysmod = "cp $cfgdir/README $caseroot/README.science_support"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; #----------------------------------------------------------------------------------------------- # (3) Check if grid is valid for given compset check_grid("$cfgdir/ccsm_utils/Case.template/config_grid.xml", $grid, $compset_longname); if ($print>=2) { print "Grid is valid for input compset. $eol"; } #----------------------------------------------------------------------------------------------- # (4) Machine parameters if ($mach =~ /(.*)_(.*)/){ $mach = $1; $compiler = $2 unless defined($compiler); $cfg_ref->set_machine("$machdir/$machine_file", $mach, $print); } else { $cfg_ref->set_machine("$machdir/$machine_file", $mach, $print); } $cfg_ref->set('CCSM_MACHDIR', "$machdir"); # Check that compiler request for target machine matches a supported value # Or set default compiler - if not provided compiler request my $compilers; if ($mach =~ /userdefined/){ $cfg_ref->set('COMPILER', "USERDEFINED_required_build"); } else { $compilers = $cfg_ref->get('COMPILERS'); my @compilers = split ",", $compilers, -1; if ($compiler) { if (! ($mach =~ "generic")){ my $found = 0; foreach my $comp (@compilers) { if ($compiler eq $comp) { $found = 1; } } if (!$found) { my $sysmod = "rm -rf $caseroot"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; die "ERROR: compiler setting of $compiler does not match supported values of $compilers \n"; } } $cfg_ref->set('COMPILER', "$compiler"); if ($print>=2) { print "Machine compiler specifier: $compiler.$eol"; } } else { $compiler = $compilers[0]; $cfg_ref->set('COMPILER', "$compiler"); if ($print>=2) { print "Machine compiler specifier: $compiler.$eol"; } } } if ($print>=2) { print "Machine specifier: $mach.$eol"; } #----------------------------------------------------------------------------------------------- # (5) Testname parameters if (defined $opts{'testname'}) { $testname = $opts{'testname'}; set_test("$cfgdir/ccsm_utils/Testcases/config_tests.xml", $testname, $cfg_ref); } #----------------------------------------------------------------------------------------------- # (6) Configure Options if (defined $opts{'confopts'}) { $confopts = $opts{'confopts'}; set_confopts($confopts, $cfg_ref); } #----------------------------------------------------------------------------------------------- # (7) Points mode settings on command line #----------------------------------------------------------------------------------------------- if ( defined($opts{'pts_lat'}) && defined($opts{'pts_lon'}) ) { $cfg_ref->set('PTS_MODE', "TRUE" ); $cfg_ref->set('PTS_LAT', $opts{'pts_lat'} ); $cfg_ref->set('PTS_LON', $opts{'pts_lon'} ); $cfg_ref->set('ATM_NX', 0); $cfg_ref->set('ATM_NY', 0); $cfg_ref->set('LND_NX', 0); $cfg_ref->set('LND_NY', 0); $cfg_ref->set('ICE_NX', 0); $cfg_ref->set('ICE_NY', 0); $cfg_ref->set('OCN_NX', 0); $cfg_ref->set('OCN_NY', 0); $cfg_ref->set('GLC_NX', 0); $cfg_ref->set('GLC_NY', 0); $cfg_ref->set('ROF_NX', 0); $cfg_ref->set('ROF_NY', 0); } #----------------------------------------------------------------------------------------------- # (8) Determine pes for machine #----------------------------------------------------------------------------------------------- # Always match on the full grid name and input compset name my $pmode = $cfg_ref->get('PTS_MODE'); if ( $pmode eq "TRUE" ) { $pecount = 1; } ##print "pes_match $grid_match $compset_match $mach $pecount \n"; my %decomp = (NTASKS_ATM=>16, NTHRDS_ATM=>1, ROOTPE_ATM=>0, NINST_ATM=>1, NTASKS_LND=>16, NTHRDS_LND=>1, ROOTPE_LND=>0, NINST_LND=>1, NTASKS_ICE=>16, NTHRDS_ICE=>1, ROOTPE_ICE=>0, NINST_ICE=>1, NTASKS_OCN=>16, NTHRDS_OCN=>1, ROOTPE_OCN=>0, NINST_OCN=>1, NTASKS_CPL=>16, NTHRDS_CPL=>1, ROOTPE_CPL=>0, NTASKS_GLC=>16, NTHRDS_GLC=>1, ROOTPE_GLC=>0, NINST_GLC=>1, NTASKS_ROF=>16, NTHRDS_ROF=>1, ROOTPE_ROF=>0, NINST_ROF=>1, PIO_NUMTASKS=>-1, PIO_STRIDE=>-1, PIO_TYPENAME=>'netcdf',PIO_ROOT=>1,PIO_DEBUG_LEVEL=>0, ATM_PIO_NUMTASKS=>-99, ATM_PIO_STRIDE=>-99, ATM_PIO_TYPENAME=>'nothing',ATM_PIO_ROOT=>-99, LND_PIO_NUMTASKS=>-99, LND_PIO_STRIDE=>-99, LND_PIO_TYPENAME=>'nothing',LND_PIO_ROOT=>-99, ICE_PIO_NUMTASKS=>-99, ICE_PIO_STRIDE=>-99, ICE_PIO_TYPENAME=>'nothing',ICE_PIO_ROOT=>-99, OCN_PIO_NUMTASKS=>-99, OCN_PIO_STRIDE=>-99, OCN_PIO_TYPENAME=>'nothing',OCN_PIO_ROOT=>0, CPL_PIO_NUMTASKS=>-99, CPL_PIO_STRIDE=>-99, CPL_PIO_TYPENAME=>'nothing',CPL_PIO_ROOT=>-99, GLC_PIO_NUMTASKS=>-99, GLC_PIO_STRIDE=>-99, GLC_PIO_TYPENAME=>'nothing',GLC_PIO_ROOT=>-99, ROF_PIO_NUMTASKS=>-99, ROF_PIO_STRIDE=>-99, ROF_PIO_TYPENAME=>'nothing',ROF_PIO_ROOT=>-99, PES_LEVEL=>0); # Reset the pes if a pes file is specified if (defined $opts{'pes_file'}) { my $pes_file = $opts{'pes_file'}; (-f "$pes_file") or die "** Cannot find pes_file \"$pes_file\" ***\n"; $cfg_ref->reset_setup("$pes_file"); } else { if ($pecount =~ m!^([0-9]+)$!) { my $ntasks = $1; my $nthrds = 1; $decomp{NTASKS_ATM} = $ntasks; $decomp{NTHRDS_ATM} = $nthrds; $decomp{NTASKS_LND} = $ntasks; $decomp{NTHRDS_LND} = $nthrds; $decomp{NTASKS_OCN} = $ntasks; $decomp{NTHRDS_OCN} = $nthrds; $decomp{NTASKS_ICE} = $ntasks; $decomp{NTHRDS_ICE} = $nthrds; $decomp{NTASKS_GLC} = $ntasks; $decomp{NTHRDS_GLC} = $nthrds; $decomp{NTASKS_ROF} = $ntasks; $decomp{NTHRDS_ROF} = $nthrds; $decomp{NTASKS_CPL} = $ntasks; $decomp{NTHRDS_CPL} = $nthrds; } elsif ($pecount =~ m!^([0-9]+)x([0-9]+)$!) { my $ntasks = $1; my $nthrds = $2; $decomp{NTASKS_ATM} = $ntasks; $decomp{NTHRDS_ATM} = $nthrds; $decomp{NTASKS_LND} = $ntasks; $decomp{NTHRDS_LND} = $nthrds; $decomp{NTASKS_OCN} = $ntasks; $decomp{NTHRDS_OCN} = $nthrds; $decomp{NTASKS_ICE} = $ntasks; $decomp{NTHRDS_ICE} = $nthrds; $decomp{NTASKS_GLC} = $ntasks; $decomp{NTHRDS_GLC} = $nthrds; $decomp{NTASKS_ROF} = $ntasks; $decomp{NTHRDS_ROF} = $nthrds; $decomp{NTASKS_CPL} = $ntasks; $decomp{NTHRDS_CPL} = $nthrds; } else { $cfg_ref->set_pes("$machdir/config_pes.xml", \%decomp, $pecount, $print); } if ($decomp{NTASKS_ATM} == 1 && $decomp{NTASKS_LND} == 1 && $decomp{NTASKS_OCN} == 1 && $decomp{NTASKS_ICE} == 1 && $decomp{NTASKS_ROF} == 1 && $decomp{NTASKS_GLC} == 1 && $decomp{NTASKS_CPL} == 1 && $mpilib =~ 'unset') { $mpilib = "mpi-serial"; } $cfg_ref->set('NTASKS_ATM', $decomp{'NTASKS_ATM'}); $cfg_ref->set('NTASKS_LND', $decomp{'NTASKS_LND'}); $cfg_ref->set('NTASKS_ICE', $decomp{'NTASKS_ICE'}); $cfg_ref->set('NTASKS_OCN', $decomp{'NTASKS_OCN'}); $cfg_ref->set('NTASKS_CPL', $decomp{'NTASKS_CPL'}); $cfg_ref->set('NTASKS_GLC', $decomp{'NTASKS_GLC'}); $cfg_ref->set('NTASKS_ROF', $decomp{'NTASKS_ROF'}); $cfg_ref->set('NTHRDS_ATM', $decomp{'NTHRDS_ATM'}); $cfg_ref->set('NTHRDS_LND', $decomp{'NTHRDS_LND'}); $cfg_ref->set('NTHRDS_ICE', $decomp{'NTHRDS_ICE'}); $cfg_ref->set('NTHRDS_OCN', $decomp{'NTHRDS_OCN'}); $cfg_ref->set('NTHRDS_CPL', $decomp{'NTHRDS_CPL'}); $cfg_ref->set('NTHRDS_GLC', $decomp{'NTHRDS_GLC'}); $cfg_ref->set('NTHRDS_ROF', $decomp{'NTHRDS_ROF'}); $cfg_ref->set('ROOTPE_ATM', $decomp{'ROOTPE_ATM'}); $cfg_ref->set('ROOTPE_LND', $decomp{'ROOTPE_LND'}); $cfg_ref->set('ROOTPE_ICE', $decomp{'ROOTPE_ICE'}); $cfg_ref->set('ROOTPE_OCN', $decomp{'ROOTPE_OCN'}); $cfg_ref->set('ROOTPE_CPL', $decomp{'ROOTPE_CPL'}); $cfg_ref->set('ROOTPE_GLC', $decomp{'ROOTPE_GLC'}); $cfg_ref->set('ROOTPE_ROF', $decomp{'ROOTPE_ROF'}); # tcraig, assume NINST is not set in config_pes.xml so it can be # set by _N, but a pes_file could override above # $cfg_ref->set('NINST_ATM', $decomp{'NINST_ATM'}); # $cfg_ref->set('NINST_LND', $decomp{'NINST_LND'}); # $cfg_ref->set('NINST_ICE', $decomp{'NINST_ICE'}); # $cfg_ref->set('NINST_OCN', $decomp{'NINST_OCN'}); # $cfg_ref->set('NINST_GLC', $decomp{'NINST_GLC'}); # $cfg_ref->set('NINST_ROF', $decomp{'NINST_ROF'}); $cfg_ref->set('PIO_TYPENAME' , $decomp{'PIO_TYPENAME'}); $cfg_ref->set('ATM_PIO_TYPENAME', $decomp{'ATM_PIO_TYPENAME'}); $cfg_ref->set('LND_PIO_TYPENAME', $decomp{'LND_PIO_TYPENAME'}); $cfg_ref->set('OCN_PIO_TYPENAME', $decomp{'OCN_PIO_TYPENAME'}); $cfg_ref->set('ICE_PIO_TYPENAME', $decomp{'ICE_PIO_TYPENAME'}); $cfg_ref->set('CPL_PIO_TYPENAME', $decomp{'CPL_PIO_TYPENAME'}); $cfg_ref->set('GLC_PIO_TYPENAME', $decomp{'GLC_PIO_TYPENAME'}); $cfg_ref->set('ROF_PIO_TYPENAME', $decomp{'ROF_PIO_TYPENAME'}); $cfg_ref->set('PIO_NUMTASKS', $decomp{'PIO_NUMTASKS'}); $cfg_ref->set('PIO_STRIDE', $decomp{'PIO_STRIDE'}); $cfg_ref->set('PIO_ROOT', $decomp{'PIO_ROOT'}); $cfg_ref->set('PIO_DEBUG_LEVEL', $decomp{'PIO_DEBUG_LEVEL'}); $cfg_ref->set('ATM_PIO_NUMTASKS', $decomp{'ATM_PIO_NUMTASKS'}); $cfg_ref->set('ATM_PIO_STRIDE', $decomp{'ATM_PIO_STRIDE'}); $cfg_ref->set('ATM_PIO_ROOT', $decomp{'ATM_PIO_ROOT'}); $cfg_ref->set('LND_PIO_NUMTASKS', $decomp{'LND_PIO_NUMTASKS'}); $cfg_ref->set('LND_PIO_STRIDE', $decomp{'LND_PIO_STRIDE'}); $cfg_ref->set('LND_PIO_ROOT', $decomp{'LND_PIO_ROOT'}); $cfg_ref->set('OCN_PIO_NUMTASKS', $decomp{'OCN_PIO_NUMTASKS'}); $cfg_ref->set('OCN_PIO_STRIDE', $decomp{'OCN_PIO_STRIDE'}); $cfg_ref->set('OCN_PIO_ROOT', $decomp{'OCN_PIO_ROOT'}); $cfg_ref->set('ICE_PIO_NUMTASKS', $decomp{'ICE_PIO_NUMTASKS'}); $cfg_ref->set('ICE_PIO_STRIDE', $decomp{'ICE_PIO_STRIDE'}); $cfg_ref->set('ICE_PIO_ROOT', $decomp{'ICE_PIO_ROOT'}); $cfg_ref->set('CPL_PIO_NUMTASKS', $decomp{'CPL_PIO_NUMTASKS'}); $cfg_ref->set('CPL_PIO_STRIDE', $decomp{'CPL_PIO_STRIDE'}); $cfg_ref->set('CPL_PIO_ROOT', $decomp{'CPL_PIO_ROOT'}); $cfg_ref->set('GLC_PIO_NUMTASKS', $decomp{'GLC_PIO_NUMTASKS'}); $cfg_ref->set('GLC_PIO_STRIDE', $decomp{'GLC_PIO_STRIDE'}); $cfg_ref->set('GLC_PIO_ROOT', $decomp{'GLC_PIO_ROOT'}); $cfg_ref->set('ROF_PIO_NUMTASKS', $decomp{'ROF_PIO_NUMTASKS'}); $cfg_ref->set('ROF_PIO_STRIDE', $decomp{'ROF_PIO_STRIDE'}); $cfg_ref->set('ROF_PIO_ROOT', $decomp{'ROF_PIO_ROOT'}); $cfg_ref->set('PES_LEVEL' , $decomp{'PES_LEVEL'}); } # mpilib can be set by -mpilib, confopts, or automatically # precedent is confopts, mpilib, automatic, default my $mpilibs = $cfg_ref->get('MPILIBS'); my @mpilibs = split ",", $mpilibs, -1; if ( $mpilib =~ 'default' || $mpilib =~ m/^\s*$/ ) { $mpilib = $mpilibs[0]; } if (! ($mpilib =~ 'unset')) { # check that mpilib request for target machine matches a supported value # if ($mach =~ "userdefined"){ # unless (defined($ENV{MPI_PATH})){ # print "\nSet environment variable MPI_PATH prior to building case\n\n"; # } # }else{ my $found = 0; foreach my $mpi (@mpilibs) { if ($mpilib eq $mpi) { $found = 1; } } if (!$found) { my $sysmod = "rm -rf $caseroot"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; die "ERROR: mpilib setting of $mpilib does not match supported values of $mpilibs \n"; } # } } else { if ($mach =~ /userdefined/){ $mpilib = "USERDEFINED_required_build"; }else{ $mpilib = $mpilibs[0]; } } $cfg_ref->set('MPILIB', "$mpilib"); if ($print>=2) { print "Machine mpilib specifier: $mpilib.$eol"; } # resolve the dollar referenced values for the pe stuff # allow up to 4 depths then stop # so, check the var value, if it starts with dollar, remove # the dollar and check the next value. continue until a # non dollar value is found up to max depths. my @xvars = qw(NTASKS_ATM NTHRDS_ATM ROOTPE_ATM NINST_ATM NTASKS_LND NTHRDS_LND ROOTPE_LND NINST_LND NTASKS_ICE NTHRDS_ICE ROOTPE_ICE NINST_ICE NTASKS_OCN NTHRDS_OCN ROOTPE_OCN NINST_OCN NTASKS_GLC NTHRDS_GLC ROOTPE_GLC NINST_GLC NTASKS_ROF NTHRDS_ROF ROOTPE_ROF NINST_ROF NTASKS_CPL NTHRDS_CPL ROOTPE_CPL ATM_PIO_NUMTASKS ATM_PIO_STRIDE ATM_PIO_TYPENAME ATM_PIO_ROOT LND_PIO_NUMTASKS LND_PIO_STRIDE LND_PIO_TYPENAME LND_PIO_ROOT ICE_PIO_NUMTASKS ICE_PIO_STRIDE ICE_PIO_TYPENAME ICE_PIO_ROOT OCN_PIO_NUMTASKS OCN_PIO_STRIDE OCN_PIO_TYPENAME OCN_PIO_ROOT CPL_PIO_NUMTASKS CPL_PIO_STRIDE CPL_PIO_TYPENAME CPL_PIO_ROOT GLC_PIO_NUMTASKS GLC_PIO_STRIDE GLC_PIO_TYPENAME GLC_PIO_ROOT ROF_PIO_NUMTASKS ROF_PIO_STRIDE ROF_PIO_TYPENAME ROF_PIO_ROOT); my $xvarf; my $xvar1; my $xvar2; my $xvar3; my $xvar4; foreach my $xvar ( @xvars ) { $xvar1 = $cfg_ref->get("$xvar"); $xvar2 = ""; $xvar3 = ""; $xvar4 = ""; $xvarf = $xvar1; if ($xvarf =~ m/^\$.+$/) { $xvar2 = $xvarf; $xvar2 =~ s/^\$(.+$)/$1/ ; $xvar2 = $cfg_ref->get("$xvar2"); $xvarf = $xvar2; if ($xvarf =~ m/^\$.+$/) { $xvar3 = $xvarf; $xvar3 =~ s/^\$(.+$)/$1/; $xvar3 = $cfg_ref->get("$xvar3"); $xvarf = $xvar3; if ($xvarf =~ m/^\$.+$/) { $xvar4 = $xvarf; $xvar4 =~ s/^\$(.+$)/$1/ ; $xvar4 = $cfg_ref->get("$xvar4"); $xvarf = $xvar4; if ($xvar4 =~ m/^\$.+$/) { die "xvar recursive search failed $xvar $xvar1 $xvar2 $xvar3 $xvar4 \n"; } } } } $cfg_ref->set("$xvar", "$xvarf"); } #----------------------------------------------------------------------------------------------- # (9) Set key xml variables #----------------------------------------------------------------------------------------------- my $ccsmuser = "$ENV{'LOGNAME'}"; $cfg_ref->set('CCSMUSER', "$ccsmuser"); $cfg_ref->set('CASEROOT', "$caseroot"); $cfg_ref->set('CASE' , "$case"); $cfg_ref->set('CCSMROOT', "$ccsmroot"); $cfg_ref->set('XMLMODE' , "$xmlmode"); my $repotag; if (-f "$ccsmroot/ChangeLog") { $repotag =`cat $ccsmroot/ChangeLog | grep 'Tag name:' | head -1`; } else { $repotag =`cat $ccsmroot/models/atm/cam/doc/ChangeLog | grep 'Tag name:' | head -1`; } my @repotag = split(/ /,$repotag); $repotag = $repotag[2]; chomp($repotag); $cfg_ref->set('CCSM_REPOTAG', $repotag); #----------------------------------------------------------------------------------------------- # (10) Create the $caseroot directory tree #----------------------------------------------------------------------------------------------- my $sysmod; my $scriptsroot = "$ccsmroot/scripts"; print "Creating $caseroot $eol"; # Create relevant directories in $caseroot my @mkdirs = qw(. SourceMods LockedFiles Buildconf Tools/XML/Lite); foreach my $mkdir ( @mkdirs ) { $sysmod = "mkdir -p $caseroot/$mkdir"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; } # Copy relevant files into $caseroot my @files = ( "$scriptsroot/ccsm_utils/Tools/cesm_setup", "$scriptsroot/ccsm_utils/Tools/check_input_data", "$scriptsroot/ccsm_utils/Tools/archive_metadata.sh", "$scriptsroot/ccsm_utils/Tools/check_case", "$scriptsroot/ccsm_utils/Tools/create_production_test", "$scriptsroot/ccsm_utils/Tools/xmlchange", "$scriptsroot/ccsm_utils/Tools/xmlquery", ); foreach my $file (@files) { $sysmod = "cp -p $file $caseroot"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; } $sysmod = "chmod u+w $caseroot/create_production_test"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; # Copy relevant files into $caseroot/Tools/ @files = ("$scriptsroot/ccsm_utils/Tools/cesm_prerun_setup", "$scriptsroot/ccsm_utils/Tools/cesm_postrun_setup", "$scriptsroot/ccsm_utils/Tools/cesm_buildstart", "$scriptsroot/ccsm_utils/Tools/cesm_buildnml", "$scriptsroot/ccsm_utils/Tools/cesm_prestage", "$scriptsroot/ccsm_utils/Tools/cesm_buildexe", "$scriptsroot/ccsm_utils/Tools/ccsm_getenv", "$scriptsroot/ccsm_utils/Tools/ccsm_check_lockedfiles", "$scriptsroot/ccsm_utils/Tools/taskmaker.pl", "$scriptsroot/ccsm_utils/Tools/xml2env", "$scriptsroot/ccsm_utils/Tools/lt_archive.sh", "$scriptsroot/ccsm_utils/Tools/st_archive.sh", "$scriptsroot/ccsm_utils/Tools/user_nlcreate", "$scriptsroot/ccsm_utils/Tools/user_nl_add", "$scriptsroot/ccsm_utils/Tools/timing/getTiming.csh", "$scriptsroot/ccsm_utils/Tools/timing/getTiming2.pl", "$scriptsroot/ccsm_utils/Case.template/config_definition.xml", "$scriptsroot/ccsm_utils/Case.template/config_grid.xml", "$scriptsroot/ccsm_utils/Case.template/ConfigCase.pm", "$scriptsroot/ccsm_utils/Tools/SetupTools.pm", "$scriptsroot/ccsm_utils/Machines/Makefile", "$scriptsroot/ccsm_utils/Machines/mkSrcfiles", "$scriptsroot/ccsm_utils/Machines/mkDepends", "$scriptsroot/ccsm_utils/Machines/mkbatch.$mach"); foreach my $file (@files) { $sysmod = "cp -p $file $caseroot/Tools/."; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; } # Create $case.build my $file = "${caseroot}/${case}.build"; $sysmod = "cp ${caseroot}/Tools/cesm_buildstart $file"; system ($sysmod); if ($? == -1) {die "$sysmod failed: $!\n";} $sysmod = "cat ${caseroot}/Tools/cesm_buildnml >> $file"; system ($sysmod); if ($? == -1) {die "$sysmod failed: $!\n";} $sysmod = "cat ${caseroot}/Tools/cesm_prestage >> $file"; system ($sysmod); if ($? == -1) {die "$sysmod failed: $!\n";} $sysmod = "cat ${caseroot}/Tools/cesm_buildexe >> $file"; system ($sysmod); if ($? == -1) {die "$sysmod failed: $!\n";} $sysmod = "chmod 755 $file"; system ($sysmod); if ($? == -1) {die "$sysmod failed: $!\n";} # Create $case.clean_build $sysmod = "cp $scriptsroot/ccsm_utils/Tools/cesm_clean_build $caseroot/$case.clean_build"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; # Create $case.submit $sysmod = "cp $scriptsroot/ccsm_utils/Tools/cesm_submit $caseroot/$case.submit"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; # Create $case.l_archive my $sysmod = "env CCSMUSER=$ccsmuser CASE=$case CASEROOT=$caseroot env PHASE=set_larch ${machdir}/mkbatch.$mach"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; # Create preview_namelist file my $file = "${caseroot}/preview_namelists"; $sysmod = "cp $scriptsroot/ccsm_utils/Tools/preview_namelists $file"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; $sysmod = "chmod 755 $file"; system ($sysmod); if ($? == -1) {die "$sysmod failed: $!\n";} # Copy relevant files into $caseroot/Tools/XML directory $sysmod = "cp -p $scriptsroot/ccsm_utils/Tools/perl5lib/XML/Lite.pm $caseroot/Tools/XML"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; $sysmod = "cp -p $scriptsroot/ccsm_utils/Tools/perl5lib/XML/Lite/Element.pm $caseroot/Tools/XML/Lite"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; # Create relevant files in the $caseroot/Buildconf my $buildconf = "$caseroot/Buildconf"; my @models = qw(COMP_ATM COMP_LND COMP_ICE COMP_OCN COMP_GLC COMP_ROF); my @comps_atm = $cfg_ref->get_valid_values("COMP_ATM"); my @comps_lnd = $cfg_ref->get_valid_values("COMP_LND"); my @comps_ocn = $cfg_ref->get_valid_values("COMP_OCN"); my @comps_ice = $cfg_ref->get_valid_values("COMP_ICE"); my @comps_glc = $cfg_ref->get_valid_values("COMP_GLC"); my @comps_rof = $cfg_ref->get_valid_values("COMP_ROF"); my @comps = (@comps_atm, @comps_lnd, @comps_ocn, @comps_ice, @comps_glc, @comps_rof); foreach my $comp (@comps) { $comp =~ s/\'//g; foreach my $model (@models) { my $model_name = $cfg_ref->get($model); if ($model_name eq $comp) { my $blddir; if ($model eq 'COMP_ATM') {$blddir = "$ccsmroot/models/atm/$comp/bld"}; if ($model eq 'COMP_LND') {$blddir = "$ccsmroot/models/lnd/$comp/bld"}; if ($model eq 'COMP_ICE') {$blddir = "$ccsmroot/models/ice/$comp/bld"}; if ($model eq 'COMP_OCN') {$blddir = "$ccsmroot/models/ocn/$comp/bld"}; if ($model eq 'COMP_GLC') {$blddir = "$ccsmroot/models/glc/$comp/bld"}; if ($model eq 'COMP_ROF') {$blddir = "$ccsmroot/models/rof/$comp/bld"}; $sysmod = "cp -p $blddir/*build*.csh $buildconf/."; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; if (-f "$blddir/$comp.template" || -f "$blddir/$comp.cpl7.template") { $sysmod = "cp -p $blddir/${comp}*template $buildconf/${comp}.user_nl.csh"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; } } } } $sysmod = "cp -p $ccsmroot/models/drv/bld/*.build*.csh $buildconf/."; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; $sysmod = "cp -p $ccsmroot/models/drv/bld/cpl.template $buildconf/cpl.user_nl.csh"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; foreach my $comp (@comps) { foreach my $model (@models) { if ($cfg_ref->get($model) eq $comp) { my $component = $cfg_ref->get($model); if ($component eq 'cice') { $sysmod = "cp $ccsmroot/models/ice/cice/bld/generate_cice_decomp.pl $buildconf/."; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; $sysmod = "cp $ccsmroot/models/ice/cice/bld/cice_decomp.xml $buildconf/."; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; } if ($component eq 'pop2') { $sysmod = "cp $ccsmroot/models/ocn/pop2/bld/generate_pop_decomp.pl $buildconf/."; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; $sysmod = "cp $ccsmroot/models/ocn/pop2/bld/pop_decomp.xml $buildconf/."; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; } } } } foreach my $lib ("gptl", "mct", "csm_share", "pio") { my $sysmod = "cp ${machdir}/buildlib.${lib} $caseroot/Buildconf/."; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; } # Create the relevant $caseroot/Sourcemods directories my $moddir = "$caseroot/SourceMods"; foreach my $comp (@comps) { foreach my $model (@models) { if ($cfg_ref->get($model) eq $comp) { $sysmod = "mkdir -p $moddir/src.$comp"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; } } } $sysmod = "mkdir -p $caseroot/SourceMods/src.share"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; $sysmod = "mkdir -p $caseroot/SourceMods/src.drv" ; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; $sysmod = "chmod -R u+w $caseroot/SourceMods"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; # Create machine specific environment file (env_mach_specific) if(-e "$machdir/env_mach_specific.$mach" ) { $sysmod = "cp $machdir/env_mach_specific.$mach $caseroot/env_mach_specific"; }else{ $sysmod = "touch $caseroot/env_mach_specific"; } system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; # Copy Depends files if they exist if( -e "$machdir/Depends.$mach" ) { $sysmod = "cp $machdir/Depends.$mach $caseroot/"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; } if( -e "$machdir/Depends.$compiler" ) { $sysmod = "cp $machdir/Depends.$compiler $caseroot/"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; } # Write the xml files $cfg_ref->write_file("$caseroot/env_case.xml" , "xml"); print "Created $caseroot/env_case.xml \n"; $cfg_ref->write_file("$caseroot/env_mach_pes.xml", "xml"); print "Created $caseroot/env_mach_pes.xml \n"; $cfg_ref->write_file("$caseroot/env_build.xml" , "xml"); print "Created $caseroot/env_build.xml \n"; $cfg_ref->write_file("$caseroot/env_run.xml" , "xml"); print "Created $caseroot/env_run.xml \n"; # Copy env_case.xml in to locked files $sysmod = "cp $caseroot/env_case.xml $caseroot/LockedFiles/env_case.xml.locked"; system($sysmod) == 0 or die "ERROR: $sysmod failed: $?\n"; print "Locking file $caseroot/env_case.xml \n"; my $file = "$caseroot/CaseStatus"; my $fh = IO::File->new($file, '>' ) or die "can't open file: $file\n"; my $time = time; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time); $year = 1900+$year; $mon = 1+$mon; print $fh "$commandline\n"; printf ($fh "case created %04u-%02u-%02u %02u:%02u:%02u\n",$year,$mon,$mday,$hour,$min,$sec); #----------------------------------------------------------------------------------------------- # (11) Create $caseroot run setup scripts (other than batch) #----------------------------------------------------------------------------------------------- print "Successfully created the case for $mach \n"; if ($print>=2) { print "create_xml done.$eol"; } # Finished create_newcase exit; #----------------------------------------------------------------------------------------------- # FINNISHED #################################################################################### #----------------------------------------------------------------------------------------------- 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 subst_env_path { # # Substitute for any environment variables contained in a pathname. # Assumes the directory separator is "/". # my $path = shift; my $newpath; # resulting pathname # Strip off any leading or trailing whitespace. (This pattern won't match if # there's embedded whitespace. $path =~ s!^\s*(\S*)\s*$!$1!; my ($dir, @dirs2); my @dirs = split "/", $path, -1; # The -1 prevents split from stripping trailing nulls # This enables correct processing of the input "/". foreach $dir (@dirs) { if ( $dir =~ /^\$(.+)$/ ) { push @dirs2, $ENV{$1}; } else { push @dirs2, $dir; } } $newpath = join '/', @dirs2; return( $newpath ); } #------------------------------------------------------------------------------- sub get_option { my ($mes, @expect) = @_; my ($ans, $expect, $max_tries); $max_tries = 5; print $mes; while ($max_tries) { $ans = <>; chomp $ans; --$max_tries; $ans =~ s/^\s+//; $ans =~ s/\s+$//; # Check for null response which indicates that default is accepted. unless ($ans) { return ""; } foreach $expect (@expect) { if ($ans =~ /^$expect$/i) { return $expect; } } if ($max_tries > 1) { print "$ans does not match any of the expected values: @expect\n"; print "Please try again: "; } elsif ($max_tries == 1) { print "$ans does not match any of the expected values: @expect\n"; print "Last chance! "; } } die "Failed to get answer to question: $mes\n"; } #------------------------------------------------------------------------------- sub print_hash { my %h = @_; my ($k, $v); while ( ($k,$v) = each %h ) { print "$k => $v\n"; } } #------------------------------------------------------------------------------- sub set_grid { # Set the parameters for the specified horizontal grid. The # parameters are read from an input file, and if no grid matches are # found then issue error message. # This routine uses the configuration defined at the package level ($cfg_ref). my ($grid_file, $grid, $cfg_ref) = @_; my $xml = XML::Lite->new( $grid_file ); my $root = $xml->root_element(); # Check for valid root node my $name = $root->get_name(); $name eq "config_horiz_grid" or die "file $grid_file is not a horizontal grid parameters file\n"; # Read the grid parameters from $grid_file. my @e = $xml->elements_by_name( "horiz_grid" ); my %a = (); # Search for matching grid. my $found = 0; HGRID: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ( ! defined($a{'GRID'} ) ) { next; } if ( ! defined($a{'SHORTNAME'}) ) { next; } if ( ($grid eq $a{'GRID'}) || ($grid eq $a{'SHORTNAME'})) { $found = 1; last HGRID; } } # Die unless search was successful. unless ($found) { print "set_grid: no match for grid $grid - possible grid values are \n"; my @e_err = $xml->elements_by_name( "horiz_grid" ); my %a_err = (); while ( my $e_err = shift @e_err ) { %a_err = $e_err->get_attributes(); if (defined($a_err{'SHORTNAME'})) { print " $a_err{'GRID'} (SHORTNAME: $a_err{'SHORTNAME'}) \n"; } } die "set_grid: exiting\n"; } my $shortname = $a{'SHORTNAME'}; my $longname = $a{'GRID'}; my @ids = keys %$cfg_ref; foreach my $id (sort @ids) { foreach my $attr (keys %a) { if ( ! $cfg_ref->is_ignore_name($attr) and ! $cfg_ref->is_valid_name($attr) ) { die "set_grid: invalid id $attr in grid $grid in file $grid_file exiting\n"; } if ($attr eq $id) { my $value = $a{$attr}; $cfg_ref->set($id, $value); } } } # Search for matching grid for each component my $atm_grid = $a{'ATM_GRID'}; my $lnd_grid = $a{'LND_GRID'}; my $ice_grid = $a{'ICE_GRID'}; my $ocn_grid = $a{'OCN_GRID'}; my $rof_grid = $a{'ROF_GRID'}; @e = $xml->elements_by_name( "horiz_grid" ); %a = (); $found = 0; HGRID: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ( $atm_grid eq $a{'GLOB_GRID'} ) { $found = 1; last HGRID; } } if ($found) { $cfg_ref->set('ATM_NX', $a{'nx'}); $cfg_ref->set('ATM_NY', $a{'ny'}); } @e = $xml->elements_by_name( "horiz_grid" ); %a = (); $found = 0; HGRID: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ( $lnd_grid eq $a{'GLOB_GRID'} ) { $found = 1; last HGRID; } } if ($found) { $cfg_ref->set('LND_NX', $a{'nx'}); $cfg_ref->set('LND_NY', $a{'ny'}); } @e = $xml->elements_by_name( "horiz_grid" ); %a = (); $found = 0; HGRID: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ( $ice_grid eq $a{'GLOB_GRID'} ) { $found = 1; last HGRID; } } if ($found) { $cfg_ref->set('ICE_NX', $a{'nx'}); $cfg_ref->set('ICE_NY', $a{'ny'}); } @e = $xml->elements_by_name( "horiz_grid" ); %a = (); $found = 0; HGRID: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ( $lnd_grid eq $a{'GLOB_GRID'} ) { $found = 1; last HGRID; } } if ($found) { $cfg_ref->set('GLC_NX', $a{'nx'}); $cfg_ref->set('GLC_NY', $a{'ny'}); } @e = $xml->elements_by_name( "horiz_grid" ); %a = (); $found = 0; HGRID: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ( $ocn_grid eq $a{'GLOB_GRID'} ) { $found = 1; last HGRID; } } if ($found) { $cfg_ref->set('OCN_NX', $a{'nx'}); $cfg_ref->set('OCN_NY', $a{'ny'}); } @e = $xml->elements_by_name( "horiz_grid" ); %a = (); $found = 0; HGRID: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ( $rof_grid eq $a{'GLOB_GRID'} ) { $found = 1; last HGRID; } } if ($found) { $cfg_ref->set('ROF_NX', $a{'nx'}); $cfg_ref->set('ROF_NY', $a{'ny'}); } return ($longname, $shortname); } #------------------------------------------------------------------------------- sub set_compset { # Set the parameters for the specified compset. The # parameters are read from an input file, and if no compset matches are # found then issue error message. # This routine uses the configuration defined at the package level ($cfg_ref). my ($compset_file, $compset, $grid_longname, $grid_shortname, $cfg_ref, $caseroot) = @_; my $fh = new IO::File; $fh->open(">>$caseroot/README.case") or die "can't open file: $file\n"; my $xml = XML::Lite->new( $compset_file ); my $root = $xml->root_element(); my $name = $root->get_name(); $name eq "config_compset" or die "file $compset_file is not a compset parameters file\n"; # Read the compset parameters from $compset_file. my @e = $xml->elements_by_name( "compset" ); my $comment; my $desc; my $compset_longname; my $compset_shortname; my $temp; my $found; my $valid_grid = 0; # ======================================================== # 0. Match on name (exactly) # ======================================================== my @e = $xml->elements_by_name( "compset" ); my %a = (); $found = 0; NAME: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ( ($compset eq $a{'NAME'}) || ($compset eq $a{'SHORTNAME'})) { $found = 1; $compset_longname = $a{'NAME'}; $compset_shortname = $a{'SHORTNAME'}; #print "(COMPSET) $compset_longname \n"; print $fh "(COMPSET) $compset_longname \n"; $temp = $a{'NAME'}." (".$a{'SHORTNAME'}.")"; $cfg_ref->set('CCSM_COMPSET' , "$temp"); $temp = $a{'NAME'} ; $cfg_ref->set('CCSM_LCOMPSET', "$temp"); $temp = $a{'SHORTNAME'} ; $cfg_ref->set('CCSM_SCOMPSET', "$temp"); if ($a{'DESC'}) { $desc = $a{'DESC'}; } last NAME; } } unless ($found) { print "set_compset: no match for compset $compset - possible compset values are \n"; print_compsets($compset_file); die "set_compset: exiting\n"; } # ======================================================== # 1. Match on default compset settings # ======================================================== @e = $xml->elements_by_name( "compset" ); while ( my $e = shift @e ) { %a = $e->get_attributes(); if ($a{'BEG_COMPSET_MATCH'}) { if ($compset_longname =~ /^$a{'BEG_COMPSET_MATCH'}/) { my @ids = keys %$cfg_ref; foreach my $id (sort @ids) { foreach my $attr (keys %a) { if ( ! $cfg_ref->is_ignore_name($attr) and ! $cfg_ref->is_valid_name($attr) ) { die "set_compset: invalid id $attr in compset $compset in file $compset_file exiting\n"; } if ($attr eq $id) { my $value = $a{$attr}; #print "(default) $attr: $value \n"; print $fh "(default) $attr: $value \n"; $cfg_ref->set($id, $value); } } } } } } # ======================================================== # 2. Match on general compset settings # ======================================================== @e = $xml->elements_by_name( "compset" ); while ( my $e = shift @e ) { %a = $e->get_attributes(); if ($a{'GEN_COMPSET_MATCH'}) { if ($compset_longname =~ /$a{'GEN_COMPSET_MATCH'}/) { my $first_time = 1; my @ids = keys %$cfg_ref; foreach my $id (sort @ids) { foreach my $attr (keys %a) { if ( ! $cfg_ref->is_ignore_name($attr) and ! $cfg_ref->is_valid_name($attr) ) { die "set_compset: invalid id $attr in compset $compset in file $compset_file exiting\n"; } if ($attr eq $id) { my $attrib = $a{$attr}; my $curval = $cfg_ref->get($id); my $newval = $attrib; # For *_CONFIG_OPTS and *_NAMELIST_OPTS, we want to merge, not replace, options. if (($attr =~ m/\s*_CONFIG_OPTS/) || ($attr =~ m/\s*_NAMELIST_OPTS/)) { if ($curval !~ m/^\s*$/) { $newval = $curval; # Split into separate options, separated by '-'. # The regex is used to ensure '-' is only noticed if it is # either the first character or follows a space. # Note that the '-' will be stripped off. my @attropts = split(/(?:^|\s)-/, $attrib); my @curopts = split(/(?:^|\s)-/, $curval); # First item in each array will be space or empty string, so # remove it with shift. shift @attropts; shift @curopts; # Iterate through new options foreach my $attropt (@attropts) { # Grab option name. my ($attrname) = $attropt =~ m/^(\w+)\s/; my $attr_found = 0; # Check current options for values to replace. foreach my $curopt (@curopts) { if ($curopt =~ m/^$attrname\s/) { $attr_found = 1; # Substitute, adding one space just in case. $newval =~ s/$curopt/$attropt /; } } # If the new option was not found in existing options, append it. if ( ! $attr_found) { $newval = "$newval -$attropt"; } } # Get rid of extra spaces. $newval =~ s/\s+/ /g; # spaces in middle $newval =~ s/\s*$//; # spaces at end } } #print "(compset) $attr: $newval \n"; print $fh "(compset) $attr: $newval \n"; $cfg_ref->set($id, $newval); } } } if ($a{'VALID_GRID_MATCH'}) { my $match = $a{'VALID_GRID_MATCH'}; if (($grid_longname =~ /$match/) || ($grid_shortname =~ /$match/)) { # do nothing } else { $match =~ s/\|/ or /g; print "\n *** ERROR: invalid grid for this compset *** \n "; print " supported grids for this compset must match \n "; print " $match \n"; die " please retry this compset at one of the supported resolutions \n \n"; } } } } } # ======================================================== # 3. Match on compset AND grid # ======================================================== @e = $xml->elements_by_name( "compset" ); $found = 0; COMPGRID_MATCH: while ( my $e = shift @e ) { %a = $e->get_attributes(); if (($a{'GRID_MATCH'} && $a{'RES_COMPSET_MATCH'}) || ($a{'GRID_MATCH'} && $a{'SSTICE_COMPSET_MATCH'})) { my $compset_match = 0; my $grid_match = 0; if ($a{'RES_COMPSET_MATCH'}) { if ($compset_longname eq $a{'RES_COMPSET_MATCH'}) { $compset_match = 1; } } if ($a{'SSTICE_COMPSET_MATCH'}) { if ($compset_longname =~ /^$a{'SSTICE_COMPSET_MATCH'}/) { $compset_match = 1; } } if ($grid_longname =~ /$a{'GRID_MATCH'}/ || $grid_shortname =~ /$a{'GRID_MATCH'}/ ) { $grid_match = 1; $valid_grid = 1; } if ($grid_match && $compset_match) { my @ids = keys %$cfg_ref; foreach my $id (sort @ids) { foreach my $attr (keys %a) { if ( ! $cfg_ref->is_ignore_name($attr) and ! $cfg_ref->is_valid_name($attr) ) { die "set_compset: invalid id $attr in compset $compset in file $compset_file exiting\n"; } if ($attr eq $id) { my $value = $a{$attr}; #print "(gridset) $attr: $value \n"; print $fh "(gridset) $attr: $value \n"; $cfg_ref->set($id, $value); } } } } } } # ======================================================== # 3. Match on name exactly # ======================================================== @e = $xml->elements_by_name( "compset" ); NAME: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ($compset_longname eq $a{'NAME'}) { my @ids = keys %$cfg_ref; foreach my $id (sort @ids) { foreach my $attr (keys %a) { if ( ! $cfg_ref->is_ignore_name($attr) and ! $cfg_ref->is_valid_name($attr) ) { die "set_compset: invalid id $attr in compset $compset in file $compset_file exiting\n"; } if ($attr eq $id) { my $value = $a{$attr}; #print "(name ) $attr: $value \n"; print $fh "(name ) $attr: $value \n"; $cfg_ref->set($id, $value); } } } last NAME; } } print "\n"; print "Component set : $compset_longname ($compset_shortname) \n"; print "Desc : $desc \n"; print $fh "Component set : $compset_longname ($compset_shortname) \n"; print $fh "Desc : $desc \n"; # Print config_ref values my @ids = keys %$cfg_ref; foreach my $id (sort @ids) { my $value = $cfg_ref->get($id); # print " $id: $value \n"; # print $fh " \n"; } return ($compset_longname, $compset_shortname); } #------------------------------------------------------------------------------- sub check_grid { # Set the parameters for the specified horizontal grid. The # parameters are read from an input file, and if no grid matches are # found then issue error message. # This routine uses the configuration defined at the package level ($cfg_ref). my ($grid_file, $grid, $compset_longname) = @_; my $xml = XML::Lite->new( $grid_file ); my $root = $xml->root_element(); # Check for valid root node my $name = $root->get_name(); $name eq "config_horiz_grid" or die "file $grid_file is not a horizontal grid parameters file\n"; # Read the grid parameters from $grid_file. my @e = $xml->elements_by_name( "horiz_grid" ); my %a = (); # Search for matching grid. HGRID: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ($grid eq $a{'GRID'} || $grid eq $a{'SHORTNAME'}) { print "$grid $a{'GRID'} $a{'SHORTNAME'} $a{'VALID_COMPSET_MATCH'}\n" if($print>1); if (defined $a{'VALID_COMPSET_MATCH'}) { if ($compset_longname =~ /^$a{'VALID_COMPSET_MATCH'}/) { # do nothing } else { die <<"EOF"; *** Invalid compset - $compset - for grid - $grid - only valid compset must match $a{'VALID_COMPSET_MATCH'} *** *** Invoke create_newcase again with a vaid compset for this grid *** EOF } } last HGRID; } } if($print>1){ foreach (keys %a){ print "GRIDMATCH: $_ $a{$_}\n"; } } } #------------------------------------------------------------------------------- sub set_test { # Set the parameters for the specified testname. The # parameters are read from an input file, and if no testname matches are # found then issue error message. # This routine uses the configuration defined at the package level ($cfg_ref). my ($test_file, $testname, $cfg_ref) = @_; my $xml = XML::Lite->new( $test_file ); my $root = $xml->root_element(); # Check for valid root node my $name = $root->get_name(); $name eq "config_ccsmtest" or die "file $test_file is not a test parameters file\n"; # Read the test parameters from $test_file. my @e = $xml->elements_by_name( "ccsmtest" ); my %a = (); # Search for matching test. my $found = 0; CCSMTEST: while ( my $e = shift @e ) { %a = $e->get_attributes(); if ( ($testname eq $a{'NAME'}) ) { $found = 1; last CCSMTEST; } } # Die unless search was successful. unless ($found) { print "set_test: no match for test $testname - possible testnames are \n"; my @e_err = $xml->elements_by_name( "ccsmtest" ); my %a_err = (); while ( my $e_err = shift @e_err ) { %a_err = $e_err->get_attributes(); print " $a_err{'NAME'} ($a_err{'DESC'}) \n" ; } die "set_test: exiting\n"; } # Loop through all entry_ids of the $cfg_ref object and if the corresponding # attributed is defined in the testname hash, then reset the cfg_ref object to # that value my @ids = keys %$cfg_ref; foreach my $id (sort @ids) { foreach my $attr (keys %a) { if ( ! $cfg_ref->is_ignore_name($attr) and ! $cfg_ref->is_valid_name($attr) ) { die "set_test: invalid id $attr in test $testname in file $test_file exiting\n"; } if ($attr eq $id) { my $value = $a{$attr}; $cfg_ref->set($id, $value); } } } } #------------------------------------------------------------------------------- sub set_confopts { # Print all currently supported valid grids my ($coptions, $cfg_ref) = @_; print " confopts = $coptions\n"; if ($coptions =~ "_D" || $coptions =~ "_ED") { $cfg_ref->set('DEBUG', "TRUE"); print " confopts DEBUG ON \n"; } if ($coptions =~ "_E" || $coptions =~ "_DE") { $cfg_ref->set('USE_ESMF_LIB', "TRUE"); $cfg_ref->set('COMP_INTERFACE', "ESMF"); print " confopts COMP_INTERFACE ESMF set \n"; } if ($coptions =~ "_P") { my $popt = $coptions; $popt =~ s/.*_P([A-Za-z0-9]*)_?.*/$1/; $pecount = $popt; print " confopts pecount set to $pecount \n"; } if ($coptions =~ "_M") { my $mopt = $coptions; $mopt =~ s/.*_M([A-Za-z0-9\-]*)_?.*/$1/; $mpilib = $mopt; print " mpilib set to $mpilib \n"; } if ($coptions =~ "_L") { my $lopt = $coptions; $lopt =~ s/.*_L([A-Za-z0-9]*)_?.*/$1/; my $loptc = substr($lopt,0,1); my $lopti = substr($lopt,1); my $lopts = 'unknown'; if ($loptc =~ "y") {$lopts = 'nyears'} if ($loptc =~ "m") {$lopts = 'nmonths'} if ($loptc =~ "d") {$lopts = 'ndays'} if ($loptc =~ "h") {$lopts = 'nhours'} if ($loptc =~ "s") {$lopts = 'nseconds'} if ($loptc =~ "n") {$lopts = 'nsteps'} if ($lopts =~ "unknown") { print "$0 _L confopts run length undefined, only y m d h s n allowed\n\n"; exit -1; } $cfg_ref->set('STOP_OPTION', $lopts); $cfg_ref->set('STOP_N', $lopti); print " confopts run length set to $lopt . $lopts . $lopti \n"; } if ($coptions =~ "_N") { my $nopt = $coptions; $nopt =~ s/.*_N([0-9]*)_?.*/$1/; $cfg_ref->set('NINST_ATM', $nopt); $cfg_ref->set('NINST_LND', $nopt); $cfg_ref->set('NINST_OCN', $nopt); $cfg_ref->set('NINST_ICE', $nopt); $cfg_ref->set('NINST_GLC', $nopt); $cfg_ref->set('NINST_ROF', $nopt); print " confopts instances set to $nopt \n"; } if ($coptions =~ "_CG") { $cfg_ref->set('CALENDAR', "GREGORIAN"); print " confopts CALENDAR set to GREGORIAN \n"; } if ($coptions =~ "_AOA") { $cfg_ref->set('AOFLUX_GRID', "atm"); print " confopts AOFLUX_GRID set to atm \n"; } if ($coptions =~ "_AOE") { $cfg_ref->set('AOFLUX_GRID', "exch"); print " confopts AOFLUX_GRID set to exch \n"; } if ($coptions =~ "_R") { if($cfg_ref->get('OS') eq 'BGP'){ print "$0 single_point cases not supported on bluegene systems\n\n"; exit -1; } my $ptsmode = "undef"; if ($coptions =~ "_RLA" ) { $cfg_ref->set('PTS_LAT', 42 ); $cfg_ref->set('PTS_LON', 260 ); my $ptsmode = "valid"; print " confopts single point mode set to RLA \n"; } if ($coptions =~ "_RLB" ) { $cfg_ref->set('PTS_LAT', -5 ); $cfg_ref->set('PTS_LON', 290 ); my $ptsmode = "valid"; print " confopts single point mode set to RLB \n"; } if ($coptions =~ "_ROA" ) { $cfg_ref->set('PTS_LAT', 30 ); $cfg_ref->set('PTS_LON', 315 ); my $ptsmode = "valid"; print " confopts single point mode set to ROA \n"; } if ($coptions =~ "_ROB" ) { $cfg_ref->set('PTS_LAT', 0 ); $cfg_ref->set('PTS_LON', 160 ); my $ptsmode = "valid"; print " confopts single point mode set to ROB \n"; } if ($ptsmode == "valid" ) { $cfg_ref->set('PTS_MODE', "TRUE" ); $cfg_ref->set('ATM_NX', 0); $cfg_ref->set('ATM_NY', 0); $cfg_ref->set('LND_NX', 0); $cfg_ref->set('LND_NY', 0); $cfg_ref->set('ICE_NX', 0); $cfg_ref->set('ICE_NY', 0); $cfg_ref->set('OCN_NX', 0); $cfg_ref->set('OCN_NY', 0); $cfg_ref->set('GLC_NX', 0); $cfg_ref->set('GLC_NY', 0); $cfg_ref->set('ROF_NX', 0); $cfg_ref->set('ROF_NY', 0); } else { print "create_newcase exited on invalid _R confopts setting\n\n"; exit -1; } } } #------------------------------------------------------------------------------- sub print_grids { # Print all currently supported valid grids my ($grid_file) = @_; my $xml = XML::Lite->new( $grid_file ); my $root = $xml->root_element(); # Check for valid root node my $name = $root->get_name(); $name eq "config_horiz_grid" or die "file $grid_file is not a horizontal grid parameters file\n"; print (" \n"); print (" RESOLUTIONS: name (shortname) \n"); # Read the grid parameters from $grid_file. my @e = $xml->elements_by_name( "horiz_grid" ); my %a = (); while ( my $e = shift @e ) { %a = $e->get_attributes(); if (defined($a{'SHORTNAME'})) { print " $a{'GRID'} ($a{'SHORTNAME'}) \n"; print " $a{'DESC'} \n"; } } } #------------------------------------------------------------------------------- sub print_compsets { # Print all currently supported valid grids my ($compset_file, $grid_longname, $grid_shortname) = @_; my $xml = XML::Lite->new( $compset_file ); my $root = $xml->root_element(); # Check for valid root node my $name = $root->get_name(); $name eq "config_compset" or die "file $compset_file is not a compset parameters file\n"; print (" \n"); print (" COMPSETS: name (shortname): description \n"); # Read the compset parameters from $compset_file. my @e = $xml->elements_by_name( "compset" ); my %a = (); my $e; while ( $e = shift @e ) { %a = $e->get_attributes(); if ($a{'NAME'}) { print " $a{'NAME'} ($a{'SHORTNAME'}) \n"; print " $a{'DESC'} \n"; } } } #------------------------------------------------------------------------------- sub print_tests { # Print all currently supported tests my ($test_file) = @_; my $xml = XML::Lite->new( $test_file ); my $root = $xml->root_element(); # Check for valid root node my $name = $root->get_name(); $name eq "config_ccsmtest" or die "file $test_file is not a ccsmtest parameters file\n"; print (" \n"); print (" TESTS: name (description) \n"); my @e = $xml->elements_by_name( "ccsmtest" ); my %a = (); while ( my $e = shift @e ) { %a = $e->get_attributes(); if (defined($a{'DESC'})) { print " $a{'NAME'} ($a{'DESC'}) \n"; } } } # Check the CESM repository for known problems, see the SVN url below. # If there is a known_problems file in the repository that matches sub check_known_problems { print "-------------------------------------------------------------------------------\n"; print " IMPORTANT INFORMATION ABOUT SCIENTIFIC VALIDATION - THERE\n"; print " ARE ONLY LIMITED SCIENTIFICALLY VALIDATED COMPONENT SETS IN CESM1.1\n"; print " (Currently, only WACCM-X under solar minimum conditions)\n\n"; print " For both a quick start and details of creating and running a CESM model case\n"; print " see the CESM1.1 User's Guide at http://www.cesm.ucar.edu/models/cesm1.1\n\n"; print "-------------------------------------------------------------------------------\n"; print " For a list of potential issues in the current tag, please point your web browser to:\n"; print " http://www.cesm.ucar.edu/models/cesm1.1/tags/cesm1_1/knownproblems.html\n"; print "-------------------------------------------------------------------------------\n"; }