1 | #!/usr/bin/env python3 |
---|
2 | ''' |
---|
3 | Script to check water conservation in the IPSL coupled model |
---|
4 | |
---|
5 | Here, some common utilities to all scripts |
---|
6 | |
---|
7 | Warning, to install, configure, run, use any of included software or |
---|
8 | to read the associated documentation you'll need at least one (1) |
---|
9 | brain in a reasonably working order. Lack of this implement will |
---|
10 | void any warranties (either express or implied). Authors assumes |
---|
11 | no responsability for errors, omissions, data loss, or any other |
---|
12 | consequences caused directly or indirectly by the usage of his |
---|
13 | software by incorrectly or partially configured personal |
---|
14 | |
---|
15 | |
---|
16 | SVN information |
---|
17 | $Author$ |
---|
18 | $Date$ |
---|
19 | $Revision$ |
---|
20 | $Id: $ |
---|
21 | $HeadURL$ |
---|
22 | ''' |
---|
23 | |
---|
24 | import os, sys |
---|
25 | import functools |
---|
26 | import time |
---|
27 | import configparser, re |
---|
28 | import numpy as np |
---|
29 | import libIGCM_sys |
---|
30 | |
---|
31 | def ReadConfig ( ini_file, default_ini_file='defaults.ini' ) : |
---|
32 | ''' |
---|
33 | Reads experiment parameters |
---|
34 | |
---|
35 | Reads <default_ini_file> config file to set all defaults parameters |
---|
36 | Reads <ini_file> config file to set all experiment parameters |
---|
37 | Reads config.card files if specified in <ini_file> |
---|
38 | |
---|
39 | ''' |
---|
40 | ## Read file with defaults values |
---|
41 | ## ------------------------------ |
---|
42 | params = configparser.ConfigParser ( interpolation=configparser.ExtendedInterpolation() ) |
---|
43 | params.optionxform = str # To keep capitals |
---|
44 | params.read (default_ini_file) |
---|
45 | print ( f'\nConfig file readed : {default_ini_file} ' ) |
---|
46 | |
---|
47 | ## Read Experiment config file |
---|
48 | ## ---------------------------- |
---|
49 | exp_params = configparser.ConfigParser ( interpolation=configparser.ExtendedInterpolation() ) |
---|
50 | exp_params.optionxform = str # To keep capitals |
---|
51 | exp_params.read (ini_file) |
---|
52 | print ( f'\nConfig file readed : {ini_file} ' ) |
---|
53 | |
---|
54 | ## Reading config.card if possible |
---|
55 | ## ------------------------------- |
---|
56 | if 'Experiment' in params.keys () : ## Read Experiment on parameter file if possible |
---|
57 | if 'ConfigCard' in exp_params['Experiment'].keys () : |
---|
58 | ConfigCard = exp_params['Experiment']['ConfigCard'] |
---|
59 | print ( f'{ConfigCard=}' ) |
---|
60 | |
---|
61 | if ConfigCard : ## Read config card if it exists |
---|
62 | # Text existence of ConfigCard |
---|
63 | if os.path.exists ( ConfigCard ) : |
---|
64 | print ( f'Reading Config Card : {ConfigCard}' ) |
---|
65 | ## Creates parser for reading .ini input file |
---|
66 | config = configparser.ConfigParser (interpolation=configparser.ExtendedInterpolation() ) |
---|
67 | config.optionxform = str # To keep capitals |
---|
68 | |
---|
69 | config.read (ConfigCard) |
---|
70 | |
---|
71 | for VarName in ['JobName', 'ExperimentName', 'SpaceName', 'LongName', 'ModelName', 'TagName', |
---|
72 | 'ORCA_version', 'ExpType', 'PeriodLength', 'ResolAtm', 'ResolOce' ] : |
---|
73 | if VarName in config['UserChoices'].keys() : |
---|
74 | exp_params['Experiment'][VarName] = str2value ( config['UserChoices'][VarName] ) |
---|
75 | |
---|
76 | if 'Post' in config.sections() : |
---|
77 | if 'PackFrequency' in config['Post'] : |
---|
78 | PackFrequency = config['Post']['PackFrequency'] |
---|
79 | exp_params['Experiment']['PackFrequency'] = PackFrequency |
---|
80 | |
---|
81 | else : |
---|
82 | raise FileExistsError ( f"File not found : {ConfigCard = }" ) |
---|
83 | |
---|
84 | ## Reading config file |
---|
85 | ## ------------------- |
---|
86 | for Section in exp_params.keys () : |
---|
87 | params[Section].update ( exp_params[Section] ) |
---|
88 | print ( f'\nConfig file readed : {ini_file} ' ) |
---|
89 | |
---|
90 | return config2dict (params) |
---|
91 | |
---|
92 | def SetDatesAndFiles ( pdict ) : |
---|
93 | ''' |
---|
94 | From readed experiment parameters, set all needed parameters |
---|
95 | ''' |
---|
96 | |
---|
97 | ## Set libIGCM and machine dependant values |
---|
98 | ## ---------------------------------------- |
---|
99 | pdict['Experiment']['ICO'] = 'ICO' in pdict['Experiment']['ResolAtm'] |
---|
100 | pdict['Experiment']['LMDZ'] = 'LMD' in pdict['Experiment']['ResolAtm'] |
---|
101 | |
---|
102 | mm = libIGCM_sys.config ( TagName = pdict['Experiment']['TagName'], |
---|
103 | SpaceName = pdict['Experiment']['SpaceName'], |
---|
104 | ExperimentName= pdict['Experiment']['ExperimentName'], |
---|
105 | JobName = pdict['Experiment']['JobName'], |
---|
106 | User = pdict['Experiment']['User'], |
---|
107 | Group = pdict['Experiment']['Group'], |
---|
108 | ARCHIVE = pdict['libIGCM']['ARCHIVE'], |
---|
109 | SCRATCHDIR = pdict['libIGCM']['SCRATCHDIR'], |
---|
110 | STORAGE = pdict['libIGCM']['STORAGE'], |
---|
111 | R_IN = pdict['libIGCM']['R_IN'], |
---|
112 | R_OUT = pdict['libIGCM']['R_OUT'], |
---|
113 | R_FIG = pdict['libIGCM']['R_FIG'], |
---|
114 | TmpDir = pdict['Files']['TmpDir'], |
---|
115 | R_SAVE = pdict['libIGCM']['R_SAVE'], |
---|
116 | R_FIGR = pdict['libIGCM']['R_FIGR'], |
---|
117 | R_BUFR = pdict['libIGCM']['R_BUFR'], |
---|
118 | R_BUF_KSH = pdict['libIGCM']['R_BUF_KSH'], |
---|
119 | POST_DIR = pdict['libIGCM']['POST_DIR'], |
---|
120 | L_EXP = pdict['libIGCM']['L_EXP'] ) |
---|
121 | |
---|
122 | |
---|
123 | pdict['Files']['TmpDir'] = mm['TmpDir'] |
---|
124 | |
---|
125 | for key in mm.keys() : |
---|
126 | pdict['libIGCM'][key] = mm[key] |
---|
127 | |
---|
128 | ## Complete configuration |
---|
129 | ## ---------------------- |
---|
130 | if not pdict['Experiment']['NEMO'] and pdict['Experiment']['ORCA_version'] : |
---|
131 | if '1.2' in pdict['Experiment']['ORCA_version'] : |
---|
132 | pdict['Experiment']['NEMO'] = 3.6 |
---|
133 | if '4.0' in pdict['Experiment']['ORCA_version'] : |
---|
134 | pdict['Experiment']['NEMO'] = 4.0 |
---|
135 | if '4.2' in pdict['Experiment']['ORCA_version'] : |
---|
136 | pdict['Experiment']['NEMO'] = 4.2 |
---|
137 | |
---|
138 | if pdict['Experiment']['ATM_HIS'] : |
---|
139 | if not pdict['Experiment']['SRF_HIS'] : |
---|
140 | pdict['Experiment']['SRF_HIS'] = pdict['Experiment']['ATM_HIS'] |
---|
141 | if not pdict['Experiment']['RUN_HIS'] : |
---|
142 | pdict['Experiment']['RUN_HIS'] = pdict['Experiment']['ATM_HIS'] |
---|
143 | |
---|
144 | ## |
---|
145 | ## Reading prec |
---|
146 | if not pdict['Config']['readPrec'] : |
---|
147 | pdict['Config']['readPrec'] = np.float64 |
---|
148 | else : |
---|
149 | if pdict['Config']['readPrec'] in ["float", "float64", "r8", "double", "<class 'float'>" ] : |
---|
150 | pdict['Config']['readPrec'] = float |
---|
151 | if pdict['Config']['readPrec'] in [ "float32", "r4", "single", "<class 'numpy.float32'>" ] : |
---|
152 | pdict['Config']['readPrec'] = np.float32 |
---|
153 | if pdict['Config']['readPrec'] in [ "float16", "r2", "half" , "<class 'numpy.float16'>" ] : |
---|
154 | pdict['Config']['readPrec'] = np.float16 |
---|
155 | |
---|
156 | |
---|
157 | ## Defines begining and end of experiment |
---|
158 | ## -------------------------------------- |
---|
159 | if not pdict['Experiment']['DateBegin'] : |
---|
160 | pdict['Experiment']['DateBegin'] = f"{pdict['Experiment']['YearBegin']}0101" |
---|
161 | else : |
---|
162 | YearBegin, MonthBegin, DayBegin = SplitDate ( pdict['Experiment']['DateBegin'] ) |
---|
163 | DateBegin = FormatToGregorian (pdict['Experiment']['DateBegin']) |
---|
164 | pdict['Experiment']['YearBegin'] = YearBegin |
---|
165 | |
---|
166 | if not pdict['Experiment']['DateEnd'] : |
---|
167 | pdict['Experiment']['DateEnd'] = f"{pdict['Experiment']['YearEnd']}1231" |
---|
168 | else : |
---|
169 | YearEnd, MonthEnd, DayEnd = SplitDate ( pdict['Experiment']['DateEnd'] ) |
---|
170 | DateEnd = FormatToGregorian (pdict['Experiment']['DateEnd']) |
---|
171 | pdict['Experiment']['DateEnd'] = DateEnd |
---|
172 | |
---|
173 | if not pdict['Experiment']['PackFrequency'] : |
---|
174 | PackFrequencypdict['Experiment']['PackFrequency'] = YearEnd - YearBegin + 1 |
---|
175 | |
---|
176 | if isinstance ( pdict['Experiment']['PackFrequency'], str ) : |
---|
177 | if 'Y' in pdict['Experiment']['PackFrequency'] : |
---|
178 | zPackFrequency = pdict['Experiment']['PackFrequency'].replace ( 'Y', '') |
---|
179 | pdict['Experiment']['PackFrequency'] = f'{zPackFrequency}Y' |
---|
180 | pdict['Experiment']['zPackFrequency'] = int (zPackFrequency) |
---|
181 | if 'M' in pdict['Experiment']['PackFrequency'] : |
---|
182 | zPackFrequency = pdict['Experiment']['PackFrequency'].replace ( 'M', '') |
---|
183 | pdict['Experiment']['PackFrequency'] = f'{zPackFrequency}M' |
---|
184 | pdict['Experiment']['zPackFrequency'] = int (zPackFrequency) |
---|
185 | |
---|
186 | ## Set directory to extract files |
---|
187 | ## ------------------------------ |
---|
188 | if not pdict['Files']['FileDir'] : |
---|
189 | pdict['Files']['FileDir'] = os.path.join ( pdict['Files']['TmpDir'], f"WATER_{pdict['Experiment']['JobName']}" ) |
---|
190 | |
---|
191 | if not os.path.isdir ( pdict['Files']['FileDir'] ) : os.makedirs ( pdict['Files']['FileDir'] ) |
---|
192 | |
---|
193 | FileOut = str2value (pdict['Files']['FileOut']) |
---|
194 | if not FileOut : |
---|
195 | FileOut = f"ATM_waterbudget_{pdict['Experiment']['JobName']}_{pdict['Experiment']['YearBegin']}_{pdict['Experiment']['YearEnd']}" |
---|
196 | if pdict['Experiment']['ICO'] : |
---|
197 | if pdict['Experiment']['ATM_HIS'] == 'latlon' : FileOut = f'{FileOut}_LATLON' |
---|
198 | if pdict['Experiment']['ATM_HIS'] == 'ico' : FileOut = f'{FileOut}_ICO' |
---|
199 | if pdict['Config']['readPrec'] == np.float32 : FileOut = f'{FileOut}_float32' |
---|
200 | FileOut = f'{FileOut}.out' |
---|
201 | |
---|
202 | pdict['Files']['FileOut'] = FileOut |
---|
203 | f_out = open ( FileOut, mode = 'w', encoding="utf-8" ) |
---|
204 | pdict['Files']['f_out'] = f_out |
---|
205 | |
---|
206 | echo (' ', f_out) |
---|
207 | echo ( f"JobName : {pdict['Experiment']['JobName']}" , f_out=f_out ) |
---|
208 | echo ( f"Comment : {pdict['Experiment']['Comment']}" , f_out=f_out ) |
---|
209 | echo ( f"TmpDir : {pdict['Files']['TmpDir']}" , f_out=f_out ) |
---|
210 | echo ( f"FileDir : {pdict['Files']['FileDir']}" , f_out=f_out ) |
---|
211 | |
---|
212 | echo ( f"\nDealing with {pdict['libIGCM']['L_EXP']}", f_out ) |
---|
213 | |
---|
214 | ## Creates model output directory names |
---|
215 | ## ------------------------------------ |
---|
216 | if not pdict['Files']['FreqDir'] : |
---|
217 | if pdict['Experiment']['Freq'] == "MO" : |
---|
218 | pdict['Files']['FreqDir'] = os.path.join ('Output' , 'MO' ) |
---|
219 | if pdict['Experiment']['Freq'] == "SE" : |
---|
220 | pdict['Files']['FreqDir'] = os.path.join ('Analyse', 'SE' ) |
---|
221 | |
---|
222 | if not pdict['Files']['dir_ATM_his'] : |
---|
223 | pdict['Files']['dir_ATM_his'] = os.path.join ( pdict['libIGCM']['R_SAVE'], "ATM", pdict['Files']['FreqDir'] ) |
---|
224 | if not pdict['Files']['dir_SRF_his'] : |
---|
225 | pdict['Files']['dir_SRF_his'] = os.path.join ( pdict['libIGCM']['R_SAVE'], "SRF", pdict['Files']['FreqDir'] ) |
---|
226 | |
---|
227 | if not pdict['Files']['dir_OCE_his'] : |
---|
228 | pdict['Files']['dir_OCE_his'] = os.path.join ( pdict['libIGCM']['R_SAVE'], "OCE", pdict['Files']['FreqDir'] ) |
---|
229 | if not pdict['Files']['dir_ICE_his'] : |
---|
230 | pdict['Files']['dir_ICE_his'] = os.path.join ( pdict['libIGCM']['R_SAVE'], "ICE", pdict['Files']['FreqDir'] ) |
---|
231 | |
---|
232 | echo ( 'The analysis relies on files from the following model output directories : ', f_out ) |
---|
233 | echo ( f"{pdict['Files']['dir_ATM_his'] = }" , f_out ) |
---|
234 | echo ( f"{pdict['Files']['dir_SRF_his'] = }" , f_out ) |
---|
235 | echo ( f"{pdict['Files']['dir_OCE_his'] = }" , f_out ) |
---|
236 | echo ( f"{pdict['Files']['dir_ICE_his'] = }" , f_out ) |
---|
237 | |
---|
238 | |
---|
239 | ## Creates files names |
---|
240 | ## -------------------- |
---|
241 | if not pdict['Experiment']['Period'] : |
---|
242 | if pdict['Experiment']['Freq'] == 'MO' : |
---|
243 | pdict['Experiment']['Period'] = f"{pdict['Experiment']['DateBegin']}_{pdict['Experiment']['DateEnd']}_1M" |
---|
244 | if pdict['Experiment']['Freq'] == 'SE' : |
---|
245 | pdict['Experiment']['Period'] = f"SE_{pdict['Files']['DateBegin']}_{pdict['Files']['DateEnd']}_1M" |
---|
246 | |
---|
247 | echo ( f"Period : {pdict['Experiment']['Period']}", f_out ) |
---|
248 | |
---|
249 | if not pdict['Files']['FileCommon'] : |
---|
250 | pdict['Files']['FileCommon'] = f"{pdict['Experiment']['JobName']}_{pdict['Experiment']['Period']}" |
---|
251 | |
---|
252 | if not pdict['Files']['Title'] : |
---|
253 | pdict['Files']['Title'] = f"{pdict['Experiment']['JobName']} : {pdict['Experiment']['Freq']} : {pdict['Experiment']['DateBegin']} - {pdict['Experiment']['DateEnd']}" |
---|
254 | |
---|
255 | echo ('\nOpen history files', f_out ) |
---|
256 | if not pdict['Files']['file_ATM_his'] : |
---|
257 | if pdict['Experiment']['ATM_HIS'] == 'latlon' : |
---|
258 | pdict['Files']['file_ATM_his'] = os.path.join ( pdict['Files']['dir_ATM_his'], f"{pdict['Files']['FileCommon']}_histmth.nc" ) |
---|
259 | if pdict['Experiment']['ATM_HIS'] == 'ico' : |
---|
260 | pdict['Files']['file_ATM_his'] = os.path.join ( pdict['Files']['dir_ATM_his'], f"{pdict['Files']['FileCommon']}_histmth_ico.nc" ) |
---|
261 | if not pdict['Files']['file_SRF_his'] : |
---|
262 | if pdict['Experiment']['ATM_HIS'] == 'latlon' : |
---|
263 | pdict['Files']['file_SRF_his'] = os.path.join ( pdict['Files']['dir_SRF_his'], f"{pdict['Files']['FileCommon']}_sechiba_history.nc" ) |
---|
264 | if pdict['Experiment']['ATM_HIS'] == 'ico' : |
---|
265 | pdict['Files']['file_SRF_his'] = os.path.join ( pdict['Files']['dir_SRF_his'], f"{pdict['Files']['FileCommon']}_sechiba_history_ico.nc" ) |
---|
266 | |
---|
267 | if pdict['Experiment']['SRF'] and pdict['Experiment']['Routing'] == 'SIMPLE' : |
---|
268 | if not pdict['Files']['file_RUN_his'] : |
---|
269 | if pdict['Experiment']['RUN_HIS'] == 'latlon' : |
---|
270 | pdict['Files']['file_RUN_his'] = os.path.join ( pdict['Files']['dir_SRF_his'], f"{pdict['Files']['FileCommon']}_sechiba_history.nc" ) |
---|
271 | if pdict['Experiment']['SRF_HIS'] == 'ico' : |
---|
272 | pdict['Files']['file_RUN_his'] = os.path.join ( pdict['Files']['dir_SRF_his'], f"{pdict['Files']['FileCommon']}_sechiba_history_ico.nc" ) |
---|
273 | |
---|
274 | echo ( f"{pdict['Files']['file_ATM_his'] = }", f_out ) |
---|
275 | if pdict['Experiment']['SRF'] : |
---|
276 | echo ( f"{pdict['Files']['file_SRF_his'] = }", f_out ) |
---|
277 | if pdict['Experiment']['Routing'] == 'SIMPLE' : echo ( f"{pdict['Files']['file_RUN_his'] = }", f_out ) |
---|
278 | |
---|
279 | |
---|
280 | if not pdict['Files']['file_OCE_his'] : |
---|
281 | pdict['Files']['file_OCE_his'] = os.path.join ( pdict['Files']['dir_OCE_his'], f"{pdict['Files']['FileCommon']}_grid_T.nc" ) |
---|
282 | if not pdict['Files']['file_OCE_sca'] : |
---|
283 | pdict['Files']['file_OCE_sca'] = os.path.join ( pdict['Files']['dir_OCE_his'], f"{pdict['Files']['FileCommon']}_scalar.nc" ) |
---|
284 | if not pdict['Files']['file_OCE_srf'] : |
---|
285 | pdict['Files']['file_OCE_srf'] = os.path.join ( pdict['Files']['dir_OCE_his'], f"{pdict['Files']['FileCommon']}_sbc.nc" ) |
---|
286 | if not pdict['Files']['file_ICE_his'] : |
---|
287 | pdict['Files']['file_ICE_his'] = os.path.join ( pdict['Files']['dir_ICE_his'], f"{pdict['Files']['FileCommon']}_icemod.nc" ) |
---|
288 | |
---|
289 | return pdict |
---|
290 | |
---|
291 | def SetRestartNames ( pdict, f_out) : |
---|
292 | zdict = pdict |
---|
293 | if not zdict['Files']['TarRestartDate_beg'] : |
---|
294 | zdict['Files']['TarRestartDate_beg'] = DateMinusOneDay ( zdict['Experiment']['DateBegin'] ) |
---|
295 | if not zdict['Files']['TarRestartDate_end'] : |
---|
296 | zdict['Files']['TarRestartDate_end'] = FormatToGregorian ( zdict['Experiment']['DateEnd'] ) |
---|
297 | |
---|
298 | if not zdict['Files']['TarRestartPeriod_beg'] : |
---|
299 | |
---|
300 | zdict['Files']['TarRestartPeriod_beg_DateEnd'] = zdict['Files']['TarRestartDate_beg'] |
---|
301 | zdict['Files']['TarRestartPeriod_beg_DateBeg'] = DateAddYear ( zdict['Files']['TarRestartPeriod_beg_DateEnd'], -zdict['Experiment']['zPackFrequency'] ) |
---|
302 | zdict['Files']['TarRestartPeriod_beg_DateBeg'] = DatePlusOneDay ( zdict['Files']['TarRestartPeriod_beg_DateBeg'] ) |
---|
303 | |
---|
304 | zdict['Files']['TarRestartPeriod_beg'] = f"{zdict['Files']['TarRestartPeriod_beg_DateBeg']}_{zdict['Files']['TarRestartPeriod_beg_DateEnd']}" |
---|
305 | echo ( f"Tar period for initial restart : {zdict['Files']['TarRestartPeriod_beg']}", f_out) |
---|
306 | |
---|
307 | if not zdict['Files']['TarRestartPeriod_end'] : |
---|
308 | |
---|
309 | zdict['Files']['TarRestartPeriod_end_DateEnd'] = zdict['Files']['TarRestartDate_end'] |
---|
310 | zdict['Files']['TarRestartPeriod_end_DateBeg'] = DateAddYear ( zdict['Files']['TarRestartPeriod_end_DateEnd'], -zdict['Experiment']['zPackFrequency'] ) |
---|
311 | zdict['Files']['TarRestartPeriod_end_DateBeg'] = DatePlusOneDay ( zdict['Files']['TarRestartPeriod_end_DateBeg']) |
---|
312 | |
---|
313 | zdict['Files']['TarRestartPeriod_end'] = f"{zdict['Files']['TarRestartPeriod_end_DateBeg']}_{zdict['Files']['TarRestartPeriod_end_DateEnd']}" |
---|
314 | echo ( f"Tar period for final restart : {zdict['Files']['TarRestartPeriod_end']}", f_out ) |
---|
315 | |
---|
316 | echo ( f"Restart dates - Start : {zdict['Files']['TarRestartPeriod_beg']} / End : {zdict['Files']['TarRestartPeriod_end']}", f_out) |
---|
317 | |
---|
318 | if not zdict['Files']['tar_restart_beg'] : |
---|
319 | zdict['Files']['tar_restart_beg'] = os.path.join ( zdict['libIGCM']['R_SAVE'], 'RESTART', f"{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartPeriod_beg']}_restart.tar" ) |
---|
320 | if not zdict['Files']['tar_restart_end'] : |
---|
321 | zdict['Files']['tar_restart_end'] = os.path.join ( zdict['libIGCM']['R_SAVE'], 'RESTART', f"{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartPeriod_end']}_restart.tar" ) |
---|
322 | |
---|
323 | echo ( f"{ zdict['Files']['tar_restart_beg'] = }", f_out ) |
---|
324 | echo ( f"{ zdict['Files']['tar_restart_end'] = }", f_out ) |
---|
325 | |
---|
326 | ##-- Names of tar files with restarts |
---|
327 | |
---|
328 | if not zdict['Files']['tar_restart_beg_ATM'] : |
---|
329 | zdict['Files']['tar_restart_beg_ATM'] = zdict['Files']['tar_restart_beg'] |
---|
330 | if not zdict['Files']['tar_restart_beg_DYN'] : |
---|
331 | zdict['Files']['tar_restart_beg_DYN'] = zdict['Files']['tar_restart_beg'] |
---|
332 | if not zdict['Files']['tar_restart_beg_RUN'] : |
---|
333 | zdict['Files']['tar_restart_beg_RUN'] = zdict['Files']['tar_restart_beg'] |
---|
334 | if not zdict['Files']['tar_restart_beg_OCE'] : |
---|
335 | zdict['Files']['tar_restart_beg_OCE'] = zdict['Files']['tar_restart_beg'] |
---|
336 | if not zdict['Files']['tar_restart_beg_ICE'] : |
---|
337 | zdict['Files']['tar_restart_beg_ICE'] = zdict['Files']['tar_restart_beg'] |
---|
338 | |
---|
339 | if not zdict['Files']['tar_restart_end_ATM'] : |
---|
340 | zdict['Files']['tar_restart_end_ATM'] = zdict['Files']['tar_restart_end'] |
---|
341 | if not zdict['Files']['tar_restart_end_DYN'] : |
---|
342 | zdict['Files']['tar_restart_end_DYN'] = zdict['Files']['tar_restart_end'] |
---|
343 | if not zdict['Files']['tar_restart_end_RUN'] : |
---|
344 | zdict['Files']['tar_restart_end_RUN'] = zdict['Files']['tar_restart_end'] |
---|
345 | if not zdict['Files']['tar_restart_end_OCE'] : |
---|
346 | zdict['Files']['tar_restart_end_OCE'] = zdict['Files']['tar_restart_end'] |
---|
347 | if not zdict['Files']['tar_restart_end_ICE'] : |
---|
348 | zdict['Files']['tar_restart_end_ICE'] = zdict['Files']['tar_restart_end'] |
---|
349 | |
---|
350 | if not zdict['Files']['file_DYN_beg'] : |
---|
351 | if zdict['Experiment']['LMDZ'] : |
---|
352 | zdict['Files']['file_DYN_beg'] = f"{zdict['Files']['FileDir']}/ATM_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_beg']}_restart.nc" |
---|
353 | if zdict['Experiment']['ICO'] : |
---|
354 | zdict['Files']['file_DYN_beg'] = f"{zdict['Files']['FileDir']}/ICO_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_beg']}_restart.nc" |
---|
355 | |
---|
356 | if not zdict['Files']['file_DYN_end'] : |
---|
357 | if zdict['Experiment']['LMDZ'] : |
---|
358 | zdict['Files']['file_DYN_end'] = f"{zdict['Files']['FileDir']}/ATM_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_end']}_restart.nc" |
---|
359 | if zdict['Experiment']['ICO'] : |
---|
360 | zdict['Files']['file_DYN_end'] = f"{zdict['Files']['FileDir']}/ICO_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_end']}_restart.nc" |
---|
361 | |
---|
362 | if zdict['Experiment']['SRF'] : |
---|
363 | if not zdict['Files']['file_SRF_beg'] : |
---|
364 | zdict['Files']['file_SRF_beg'] = f"{zdict['Files']['FileDir']}/SRF_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_beg']}_sechiba_rest.nc" |
---|
365 | if not zdict['Files']['file_SRF_end'] : |
---|
366 | zdict['Files']['file_SRF_end'] = f"{zdict['Files']['FileDir']}/SRF_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_end']}_sechiba_rest.nc" |
---|
367 | |
---|
368 | if zdict['Experiment']['SRF'] : |
---|
369 | if not zdict['Files']['tar_restart_beg_SRF'] : |
---|
370 | zdict['Files']['tar_restart_beg_SRF'] = zdict['Files']['tar_restart_beg'] |
---|
371 | if not zdict['Files']['tar_restart_end_SRF'] : |
---|
372 | zdict['Files']['tar_restart_end_SRF'] = zdict['Files']['tar_restart_end'] |
---|
373 | |
---|
374 | if not zdict['Files']['file_ATM_beg'] : |
---|
375 | zdict['Files']['file_ATM_beg'] = f"{zdict['Files']['FileDir']}/ATM_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_beg']}_restartphy.nc" |
---|
376 | if not zdict['Files']['file_ATM_end'] : |
---|
377 | zdict['Files']['file_ATM_end'] = f"{zdict['Files']['FileDir']}/ATM_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_end']}_restartphy.nc" |
---|
378 | |
---|
379 | if zdict['Experiment']['SRF'] : |
---|
380 | echo ( f"{zdict['Files']['file_SRF_beg'] = }", f_out) |
---|
381 | echo ( f"{zdict['Files']['file_SRF_end'] = }", f_out) |
---|
382 | |
---|
383 | if zdict['Experiment']['ICO'] : |
---|
384 | if not zdict['Files']['file_DYN_aire'] : |
---|
385 | zdict['Files']['file_DYN_aire'] = os.path.join ( zdict['libIGCM']['R_IN'], 'ATM', 'GRID', f"{zdict['Experiment']['ResolAtm']}_grid.nc" ) |
---|
386 | |
---|
387 | if zdict['Experiment']['SRF'] and zdict['Experiment']['Routing'] == 'SIMPLE' : |
---|
388 | if not zdict['Files']['file_RUN_beg'] : |
---|
389 | zdict['Files']['file_RUN_beg'] = f"{ zdict['Files']['FileDir']}/SRF_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_beg']}_routing_restart.nc" |
---|
390 | if not zdict['Files']['file_RUN_end'] : |
---|
391 | zdict['Files']['file_RUN_end'] = f"{ zdict['Files']['FileDir']}/SRF_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_end']}_routing_restart.nc" |
---|
392 | |
---|
393 | if not zdict['Files']['tar_restart_beg_OCE'] : |
---|
394 | zdict['Files']['tar_restart_beg_OCE'] = zdict['Files']['tar_restart_beg'] |
---|
395 | if not zdict['Files']['tar_restart_beg_ICE'] : |
---|
396 | zdict['Files']['tar_restart_beg_ICE'] = zdict['Files']['tar_restart_beg'] |
---|
397 | |
---|
398 | if not zdict['Files']['tar_restart_end_OCE'] : |
---|
399 | zdict['Files']['tar_restart_end_OCE'] = zdict['Files']['tar_restart_end'] |
---|
400 | if not zdict['Files']['tar_restart_end_ICE'] : |
---|
401 | zdict['Files']['tar_restart_end_ICE'] = zdict['Files']['tar_restart_end'] |
---|
402 | |
---|
403 | if not zdict['Files']['file_OCE_beg'] : |
---|
404 | zdict['Files']['file_OCE_beg'] = f"{zdict['Files']['FileDir']}/OCE_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_beg']}_restart.nc" |
---|
405 | if not zdict['Files']['file_OCE_end'] : |
---|
406 | zdict['Files']['file_OCE_end'] = f"{zdict['Files']['FileDir']}/OCE_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_end']}_restart.nc" |
---|
407 | if not zdict['Files']['file_ICE_beg'] : |
---|
408 | zdict['Files']['file_ICE_beg'] = f"{zdict['Files']['FileDir']}/ICE_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_beg']}_restart_icemod.nc" |
---|
409 | if not zdict['Files']['file_ICE_end'] : |
---|
410 | zdict['Files']['file_ICE_end'] = f"{zdict['Files']['FileDir']}/ICE_{zdict['Experiment']['JobName']}_{zdict['Files']['TarRestartDate_end']}_restart_icemod.nc" |
---|
411 | |
---|
412 | return zdict |
---|
413 | |
---|
414 | def config2dict ( pconf ) : |
---|
415 | ''' |
---|
416 | Convert a config parser object into a dictionary |
---|
417 | ''' |
---|
418 | zdict = {} |
---|
419 | for section in pconf.keys () : |
---|
420 | zdict[section] = {} |
---|
421 | for key in pconf[section].keys() : |
---|
422 | zz = str2value ( pconf[section][key] ) |
---|
423 | zdict[section].update ( {key:zz} ) |
---|
424 | return zdict |
---|
425 | |
---|
426 | def dict2config ( pdict ): |
---|
427 | ''' |
---|
428 | Convert a dictionary into a configparser object |
---|
429 | |
---|
430 | The dictionary should have two levels (see configparser) |
---|
431 | ''' |
---|
432 | zconf = configparser.ConfigParser ( interpolation=configparser.ExtendedInterpolation() ) |
---|
433 | zconf.optionxform = str # To keep capitals |
---|
434 | |
---|
435 | for section in pdict.keys () : |
---|
436 | zconf[section] = {} |
---|
437 | for key in pdict[section].keys() : |
---|
438 | zconf[section][key] = str (pdict[section][key] ) |
---|
439 | |
---|
440 | return zconf |
---|
441 | |
---|
442 | # def updateConf ( pconf, pdict ): |
---|
443 | # ''' |
---|
444 | # Update a config parser with a dictionary |
---|
445 | # ''' |
---|
446 | # zconf = pconf |
---|
447 | # for section in pdict.keys() : |
---|
448 | # if section not in pconf.keys() : pconf[section] = {} |
---|
449 | # for key in pdict[section].keys() : |
---|
450 | # pconf[section][key] = str(pdict[section][key]) |
---|
451 | # return pconf |
---|
452 | |
---|
453 | def echo (string, f_out, end='\n') : |
---|
454 | '''Function to print to stdout *and* output file''' |
---|
455 | print ( str(string), end=end ) |
---|
456 | sys.stdout.flush () |
---|
457 | f_out.write ( str(string) + end ) |
---|
458 | f_out.flush () |
---|
459 | |
---|
460 | def str2value ( pz ) : |
---|
461 | ''' |
---|
462 | Tries to convert a string into integer, real, boolean or None |
---|
463 | ''' |
---|
464 | zz = pz |
---|
465 | zz = setBool (zz) |
---|
466 | zz = setNum (zz) |
---|
467 | zz = setNone (zz) |
---|
468 | return zz |
---|
469 | |
---|
470 | def setBool (chars) : |
---|
471 | '''Convert specific char string in boolean if possible''' |
---|
472 | z_set_bool = chars |
---|
473 | if isinstance (chars, str) : |
---|
474 | for key in configparser.ConfigParser.BOOLEAN_STATES.keys () : |
---|
475 | if chars.lower() == key : |
---|
476 | z_set_bool = configparser.ConfigParser.BOOLEAN_STATES[key] |
---|
477 | return z_set_bool |
---|
478 | |
---|
479 | def setNum (chars) : |
---|
480 | '''Convert specific char string in integer or real if possible''' |
---|
481 | if isinstance (chars, str) : |
---|
482 | realnum = re.compile ("^[-+]?[0-9]*\.?[0-9]+(e[-+]?[0-9]+)?$") |
---|
483 | is_number = realnum.match(chars.strip()) != None |
---|
484 | is_int = chars.strip().isdigit() |
---|
485 | if is_number : |
---|
486 | if is_int : zset_num = int (chars) |
---|
487 | else : zset_num = float (chars) |
---|
488 | else : zset_num = chars |
---|
489 | else : |
---|
490 | zset_num = chars |
---|
491 | return zset_num |
---|
492 | |
---|
493 | def setNone (chars) : |
---|
494 | '''Convert specific char string to None if possible''' |
---|
495 | zset_none = chars |
---|
496 | if isinstance (chars, str) : |
---|
497 | if chars in ['None', 'NONE', 'none'] : zset_none = None |
---|
498 | return zset_none |
---|
499 | |
---|
500 | def unDefined (char) : |
---|
501 | '''True if a variable is not defined, or set to None''' |
---|
502 | if char in globals () : |
---|
503 | if globals()[char] is None : |
---|
504 | zun_defined = True |
---|
505 | else : zun_defined = False |
---|
506 | else : zun_defined = True |
---|
507 | return zun_defined |
---|
508 | |
---|
509 | def Defined (char) : |
---|
510 | '''True if a variable is defined and not equal to None''' |
---|
511 | if char in globals () : |
---|
512 | if globals()[char] is None : |
---|
513 | zdefined = False |
---|
514 | else : zdefined = True |
---|
515 | else : zdefined = False |
---|
516 | return zdefined |
---|
517 | |
---|
518 | def Ksum (tab) : |
---|
519 | '''Kahan summation algorithm, also known as compensated summation |
---|
520 | |
---|
521 | https://en.wikipedia.org/wiki/Kahan_summation_algorithm |
---|
522 | ''' |
---|
523 | # Prepare the accumulator. |
---|
524 | ksum = 0.0 |
---|
525 | # A running compensation for lost low-order bits. |
---|
526 | comp = 0.0 |
---|
527 | |
---|
528 | for xx in np.where ( np.isnan(tab), 0., tab ) : |
---|
529 | # comp is zero the first time around. |
---|
530 | yy = xx - comp |
---|
531 | # Alas, sum is big, y small, so low-order digits of y are lost. |
---|
532 | tt = ksum + yy |
---|
533 | # (tt - Ksum) cancels the high-order part of y; subtracting y recovers negative (low part of yy) |
---|
534 | comp = (tt - ksum) - yy |
---|
535 | # Algebraically, comp should always be zero. Beware overly-aggressive optimizing compilers ! |
---|
536 | ksum = tt |
---|
537 | # Next time around, the lost low part will be added to y in a fresh attempt. |
---|
538 | |
---|
539 | return ksum |
---|
540 | |
---|
541 | def Ssum (tab) : |
---|
542 | '''Precision summation by sorting by absolute values''' |
---|
543 | ssum = np.sum ( tab[np.argsort(np.abs(tab))] ) |
---|
544 | return ssum |
---|
545 | |
---|
546 | def KSsum (tab) : |
---|
547 | '''Precision summation by sorting by absolute value, and applying Kahan summation''' |
---|
548 | kssum = Ksum ( tab[np.argsort(np.abs(tab))] ) |
---|
549 | return kssum |
---|
550 | |
---|
551 | # Choosing algorithm for precise summation |
---|
552 | Psum = KSsum |
---|
553 | |
---|
554 | def IsLeapYear ( year, CalendarType="Gregorian" ) : |
---|
555 | '''True is Year is a leap year''' |
---|
556 | year = int ( year ) |
---|
557 | zis_leap_year = None |
---|
558 | |
---|
559 | # What is the calendar : |
---|
560 | if CalendarType in [ '360d', '360_day', 'noleap', '365_day'] : |
---|
561 | zis_leap_year = False |
---|
562 | |
---|
563 | if CalendarType in [ 'all_leap', '366_day' ] : |
---|
564 | zis_leap_year = True |
---|
565 | |
---|
566 | # a year is a leap year if it is even divisible by 4 |
---|
567 | # but not evenly divisible by 100 |
---|
568 | # unless it is evenly divisible by 400 |
---|
569 | |
---|
570 | # if it is evenly divisible by 400 it must be a leap year |
---|
571 | if not zis_leap_year and np.mod ( year, 400 ) == 0 : |
---|
572 | zis_leap_year = True |
---|
573 | |
---|
574 | # if it is evenly divisible by 100 it must not be a leap year |
---|
575 | if not zis_leap_year and np.mod ( year, 100 ) == 0 : |
---|
576 | zis_leap_year = False |
---|
577 | |
---|
578 | # if it is evenly divisible by 4 it must be a leap year |
---|
579 | if not zis_leap_year and np.mod ( year, 4 ) == 0 : |
---|
580 | zis_leap_year = True |
---|
581 | |
---|
582 | if not zis_leap_year : |
---|
583 | zis_leap_year = False |
---|
584 | |
---|
585 | return zis_leap_year |
---|
586 | |
---|
587 | def DateFormat ( date ) : |
---|
588 | '''Get date format : |
---|
589 | |
---|
590 | [yy]yymmdd is Gregorian |
---|
591 | [yy]yy-mm-dd is Human |
---|
592 | ''' |
---|
593 | if isinstance (date, str) : |
---|
594 | if '-' in date : |
---|
595 | zdate_format = 'Human' |
---|
596 | else : |
---|
597 | zdate_format = 'Gregorian' |
---|
598 | if isinstance (date, int) : zdate_format = 'Gregorian' |
---|
599 | return zdate_format |
---|
600 | |
---|
601 | def PrintDate ( ye, mo, da, pformat ) : |
---|
602 | '''Return a date in the requested format |
---|
603 | ''' |
---|
604 | if pformat == 'Human' : zPrintDate = f'{ye:04d}-{mo:02d}-{da:02d}' |
---|
605 | if pformat == 'Gregorian' : zPrintDate = f'{ye:04d}{mo:02d}{da:02d}' |
---|
606 | return zPrintDate |
---|
607 | |
---|
608 | def FormatToGregorian ( date ) : |
---|
609 | '''From a yyyy-mm-dd or yyymmdd date format returns |
---|
610 | a yyymmdd date format |
---|
611 | ''' |
---|
612 | ye, mo, da = SplitDate ( date ) |
---|
613 | return f'{ye:04d}{mo:02d}{da:02d}' |
---|
614 | |
---|
615 | def FormatToHuman ( date ) : |
---|
616 | '''From a yyyymmdd or yyymmdd date format returns |
---|
617 | a yyy-mm-dd date format |
---|
618 | ''' |
---|
619 | ye, mo, da = SplitDate ( date ) |
---|
620 | return f'{ye:04d}-{mo:02d}-{da:02d}' |
---|
621 | |
---|
622 | def SplitDate ( date ) : |
---|
623 | '''Split Date in format [yy]yymmdd or [yy]yy-mm-dd |
---|
624 | to yy, mm, dd ''' |
---|
625 | if isinstance (date, str) : |
---|
626 | if '-' in date : |
---|
627 | ye, mo, da = date.split ('-') |
---|
628 | else : |
---|
629 | ye, mo, da = date[:-4], date[-4:-2], date[-2:] |
---|
630 | if isinstance (date, int) : |
---|
631 | da = np.mod ( date, 100) |
---|
632 | mo = np.mod ( date//100, 100) |
---|
633 | ye = date // 10000 |
---|
634 | |
---|
635 | ye = int(ye) ; mo = int(mo) ; da=int(da) |
---|
636 | return ye, mo, da |
---|
637 | |
---|
638 | def DateAddYear ( date, year_inc=1 ) : |
---|
639 | '''Add on year(s) to date in format [yy]yymmdd or [yy]yy-mm-dd''' |
---|
640 | zformat = DateFormat ( date ) |
---|
641 | ye, mo, da = SplitDate ( date ) |
---|
642 | ye_new = ye + year_inc |
---|
643 | return PrintDate ( ye_new, mo, da, zformat) |
---|
644 | |
---|
645 | def DateMinusOneDay ( date ) : |
---|
646 | '''Substracts one day to date in format [yy]yymmdd or [yy]yy-mm-dd''' |
---|
647 | zformat = DateFormat ( date ) |
---|
648 | mth_length = np.array ( [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] ) |
---|
649 | ye, mo, da = SplitDate ( date ) |
---|
650 | if IsLeapYear ( ye) : mth_length[1] += 1 |
---|
651 | |
---|
652 | ye = int(ye) ; mo = int(mo) ; da=int(da) |
---|
653 | if da == 1 : |
---|
654 | if mo == 1 : |
---|
655 | da_new, mo_new, ye_new = mth_length[-1 ], 12 , ye - 1 |
---|
656 | else : |
---|
657 | da_new, mo_new, ye_new = mth_length[mo-2], mo - 1, ye |
---|
658 | else : |
---|
659 | da_new, mo_new, ye_new = da - 1, mo, ye |
---|
660 | |
---|
661 | return PrintDate ( ye_new, mo_new, da_new, zformat) |
---|
662 | |
---|
663 | def DatePlusOneDay ( date ) : |
---|
664 | '''Add one day to date in format [yy]yymmdd or [yy]yy-mm-dd''' |
---|
665 | zformat = DateFormat ( date ) |
---|
666 | mth_length = np.array ( [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] ) |
---|
667 | ye, mo, da = SplitDate ( date ) |
---|
668 | if IsLeapYear ( ye ) : mth_length[1] += 1 |
---|
669 | |
---|
670 | ye_new = ye |
---|
671 | mo_new = mo |
---|
672 | da_new = da+1 |
---|
673 | if da_new > mth_length [mo_new-1] : |
---|
674 | da_new = 1 |
---|
675 | mo_new = mo_new + 1 |
---|
676 | if mo_new == 13 : |
---|
677 | mo_new = 1 |
---|
678 | ye_new += 1 |
---|
679 | |
---|
680 | return PrintDate ( ye_new, mo_new, da_new, zformat ) |
---|
681 | |
---|
682 | class Timer : |
---|
683 | '''Measures execution time of a function''' |
---|
684 | def __str__ (self): |
---|
685 | return str (self.__class__) |
---|
686 | |
---|
687 | def __name__ (self): |
---|
688 | return self.__class__.__name__ |
---|
689 | |
---|
690 | def __init__ (self, func, debug=False, timer=True) : |
---|
691 | functools.update_wrapper (self, func) |
---|
692 | self.func = func |
---|
693 | self.num_calls = 0 |
---|
694 | self.cumul_time = 0. |
---|
695 | self.debug = debug |
---|
696 | self.timer = timer |
---|
697 | |
---|
698 | def __call__ (self, *args, **kwargs) : |
---|
699 | self.num_calls += 1 |
---|
700 | if self.debug : |
---|
701 | print ( f'>-- Calling {self.__name__} --------------------------------------------------' ) |
---|
702 | args_repr = [f"{repr (a)}" for a in args] |
---|
703 | kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items ()] |
---|
704 | signature = ", ".join (args_repr + kwargs_repr) |
---|
705 | print ( f"Signature : ({signature}") |
---|
706 | start_time = time.perf_counter () |
---|
707 | values = self.func (*args, **kwargs) |
---|
708 | end_time = time.perf_counter () |
---|
709 | run_time = end_time - start_time |
---|
710 | self.cumul_time += run_time |
---|
711 | if self.timer : |
---|
712 | print ( f"--> Calling {self.__name__!r} : {run_time:.3f} secs / cumul {self.cumul_time:.3f} # {self.num_calls:2d} calls") |
---|
713 | if self.debug : |
---|
714 | print ( '<------------------------------------------------------------' ) |
---|
715 | return values |
---|
716 | |
---|