source: lmdz_wrf/branches/LMDZ_WRFmeas/tools/WRF_namelist_check.py

Last change on this file was 414, checked in by lfita, 10 years ago

Removing WRFV3 folder and keeping only the essential

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.