source: lmdz_wrf/trunk/tools/WRF_namelist_check.py @ 286

Last change on this file since 286 was 221, checked in by lfita, 10 years ago

Python script to check the 'namelis.input' file directly from the WRF compiled

source

File size: 16.2 KB
Line 
1# Python script to check namelist.input consistency with a given WRF version
2# L. Fita, LMD, December 2014
3import numpy as np
4import os
5from optparse import OptionParser
6import sys
7import nc_var_tools as ncvar
8
9## e.g. # WRF_namelist_check.py -w /home/lluis/DATA/WRF/WRFV3.3/serial -n /home/lluis/DATA/WRF/WRFV3.3/serial/WRFV3/run/namelist.input
10#* WRF structure
11# - module_config_rec definition on:
12#   .- 'inc/namelist_defines.inc' definition of variables from 'namelist.input' called from 'frame/module_configure.F'
13#   .- 'include/config_assigns.inc' assigment to the grid structure  called from 'frame/module_configure.F'
14
15# - grid definition on:
16#   .- 'inc/state_struct.inc' types of the grid content
17#   .- 'frame/module_domain_type.F' definition of the grid
18#   .- 'dyn_em/start_em.F' filling the grid
19
20# - namelist reading in include: config_assigns.inc
21
22main = 'WRF_namelist_check.py'
23
24errormsg = 'ERROR -- error -- ERROR -- error'
25warnmsg = 'WARNING -- waring -- WARNING -- warning'
26
27def searchInlist(listname, nameFind):
28    """ Function to search a value within a list
29    listname = list
30    nameFind = value to find
31    >>> searInlist(['1', '2', '3', '5'], '5')
32    True
33    """
34    for x in listname:
35      if x == nameFind:
36        return True
37    return False
38
39def reduce_spaces(string):
40    """ Function to give words of a line of text removing any extra space
41    """
42    values = string.replace('\n','').split(' ')
43    vals = []
44    for val in values:
45         if len(val) > 0:
46             vals.append(val)
47
48    return vals
49
50def numVector_String(vec,char):
51    """ Function to transform a vector of numbers to a single string [char] separated
52    numVector_String(vec,char)
53      vec= vector with the numerical values
54      char= single character to split the values
55    >>> print numVector_String(np.arange(10),' ')
56    0 1 2 3 4 5 6 7 8 9
57    """
58    fname = 'numVector_String'
59
60    if vec == 'h':
61        print fname + '_____________________________________________________________'
62        print numVector_String.__doc__
63        quit()
64
65    Nvals = len(vec)
66
67    string=''
68    for i in range(Nvals):
69        if i == 0:
70            string = str(vec[i])
71        else:
72            string = string + char + str(vec[i])
73
74    return string
75
76def get_namelist_vars(values, namelist):
77    """ Function to get namelist-like  values ([varname] = [value])
78    get_namelist_vars(namelist)
79      values= [sectionname],[kout]
80        [sectionname]: name of the section from which one want the values ('all', for all)
81        [kout]: kind of output
82          'tex3': printed output as LaTeX table of three columns \verb+namelist_name+ & value
83          'column': printed output as namelist_name value
84          'dict': as two python dictionary object (namelistname, value and namelistname, sectionname)
85      namelist= namelist_like file to retrieve values
86    >>> get_namelist_vars('geogrid,dic','/home/lluis/etudes/domains/medic950116/namelist.wps')
87    {'e_sn': '32, 97,', 'stand_lon': '0.', 'opt_geogrid_tbl_path': "'./'", 'geog_data_path': "'/home/lluis/DATA/WRF/geog'", 'pole_lat': '90.0', 'ref_lat': '35.0,', 'map_proj': "'lat-lon',", 'parent_id': '1, 1,', 'geog_data_res': "'2m','2m',", 'e_we': '32, 112,', 'dx': '0.35,', 'dy': '0.35,', 'parent_grid_ratio': '1, 3,', 'pole_lon': '0.0', 'ref_lon': '20,', 'j_parent_start': '1, 17,', 'i_parent_start': '1, 31,'}
88    """
89
90    fname = 'get_namelist_vars'
91
92# List of characters which split pairs name/value
93    valuessep = ['=']
94# List of characters which indicate a comment
95    commentchars = ['#']
96
97    if values == 'h':
98        print fname + '_____________________________________________________________'
99        print get_namelist_vars.__doc__
100        quit()
101
102    expectargs = '[sectionname],[kout]'
103    check_arguments(fname,len(expectargs.split(',')),values,',',expectargs)
104
105    secname = values.split(',')[0]
106    kout = values.split(',')[1]
107
108    if not os.path.isfile(namelist):
109        print errormsg
110        print '  ' + fname + ": namelist file '" + namelist + "' does not exist !!"
111        quit(-1)
112
113    ncml = open(namelist, 'r')
114
115    sections = {}
116    namelistvals = {}
117    namelistsecs = {}
118    sectionnames = []
119    namessec = []
120    allnames = []
121    namelistvalssec = {}
122    namelistsecssec = {}
123    nmlname = ''
124    sectionname = ''
125
126    for line in ncml:
127        linevals = reduce_spaces(line)
128        Nvals = len(linevals)
129
130        if Nvals >= 1 and linevals[0][0:1] == '&':
131            if len(sectionnames) > 1:
132                sections[sectionname] = namessec
133
134            sectionname = linevals[0][1:len(linevals[0])+1]
135#            print '    ' + fname + ": new section '" + sectionname + "' !!!"
136            sectionnames.append(sectionname)
137            namessec = []
138            nmlname = ''
139        elif Nvals >= 1 and not searchInlist(commentchars,linevals[0][0:1]):
140            if Nvals >= 3 and searchInlist(valuessep,linevals[1]):
141                nmlname = linevals[0]
142                nmlval = numVector_String(linevals[2:Nvals],' ')
143            elif Nvals == 1:
144                for valsep in valuessep:
145                    if linevals[0].find(valsep) != -1:
146                        nmlname = linevals[0].split(valsep)[0]
147                        nmlval = linevals[0].split(valsep)[1]
148                        break
149            elif Nvals == 2:
150                for valsep in valuessep:
151                    if linevals[0].find(valsep) != -1:
152                        nmlname = linevals[0].split(valsep)[0]
153                        nmlval = linevals[1]
154                        break
155                    elif linevals[1].find(valsep) != -1:
156                        nmlname = linevals[0]
157                        nmlval = linevals[1].split(valsep)[0]
158                        break
159            else:
160                print warnmsg
161                print '  ' + fname + ': wrong number of values', Nvals,              \
162                  'in the namelist line!'
163                print '    line: ',line
164                print '    line values:',linevals
165#                quit(-1)
166
167            namelistvals[nmlname] = nmlval
168            namelistsecs[nmlname] = sectionname
169
170            namessec.append(nmlname)
171            allnames.append(nmlname)
172
173    if len(sectionname) > 1:
174        sections[sectionname] = namessec
175
176    if secname != 'all':
177        if not searchInlist(sections.keys(),secname):
178            print errormsg
179            print '  ' + fname + ": section '" + values + "' does not exist !!"
180            print '    only found:',sectionnames
181            quit(-1)
182
183        namestouse = []
184        for nml in allnames:
185            for nnml in sections[secname]:
186                namelistvalssec[nnml] = namelistvals[nnml]
187                namelistsecssec[nnml] = secname
188                if nml == nnml: namestouse.append(nml)
189    else:
190        namestouse = allnames
191        namelistvalssec = namelistvals
192        namelistsecssec = namelistsecs
193
194    if kout == 'tex3':
195        ofile='get_namelist_vars_3col.tex'
196        fobj = open(ofile, 'w')
197
198        vals = namestouse
199        Nvals = len(vals)
200        Nvals3 = int(Nvals/3)
201        latextab = '\\begin{center}\n\\begin{tabular}{lclclc}\n'
202        for il in range(2):
203            latextab = latextab + '{\\bfseries{name}} & {\\bfseries{value}} & '
204        latextab= latextab+ '{\\bfseries{name}} & {\\bfseries{value}} \\\\ \\hline\n'
205
206        if np.mod(Nvals,3) != 0:
207            Nvals0 = Nvals - np.mod(Nvals,3)
208        else:
209            Nvals0 = Nvals
210
211        for ival in range(0,Nvals0,3):
212            line = ''
213            print '  ival:',ival
214            for il in range(2):
215                line = line + '\\verb+' + vals[ival+il] + '+ & ' +                   \
216                   namelistvalssec[vals[ival+il]].replace('_','\\_') +' & '
217            line = line + '\\verb+' + vals[ival+2] + '+ & ' +                       \
218               namelistvalssec[vals[ival+2]].replace('_','\\_') + ' \\\\\n'
219            latextab = latextab + line
220
221        latextab = latextab + '%not multiple of three!!!!\n'
222        print 'mod:', np.mod(Nvals,3),Nvals0,Nvals
223        if np.mod(Nvals,3) != 0:
224            ival = Nvals0
225            line = ''
226            for il in range(np.mod(Nvals,3)):
227                print 'ival:',ival + il
228                line = line + '\\verb+' + vals[ival+il] + '+ & ' +                   \
229                      namelistvalssec[vals[ival+il]].replace('_','\\_') + ' & '
230            for il in range(2-np.mod(Nvals,3)):
231                line = line + ' & & '
232            latextab = latextab + line + ' & \\\\\n'
233        latextab = latextab + '\\end{tabular}\n\\end{center}\n'
234
235#        print latextab
236        fobj.write(latextab)
237 
238        fobj.close()
239        print fname + ": successful writen '" + ofile + "' LaTeX tale file !!"
240
241        return 
242    elif kout == 'column':
243        for dictv in namestouse:
244            print dictv + ' = ' + namelistvalssec[dictv]
245        return
246    elif kout == 'dict':
247        return namelistvalssec, namelistsecssec
248    else:
249        print errormsg
250        print '  ' + fname + ": kind of output '" + kout + "' not ready!!!"
251        quit(-1)
252
253    return
254
255def check_arguments(funcname,Nargs,args,char,expectargs):
256    """ Function to check the number of arguments if they are coincident
257    check_arguments(funcname,Nargs,args,char)
258      funcname= name of the function/program to check
259      Nargs= theoretical number of arguments
260      args= passed arguments
261      char= character used to split the arguments
262    """
263
264    fname = 'check_arguments'
265
266    Nvals = len(args.split(char))
267    if Nvals != Nargs:
268        print errormsg
269        print '  ' + fname + ': wrong number of arguments:',Nvals," passed to  '",   \
270          funcname, "' which requires:",Nargs,'!!'
271        print '    given arguments:',args.split(char)
272        print '    expected arguments:',expectargs
273        quit(-1)
274
275    return
276
277def check_conversion(value, trykind):
278    """ Function to check a variable conversion to a python type
279      from: http://stackoverflow.com/questions/4690600/python-exception-message-capturing
280      value= value to convert
281      trykind: kind to try to convert to
282        integer: 'INTEGER', 'integer', 'int'
283        float: 'REAL', 'real', 'float'
284        intl: 'LOGICAL', 'logical', 'bool'
285      >>> check_conversion('1.3','integer')
286      ERROR -- error -- ERROR -- error
287        check_conversion: Failed to convert '1.3' to 'int': invalid literal for int() with base 10: '1.3'
288    """
289    import sys, traceback
290    fname = 'check_conversion'
291
292    intk = ['INTEGER', 'integer', 'int']
293    intr = ['REAL', 'real', 'float']
294    intl = ['LOGICAL', 'logical', 'boolean', 'bool']
295# Accepted values as boolean values:
296    intlv = ['y', 'n', 'yes', 'no', '.TRUE.', '.FALSE.', '.true.', '.false.',        \
297      '.T.', '.F.', '.t.', '.f.']
298
299# All kinds
300    allkinds = intk + intr + intl
301    if not searchInlist(allkinds, trykind):
302        print errormsg
303        print '  ' + fname + ": kind '" + trykind + "' not ready !!"
304        quit(-1)
305
306    try:
307        if searchInlist(intk,trykind):
308            conv = int(value)
309        elif searchInlist(intr,trykind):
310            conv = np.float(value)
311        elif searchInlist(intl,trykind):
312            if not searchInlist(intlv, value):
313                print errormsg
314                print '  ' + fname + ": Failed to convert '" + value + "' to '" +    \
315                  trykind + "' !!"
316                return -1
317    except:
318        exc_type, exc_value, exc_traceback = sys.exc_info()
319        print errormsg
320        print '  ' + fname + ": Failed to convert '" + value + "' to '" + trykind +  \
321          "': " + str(exc_value)
322        return -1
323
324    return 0
325
326####### ###### ##### #### ### ## #
327
328parser = OptionParser()
329parser.add_option("-w", "--WRF_folder", dest="wfold", 
330                  help="compiled WRF folder to use", metavar="FOLDER")
331parser.add_option("-n", "--WRF_namelist", dest="namelist", 
332                  help="'namelist.input' to use", metavar="FILE")
333
334(opts, args) = parser.parse_args()
335
336#######    #######
337## MAIN
338    #######
339
340if not os.path.isfile(opts.wfold + '/WRFV3/main/wrf.exe'):
341    print errormsg
342    print '  ' + main + ": compiled WRF '" + opts.wfold + "/WRFV3/main/wrf.exe'" +   \
343      'does not exist !!'
344    quit(-1)
345
346if not os.path.isfile(opts.namelist):
347    print errormsg
348    print '  ' + main + ": WRF namelist '" + opts.namelist + "' does not exist !!"
349    quit(-1)
350
351infold = opts.wfold + '/WRFV3'
352
353# Reading namelist characteristics
354##
355nmldef = infold + '/inc/namelist_defines.inc'
356
357if not os.path.isfile(nmldef):
358    print errormsg
359    print '  ' + main + ": included WRF '" + nmldef + "' does not exist !!"
360    quit(-1)
361
362onmldef = open(nmldef, 'r')
363
364nmlpar = []
365nmlpark = {}
366nmlpard = {}
367
368for line in onmldef:
369    if line[0:1] != '!':
370        values = line.split(' ')
371        par = line.split('::')[1].replace('\n','').replace(' ','')
372        nmlpar.append(par)
373        nmlpark[par] = values[0].replace(' ','')
374        if len(line.split(',')) > 1:
375            dim = line.split(',')[1].split('::')[0].split('(')[1].replace(')','')
376            nmlpard[par] = dim.replace(' ','')
377
378#        if nmlpard.has_key(par):
379#            print par,':',nmlpark[par],'=',nmlpard[par]
380#        else:
381#            print par,':',nmlpark[par]
382
383onmldef.close()
384
385# Reading namelist sections
386##
387nmlsec = infold + '/inc/namelist_statements.inc'
388
389if not os.path.isfile(nmlsec):
390    print errormsg
391    print '  ' + main + ": included WRF '" + nmlsec + "' does not exist !!"
392    quit(-1)
393
394onmlsec = open(nmlsec, 'r')
395
396nmlpars = {}
397nmlsecs = []
398
399for line in onmlsec:
400#    print 'line:',line
401    if line[0:1] != '!':
402        values = line.split('/')
403        par = values[2].replace('\n','').replace(' ','')
404        sec = values[1].replace(' ','')
405
406        nmlpars[par] = sec
407        if not searchInlist(nmlsecs,sec):
408            nmlsecs.append(sec)
409
410onmlsec.close()
411
412# Getting values from 'namelist.input
413##
414readnmlvals, readnmlsecs = get_namelist_vars('all,dict', opts.namelist)
415
416# Checking values
417##
418readparam = set(readnmlvals.keys())
419configparam = set(nmlpark.keys())
420
421coinread = list(readparam & configparam)
422Wrongread = list(readparam - configparam)
423
424# Wrong pramater name
425##
426Nwrong = len(Wrongread)
427
428if Nwrong > 0:
429  print errormsg
430  print '  ' + main + ': some readed parameters are wrong!'
431  print '    wrong parameters: ', Wrongread
432
433# Wrong section
434##
435for readpar in readnmlsecs.keys():
436    if nmlpars.has_key(readpar) and readnmlsecs[readpar] != nmlpars[readpar]:
437        print errormsg
438        print '  ' + main + ": readed parameter '" + readpar + "' in section '" +    \
439            readnmlsecs[readpar] + "' should be in section '" + nmlpars[readpar] +   \
440            "' !!"
441
442# Wrong type of value
443##
444for readpar in readnmlvals.keys():
445    if nmlpark.has_key(readpar):
446        pkind = nmlpark[readpar]
447        readvals = readnmlvals[readpar].replace(' ','').split(',')
448        Nreadvals = len(readvals)
449
450        if Nreadvals > 1:
451            for ival in range(Nreadvals):
452                if len(readvals[ival]) > 0:
453                    ier = check_conversion(readvals[ival], pkind)
454                    if ier != 0:
455                        print errormsg
456                        print '  ' + main + ": wrong readed '" + readpar +           \
457                          "' value: '" + readvals[ival] + "' is not of type '" +     \
458                          pkind + "' !!"
459                    else:
460                        if readpar == 'max_dom':
461                            Ndomains = int(readvals[0])
462
463        else:
464            ier = check_conversion(readnmlvals[readpar], pkind)
465            if ier != 0:
466                print errormsg
467                print '  ' + main + ": wrong readed '" + readpar + "' value: '" +    \
468                  readvals + "' is not of type '", pkind, "' !!"
469 
470# Checking number of values
471##
472for readpar in readnmlvals.keys():
473    if nmlpard.has_key(readpar):
474        if nmlpard[readpar] == 'max_domains':
475            readvals = readnmlvals[readpar].replace(' ','').split(',')
476            Nreadvals = len(readvals)
477# Removing spurious value due to ',' at the end of the parameter values in namelist
478            if len(readvals[Nreadvals - 1]) == 0: Nreadvals = Nreadvals - 1
479
480            if Nreadvals < Ndomains:
481                print errormsg
482                print '  ' + main + ': wrong number of values: ', Nreadvals, '=',    \
483                  readnmlvals[readpar]," for parameter '" + readpar + "' should be:",\
484                  Ndomains,'!!'
Note: See TracBrowser for help on using the repository browser.