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