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

Last change on this file since 525 was 412, checked in by lfita, 10 years ago

Adding Excess of values if the variable is not 'max_dom'

File size: 16.5 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) and trykind[0:9] != 'character' and       \
302      trykind[0:9] != 'CHARACTER':
303        print errormsg
304        print '  ' + fname + ": kind '" + trykind + "' not ready !!"
305        quit(-1)
306
307    try:
308        if searchInlist(intk,trykind):
309            conv = int(value)
310        elif searchInlist(intr,trykind):
311            conv = np.float(value)
312        elif searchInlist(intl,trykind):
313            if not searchInlist(intlv, value):
314                print errormsg
315                print '  ' + fname + ": Failed to convert '" + value + "' to '" +    \
316                  trykind + "' !!"
317                return -1
318    except:
319        exc_type, exc_value, exc_traceback = sys.exc_info()
320        print errormsg
321        print '  ' + fname + ": Failed to convert '" + value + "' to '" + trykind +  \
322          "': " + str(exc_value)
323        return -1
324
325    return 0
326
327####### ###### ##### #### ### ## #
328
329parser = OptionParser()
330parser.add_option("-w", "--WRF_folder", dest="wfold", 
331                  help="compiled WRF folder to use", metavar="FOLDER")
332parser.add_option("-n", "--WRF_namelist", dest="namelist", 
333                  help="'namelist.input' to use", metavar="FILE")
334
335(opts, args) = parser.parse_args()
336
337#######    #######
338## MAIN
339    #######
340
341if not os.path.isfile(opts.wfold + '/WRFV3/main/wrf.exe'):
342    print errormsg
343    print '  ' + main + ": compiled WRF '" + opts.wfold + "/WRFV3/main/wrf.exe'" +   \
344      'does not exist !!'
345    quit(-1)
346
347if not os.path.isfile(opts.namelist):
348    print errormsg
349    print '  ' + main + ": WRF namelist '" + opts.namelist + "' does not exist !!"
350    quit(-1)
351
352infold = opts.wfold + '/WRFV3'
353
354# Reading namelist characteristics
355##
356nmldef = infold + '/inc/namelist_defines.inc'
357
358if not os.path.isfile(nmldef):
359    print errormsg
360    print '  ' + main + ": included WRF '" + nmldef + "' does not exist !!"
361    quit(-1)
362
363onmldef = open(nmldef, 'r')
364
365nmlpar = []
366nmlpark = {}
367nmlpard = {}
368
369for line in onmldef:
370    if line[0:1] != '!':
371        values = line.split(' ')
372        par = line.split('::')[1].replace('\n','').replace(' ','')
373        nmlpar.append(par)
374        nmlpark[par] = values[0].replace(' ','')
375        if len(line.split(',')) > 1:
376            dim = line.split(',')[1].split('::')[0].split('(')[1].replace(')','')
377            nmlpard[par] = dim.replace(' ','')
378
379#        if nmlpard.has_key(par):
380#            print par,':',nmlpark[par],'=',nmlpard[par]
381#        else:
382#            print par,':',nmlpark[par]
383
384onmldef.close()
385
386# Reading namelist sections
387##
388nmlsec = infold + '/inc/namelist_statements.inc'
389
390if not os.path.isfile(nmlsec):
391    print errormsg
392    print '  ' + main + ": included WRF '" + nmlsec + "' does not exist !!"
393    quit(-1)
394
395onmlsec = open(nmlsec, 'r')
396
397nmlpars = {}
398nmlsecs = []
399
400for line in onmlsec:
401#    print 'line:',line
402    if line[0:1] != '!':
403        values = line.split('/')
404        par = values[2].replace('\n','').replace(' ','')
405        sec = values[1].replace(' ','')
406
407        nmlpars[par] = sec
408        if not searchInlist(nmlsecs,sec):
409            nmlsecs.append(sec)
410
411onmlsec.close()
412
413# Getting values from 'namelist.input
414##
415readnmlvals, readnmlsecs = get_namelist_vars('all,dict', opts.namelist)
416
417# Checking values
418##
419readparam = set(readnmlvals.keys())
420configparam = set(nmlpark.keys())
421
422coinread = list(readparam & configparam)
423Wrongread = list(readparam - configparam)
424
425# Wrong pramater name
426##
427Nwrong = len(Wrongread)
428
429if Nwrong > 0:
430  print errormsg
431  print '  ' + main + ': some readed parameters are wrong!'
432  print '    wrong parameters: ', Wrongread
433
434# Wrong section
435##
436for readpar in readnmlsecs.keys():
437    if nmlpars.has_key(readpar) and readnmlsecs[readpar] != nmlpars[readpar]:
438        print errormsg
439        print '  ' + main + ": readed parameter '" + readpar + "' in section '" +    \
440            readnmlsecs[readpar] + "' should be in section '" + nmlpars[readpar] +   \
441            "' !!"
442
443# Wrong type of value
444##
445for readpar in readnmlvals.keys():
446    if nmlpark.has_key(readpar):
447        pkind = nmlpark[readpar]
448        readvals = readnmlvals[readpar].replace(' ','').split(',')
449        Nreadvals = len(readvals)
450
451        if Nreadvals > 1:
452            for ival in range(Nreadvals):
453                if len(readvals[ival]) > 0:
454                    ier = check_conversion(readvals[ival], pkind)
455                    if ier != 0:
456                        print errormsg
457                        print '  ' + main + ": wrong readed '" + readpar +           \
458                          "' value: '" + readvals[ival] + "' is not of type '" +     \
459                          pkind + "' !!"
460                    else:
461                        if readpar == 'max_dom':
462                            Ndomains = int(readvals[0])
463
464        else:
465            ier = check_conversion(readnmlvals[readpar], pkind)
466            if ier != 0:
467                print errormsg
468                print '  ' + main + ": wrong readed '" + readpar + "' value: '" +    \
469                  readvals + "' is not of type '", pkind, "' !!"
470 
471# Checking number of values
472##
473
474for readpar in readnmlvals.keys():
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 nmlpard.has_key(readpar):
481#        print 'readpar:',readpar,'Nvals:',Nreadvals,'WRF:',nmlpard[readpar],'Ndoms:',Ndomains
482
483        if nmlpard[readpar] == 'max_domains':
484            if Nreadvals < Ndomains:
485                print errormsg
486                print '  ' + main + ': wrong number of values: ', Nreadvals, '=',    \
487                  readnmlvals[readpar]," for parameter '" + readpar + "' should be:",\
488                  Ndomains,'!!'
489
490    else:
491        if Nreadvals > 1:
492            print errormsg
493            print '  ' + main + ': wrong number of values: ', Nreadvals,             \
494              " for parameter '" + readpar + "' should be: 1 !!"
Note: See TracBrowser for help on using the repository browser.