PISM, A Parallel Ice Sheet Model stable 0.4.1779

test/vfnow.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 ## @package vfnow
00004 ## \author Ed Bueler and Constantine Khroulev, University of Alaska Fairbanks, USA
00005 ## \brief A script for verification of numerical schemes in PISM.
00006 ## \details It specifies a refinement path for each of Tests ABCDEFGIJKL and runs
00007 ## pismv accordingly.
00008 ## Copyright (C) 2007--2011 Ed Bueler and Constantine Khroulev
00009 ##
00010 ## Organizes the process of verifying PISM.  It specifies standard refinement paths for each of the tests described in the user manual.  It runs the tests, times them, and summarizes the numerical errors reported at the end.
00011 ##
00012 ## Examples:
00013 ##    - \verbatim vfnow.py \endverbatim use one processor and do three levels of refinement; this command is equivalent to \verbatim vfnow.py -n 2 -l 2 -t CGIJ \endverbatim,
00014 ##    - \verbatim vfnow.py -n 8 -l 5 -t J --prefix=bin/ --mpido='aprun -n' \endverbatim will use \verbatim aprun -n 8 bin/pismv \endverbatim as the command and do five levels (the maximum) of refinement only on test J,
00015 ##    - \verbatim vfnow.py -n 2 -l 3 -t CEIJGKLO \endverbatim uses two processers (cores) and runs in about an hour,
00016 ##    - \verbatim vfnow.py -n 40 -l 5 -t ABCDEFGIJKLO \endverbatim will use forty processors to do all possible verification as managed by \c vfnow.py; don't run this unless you have a big computer and you are prepared to wait.
00017 ## For a list of options do \verbatim test/vfnow.py --help \endverbatim.
00018 ## Timing information is given in the \c vfnow.py output so performance, including parallel performance, can be assessed along with accuracy. 
00019 
00020 import sys, getopt, time, commands
00021 from numpy import array, double, int
00022 
00023 ## A class describing a refinement path and command-line options
00024 ## for a particular PISM verification test.
00025 class PISMVerificationTest:
00026 
00027     ## max number of levels that will work with
00028     N = 50
00029     ## one-letter test name
00030     name = ""
00031     ## test description
00032     test = ""
00033     ## description of the refinement path
00034     path = ""                   
00035     Mx = []
00036     My = []
00037     ## 31 levels in the ice
00038     Mz = [31] * N
00039     ## no bedrock by default
00040     Mbz = [1] * N
00041     ## extra options (such as -y, -ys, -ssa_rtol)
00042     opts = ""                   
00043     executable = "pismv"
00044     
00045     def build_command(self, exec_prefix, level):
00046         M = zip(self.Mx, self.My, self.Mz, self.Mbz)
00047 
00048         if level > len(M):
00049             print "Test %s: Invalid refinement level: %d (only %d are available)" % (
00050                 self.name, level, len(M))
00051             return ""
00052 
00053         grid_options = "-Mx %d -My %d -Mz %d -Mbz %d" % M[level - 1]
00054         return "%s%s -test %s %s %s" % (exec_prefix, self.executable, self.name, grid_options, self.opts)
00055 
00056 def run_test(executable, name, level, extra_options = "", debug = False):
00057     try:
00058         test = tests[name]
00059     except:
00060         print "Test %s not found." % name
00061         return
00062 
00063     if level == 1:
00064         print " ++++  TEST %s:  verifying with %s exact solution  ++++\n %s" % (
00065             test.name, test.test, test.path)
00066 
00067     command = test.build_command(executable, level) + " " + extra_options
00068 
00069     if debug:
00070         print ' L%d: would try "%s"' % (level, command)
00071         return
00072     else:
00073         print ' L%d: trying "%s"' % (level, command)
00074 
00075     # run PISM:
00076     try:
00077         lasttime = time.time()
00078         (status,output) = commands.getstatusoutput(command)
00079         elapsetime = time.time() - lasttime      
00080     except KeyboardInterrupt:
00081         sys.exit(2)
00082     if status:
00083         sys.exit(status)
00084     print ' finished in %7.4f seconds; reported numerical errors as follows:' % elapsetime
00085 
00086     # process the output:
00087     position = output.find('NUMERICAL ERRORS')
00088     if position >= 0:
00089         report = output[position:output.find('NUM ERRORS DONE')]
00090         endline = report.find('\n')
00091         print '    ' + report[0:endline]
00092         report = report[endline+1:]
00093         while (len(report) > 1) and (endline > 0):
00094             endline = report.find('\n')
00095             if endline == -1:
00096                 endline = len(report)
00097             print '   #' + report[0:endline]
00098             report = report[endline+1:]       
00099             endline = report.find('\n')
00100             if endline == -1:
00101                 endline = len(report)
00102             print '   |' + report[0:endline]
00103             report = report[endline+1:]       
00104     else:
00105         print " ERROR: can't find reported numerical error"
00106         sys.exit(99)
00107 
00108 
00109 def define_refinement_paths(KSPRTOL, SSARTOL):
00110     # Define all the supported refinement paths:
00111     tests = {}
00112     # A
00113     A = PISMVerificationTest()
00114     A.name = "A"
00115     A.test = "steady, marine margin isothermal SIA"
00116     A.path = "(refine dx=53.33,40,26.67,20,13.33,km, dx=dy and Mx=My=31,41,61,81,121)"
00117     A.Mx   = [31, 41, 61, 81, 121]
00118     A.My   = A.Mx
00119     A.opts = "-y 25000.0"
00120     tests['A'] = A
00121     # B
00122     B = PISMVerificationTest()
00123     B.name = "B"
00124     B.test = "moving margin isothermal SIA (Halfar)"
00125     B.path = "(refine dx=80,60,40,30,20,km, dx=dy and Mx=My=31,41,61,81,121)"
00126     B.Mx   = [31, 41, 61, 81, 121]
00127     B.My   = B.Mx
00128     B.opts = "-ys 422.45 -y 25000.0"
00129     tests['B'] = B
00130     # C
00131     C = PISMVerificationTest()
00132     C.name = "C"
00133     C.test = "non-zero accumulation moving margin isothermal SIA"
00134     C.path = "(refine dx=50,33.33,25,20,16,km, dx=dy and Mx=My=41,61,81,101,121)"
00135     C.Mx   = [41, 61, 81, 101, 121]
00136     C.My   = C.Mx
00137     C.opts = "-y 15208.0"
00138     tests['C'] = C
00139     # D
00140     D = PISMVerificationTest()
00141     D.name = "D"
00142     D.test = "time-dependent isothermal SIA"
00143     D.path = "(refine dx=50,33.33,25,20,16.67,km, dx=dy and Mx=My=41,61,81,101,121)"
00144     D.Mx   = [41, 61, 81, 101, 121]
00145     D.My   = D.Mx
00146     D.opts = "-y 25000.0"
00147     tests['D'] = D
00148     # E
00149     E = PISMVerificationTest()
00150     E.name = "E"
00151     E.test = "steady sliding marine margin isothermal SIA"
00152     E.path = "(refine dx=53.33,40,26.67,20,13.33,km, dx=dy and Mx=My=31,41,61,81,121)"
00153     E.Mx   = [31, 41, 61, 81, 121]
00154     E.My   = E.Mx
00155     E.opts = "-y 25000.0"
00156     tests['E'] = E
00157     # F
00158     F = PISMVerificationTest()
00159     F.name = "F"
00160     F.test = "steady thermomechanically-coupled SIA"
00161     F.path = "(refine dx=30,20,15,10,7.5,km, dx=dy, dz=66.67,44.44,33.33,22.22,16.67 m\n  and Mx=My=Mz=61,91,121,181,241)"
00162     F.Mx   = [61, 91, 121, 181, 241]
00163     F.My   = F.Mx
00164     F.Mz   = F.Mx
00165     F.opts = "-y 25000.0"
00166     tests['F'] = F
00167     # G
00168     G = PISMVerificationTest()
00169     G.name = "G"
00170     G.test = "time-dependent thermomechanically-coupled SIA"
00171     G.path = "(refine dx=30,20,15,10,7.5,km, dx=dy, dz=66.67,44.44,33.33,22.22,16.67 m\n  and Mx=My=Mz=61,91,121,181,241)"
00172     G.Mx   = [61, 91, 121, 181, 241]
00173     G.My   = G.Mx
00174     G.Mz   = G.Mx
00175     G.opts = "-y 25000.0"
00176     tests['G'] = G
00177     # H
00178     H = PISMVerificationTest()
00179     H.name = "H"
00180     H.test = "moving margin, isostatic bed, isothermal SIA"
00181     H.path = "(refine dx=80,60,40,30,20,km, dx=dy and Mx=My=31,41,61,81,121)"
00182     H.Mx   = [31, 41, 61, 81, 121]
00183     H.My   = H.Mx
00184     H.opts = "-bed_def iso -y 60000.0"
00185     tests['H'] = H
00186     # I
00187     I = PISMVerificationTest()
00188     I.name = "I"
00189     I.test = "plastic till ice stream (SSA)"
00190     I.path = "(refine dy=5000,1250,312.5,78.13,19.53,m, My=49,193,769,3073,12289)"
00191     I.Mx   = [5] * 5
00192     I.My   = [49, 193, 769, 3073, 12289]
00193     I.executable = "ssa_testi"
00194     I.opts = "-ssa_method fd -ssa_rtol %1.e -ksp_rtol %1.e" % (SSARTOL, KSPRTOL)
00195     tests['I'] = I
00196     # J
00197     J = PISMVerificationTest()
00198     J.name = "J"
00199     J.test = "periodic ice shelf (linearized SSA)"
00200     J.path = "(refine dy=5000,1250,312.5,78.13,19.53,m, Mx=49,193,769,3073,12289)"
00201     J.Mx   = [49, 98, 196, 392, 784]
00202     J.My   = J.Mx
00203     J.Mz   = [11] * 5
00204     J.executable = "ssa_testj"
00205     J.opts = "-ssa_method fd -pc_type asm -sub_pc_type lu -ksp_rtol %1.e" % KSPRTOL
00206     tests['J'] = J
00207     # K
00208     K = PISMVerificationTest()
00209     K.name = "K"
00210     K.test = "pure conduction problem in ice and bedrock"
00211     K.path = "(refine dz=100,50,25,12.5,6.25,m, Mz=41,81,161,321,641)"
00212     K.Mx   = [8] * 5
00213     K.My   = K.Mx
00214     K.Mz   = array([41, 81, 161, 321, 641])
00215     K.Mbz  = (K.Mz - 1) / 4 + 1
00216     K.opts = "-y 130000.0 -Lbz 1000 -z_spacing equal"
00217     tests['K'] = K
00218     # L
00219     L = PISMVerificationTest()
00220     L.name = "L"
00221     L.test = "non-flat bed stead isothermal SIA"
00222     L.path = "(refine dx=60,30,20,15,10,km, dx=dy and Mx=My=31,61,91,121,181)"
00223     L.Mx   = [31, 61, 91, 121, 181]
00224     L.My   = L.Mx
00225     L.opts = "-y 25000.0"
00226     tests['L'] = L
00227     # M
00228     M = PISMVerificationTest()
00229     M.name = "M"
00230     M.test = "annular ice shelf with a calving front (SSA)"
00231     M.path = "(refine dx=50,25,16.666,12.5,8.333 km; dx=dy and My=31,61,91,121,181)"
00232     M.Mx   = [31, 61, 91, 121, 181]
00233     M.My   = M.Mx
00234     M.Mz   = [11] * 5
00235     M.opts = "-ssa_rtol %1.e -ksp_rtol %1.e" % (SSARTOL, KSPRTOL)
00236     tests['M'] = M
00237     # O
00238     O = PISMVerificationTest()
00239     O.name = "O"
00240     O.test = "basal melt rate from conduction problem in ice and bedrock"
00241     O.path = "(refine dz=100,50,25,12.5,6.25,m, Mz=41,81,161,321,641)"
00242     O.Mx   = [8] * 5
00243     O.My   = O.Mx
00244     O.Mz   = array([41, 81, 161, 321, 641])
00245     O.Mbz  = (O.Mz - 1) / 4 + 1
00246     O.opts = "-z_spacing equal -zb_spacing equal -Lbz 1000 -y 1000 -no_mass"
00247     tests['O'] = O
00248 
00249     # test K (for a figure in the User's Manual)
00250     K = PISMVerificationTest()
00251     K.name = "K"
00252     K.test = "pure conduction problem in ice and bedrock"
00253     K.path = "(lots of levels)"
00254     K.Mz   = array([101, 121, 141, 161, 181, 201, 221, 241, 261, 281, 301, 321])
00255     K.Mbz  = (K.Mz - 1) / 4 + 1
00256     K.Mx   = [8] * len(K.Mz)
00257     K.My   = K.Mx
00258     K.opts = "-y 130000.0 -Lbz 1000"
00259     tests['K_userman'] = K
00260 
00261     # test B (for a figure in the User's Manual)
00262     B = PISMVerificationTest()
00263     B.name = "B"
00264     B.test = "moving margin isothermal SIA (Halfar)"
00265     B.path = "(lots of levels)"
00266     B.Mx   = [31, 41, 51, 61, 71, 81, 91, 101, 111, 121]
00267     B.My   = B.Mx
00268     B.Mz   = [31] * len(B.Mx)
00269     B.Mbz  = [1]  * len(B.Mx)
00270     B.opts = "-ys 422.45 -y 25000.0"
00271     tests['B_userman'] = B
00272 
00273     # test G (for a figure in the User's Manual)
00274     G = PISMVerificationTest()
00275     G.name = "G"
00276     G.test = "time-dependent thermomechanically-coupled SIA"
00277     G.path = "(lots of levels)"
00278     G.Mx   = [61, 71, 81, 91, 101, 111, 121, 151, 181]
00279     G.My   = G.Mx
00280     G.Mz   = G.Mx
00281     G.opts = "-y 25000.0"
00282     tests['G_userman'] = G
00283     
00284     # test I (for a figure in the User's Manual)
00285     I = PISMVerificationTest()
00286     I.name = "I"
00287     I.test = "plastic till ice stream (SSA)"
00288     I.path = "(lots of levels)"
00289     I.My   = [51, 101, 151, 201, 401, 601, 801, 1001, 1501, 2001, 2501, 3073]
00290     I.Mx   = [5] * len(I.My)
00291     I.opts = "-ssa_rtol %1.e -ksp_rtol %1.e" % (SSARTOL, KSPRTOL)
00292     tests['I_userman'] = I
00293 
00294     return tests
00295 
00296 #####
00297 ## get options; see --help msg for meaning
00298 ## default settings
00299 KSPRTOL = 1e-12 # for tests I, J, M
00300 SSARTOL = 5e-7  # ditto
00301 nproc   = 2  ## default; will not use 'mpiexec' if equal to one
00302 levels  = 2
00303 mpi     = "mpiexec -np"
00304 prefix  = ""
00305 test_names    = "CGIJ"
00306 userman_tests = ["B_userman", "G_userman", "K_userman", "I_userman"]
00307 extra_options = "-verbose 1"
00308 do_userman = False
00309 debug      = False
00310 try:
00311   opts, args = getopt.getopt(sys.argv[1:], "ep:n:l:t:ur:",
00312      ["eta","prefix=","nproc=","levels=","tests=","userman", "debug",
00313       "uneq","mpido=","report_file=","help","usage"])
00314   for opt, arg in opts:
00315     if opt in ("-p", "--prefix"):
00316         prefix = arg
00317     elif opt == "--userman":
00318         do_userman = True
00319     elif opt == "--debug":
00320         debug = True
00321     elif opt in ("-m", "--mpido"):
00322         mpi = arg
00323     elif opt in ("-n", "--nproc"):
00324         nproc = int(arg)
00325     elif opt in ("-l", "--levels"):
00326         levels = int(arg)
00327     elif opt in ("-t", "--tests"):
00328         test_names = arg.upper()
00329     elif opt in ("-u", "--uneq"):
00330         extra_options += " -z_spacing quadratic"
00331     elif opt in ("-e", "--eta"):
00332         extra_options += " -eta"
00333     elif opt in ("-r", "--report_file"):
00334         extra_options += " -report_file %s" % arg
00335     elif opt in ("--help", "--usage"):
00336         print """PISM verification script; usage:
00337   -e,--eta=     to add '-eta' option to pismv call
00338   -l,--levels=  number of levels of verification; '-l 1' fast, '-l 5' slowest
00339   --mpido=      specify MPI executable
00340                   (e.g. 'mpirun -np' or 'aprun -n' instead of default 'mpiexec -np')
00341   -n,--nproc=   specify number of processors to MPI
00342   -p,--prefix=  path prefix to pismv executable
00343   -r,--report_file=  name of the NetCDF error report file
00344   -t,--tests=   verification tests to use: A,B,C,D,E,F,G,H,I,J,K,L,M,O
00345   -u            use unequal spaced (quadratic) vertical spacing
00346   --userman     run tests necessary to produce figures in the User's Manual
00347   --debug       do not run PISM, just print commands
00348   --help        prints this message
00349   --usage       ditto"""
00350         sys.exit(0)
00351 except getopt.GetoptError:
00352     print 'Incorrect command line arguments'
00353     sys.exit(2)
00354 # should do range checking on option arguments here
00355 
00356 if nproc > 1:
00357   predo = "%s %d " % (mpi, nproc)
00358 else:
00359   predo = ""
00360 exec_prefix = predo + prefix
00361 
00362 tests = define_refinement_paths(KSPRTOL, SSARTOL)
00363 
00364 if do_userman:
00365     print " VFNOW.PY: test(s) %s, using '%s...'\n" % (userman_tests, exec_prefix) + \
00366           "           and ignoring options -t and -l" 
00367     for test in userman_tests:
00368         N = len(tests[test].Mx)
00369         for j in range(1, N + 1):
00370             run_test(exec_prefix, test, j, extra_options, debug)
00371 else:
00372     print " VFNOW.PY: test(s) %s, %d refinement level(s), using '%s...'" % (
00373         test_names, levels, exec_prefix)
00374 
00375     for test in test_names:
00376         for j in range(1, levels + 1):
00377             run_test(exec_prefix, test, j, extra_options, debug)
00378 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines