| 1 | |
| 2 | == How to make an AVAILABLE file == |
| 3 | |
| 4 | There used to be a Fortran programme for automatic creation of the AVAILBLE file (which is read by FLEXPART to know which windfields are available). Thanks to John Burkhardt's efforts, it has been superseded by python programme with better functionality. |
| 5 | |
| 6 | Find the latest version of `mkAVAIL.py` below: |
| 7 | |
| 8 | |
| 9 | {{{ |
| 10 | #!/usr/bin/env python |
| 11 | |
| 12 | """ |
| 13 | SYNOPSIS |
| 14 | |
| 15 | mk_AVAILABLE.py: [-s,--startdate] [-e,--enddate] [-m,--model /ECWMF/ERAI/GFS] [-p, --path] [-a, --avpath] [-i, --interval] [-h] [-v,--verbose] [--version] |
| 16 | |
| 17 | DESCRIPTION |
| 18 | |
| 19 | mk_AVAIL is a script to create AVAILABLE files for FLEXPART windfields. |
| 20 | |
| 21 | Example usage: |
| 22 | %mk_AVAIL.py -s 200601 -e 200701 -m ECMWF -p . -h |
| 23 | |
| 24 | would create a file: AVAIALABLE that contained paths |
| 25 | of all files available in the current directory between 200601 and 200701. |
| 26 | The default start date is 197001 and the default end date is TODAY. |
| 27 | |
| 28 | adapted and simplified version / Petra Seibert |
| 29 | v.004: add ERA-Interim with EI as model, proper sorting of dates if year 2000 included, option to define a path for AVAILABLE / Petra Seibert 2015-10-21 |
| 30 | |
| 31 | QUESTIONS |
| 32 | |
| 33 | JFB: <jfb@nilu.no> |
| 34 | v.003: petra.seibert at boku.ac.at |
| 35 | v.004: petra.seibert at boku.ac.at |
| 36 | |
| 37 | LICENSE |
| 38 | |
| 39 | This script follows creative commons usage. |
| 40 | |
| 41 | VERSION |
| 42 | |
| 43 | $Id: 0.004 $ |
| 44 | |
| 45 | """ |
| 46 | |
| 47 | import sys |
| 48 | import os |
| 49 | import traceback |
| 50 | import optparse |
| 51 | import time |
| 52 | import datetime |
| 53 | import socket |
| 54 | import glob |
| 55 | import string |
| 56 | |
| 57 | |
| 58 | def main (): |
| 59 | |
| 60 | global options, args |
| 61 | |
| 62 | WIND_dir = '/xnilu_wrk/flex_wrk/WIND_FIELDS' |
| 63 | |
| 64 | ## THE AVAILABE MODEL PRODUCTS (ultimately this comes from a DB) |
| 65 | MODEL = {} |
| 66 | MODEL['ECMWF'] = {'prefix':'EN', 'timeindex':2} |
| 67 | MODEL['ERAI'] = {'prefix':'EI', 'timeindex':2} |
| 68 | MODEL['GFS'] = {'prefix':'GF', 'timeindex':2} |
| 69 | |
| 70 | AVAIL_head = """DATE TIME FILENAME SPECIFICATIONS\ |
| 71 | \nYYYYMMDD HHMISS\ |
| 72 | \n________ ______ __________________ __________________\n""" |
| 73 | start_date = options.startdate |
| 74 | sy = int(start_date[0:4]) |
| 75 | sm = int(start_date[4:6]) |
| 76 | end_date = options.enddate |
| 77 | ey = int(end_date[0:4]) |
| 78 | em = int(end_date[4:6]) |
| 79 | # print end_date |
| 80 | |
| 81 | #Get the directory information |
| 82 | M = MODEL[options.model] |
| 83 | prfx = M['prefix'] |
| 84 | t = options.path |
| 85 | avpath = options.avpath |
| 86 | |
| 87 | |
| 88 | #Loop through the files in the directories |
| 89 | warned = False |
| 90 | d = t #directory |
| 91 | # print d |
| 92 | tind = M['timeindex'] #timestamp index |
| 93 | searchstr = os.path.join(t,prfx) |
| 94 | #Prepare output files |
| 95 | fout = file(os.path.join(avpath,'AVAILABLE'),'w') |
| 96 | fout.write(AVAIL_head) |
| 97 | print 'searchstring:',searchstr |
| 98 | files = glob.glob(searchstr+'*') |
| 99 | # print files |
| 100 | dict_dates={} |
| 101 | for f in files: |
| 102 | if (f[0:2] == './'): f = f[2:] # PS - remove this part if present |
| 103 | fn = os.path.basename(f) |
| 104 | if fn[-1]!='*': |
| 105 | timestamp = fn[tind:] |
| 106 | year = int(timestamp[0:2]) |
| 107 | if year < 58: |
| 108 | year += 2000 |
| 109 | else: |
| 110 | year += 1900 |
| 111 | dtstring = str(year)+' '+timestamp[2:9] |
| 112 | dict_dates[dtstring] = f |
| 113 | dates=sorted(dict_dates.items()) |
| 114 | for i,date in enumerate(dates): # go through dates in ascending order |
| 115 | f = date[1] # now we have the filename+path |
| 116 | fn = os.path.basename(f) |
| 117 | if fn[-1]!='*': |
| 118 | timestamp = fn[tind:] |
| 119 | year = int(timestamp[0:2]) |
| 120 | if year < 58: |
| 121 | year += 2000 |
| 122 | else: |
| 123 | year += 1900 |
| 124 | month = int(timestamp[2:4]) |
| 125 | day = int(timestamp[4:6]) |
| 126 | hour = int(timestamp[6:8]) |
| 127 | fileT = year*100 + int(timestamp[2:4]) |
| 128 | # PS: check for irregular intervals |
| 129 | date = datetime.datetime(year,month,day,hour) |
| 130 | if i == 2: |
| 131 | if options.timeint == '': |
| 132 | timeint = date - date1 |
| 133 | else: |
| 134 | timeint = datetime.timedelta(0,3600*int(options.timeint)) |
| 135 | if timeint != date - date1: |
| 136 | print 'WARNING - irregular interval',date - date1 |
| 137 | print date1,f1,'\n',date, f,'\n' |
| 138 | elif i > 2: |
| 139 | if timeint != date - date1: |
| 140 | print 'WARNING - irregular interval',date - date1 |
| 141 | print date1,f1,'\n',date, f,'\n' |
| 142 | if options.timeint == '': timeint = date - date1 |
| 143 | date1 = date |
| 144 | f1 = f |
| 145 | |
| 146 | if i%5000 == 0: print 'progress:', i, f |
| 147 | |
| 148 | if fileT <= ey*100 + em and fileT >= sy*100 + sm: |
| 149 | #if month <= em and month >= sm: |
| 150 | #print 'Match: %s' % fn |
| 151 | #This is the fortran format: (i8,1x,i6,2(6x,a18)) |
| 152 | relpath = os.path.relpath(os.path.dirname(f),avpath) |
| 153 | f = os.path.join(relpath,fn) |
| 154 | if (f[0:2] == './'): f = f[2:] # remove this part if present |
| 155 | # print fn,f |
| 156 | if len(f) > 18: #PS |
| 157 | if not warned: |
| 158 | print 'WARNING: Flexpart can only read 18 chars in WF-name' |
| 159 | print f, ' has ', len(f), ' characters!\n' |
| 160 | warned = True |
| 161 | string = "%s%s%s %s0000 %s ON DISC\n" %\ |
| 162 | (year,str(month).zfill(2),str(day).zfill(2),str(hour).zfill(2),f.ljust(18)) |
| 163 | fout.write(string) |
| 164 | |
| 165 | print 'Done: ',i |
| 166 | print 'Written:', os.path.join(avpath,'AVAILABLE') |
| 167 | fout.close() |
| 168 | |
| 169 | if __name__ == '__main__': |
| 170 | |
| 171 | try: |
| 172 | start_time = time.time() |
| 173 | today = datetime.datetime.now() |
| 174 | parser = optparse.OptionParser( |
| 175 | formatter=optparse.TitledHelpFormatter(), |
| 176 | usage=globals()['__doc__'], |
| 177 | version='$Id: 0.001 $') |
| 178 | parser.add_option ('-v', '--verbose', action='store_true', |
| 179 | default=False, help='verbose output') |
| 180 | parser.add_option ('-s', '--startdate', |
| 181 | dest='startdate', |
| 182 | default='197001', |
| 183 | help='YYYYMM integer') |
| 184 | parser.add_option ('-e', '--enddate', |
| 185 | # setting default as TODAY |
| 186 | dest='enddate', |
| 187 | default = str(today.year) + str(today.month).zfill(2), |
| 188 | #default='200712', |
| 189 | help='YYYYMM integer') |
| 190 | parser.add_option ('-m', '--model', |
| 191 | dest='model', |
| 192 | default='ECMWF', help='ECMWF or GFS') |
| 193 | parser.add_option ('-p', '--path', |
| 194 | dest='path', |
| 195 | default='.', help='path to be searched. Escape or quote * and ? ') |
| 196 | parser.add_option ('-a', '--avpath', |
| 197 | dest='avpath', |
| 198 | default='.', help='path for AVAILABLE file ') |
| 199 | parser.add_option ('-i', '--interval', |
| 200 | dest='timeint', |
| 201 | default='', help='expected time interval in h. If omitted, show every change') |
| 202 | (options, args) = parser.parse_args() |
| 203 | #QUERY['modelType'] = options.model |
| 204 | #QUERY['start_date'] = options.startdate |
| 205 | #QUERY['end_date'] = options.enddate |
| 206 | |
| 207 | #if len(args) < 1: |
| 208 | # parser.error ('missing argument') |
| 209 | if options.verbose: print time.asctime() |
| 210 | exit_code = main() |
| 211 | if exit_code is None: |
| 212 | exit_code = 0 |
| 213 | if options.verbose: print time.asctime() |
| 214 | if options.verbose: print 'TOTAL TIME IN MINUTES:', |
| 215 | if options.verbose: print (time.time() - start_time) / 60.0 |
| 216 | sys.exit(exit_code) |
| 217 | except KeyboardInterrupt, e: # Ctrl-C |
| 218 | raise e |
| 219 | except SystemExit, e: # sys.exit() |
| 220 | raise e |
| 221 | except Exception, e: |
| 222 | print 'ERROR, UNEXPECTED EXCEPTION' |
| 223 | print str(e) |
| 224 | traceback.print_exc() |
| 225 | os._exit(1) |
| 226 | |
| 227 | |
| 228 | |
| 229 | # vim:set sr et ts=4 sw=4 ft=python fenc=utf-8: // See Vim, :help 'modeline' |
| 230 | |
| 231 | }}} |