tpism_config_editor.py - pism - [fork] customized build of PISM, the parallel ice sheet model (tillflux branch)
 (HTM) git clone git://src.adamsgaard.dk/pism
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       tpism_config_editor.py (7543B)
       ---
            1 #!/usr/bin/env python3
            2 # import modules:
            3 
            4 # @package pism_config_editor
            5 ##
            6 # A script simplifying creating configuration files to use with PISM's -config_override option.
            7 ##
            8 # Does not take any command-line options; the only argument is a name of a
            9 # NetCDF configuration file to start from. Run
           10 # \verbatim
           11 # pism_config_editor.py lib/pism_config.nc
           12 # \endverbatim
           13 # to edit lib/pism_config.nc or create a file based on lib/pism_config.nc
           14 ##
           15 # \verbatim
           16 # macbook:pism> pism_config_editor.py lib/pism_config.nc
           17 # PISM config file editor: using attributes from 'pism_config' in 'lib/pism_config.nc'.
           18 ##
           19 # Please enter a parameter name or hit Return to save your changes.
           20 # You can also hit 'tab' for completions.
           21 # >
           22 # \endverbatim
           23 # Next, start typing the name of a flag or parameter you want to change; hit [tab] to complete:
           24 # \verbatim
           25 # > sta[tab][tab]
           26 # standard_gravity  start_year
           27 # > sta
           28 # \endverbatim
           29 # typing "n[tab][return]" produces:
           30 # \verbatim
           31 # > standard_gravity
           32 ##
           33 # Documentation: m s-2; acceleration due to gravity on Earth geoid
           34 # Current value: standard_gravity = 9.8100000000000005
           35 # New value: standard_gravity =
           36 # \endverbatim
           37 # enter the new value (10, for example), press [return]; you would see
           38 # \verbatim
           39 # New value set: standard_gravity = 10.0
           40 ##
           41 # List of changes so far:
           42 # standard_gravity = 10.0
           43 ##
           44 # Please enter a parameter name or hit Return to save your changes.
           45 # You can also hit 'tab' for completions.
           46 # >
           47 # \endverbatim
           48 ##
           49 # Now you can select a different parameter or hit [return] to save to a file:
           50 # \verbatim
           51 # Please enter the file name to save to or hit Return to save to the original file (lib/pism_config.nc).
           52 # > g_equals_10.nc
           53 # \endverbatim
           54 # Next, press [return] if you edited a PISM config file containing \b all the
           55 # parameters or type "pism_overrides[return]" to create a config to use with -config_override.
           56 # \verbatim
           57 # > pism_overrides
           58 # Created variable pism_overrides in g_equals_10.nc.
           59 # Done.
           60 # \endverbatim
           61 
           62 import sys
           63 from numpy import double
           64 try:
           65     import readline
           66 except:
           67     print("GNU readline library is not available.")
           68     sys.exit(0)
           69 
           70 try:
           71     from netCDF4 import Dataset as NC
           72 except:
           73     print("netCDF4 is not installed!")
           74     sys.exit(1)
           75 
           76 
           77 def list_completer(text, state, list):
           78     """Completes strings from the list 'list'. Skips documenting strings."""
           79     matches = [x for x in list if (x.startswith(text) and not x.endswith("_doc"))]
           80     if (state >= len(matches)):
           81         return None
           82     else:
           83         return matches[state]
           84 
           85 
           86 def edit_attr(dict, attr):
           87     """Edits an attribute in the dictionary dict."""
           88     completer = readline.get_completer()
           89     readline.set_completer(None)
           90     current_value = dict[attr]
           91     try:
           92         print("\n# Documentation: %s" % dict[attr + "_doc"])
           93     except:
           94         pass
           95 
           96     print("# Current value: %s = %s" % (attr, str(current_value)))
           97 
           98     while True:
           99         new_value = eval(input("#     New value: %s = " % attr))
          100 
          101         if new_value == "":
          102             new_value = current_value
          103             print("# Using the current value (%s)" % str(current_value))
          104             break
          105 
          106         try:
          107             new_value = double(new_value)  # try interpreting as a number
          108         except:
          109             pass                # leave as a string
          110 
          111         break
          112 
          113     readline.set_completer(completer)
          114     return new_value
          115 
          116 
          117 def main_loop(dict):
          118     changes = {}
          119     while True:
          120         print("\n# Please enter a parameter name or hit Return to save your changes.\n# You can also hit 'tab' for completions.")
          121         attr = eval(input("> "))
          122         if attr == "":
          123             break
          124 
          125         try:
          126             old_value = dict[attr]
          127             new_value = edit_attr(dict, attr)
          128             changes[attr] = new_value
          129             if (old_value != new_value):
          130                 print("# New value set: %s = %s\n" % (attr, str(new_value)))
          131         except:
          132             print("ERROR: attribute '%s' was not found." % attr)
          133 
          134         print("## List of changes so far:")
          135         for each in list(changes.keys()):
          136             print("## %s = %s" % (each, str(changes[each])))
          137     return changes
          138 
          139 
          140 def read(filename):
          141     """Reads attributes from a file."""
          142     try:
          143         nc = NC(filename)
          144     except:
          145         print("ERROR: can't open %s" % filename)
          146         sys.exit(0)
          147 
          148     names = ['pism_config', 'pism_overrides']
          149     varname = None
          150     var = None
          151     for name in names:
          152         try:
          153             var = nc.variables[name]
          154             varname = name
          155         except:
          156             pass
          157 
          158     if var == None:
          159         print("ERROR: can't find 'pism_config' or 'pism_overrides' in '%s'." % filename)
          160         sys.exit(0)
          161 
          162     attrs = var.ncattrs()
          163     dict = {}
          164     for each in attrs:
          165         dict[each] = getattr(var, each)
          166     nc.close()
          167 
          168     return (varname, dict)
          169 
          170 
          171 def save(dict, changes, default_filename, default_varname):
          172     """Saves attributes stored in the dictionary changes, adding doc-strings from dict."""
          173     readline.set_completer(None)
          174 
          175     print("\nPlease enter the file name to save to or hit Return to save to the original file (%s)." % default_filename)
          176     filename = eval(input("> "))
          177     if filename == "":
          178         filename = default_filename
          179 
          180     def varname_completer(text, state):
          181         names = ['pism_config', 'pism_overrides']
          182         matches = [x for x in names if x.startswith(text)]
          183 
          184         if state < 2:
          185             return matches[state]
          186         else:
          187             return None
          188 
          189     readline.set_completer(varname_completer)
          190     print("# Please enter the variable name to use or hit Return to use '%s'." % default_varname)
          191     varname = eval(input("> "))
          192     if varname == "":
          193         varname = default_varname
          194 
          195     try:
          196         nc = NC(filename, 'a')      # append
          197     except:
          198         try:
          199             nc = NC(filename, 'w', format='NETCDF3_CLASSIC')  # if not found, then create
          200         except:
          201             print("ERROR: can't open '%s'." % filename)
          202             return False
          203 
          204     try:
          205         var = nc.variables[varname]
          206     except:
          207         var = nc.createVariable(varname, 'b')
          208         print("# Created variable %s in %s." % (varname, filename))
          209 
          210     for each in list(changes.keys()):
          211         try:
          212             doc = each + "_doc"
          213             setattr(var, doc, dict[doc])
          214         except:
          215             pass
          216         setattr(var, each, changes[each])
          217 
          218     nc.close()
          219     return True
          220 
          221 
          222 from optparse import OptionParser
          223 
          224 parser = OptionParser()
          225 
          226 parser.usage = """Run "%prog config.nc"
          227   to edit config.nc or create a new configuration file (such as an "overrides" file)
          228   based on config.nc"""
          229 parser.description = "This scrips simplifies creating a customized PISM configuration file."
          230 
          231 (options, args) = parser.parse_args()
          232 
          233 if (len(args) != 1):
          234     print("Please specify an input file. Exiting...")
          235     sys.exit(1)
          236 
          237 # Get the input filename:
          238 try:
          239     filename = args[0]
          240 except:
          241     sys.exit(0)
          242 
          243 # Read attributes:
          244 varname, dict = read(filename)
          245 
          246 print("PISM config file editor: using attributes from '%s' in '%s'." % (varname, filename))
          247 
          248 # Set up tab completion:
          249 
          250 
          251 def complete(text, state):
          252     return list_completer(text, state, list(dict.keys()))
          253 
          254 
          255 readline.parse_and_bind("tab: complete")
          256 readline.set_completer(complete)
          257 
          258 # Process user input:
          259 changes = main_loop(dict)
          260 if changes == {}:
          261     sys.exit(0)
          262 
          263 # Save to a file:
          264 while True:
          265     result = save(dict, changes, filename, varname)
          266 
          267     if result == True:
          268         print("Done.")
          269         break
          270 
          271     print("Do you want to try a different file name? [y/n]")
          272     answer = eval(input())
          273     if answer not in ["y", "Y", "yes", "Yes", "YES"]:
          274         break