source: TOOLS/WATER_BUDGET/WaterUtils.py @ 6676

Last change on this file since 6676 was 6676, checked in by omamce, 8 months ago

O.M. : WATER_BUDGET

Code restructuration

  • Property svn:keywords set to Date Revision HeadURL Author
File size: 32.1 KB
Line 
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
24import os, sys
25import functools
26import time
27import configparser, re
28import numpy as np
29import libIGCM_sys
30
31def 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   
92def 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
291def 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
414def 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
426def 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   
453def 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
460def 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
470def 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
479def 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
493def 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
500def 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
509def 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
518def 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
541def Ssum (tab) :
542    '''Precision summation by sorting by absolute values'''
543    ssum = np.sum ( tab[np.argsort(np.abs(tab))] )
544    return ssum
545
546def 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
552Psum = KSsum
553
554def 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
587def 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
601def 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
608def 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
615def 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
622def 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
638def 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
645def 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
663def 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
682class 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   
Note: See TracBrowser for help on using the repository browser.