source: trunk/libIGCM/libIGCM_post/xios_parser.py

Last change on this file was 1620, checked in by aclsce, 4 months ago

Modified to use python2 (instead of python3)

  • Property svn:executable set to *
  • Property svn:keywords set to Revision Date Author
File size: 19.2 KB
Line 
1#! /usr/bin/env python2
2# coding: utf-8
3
4#**************************************************************
5# Author: Sebastien Denvil
6# Contact: Sebastien.Denvil__at__ipsl.jussieu.fr
7# $Revision::                                         $ Revision of last commit
8# $Author::                                           $ Author of last commit
9# $Date::                                             $ Date of last commit
10# IPSL (2006)
11#  This software is governed by the CeCILL licence see libIGCM/libIGCM_CeCILL.LIC
12#
13#**************************************************************
14
15import os, pwd, sys, traceback, argparse
16import xml.etree.ElementTree as ET
17#import readline, rlcompleter
18#readline.parse_and_bind("tab: complete")
19
20indent = 0
21currentDepth = 0
22ignoreElems = []
23fromField=[]
24fromFile=[]
25
26def dump(args):
27    """Dump XIOS xmls files."""
28    # Read and dump xios_def_xml
29    for inputFile in args.file:       
30        # Read the file_def_xml
31        print '\nReading %s \n|' % (inputFile)
32        try:
33            tree = ET.parse(inputFile)
34        except:
35            print "Parse error. Please fix so that it can be parsed."
36            traceback.print_exc(file=sys.stdout)
37            return
38        root=tree.getroot()
39        # Call the recursive print
40        printRecur(root)
41
42def tsquery(args):
43    """query timeseries related parameters from an XIOS xml file."""
44    if args.verbosity >= 1: print 'Reading timeseries_def_xml=',args.file[0]
45    try:
46        tree = ET.parse(args.file[0])
47    except:
48        print "Parse error. Please fix so that it can be parsed."
49        traceback.print_exc(file=sys.stdout)
50        return
51    root=tree.getroot()
52    if args.verbosity >= 3: print root.tag, root.attrib
53    findTimeSeries(root)
54       
55def printRecur(root):
56    """Recursively prints the tree."""
57    global indent
58    global currentDepth
59    if root.tag in ignoreElems:
60        return
61    print ' '*indent + '|--> %s: %s' % (root.tag, root.attrib)
62    currentDepth += 1
63    indent += 4
64    if currentDepth <= args.depth or args.depth == None:
65        for elem in list(root):
66            printRecur(elem)
67    currentDepth -= 1
68    indent -= 4
69
70def findTimeSeries(root):
71    """Recursively find and list field tag with "timeseries", "id", "output_freq" and enable=.TRUE. attribute."""
72    if root.tag == 'file' and root.attrib.get('timeseries'):
73        if root.attrib.get('enabled') == '.TRUE.':
74            print 'output_freq=%-5s,id=%s' % (root.attrib.get('output_freq'), root.attrib.get('id'))
75    elif root.tag == 'file' and root.attrib.get('uuid_name'):
76        print 'output_freq=%-5s,name=%85s' % (root.attrib.get('output_freq'), root.attrib.get('name'))
77    else:
78        for elem in list(root):
79            findTimeSeries(elem)
80   
81def findField(root):
82    """Recursively find and list field tag with "id" or "field_ref" attribute."""
83    global fromField
84    global fromFile
85    if root.tag in ignoreElems:
86        return   
87    if root.tag == 'field' and root.attrib.get('id'):
88        fromField.append(root.attrib.get('id'))
89    elif root.tag == 'field' and root.attrib.get('field_ref'):
90        fromFile.append(root.attrib.get('field_ref'))
91    else:
92        for elem in list(root):
93            findField(elem)
94
95def findFieldToRemove(root, fieldToRemove):
96    """Recursively find tag having a field_ref in fieldToRemove."""
97    if args.verbosity >= 3 and root.tag == 'file' and root.attrib.get('id'):
98        print '\nFIELDS FROM FILE_DEF with id', root.attrib.get('id')
99    for field in root.findall('field'):
100        if args.verbosity >= 3: print 'field_ref=', field.attrib.get('field_ref')
101        if field.attrib.get('field_ref') in fieldToRemove:
102            if args.correction:
103                if args.verbosity >= 2: print 'removing ', field.attrib.get('field_ref')
104                root.remove(field)
105            else:
106                if args.verbosity >= 2: print 'To be removed ', field.attrib.get('field_ref')
107    for elem in list(root):
108        findFieldToRemove(elem, fieldToRemove)
109       
110def check(args):
111    global fromFile
112    exitCode=0
113    # Read the field_def_xml
114    if args.verbosity >= 1: print '\nReading field_def_xml=',args.field[0]
115    try:
116        tree = ET.parse(args.field[0])
117    except:
118        print 'Parse error with %s. Please fix so that it can be parsed.' % (args.field[0])
119        traceback.print_exc(file=sys.stdout)
120        return
121    root=tree.getroot()
122    if args.verbosity >= 3: print root.tag, root.attrib, '\n'
123    # Build a list of field.id from field_def
124    findField(root)
125
126    # Loop over file_def files
127    for inputFile in args.file:       
128        # Read the file_def_xml
129        if args.verbosity >= 1: print '\nReading file_def_xml=',inputFile
130        try:
131            tree = ET.parse(inputFile)
132        except:
133            print "Parse error. Please fix so that it can be parsed."
134            traceback.print_exc(file=sys.stdout)
135            return
136        root=tree.getroot()
137        fromFile=[]
138        if args.verbosity >= 3: print root.tag, root.attrib, '\n'
139
140        # Build a list of field_ref from file_def
141        findField(root)
142        #print '4. fromFile=', fromFile
143       
144        # Compare the two lists. fromField must be a superset of fromFile.
145        if set(fromField).issuperset(set(fromFile)):
146            if args.verbosity >= 1: print '\nALL GOOD with %s' % (inputFile)
147            if args.verbosity >= 3: print 'fromField=', fromField
148            if args.verbosity >= 3: print 'fromFile=', fromFile
149        else:
150            if args.verbosity >= 1: print '\nTROUBLE AHEAD with %s' % (inputFile)
151            if args.verbosity >= 3: print ', '.join(sorted(list(set(fromFile)-set(fromField))))
152            # Identify fields in fromFile but not in fromField
153            fieldToRemove=list(set(fromFile)-set(fromField))
154            if args.verbosity >= 3: print 'fieldToRemove=', fieldToRemove
155            #
156            # And now locate and remove them if the modify command has been called
157            findFieldToRemove(root, fieldToRemove)
158            # Final steps
159            if args.correction: tree.write('modified.'+inputFile)
160            if not len(fieldToRemove) == 0 and not args.correction:
161                exitCode=1
162    # The end
163    sys.exit(exitCode)
164
165def showtime(args):
166    """
167    prints table of formatted text format options
168    """
169    for style in xrange(6):
170        for fg in xrange(30,36):
171            s1 = ''
172            for bg in xrange(40,46):
173                format = ';'.join([str(style), str(fg), str(bg)])
174                s1 += '\x1b[%sm %s \x1b[0m' % (format, pwd.getpwuid(os.getuid())[4]+' is on fire')
175            print s1
176        print '\n'
177   
178def modifydr2xmlIPSL(args):
179    """Recursively find tree element with file tag and change the path prefix of the name attribute."""
180
181    # Loop over file_def files
182    for inputFile in args.file:
183        # Read the file_def_xml
184        if args.verbosity >= 1: print '\nReading dr2xml_def_xml=',inputFile
185        try:
186            tree = ET.parse(inputFile)
187        except:
188            print "Parse error. Please fix so that it can be parsed."
189            traceback.print_exc(file=sys.stdout)
190            return
191        root=tree.getroot()
192        if args.verbosity >= 3: print root.tag, root.attrib, '\n'
193
194        # Change file name prefix to point where we want
195        for elem in tree.iter(tag='file'):
196            if not elem.attrib.get('mode') == 'read':
197                name=elem.attrib.get('name')
198                if args.JobName is not None:
199                    name = name.replace('JobName', args.JobName[0]).replace('ModelName', args.ModelName[0])
200                    elem.set('name', os.path.normpath(args.newPath[0]) + '/' + os.path.normpath(name))
201                else:
202                    elem.set('name', os.path.normpath(args.newPath[0]) + '/' + os.path.normpath(name))
203                if args.verbosity >= 2: print elem.tag, elem.attrib
204                if args.splitLastDate is not None: elem.set('split_last_date', args.splitLastDate[0] + '-01-01 00:00:00')
205                if args.ModelVersion is not None:
206                    for childElem in elem.iter(tag='variable'):
207                        if args.verbosity >= 2: print childElem.tag, childElem.attrib
208                        if childElem.attrib.get('name') is not None:
209                            if childElem.attrib.get('name') == 'model_version':
210                               childElem.text = args.ModelVersion[0]
211                if args.ModelName is not None:
212                    for childElem in elem.iter(tag='variable'):
213                        if args.verbosity >= 2: print childElem.tag, childElem.attrib
214                        if childElem.attrib.get('name') is not None:
215                            if childElem.attrib.get('name') == 'source_id':
216                               childElem.text = args.ModelName[0]
217                if args.ExperimentName is not None:
218                    for childElem in elem.iter(tag='variable'):
219                        if args.verbosity >= 2: print childElem.tag, childElem.attrib
220                        if childElem.attrib.get('name') is not None:
221                            if childElem.attrib.get('name') == 'experiment':
222                               childElem.text = args.ExperimentName[0]
223
224
225        # Write out the results
226        if args.verbosity >= 1: print '\nWriting dr2xml_def_xml=','modified.' + inputFile
227        try:
228            tree.write ('modified.' + inputFile)
229        except:
230            print "Write error. Please fix so that it can be parsed."
231            traceback.print_exc(file=sys.stdout)
232            return
233
234def modifyPath(args):
235    """Recursively find tree element with file tag and change the path prefix of the name attribute."""
236    # Loop over file_def files
237    for inputFile in args.file:
238        # Read the file_def_xml
239        if args.verbosity >= 1: print '\nReading dr2xml_def_xml=',inputFile
240        try:
241            tree = ET.parse(inputFile)
242        except:
243            print "Parse error. Please fix so that it can be parsed."
244            traceback.print_exc(file=sys.stdout)
245            return
246        root=tree.getroot()
247        if args.verbosity >= 3: print root.tag, root.attrib, '\n'
248        # Change file name prefix to point where we want
249        for elem in tree.iter(tag='file'):
250            if not elem.attrib.get('mode') == 'read':
251                name=elem.attrib.get('name')
252                if args.filePrefix is not None:
253                    elem.set('name', os.path.normpath(args.newPath[0]) + '/' + args.filePrefix[0] + '_' + os.path.normpath(name))
254                else:
255                    elem.set('name', os.path.normpath(args.newPath[0]) + '/' + os.path.normpath(name))
256                if args.verbosity >= 2: print elem.tag, elem.attrib
257                   
258        # Write out the results
259        if args.verbosity >= 1: print '\nWriting dr2xml_def_xml=','modified.' + inputFile
260        try:
261            tree.write ('modified.' + inputFile)
262        except:
263            print "Write error. Please fix so that it can be parsed."
264            traceback.print_exc(file=sys.stdout)
265            return
266
267def modifyDR2XML(args):
268    """Recursively find tree element with file tag and change the path prefix of the name attribute."""
269    # Need to fine tune their freq_op and freq_offset
270    cospTuple=('CMIP6_albisccp', 'CMIP6_cfadDbze94', 'CMIP6_cfadLidarsr532', 'CMIP6_clcalipso2', 'CMIP6_clcalipsoice', 'CMIP6_climodis', 'CMIP6_clisccp', 'CMIP6_clmisr', 'CMIP6_cltmodis', 'CMIP6_clwmodis', 'CMIP6_jpdftaureicemodis', 'CMIP6_jpdftaureliqmodis', 'CMIP6_pctisccp', 'CMIP6_parasolRefl', 'CMIP6_clcalipso', 'CMIP6_clhcalipso', 'CMIP6_cllcalipso', 'CMIP6_clmcalipso', 'CMIP6_cltcalipso', 'CMIP6_cltisccp')
271    # Dont touch those when fine tuning cfsites field freq_op
272    excluded_field=('CMIP6_ap', 'CMIP6_b', 'CMIP6_b_bnds', 'CMIP6_ap_bnds')
273   
274    # Loop over file_def files
275    for inputFile in args.file:
276        write=False
277        # Read the file_def_xml
278        if args.verbosity >= 1: print '\nReading dr2xml_def_xml=',inputFile
279        try:
280            tree = ET.parse(inputFile)
281        except:
282            print "Parse error. Please fix so that it can be parsed."
283            traceback.print_exc(file=sys.stdout)
284            return
285        root=tree.getroot()
286        if args.verbosity >= 3: print root.tag, root.attrib, '\n'
287
288        # Change some elements to overrule dr2xml
289        for elem in tree.iter(tag='field'):
290            if elem.attrib.get('id') is not None:
291                if elem.attrib.get('id') == 'CMIP6_siconc_Scaltypesi':
292                    write=True
293                    elem.set('freq_op', '2ts')
294                    elem.set('freq_offset', '0ts')
295                    if args.verbosity >= 2: print elem.tag, elem.attrib
296                elif (elem.attrib.get('id').startswith(cospTuple)):
297                    write=True
298                    elem.set('freq_op', '3h')
299                    elem.set('freq_offset', '0ts')
300                    if args.verbosity >= 2: print elem.tag, elem.attrib
301        # Change elements related to CFsubhr files
302        for elem in tree.iter(tag='file'):
303            if elem.attrib.get('id') is not None:
304                if ("_CFsubhr_" in elem.attrib.get('id')):
305                    write=True
306                    elem.set('output_freq', '2ts')
307                    elem.set('split_start_offset', '2ts')
308                    if args.verbosity >= 2: print elem.tag, elem.attrib
309                    for childElem in elem.iter(tag='field'):
310                        if childElem.attrib.get('field_ref') is not None:
311                            if childElem.attrib.get('field_ref') not in excluded_field:
312                                childElem.set('freq_op', '2ts')
313                                if args.verbosity >= 2: print childElem.tag, childElem.attrib
314        # Changes related to cth16
315        for elem in tree.iter(tag='grid'):
316            if elem.attrib.get('id') is not None:
317                if elem.attrib.get('id') == 'grid4Dmisr_greordered':
318                    write=True
319                    if args.verbosity >= 2: print elem.tag, elem.attrib
320                    for childElem in elem.iter(tag='axis'):
321                        if args.verbosity >= 2: print childElem.tag, childElem.attrib
322                        if childElem.attrib.get('axis_ref') is not None:
323                            if childElem.attrib.get('axis_ref') == 'cth16':
324                                childElem.set('axis_ref', 'cth')
325        # Ready
326        if write:
327            # Write out the results
328            if args.verbosity >= 1: print '\nWriting dr2xml_def_xml=','modified.' + inputFile
329            try:
330                tree.write ('modified.' + inputFile)
331            except:
332                print "Write error. Please fix so that it can be parsed."
333                traceback.print_exc(file=sys.stdout)
334                return
335
336if __name__ == '__main__':
337
338    try:
339        # Create the top-level parser
340        parser = argparse.ArgumentParser(description='XIOS2 xml files tooling and ironsmith')
341        subparsers = parser.add_subparsers(description='Dump, check or modify xios xml files')
342
343        # create the parser for the "dump" command
344        parser_dump = subparsers.add_parser('dump',help='Dump the xml content without all the xml\'s ironsmith')
345        parser_dump.add_argument('-d', '--depth', type=int, default=None, help='How deep do we go. Full tree by default')
346        parser_dump.add_argument('file', nargs='+', help='XIOS xml file(s) to dump')
347        parser_dump.set_defaults(func=dump)
348
349        # create the parser for the "tsquery" command
350        parser_check = subparsers.add_parser('tsquery', help='query timeseries related parameters from an xml file')
351        parser_check.add_argument('--file', nargs=1, required=True, help='XIOS xml timeseries_def type')
352        parser_check.set_defaults(func=tsquery)
353       
354        # create the parser for the "check" command
355        parser_check = subparsers.add_parser('check', help='Check consistency between field_def and file_def files')
356        parser_check.add_argument('--field', nargs=1, required=True, help='XIOS xml field_def type')
357        parser_check.add_argument('--file', nargs='+', required=True, help='XIOS xml file_def type')
358        parser_check.set_defaults(func=check, correction=False)
359
360        # create the parser for the "modify" command
361        parser_check = subparsers.add_parser('modify', help='Will make sure field_def is a superset of file_def')
362        parser_check.add_argument('--field', nargs=1, required=True, help='XIOS xml field_def type')
363        parser_check.add_argument('--file', nargs='+', required=True, help='XIOS xml file_def type')
364        parser_check.set_defaults(func=check, correction=True)
365       
366        # create the parser for the "modifydr2xmlIPSL" command
367        parser_check = subparsers.add_parser('modifydr2xmlIPSL', help='Adapt dr2xml_file to produce output files according to IPSL requirements')
368        parser_check.add_argument('--newPath', nargs=1, required=True, help='Directory output for file produced from dr2xml_file type')
369        parser_check.add_argument('--JobName', nargs=1, required=False, help='Name of the simulation to be added in the name of file produced from dr2xml_file type')
370        parser_check.add_argument('--ModelName', nargs=1, required=False, help='Name of the model to be added in the name of file produced from dr2xml_file type')
371        parser_check.add_argument('--ModelVersion', nargs=1, required=False, help='Model version to be added in global attributes of files produced from dr2xml_file type')
372        parser_check.add_argument('--ExperimentName',nargs=1, required=False, help='Name of the experiment')
373        parser_check.add_argument('--file', nargs='+', required=True, help='XIOS xml dr2xml_file type')
374        parser_check.add_argument('--splitLastDate', nargs=1, required=False, help='Date to be used as split_last_date')
375        parser_check.set_defaults(func=modifydr2xmlIPSL)
376
377        # create the parser for the "modifyPath" command
378        parser_check = subparsers.add_parser('modifyPath', help='Will make sure dr2xml write files where it should be')
379        parser_check.add_argument('--newPath', nargs=1, required=True, help='Directory output for file produced from dr2xml_file type')
380        parser_check.add_argument('--filePrefix', nargs=1, required=False, help='Prefix to be added to file produced from dr2xml_file type')
381        parser_check.add_argument('--file', nargs='+', required=True, help='XIOS xml dr2xml_file type')
382        parser_check.set_defaults(func=modifyPath)
383
384        # create the parser for the "modifyDR2XML" command
385        parser_check = subparsers.add_parser('modifyDR2XML', help='Fine tune dr2xml files for CMIP6 production')
386        parser_check.add_argument('--file', nargs='+', required=True, help='XIOS xml dr2xml_file type')
387        parser_check.set_defaults(func=modifyDR2XML)
388       
389        # create the parser for the "showtime" command
390        parser_check = subparsers.add_parser('showtime', help='Just want to make sure you feel good today')
391        parser_check.set_defaults(func=showtime)
392       
393        # Each possible option
394        parser.add_argument('-v', '--verbosity', action='count', default=0)
395
396        # Parse the args.
397        args = parser.parse_args()
398
399        # And call whatever function was selected
400        args.func(args)
401    except KeyboardInterrupt:
402        print "Shutdown requested...exiting"
403    except Exception:
404        traceback.print_exc(file=sys.stdout)
405    sys.exit(0)
Note: See TracBrowser for help on using the repository browser.