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