#!/bin/bash # Bill Sacks # 8-22-12 #====================================================================== # Overview #====================================================================== # This script generates baselines for a single CESM component, and/or # compares with previous baselines for a component, for all tests that # were run in a single test suite. It compares the last history file # from that component, similarly to what is done in testcase_end for # cpl hist files (though the meaning of the test results differs # slightly from that in testcase_end). It then outputs the test status # (PASS/FAIL/etc.) for each comparison / generation. # # This is meant to be run after all tests in a given test suite are # complete. The test suite must have been run with '-clean off'. In # addition to some of the options given to create_test_suite, you also # need to provide the script with (1) the unique test ID of the test # suite, (2) the name of the component you wish to generate / compare # baselines for, and (3) the directory in which the various test run # directories can be found. # # See usage message for details on inputs. #====================================================================== # Limitations #====================================================================== # - Only uses last history file for a given component. This has three # implications: # # - Does not use earlier history files if there are history files # from multiple times for a component. This is probably okay. # # - If a component outputs multiple sets of history files (e.g., h0 # and h1 files), only one history file will be used (an h1 file if # there are h0 and h1 history files, since h1 is later # alphabetically). This should probably be generalized so that we # use the last of each set of history files (e.g., the last h0 # file and the last h1 file). # # - For a multi-instance run, only uses a history file from the last # instance. This is probably okay. # # - Doesn't look at the PASS/FAIL status of a test. This means, for # example, that a -generate may copy files to the baseline directory # from a test that failed; these files might not be the correct, # end-of-run history files, and so could later result in a # misleading FAIL message from a -compare. # # - Only looks for history files in the run directory. This will fail # to find a history file if things have been moved to the short-term # archive directory. This could be fixed to look in the short-term # archive directory if a file can't be found in the run directory, # as is done in testcase_end. I haven't done this yet, partly # because it adds an extra directory that the user has to specify # (because we don't have access to the DOUT_S_ROOT variable), and # partly because this shouldn't matter for most tests. #====================================================================== # Testing #====================================================================== # There currently is no unit test script for this. Here are the tests # that should be done on this script: # # - Missing arguments # # --- Do the following with just the -generate flag --- # # (the following can be done together with a single run, if some # directories with a given test id have history files for a given # component, and others don't) # # - test PASS for generate # # - test BFAIL for generate due to no hist file # # - test with multiple history files for the component: make sure the # right one is chosen # # --- Do the following with just the -compare flag --- # # (You can do the following by first running -generate tag01, then # running -compare tag01 using the same testid) # # (as with the -generate tests, you can combine some of these tests # into a single run of the script) # # - test PASS for compare # # - test BFAIL for compare due to no baseline directory # # - test FAIL for compare due to no hist file (can do this by # temporarily removing a history file from one test directory) # # - test FAIL for compare due to difference in values (can do this by # modifying a history file with: ncap2 -s # 'vvel[$time,$level,$y0,$x0]=1.7') # # --- Do the following with both '-generate' and '-compare' # # - one test with both options - e.g., # component_gen_comp -baselineroot /glade/scratch/sacks/cesm_baselines -compare tag01 -generate tag02 -testid 114029 -model cism #====================================================================== # Local functions #====================================================================== function Usage { echo "SYNOPSIS" echo " $progname [options]" echo "" echo " Generates baselines for a single CESM component, and/or compares with previous" echo " baselines for a component, for all tests that were run in a single test suite." echo " It then outputs the test status (PASS/FAIL/etc.) for each comparison / generation." echo "" echo " This is meant to be run after all tests in a given test suite are complete." echo " The test suite must have been run with '-clean off'." echo "" echo " The -baselineroot, -generate and -compare arguments will usually match the arguments" echo " given to create_test_suite. The -testid argument will match the -testid argument" echo " given to create_test_suite, if provided; otherwise, it will be the testid created" echo " on the fly by that script." echo "" echo "OPTIONS" echo " -baselineroot Path to directory containing baselines (required)" echo "" echo " -generate Tag name to use for generation (optional)" echo " A directory with this name is created in baselineroot," echo " if it doesn't already exist." echo " Either -generate or -compare must be given" echo "" echo " -compare Tag name to use for comparison (optional)" echo " Baselines are found in a directory with the name of this tag" echo " within baselineroot." echo " Either -generate or -compare must be given" echo "" echo " -testid ID of the test suite on which to run this script (required)" echo " (e.g., 123456)" echo "" echo " -model Name of model component (required)" echo " This provides the name as in history file names (e.g., clm2)" echo "" echo " -runloc Path to directory containing test run directories (optional)" echo " A given test's run directory can be found in:" echo " \$runloc/\$CASE/run" echo " If not given, defaults to: $runloc_default" echo "" echo " -help Print this help message and exit" echo "" echo "EXAMPLES" echo " $progname" echo " -baselineroot /glade/scratch/\$USER/cesm_baselines" echo " -generate cesm1_1_beta17" echo " -compare cesm1_1_beta16" echo " -testid 123456" echo " -model cism" echo " -runloc /glade/scratch/\$USER" echo " This will find directories in /glade/scratch/\$USER whose name ends with" echo " the testid, 123456. For each such test (say, SMS.f09_g16.TG.bluefire_ibm.GC.123456)" echo " it will find the last cism history file in the run directory of that test." echo " It will then copy that history file to" echo " /glade/scratch/\$USER/cesm_baselines/cesm1_1_beta17/SMS.f09_g16.TG.bluefire_ibm" echo " and will compare that history file with the existing baseline in" echo " /glade/scratch/\$USER/cesm_baselines/cesm1_1_beta16/SMS.f09_g16.TG.bluefire_ibm" echo "" } # Prints the status of the test in a standardized format for test results # Inputs: # - status_and_info: colon-delimited string of the format # "STATUS:Extra info about failure". The string before the colon # is the test status. The string after the colon is extra # information abaout a failure (this may be blank, but the colon # must be present). (It is okay for the extra info to itself # contain one or more colons.) # - testcase: name of test case # - qualifier: additional string to tack on to the end of testcase function print_status { status_and_info="$1" testcase="$2" qualifier="$3" # Separate status & info status=`echo $status_and_info | cut -d ':' -f 1` info=`echo $status_and_info | cut -d ':' -f 2-` # Enclose info in parentheses if [ -n "$info" ]; then info_str="($info)" else info_str="" fi # Print formatted test result printf '%-5s %s %s\n' "$status" "${testcase}.${qualifier}" "$info_str" } #====================================================================== # Begin main script #====================================================================== progname=`basename $0` tools_dir=`dirname $0` #---------------------------------------------------------------------- # Define default values for command-line arguments #---------------------------------------------------------------------- baselineroot='' generate_tag='' compare_tag='' testid='' model='' runloc_default="/ptmp/$USER" runloc=$runloc_default #---------------------------------------------------------------------- # Process command-line arguments #---------------------------------------------------------------------- while [ $# -gt 0 ]; do case $1 in -baselineroot ) baselineroot=$2 shift ;; -generate ) generate_tag=$2 shift ;; -compare ) compare_tag=$2 shift ;; -testid ) testid=$2 shift ;; -model ) model=$2 shift ;; -runloc ) runloc=$2 shift ;; -help ) Usage exit 0 ;; * ) echo "Unknown argument: $1" >&2 echo "Run $progname -help for usage" >&2 exit 1 ;; esac shift done #---------------------------------------------------------------------- # Exit if required command-line arguments weren't provided #---------------------------------------------------------------------- error=0 # no errors yet if [ -z "$baselineroot" ]; then echo "$progname: baselineroot must be provided" >&2 error=1 fi # Either -generate or -compare must be provided, but not necessarily both if [[ -z "$generate_tag" && -z "$compare_tag" ]]; then echo "$progname: At least one of generate_tag or compare_tag must be provided" >&2 error=1 fi if [ -z "$testid" ]; then echo "$progname: testid must be provided" >&2 error=1 fi if [ -z "$model" ]; then echo "$progname: model must be provided" >&2 error=1 fi if [ -z "$runloc" ]; then echo "$progname: runloc must be provided" >&2 error=1 fi if [ $error -gt 0 ]; then echo "" >&2 echo "Run $progname -help for usage" >&2 exit 1 fi #---------------------------------------------------------------------- # Print possible test results #---------------------------------------------------------------------- echo "Possible test result outcomes:" echo " UNDEF - undefined result (may be an error in the script)" echo " BFAIL - compare test couldn't find baseline (history file for the test case may or may not be present)" echo " - generate test couldn't generate baseline (e.g., can't find any history file for this component)" echo " FAIL - compare test fails (including: baseline exists but no history file for the test case)" echo " (see *.cprnc.out in the test's run directory for details)" echo " PASS - test passes" echo "" #---------------------------------------------------------------------- # Loop over directories with the given testid #---------------------------------------------------------------------- tests=`cd $runloc; ls -1d *.${testid}` for testcase in $tests; do # testcase will look like: SMS.T31_g37.IG4804.bluefire_ibm.134426 # optionally with .C or .G or .GC before the testid # Form testcase_base by stripping off the trailing testid and the optional .C, .G or .GC: testcase_base=`echo $testcase | perl -p -e "s/(\.G?C?)?\.$testid\$//"` rundir=${runloc}/${testcase}/run #------------------------------------------------------------------ # Find last component hist file in this run directory, and # determine corresponding name of the baseline file (used for # either generation or comparison) #------------------------------------------------------------------ # Note that we find the last alphabetically rather than by time # stamp, because the last by time stamp can be non-deterministic. # Note that we need a * after ${model} to capture multi-instance # output test_hist=`cd $rundir; ls -1 ${testcase}.${model}*.h*.nc 2>/dev/null | tail -1` # Note that this name drops (1) the timestamp, and (2) the # distinction between h0 / h1 / etc. baseline_hist=${model}.h.nc #------------------------------------------------------------------ # Do comparison, if desired #------------------------------------------------------------------ if [ -n "$compare_tag" ]; then baseline_dir=${baselineroot}/${compare_tag}/${testcase_base} compare_result=`${tools_dir}/component_compare.sh -baseline_dir "$baseline_dir" -baseline_hist "$baseline_hist" -test_dir "$rundir" -test_hist "$test_hist"` print_status "$compare_result" "$testcase_base" "compare_hist.${compare_tag}.$model" fi #------------------------------------------------------------------ # Do baseline generation, if desired #------------------------------------------------------------------ if [ -n "$generate_tag" ]; then baseline_dir=${baselineroot}/${generate_tag}/${testcase_base} generate_result=`${tools_dir}/component_generate.sh -baseline_dir "$baseline_dir" -baseline_hist "$baseline_hist" -test_dir "$rundir" -test_hist "$test_hist"` print_status "$generate_result" "$testcase_base" "generate.$model" fi done