Changeset 6665 for TOOLS


Ignore:
Timestamp:
10/25/23 11:31:03 (6 months ago)
Author:
omamce
Message:

O.M. : WATER BUDGET

Improved code with pylint analysis

Location:
TOOLS/WATER_BUDGET
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • TOOLS/WATER_BUDGET/ATM_waterbudget.py

    r6651 r6665  
    2323### 
    2424## Import system modules 
    25 import sys, os, shutil#, subprocess, platform 
    26 import configparser, re 
     25import sys 
     26import os 
     27import configparser 
    2728 
    2829## Import needed scientific modules 
    29 import numpy as np, xarray as xr 
    30  
    31 # Check python version 
    32 if sys.version_info < (3, 8, 0) : 
    33     print ( f'Python version : {platform.python_version()}' )  
    34     raise Exception ( "Minimum Python version is 3.8" ) 
     30import numpy as np 
     31import xarray as xr 
    3532 
    3633## Import local modules 
    3734import WaterUtils as wu 
    3835import libIGCM_sys 
    39 import nemo, lmdz 
    40  
    41 from WaterUtils import VarInt, Rho, Ra, Grav, ICE_rho_ice, ICE_rho_sno, OCE_rho_liq, ATM_rho, SRF_rho, RUN_rho, ICE_rho_pnd, YearLength 
     36import lmdz 
     37 
     38from WaterUtils import RA, GRAV, ICE_RHO_ICE, ICE_RHO_SNO, \ 
     39                       OCE_RHO_LIQ, ATM_RHO, SRF_RHO, RUN_RHO, ICE_RHO_PND, YEAR_LENGTH 
    4240 
    4341## Creates parser for reading .ini input file 
     
    4846## Experiment parameters 
    4947## --------------------- 
    50 ATM=None ; ATM_HIS='latlon' ; SRF_HIS='latlon' ; RUN_HIS='latlon' ; ORCA=None ; NEMO=None ; OCE_relax=False 
    51 OCE_icb=False ; Coupled=False ; Routing=None ; TestInterp=None 
    52 TarRestartPeriod_beg=None ; TarRestartPeriod_end=None ; Comment=None ; Period=None ; Title=None 
     48JobName=None ; TagName=None ; ExperimentName=None ; SpaceName=None 
     49SRF=True ; RUN=True 
     50ATM=None ; ATM_HIS='latlon' ; SRF_HIS='latlon' ; RUN_HIS='latlon' ; ORCA=None 
     51NEMO=None ; OCE_relax=False 
     52OCE_icb=False ; Coupled=False ; Rsouting=None ; TestInterp=None 
     53TarRestartPeriod_beg=None ; TarRestartPeriod_end=None ; Comment=None 
     54Period=None ; Title=None 
    5355YearBegin=None ; YearEnd=None ; DateBegin=None ; DateEnd=None 
    54  
     56Freq=None ; libIGCM=None ; User=None; Group=None ; Routing=None 
     57PackFrequency = None ; FreqDir=None 
     58 
     59Timer=False ; Debug=False 
    5560## 
    56 ARCHIVE=None ; STORAGE=None ; SCRATCHDIR=None ; R_IN=None ; rebuild=None ; TmpDir=None 
    57 FileDir=None ; FileOut=None 
     61ARCHIVE=None ; STORAGE=None ; SCRATCHDIR=None ; R_IN=None 
     62TmpDir=None ; FileDir=None ; FileOut=None ; R_OUT=None ; R_FIG=None 
     63R_FIGR=None ; R_BUF=None ; R_BUFR=None ; R_SAVE=None 
     64R_BUF_KSH=None ; POST_DIR=None ; L_EXP=None 
     65 
    5866dir_ATM_his=None ; dir_SRF_his=None ; dir_OCE_his=None ; dir_ICE_his=None 
    5967FileCommon=None ; file_ATM_his=None ; file_SRF_his=None ; file_RUN_his=None 
    6068file_OCE_his=None ;  file_ICE_his=None ; file_OCE_sca=None 
    61 tar_restart_beg=None ; tar_restart_end=None ; file_ATM_beg=None ; file_ATM_end=None ; file_DYN_beg=None 
     69tar_restart_beg=None ; tar_restart_end=None ; file_ATM_beg=None 
     70file_ATM_end=None ; file_DYN_beg=None 
    6271file_DYN_end=None ; file_SRF_beg=None ; file_SRF_end=None 
    6372file_RUN_beg=None ; file_RUN_end=None ; file_RUN_end=None ; file_OCE_beg=None 
    6473file_ICE_beg=None ; file_OCE_beg=None 
    6574file_OCE_end=None ; file_ICE_beg=None ; file_OCE_end=None ; file_ICE_end=None 
     75TarRestartDate_beg=None ; TarRestartDate_end=None 
     76file_DYN_aire=None 
    6677tar_restart_beg_ATM=None ; tar_restart_beg_DYN=None ; tar_restart_beg_SRF=None 
    6778tar_restart_beg_RUN=None ; tar_restart_beg_OCE=None ; tar_restart_beg_ICE=None 
    6879tar_restart_end_ATM=None ; tar_restart_end_DYN=None ; tar_restart_end_SRF=None 
    6980tar_restart_end_RUN=None ; tar_restart_end_OCE=None ; tar_restart_end_ICE=None 
    70 ContinueOnError=False ; ErrorCount=0 # ; SortIco = False 
     81ContinueOnError=False ; ErrorCount=0 ; SortIco = False 
     82 
     83FileDirOCE=None ; FileDirATM=None ; FileDirICE=None ; FileDirSRF=None ; FileDirRUN=None 
    7184 
    7285## 
     
    7487## --------------------------------- 
    7588# Default is float (full precision). Degrade the precision by using np.float32 
    76 # Restart file are always read at the full precision 
     89# Restart files are always read at the full precision 
    7790readPrec=float 
    7891 
     
    88101if 'full' in IniFile : FullIniFile = IniFile 
    89102else                 : FullIniFile = 'full_' + IniFile 
    90      
     103 
    91104print ("Input file : ", IniFile ) 
    92105config.read (IniFile) 
     
    109122        MyReader = configparser.ConfigParser (interpolation=configparser.ExtendedInterpolation() ) 
    110123        MyReader.optionxform = str # To keep capitals 
    111          
     124 
    112125        MyReader.read (ConfigCard) 
    113126 
     
    120133                exec  ( f'wu.{VarName} = {VarName}' ) 
    121134                print ( f'    {VarName:21} set to : {locals()[VarName]:}' ) 
    122                  
     135 
    123136        for VarName in ['PackFrequency'] : 
    124137            if VarName in MyReader['Post'].keys() : 
     
    131144    else : 
    132145        raise FileExistsError ( f"File not found : {ConfigCard = }" ) 
    133                  
     146 
    134147## Reading config file 
    135148## ------------------- 
    136 for Section in ['Config', 'Experiment', 'libIGCM', 'Files', 'Physics' ] : 
    137    if Section in config.keys () :  
    138         print ( f'\nReading [{Section}]' ) 
    139         for VarName in config[Section].keys() : 
    140             locals()[VarName] = config[Section][VarName] 
    141             exec  ( f'{VarName} = wu.setBool ({VarName})' ) 
    142             exec  ( f'{VarName} = wu.setNum  ({VarName})' ) 
    143             exec  ( f'{VarName} = wu.setNone ({VarName})' ) 
    144             exec  ( f'wu.{VarName} = {VarName}' ) 
    145             print ( f'    {VarName:21} set to : {locals()[VarName]}' ) 
    146             #exec ( f'del {VarName}' ) 
     149# Each entry in the .ini file will create a Python variable with the same name 
     150for Section in config.keys () :  
     151    print ( f'\nReading [{Section}]' ) 
     152    for VarName in config[Section].keys() : 
     153        locals()[VarName] = config[Section][VarName] 
     154        exec  ( f'{VarName} = wu.setBool ({VarName})' ) 
     155        exec  ( f'{VarName} = wu.setNum  ({VarName})' ) 
     156        exec  ( f'{VarName} = wu.setNone ({VarName})' ) 
     157        exec  ( f'wu.{VarName} = {VarName}' ) 
     158        print ( f'    {VarName:21} set to : {locals()[VarName]}' ) 
    147159 
    148160print ( f'\nConfig file readed : {IniFile} ' ) 
     
    150162## 
    151163## Reading prec 
    152 if wu.unDefined ( 'readPrec' ) : 
     164if readPrec : 
    153165    readPrec = np.float64 
    154166else : 
     
    156168    if readPrec in [         "float32", "r4", "single", "<class 'numpy.float32'>" ] : readPrec = np.float32 
    157169    if readPrec in [         "float16", "r2", "half"  , "<class 'numpy.float16'>" ] : readPrec = np.float16 
    158      
     170 
    159171## Some physical constants 
    160172## ======================= 
    161 if wu.unDefined ( 'Ra' )           : Ra          = wu.Ra           #-- Earth Radius (m) 
    162 if wu.unDefined ( 'Grav' )         : Grav        = wu.Grav         #-- Gravity (m^2/s 
    163 if wu.unDefined ( 'ICE_rho_ice' )  : ICE_rho_ice = wu.ICE_rho_ice  #-- Ice volumic mass (kg/m3) in LIM3 
    164 if wu.unDefined ( 'ICE_rho_sno')   : ICE_rho_sno = wu.ICE_rho_sno  #-- Snow volumic mass (kg/m3) in LIM3 
    165 if wu.unDefined ( 'OCE_rho_liq' )  : OCE_rho_liq = wu.OCE_rho_liq  #-- Ocean water volumic mass (kg/m3) in NEMO 
    166 if wu.unDefined ( 'ATM_rho' )      : ATM_rho     = wu.ATM_rho      #-- Water volumic mass in atmosphere (kg/m^3) 
    167 if wu.unDefined ( 'SRF_rho' )      : SRF_rho     = wu.SRF_rho      #-- Water volumic mass in surface reservoir (kg/m^3) 
    168 if wu.unDefined ( 'RUN_rho' )      : RUN_rho     = wu.RUN_rho      #-- Water volumic mass of rivers (kg/m^3) 
    169 if wu.unDefined ( 'ICE_rho_pnd' )  : ICE_rho_pnd = wu.ICE_rho_pnd  #-- Water volumic mass in ice ponds (kg/m^3) 
    170 if wu.unDefined ( 'YearLength' )   : YearLength  = wu.YearLength   #-- Year length (s) 
    171      
     173if not RA           : RA          = wu.RA           #-- Earth Radius (m) 
     174if not GRAV         : GRAV        = wu.GRAV         #-- Gravity (m^2/s 
     175if not ICE_RHO_ICE  : ICE_RHO_ICE = wu.ICE_RHO_ICE  #-- Ice volumic mass (kg/m3) in LIM3 
     176if not ICE_RHO_SNO  : ICE_RHO_SNO = wu.ICE_RHO_SNO  #-- Snow volumic mass (kg/m3) in LIM3 
     177if not OCE_RHO_LIQ  : OCE_RHO_LIQ = wu.OCE_RHO_LIQ  #-- Ocean water volumic mass (kg/m3) in NEMO 
     178if not ATM_RHO      : ATM_RHO     = wu.ATM_RHO      #-- Water volumic mass in atmosphere (kg/m^3) 
     179if not SRF_RHO      : SRF_RHO     = wu.SRF_RHO      #-- Water volumic mass in surface reservoir (kg/m^3) 
     180if not RUN_RHO      : RUN_RHO     = wu.RUN_RHO      #-- Water volumic mass of rivers (kg/m^3) 
     181if not ICE_RHO_PND  : ICE_RHO_PND = wu.ICE_RHO_PND  #-- Water volumic mass in ice ponds (kg/m^3) 
     182if not YEAR_LENGTH  : YEAR_LENGTH = wu.YEAR_LENGTH  #-- Year length (s) 
     183 
    172184## Set libIGCM and machine dependant values 
    173185## ---------------------------------------- 
    174 if not 'Files' in config.keys () : config['Files'] = {} 
    175  
    176 config['Physics'] = { 'Ra':str(Ra), 'Grav':str(Grav), 'ICE_rho_ice':str(ICE_rho_ice), 'ICE_rho_sno':str(ICE_rho_sno), 
    177                       'OCE_rho_liq':str(OCE_rho_liq), 'ATM_rho':str(ATM_rho), 'SRF_rho':str(SRF_rho), 'RUN_rho':str(RUN_rho)} 
    178  
    179 config['Config'] = { 'ContinueOnError':str(ContinueOnError), 'TestInterp':str(TestInterp), 'readPrec':str(readPrec) } 
     186if 'Files'   not in config.keys () : config['Files']   = {} 
     187if 'Physics' not in config.keys () : config['Physics'] = {} 
     188if 'Config'  not in config.keys () : config['Physics'] = {} 
     189 
     190 
     191config['Physics'].update ( { 'RA':str(RA), 'GRAV':str(GRAV), 'ICE_RHO_ICE':str(ICE_RHO_ICE), 'ICE_RHO_SNO':str(ICE_RHO_SNO), 
     192                             'OCE_RHO_LIQ':str(OCE_RHO_LIQ), 'ATM_RHO':str(ATM_RHO), 'SRF_RHO':str(SRF_RHO), 'RUN_RHO':str(RUN_RHO), 
     193                             'YEAR_LENGTH':str(YEAR_LENGTH)} ) 
     194 
     195config['Config'].update ( { 'ContinueOnError':str(ContinueOnError), 'TestInterp':str(TestInterp), 'readPrec':str(readPrec), 
     196                            'Debug':str(Debug), 'Timer':str(Timer)    } ) 
    180197 
    181198## -------------------------- 
    182 ICO  = ( 'ICO' in wu.ATM ) 
    183 LMDZ = ( 'LMD' in wu.ATM ) 
     199ICO  = 'ICO' in ATM 
     200LMDZ = 'LMD' in ATM 
    184201 
    185202mm = libIGCM_sys.config ( TagName=TagName, SpaceName=SpaceName, ExperimentName=ExperimentName, JobName=JobName, User=User, Group=Group, 
    186              ARCHIVE=None, SCRATCHDIR=None, STORAGE=None, R_IN=None, R_OUT=None, R_FIG=None, rebuild=None, TmpDir=None,  
    187              R_SAVE=None, R_FIGR=None, R_BUFR=None, R_BUF_KSH=None, REBUILD_DIR=None, POST_DIR=None ) 
     203             ARCHIVE=ARCHIVE, SCRATCHDIR=SCRATCHDIR, STORAGE=STORAGE, R_IN=R_IN, R_OUT=R_OUT, R_FIG=R_FIG, TmpDir=TmpDir, 
     204             R_SAVE=R_SAVE, R_FIGR=R_FIGR, R_BUFR=R_BUFR, R_BUF_KSH=R_BUF_KSH, POST_DIR=POST_DIR, L_EXP=L_EXP ) 
    188205globals().update(mm) 
    189206 
    190207config['Files']['TmpDir'] = TmpDir 
    191 config['libIGCM'] = { 'ARCHIVE':ARCHIVE, 'STORAGE':STORAGE, 'TmpDir':TmpDir, 'R_IN':R_IN, 'rebuild':rebuild } 
     208 
     209if 'libIGCM' not in config.keys () : config['libIGCM'] = {} 
     210config['libIGCM'].update ( { 'ARCHIVE':str(ARCHIVE), 'STORAGE':str(STORAGE), 'TmpDir':str(TmpDir), 'R_IN':str(R_IN) } ) 
     211 
     212## Debuging and timer 
     213Timer = wu.functools.partial (wu.Timer, debug=Debug, timer=Timer) 
    192214 
    193215## Defines begining and end of experiment 
    194216## -------------------------------------- 
    195 if wu.unDefined ( 'DateBegin' ) : 
     217if not DateBegin : 
    196218    DateBegin = f'{YearBegin}0101' 
    197219    config['Experiment']['DateBegin'] = str(DateBegin) 
     
    201223    config['Experiment']['YearBegin'] = str(YearBegin) 
    202224 
    203 if wu.unDefined ( 'DateEnd' )   : 
     225if not DateEnd  : 
    204226    DateEnd   = f'{YearEnd}1231' 
    205227    config['Experiment']['DateEnd'] = str(DateEnd) 
     
    209231    config['Experiment']['DateEnd'] = str(DateEnd) 
    210232 
    211 if wu.unDefined ( 'PackFrequency' ) : 
     233if not PackFrequency : 
    212234    PackFrequency = YearEnd - YearBegin + 1 
    213235    config['Experiment']['PackFrequency']   = f'{PackFrequency}' 
    214236 
    215 if type ( PackFrequency ) == str :  
    216     if 'Y' in PackFrequency : PackFrequency = PackFrequency.replace ( 'Y', '')  
     237if isinstance ( PackFrequency, str) : 
     238    if 'Y' in PackFrequency : PackFrequency = PackFrequency.replace ( 'Y', '') 
    217239    if 'M' in PackFrequency : PackFrequency = PackFrequency.replace ( 'M', '') 
    218240    PackFrequency = int ( PackFrequency ) 
    219      
     241 
    220242## Output file with water budget diagnostics 
    221243## ----------------------------------------- 
    222 if wu.unDefined ( 'FileOut' ) : 
     244if not FileOut : 
    223245    FileOut = f'ATM_waterbudget_{JobName}_{YearBegin}_{YearEnd}' 
    224     if ICO :  
     246    if ICO : 
    225247        if ATM_HIS == 'latlon' : FileOut = f'{FileOut}_LATLON' 
    226248        if ATM_HIS == 'ico'    : FileOut = f'{FileOut}_ICO' 
     
    230252config['Files']['FileOut'] = FileOut 
    231253 
    232 f_out = open ( FileOut, mode = 'w' ) 
     254f_out = open ( FileOut, mode = 'w', encoding="utf-8" ) 
    233255 
    234256## Useful functions 
    235257## ---------------- 
    236 if readPrec == float : 
    237     def rprec (tab) : return tab 
     258if repr(readPrec) == "<class 'numpy.float64'>" or readPrec == float : 
     259    def rprec (ptab) : 
     260        '''This version does nothing 
     261 
     262        rprec may be used to reduce floating precision when reading history files 
     263        ''' 
     264        return ptab 
    238265else                 : 
    239     def rprec (tab) : return tab.astype(readPrec).astype(float) 
    240      
    241 def kg2Sv    (val, rho=ATM_rho) : 
     266    def rprec (ptab) : 
     267        '''Returns float with a different precision''' 
     268        return ptab.astype(readPrec).astype(float) 
     269 
     270def kg2Sv    (pval, rho=ATM_RHO) : 
    242271    '''From kg to Sverdrup''' 
    243     return val/dtime_sec*1.0e-6/rho 
    244  
    245 def kg2myear (val, rho=ATM_rho) : 
     272    return pval/dtime_sec*1.0e-6/rho 
     273 
     274def kg2myear (pval, rho=ATM_RHO) : 
    246275    '''From kg to m/year''' 
    247     return val/ATM_aire_sea_tot/rho/NbYear 
    248  
    249 def var2prt (var, small=False, rho=ATM_rho) : 
    250     if small :  return var , kg2Sv(var, rho=rho)*1000., kg2myear(var, rho=rho)*1000 
    251     else     :  return var , kg2Sv(var, rho=rho)      , kg2myear(var, rho=rho) 
    252  
    253 def prtFlux (Desc, var, Form='F', small=False, rho=ATM_rho, width=15) : 
     276    return pval/ATM_aire_sea_tot/rho/NbYear 
     277 
     278def var2prt (pvar, small=False, rho=ATM_RHO) : 
     279    '''Formats value for printing''' 
     280    if small :  return pvar, kg2Sv (pvar, rho=rho)*1000., kg2myear (pvar, rho=rho)*1000 
     281    else     :  return pvar, kg2Sv (pvar, rho=rho)      , kg2myear (pvar, rho=rho) 
     282 
     283def prtFlux (Desc, pvar, Form='F', small=False, rho=ATM_RHO, width=15) : 
     284    '''Pretty print of formattd value''' 
    254285    if small : 
    255286        if Form in ['f', 'F'] : ff=" {:14.6e} kg | {:12.4f} mSv | {:12.4f} mm/year " 
     
    258289        if Form in ['f', 'F'] : ff=" {:14.6e} kg | {:12.4f} Sv  | {:12.4f} m/year  " 
    259290        if Form in ['e', 'E'] : ff=" {:14.6e} kg | {:12.4e} Sv  | {:12.4e} m/year  " 
    260     echo ( (' {:>{width}} = ' +ff).format (Desc, *var2prt(var, small=small, rho=rho), width=width ) ) 
    261     return None 
     291    echo ( (' {:>{width}} = ' +ff).format (Desc, *var2prt (pvar, small=small, rho=rho), width=width ) ) 
    262292 
    263293def echo (string, end='\n') : 
     
    267297    f_out.write ( str(string) + end ) 
    268298    f_out.flush () 
    269     return None 
    270299 
    271300echo ( f'{ContinueOnError = }' ) 
     
    274303echo ( f'{JobName         = }' ) 
    275304echo ( f'{ConfigCard      = }' ) 
    276 echo ( f'{libIGCM         = }' )      
    277 echo ( f'{User            = }' )        
    278 echo ( f'{Group           = }' )        
    279 echo ( f'{Freq            = }' )        
    280 echo ( f'{YearBegin       = }' )      
    281 echo ( f'{YearEnd         = }' )      
     305echo ( f'{libIGCM         = }' ) 
     306echo ( f'{User            = }' ) 
     307echo ( f'{Group           = }' ) 
     308echo ( f'{Freq            = }' ) 
     309echo ( f'{YearBegin       = }' ) 
     310echo ( f'{YearEnd         = }' ) 
    282311echo ( f'{DateBegin       = }' ) 
    283312echo ( f'{DateEnd         = }' ) 
    284 echo ( f'{PackFrequency   = }' )  
    285 echo ( f'{ATM             = }' )        
    286 echo ( f'{Routing         = }' )        
    287 echo ( f'{ORCA            = }' )       
    288 echo ( f'{NEMO            = }' )       
    289 echo ( f'{Coupled         = }' )       
    290 echo ( f'{ATM_HIS         = }' )       
    291 echo ( f'{SRF_HIS         = }' )       
    292 echo ( f'{RUN_HIS         = }' )       
     313echo ( f'{PackFrequency   = }' ) 
     314echo ( f'{ATM             = }' ) 
     315echo ( f'{Routing         = }' ) 
     316echo ( f'{ORCA            = }' ) 
     317echo ( f'{NEMO            = }' ) 
     318echo ( f'{Coupled         = }' ) 
     319echo ( f'{ATM_HIS         = }' ) 
     320echo ( f'{SRF_HIS         = }' ) 
     321echo ( f'{RUN_HIS         = }' ) 
    293322 
    294323## Set libIGCM directories 
    295324## ----------------------- 
    296 if wu.unDefined ('R_OUT'      ) : R_OUT       = os.path.join ( ARCHIVE   , 'IGCM_OUT' ) 
    297 if wu.unDefined ('R_BUF'      ) : R_BUF       = os.path.join ( SCRATCHDIR, 'IGCM_OUT' ) 
    298 if wu.unDefined ('L_EXP'      ) : L_EXP       = os.path.join (TagName, SpaceName, ExperimentName, JobName) 
    299 if wu.unDefined ('R_SAVE'     ) : R_SAVE      = os.path.join ( R_OUT, L_EXP ) 
    300 if wu.unDefined ('R_BUFR'     ) : R_BUFR      = os.path.join ( R_BUF, L_EXP ) 
    301 if wu.unDefined ('POST_DIR'   ) : POST_DIR    = os.path.join ( R_BUFR, 'Out' ) 
    302 if wu.unDefined ('REBUILD_DIR') : REBUILD_DIR = os.path.join ( R_BUFR, 'REBUILD' ) 
    303 if wu.unDefined ('R_BUF_KSH'  ) : R_BUF_KSH   = os.path.join ( R_BUFR, 'Out' ) 
    304 if wu.unDefined ('R_FIGR'     ) : R_FIGR      = os.path.join ( STORAGE, 'IGCM_OUT', L_EXP ) 
    305  
    306 config['libIGCM'].update ( { 'R_OUT':R_OUT, 'R_BUF':R_BUF, 'L_EXP':L_EXP, 'R_BUFR':R_BUFR, 'POST_DIR':POST_DIR, 
    307                       'REBUILD_DIR':REBUILD_DIR, 'R_BUF_KSH':R_BUF_KSH, 'R_FIGR':R_FIGR, 'rebuild':rebuild } ) 
     325if not R_OUT       : R_OUT       = os.path.join ( ARCHIVE   , 'IGCM_OUT' ) 
     326if not R_BUF       : R_BUF       = os.path.join ( SCRATCHDIR, 'IGCM_OUT' ) 
     327if not L_EXP       : 
     328    if TagName and SpaceName and ExperimentName and JobName : L_EXP = os.path.join (TagName, SpaceName, ExperimentName, JobName) 
     329    else : L_EXP = '/' 
     330if not R_SAVE      : R_SAVE      = os.path.join ( R_OUT, L_EXP ) 
     331if not R_BUFR      : R_BUFR      = os.path.join ( R_BUF, L_EXP ) 
     332if not POST_DIR    : POST_DIR    = os.path.join ( R_BUFR, 'Out' ) 
     333if not R_BUF_KSH   : R_BUF_KSH   = os.path.join ( R_BUFR, 'Out' ) 
     334if not R_FIGR      : R_FIGR      = os.path.join ( STORAGE, 'IGCM_OUT', L_EXP ) 
     335 
     336config['libIGCM'].update ( { 'R_OUT':R_OUT, 'R_BUF':R_BUF, 'L_EXP':L_EXP, 'R_BUFR':R_BUFR, 'POST_DIR':POST_DIR, 'R_SAVE':R_SAVE, 
     337                       'R_BUF_KSH':R_BUF_KSH, 'R_FIGR':R_BUFR } ) 
    308338 
    309339## Set directory to extract files 
    310340## ------------------------------ 
    311 if wu.unDefined ( 'FileDir' ) : FileDir = os.path.join ( TmpDir, f'WATER_{JobName}' ) 
     341if not FileDir : FileDir = os.path.join ( TmpDir, f'WATER_{JobName}' ) 
    312342config['Files']['FileDir'] = FileDir 
    313343 
    314344if not os.path.isdir ( FileDir ) : os.makedirs ( FileDir ) 
    315  
    316 ##- Set directories to rebuild ocean and ice restart files 
    317 if wu.unDefined ( 'FileDirOCE' ) : FileDirOCE = os.path.join ( FileDir, 'OCE' ) 
    318 if wu.unDefined ( 'FileDirICE' ) : FileDirICE = os.path.join ( FileDir, 'ICE' ) 
    319 if not os.path.exists ( FileDirOCE ) : os.mkdir ( FileDirOCE ) 
    320 if not os.path.exists ( FileDirICE ) : os.mkdir ( FileDirICE ) 
    321345 
    322346echo (' ') 
     
    325349echo ( f'TmpDir      : {TmpDir}'     ) 
    326350echo ( f'FileDir     : {FileDir}'    ) 
    327 echo ( f'FileDirOCE  : {FileDirOCE}' ) 
    328 echo ( f'FileDirICE  : {FileDirICE}' ) 
    329351 
    330352echo ( f'\nDealing with {L_EXP}'  ) 
     
    334356if Freq == "MO" : FreqDir = os.path.join ('Output' , 'MO' ) 
    335357if Freq == "SE" : FreqDir = os.path.join ('Analyse', 'SE' ) 
    336 if wu.unDefined ('dir_ATM_his' ) : 
     358if not dir_ATM_his : 
    337359    dir_ATM_his = os.path.join ( R_SAVE, "ATM", FreqDir ) 
    338360    config['Files']['dir_ATM_his'] = dir_ATM_his 
    339 if wu.unDefined ( 'dir_SRF_his' ) :  
     361if not dir_SRF_his : 
    340362    dir_SRF_his = os.path.join ( R_SAVE, "SRF", FreqDir ) 
    341363    config['Files']['dir_SRF_his'] = dir_SRF_his 
    342      
    343 echo ( f'The analysis relies on files from the following model output directories : ' ) 
     364 
     365echo (  'The analysis relies on files from the following model output directories : ' ) 
    344366echo ( f'{dir_ATM_his = }' ) 
    345367echo ( f'{dir_SRF_his = }' ) 
    346368 
    347369##-- Creates files names 
    348 if wu.unDefined ( 'Period' ) : 
     370if not Period : 
    349371    if Freq == 'MO' : Period = f'{DateBegin}_{DateEnd}_1M' 
    350372    if Freq == 'SE' : Period = f'SE_{DateBegin}_{DateEnd}_1M' 
     
    353375config['Files']['DateBegin'] = DateBegin 
    354376config['Files']['DateBegin'] = DateEnd 
    355         
     377 
    356378echo ( f'Period   : {Period}' ) 
    357      
    358 if wu.unDefined ( 'FileCommon' ) : 
     379 
     380if not FileCommon : 
    359381    FileCommon = f'{JobName}_{Period}' 
    360382    config['Files']['FileCommon'] = FileCommon 
    361383 
    362 if wu.unDefined ( 'Title' ) : 
     384if not Title : 
    363385    Title = f'{JobName} : {Freq} : {DateBegin} - {DateEnd}' 
    364386    config['Files']['Title'] = Title 
    365       
     387 
    366388echo ('\nOpen history files' ) 
    367 if wu.unDefined ( 'file_ATM_his' ) : 
     389if not file_ATM_his : 
    368390    if ATM_HIS == 'latlon' : 
    369391        file_ATM_his = os.path.join ( dir_ATM_his, f'{FileCommon}_histmth.nc' ) 
     
    371393        file_ATM_his = os.path.join ( dir_ATM_his, f'{FileCommon}_histmth_ico.nc' ) 
    372394    config['Files']['file_ATM_his'] = file_ATM_his 
    373 if wu.unDefined ( 'file_SRF_his' ) : 
     395if not file_SRF_his : 
    374396    if ATM_HIS == 'latlon' : 
    375397        file_SRF_his = os.path.join ( dir_SRF_his, f'{FileCommon}_sechiba_history.nc' ) 
     
    378400    config['Files']['file_SRF_his'] = file_SRF_his 
    379401 
    380 if Routing == 'SIMPLE' : 
    381     if file_RUN_his == None : 
     402if SRF and Routing == 'SIMPLE' : 
     403    if file_RUN_his is None : 
    382404        if ATM_HIS == 'latlon' : 
    383405            file_RUN_his = os.path.join ( dir_SRF_his, f'{FileCommon}_sechiba_history.nc' ) 
     
    387409 
    388410d_ATM_his = xr.open_dataset ( file_ATM_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
    389 d_SRF_his = xr.open_dataset ( file_SRF_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
    390 if Routing == 'SECHIBA' : d_RUN_his = d_SRF_his 
    391 if Routing == 'SIMPLE'  : d_RUN_his = xr.open_dataset ( file_RUN_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
     411if SRF : 
     412    d_SRF_his = xr.open_dataset ( file_SRF_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
     413    if Routing == 'SECHIBA' : d_RUN_his = d_SRF_his 
     414    if Routing == 'SIMPLE'  : d_RUN_his = xr.open_dataset ( file_RUN_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
    392415 
    393416echo ( f'{file_ATM_his = }' ) 
    394 echo ( f'{file_SRF_his = }' ) 
    395 if Routing == 'SIMPLE' : echo ( f'{file_RUN_his = }' ) 
     417if SRF : 
     418    echo ( f'{file_SRF_his = }' ) 
     419    if Routing == 'SIMPLE' : echo ( f'{file_RUN_his = }' ) 
    396420 
    397421## Compute run length 
     
    409433 
    410434##-- Number of years (approximative) 
    411 NbYear = dtime_sec / YearLength 
     435NbYear = dtime_sec / YEAR_LENGTH 
    412436 
    413437##-- Extract restart files from tar 
    414438 
    415 if wu.unDefined ('TarRestartDate_beg' ) : TarRestartDate_beg = wu.DateMinusOneDay ( DateBegin ) 
    416 if wu.unDefined ('TarRestartDate_end' ) : TarRestartDate_end = wu.FormatToGregorian ( DateEnd ) 
    417  
    418 if wu.unDefined ( 'TarRestartPeriod_beg' ) : 
     439if not TarRestartDate_beg : TarRestartDate_beg = wu.DateMinusOneDay ( DateBegin ) 
     440if not TarRestartDate_end : TarRestartDate_end = wu.FormatToGregorian ( DateEnd ) 
     441 
     442if not TarRestartPeriod_beg : 
    419443 
    420444    TarRestartPeriod_beg_DateEnd = TarRestartDate_beg 
    421445    TarRestartPeriod_beg_DateBeg = wu.DateAddYear ( TarRestartPeriod_beg_DateEnd, -PackFrequency ) 
    422446    TarRestartPeriod_beg_DateBeg = wu.DatePlusOneDay ( TarRestartPeriod_beg_DateBeg ) 
    423      
     447 
    424448    TarRestartPeriod_beg = f'{TarRestartPeriod_beg_DateBeg}_{TarRestartPeriod_beg_DateEnd}' 
    425449    echo (f'Tar period for initial restart : {TarRestartPeriod_beg}') 
    426450    config['Files']['TarRestartPeriod_beg'] = TarRestartPeriod_beg 
    427451 
    428 if wu.unDefined ( 'TarRestartPeriod_end' ) : 
     452if not TarRestartPeriod_end : 
    429453 
    430454    TarRestartPeriod_end_DateEnd = TarRestartDate_end 
    431455    TarRestartPeriod_end_DateBeg = wu.DateAddYear ( TarRestartPeriod_end_DateEnd, -PackFrequency ) 
    432456    TarRestartPeriod_end_DateBeg = wu.DatePlusOneDay ( TarRestartPeriod_end_DateBeg ) 
    433       
     457 
    434458    TarRestartPeriod_end = f'{TarRestartPeriod_end_DateBeg}_{TarRestartPeriod_end_DateEnd}' 
    435459    echo (f'Tar period for final restart : {TarRestartPeriod_end}') 
     
    438462echo (f'Restart dates - Start : {TarRestartPeriod_beg}  /  End : {TarRestartPeriod_end}') 
    439463 
    440 if wu.unDefined ( 'tar_restart_beg' ) : 
     464if not tar_restart_beg : 
    441465    tar_restart_beg = os.path.join ( R_SAVE, 'RESTART', f'{JobName}_{TarRestartPeriod_beg}_restart.tar' ) 
    442466    config['Files']['tar_restart_beg'] = tar_restart_beg 
    443 if wu.unDefined ( 'tar_restart_end' ) : 
     467if not tar_restart_end : 
    444468    tar_restart_end = os.path.join ( R_SAVE, 'RESTART', f'{JobName}_{TarRestartPeriod_end}_restart.tar' ) 
    445469    config['Files']['tar_restart_end'] = tar_restart_end 
    446      
     470 
    447471echo ( f'{tar_restart_beg = }' ) 
    448472echo ( f'{tar_restart_end = }' ) 
    449473 
    450474##-- Names of tar files with restarts 
    451 if wu.unDefined ( 'SRF_HIS' ) : SRF_HIS = ATM_HIS 
    452  
    453 if wu.unDefined ( 'tar_restart_beg_ATM' ) : tar_restart_beg_ATM = tar_restart_beg 
    454 if wu.unDefined ( 'tar_restart_beg_DYN' ) : tar_restart_beg_DYN = tar_restart_beg 
    455 if wu.unDefined ( 'tar_restart_beg_SRF' ) : tar_restart_beg_SRF = tar_restart_beg 
    456 if wu.unDefined ( 'tar_restart_beg_RUN' ) : tar_restart_beg_RUN = tar_restart_beg 
    457 if wu.unDefined ( 'tar_restart_beg_OCE' ) : tar_restart_beg_OCE = tar_restart_beg 
    458 if wu.unDefined ( 'tar_restart_beg_ICE' ) : tar_restart_beg_ICE = tar_restart_beg 
    459  
    460 if wu.unDefined ( 'tar_restart_end_ATM' ) : tar_restart_end_ATM = tar_restart_end 
    461 if wu.unDefined ( 'tar_restart_end_DYN' ) : tar_restart_end_DYN = tar_restart_end 
    462 if wu.unDefined ( 'tar_restart_end_SRF' ) : tar_restart_end_SRF = tar_restart_end 
    463 if wu.unDefined ( 'tar_restart_end_RUN' ) : tar_restart_end_RUN = tar_restart_end 
    464 if wu.unDefined ( 'tar_restart_end_OCE' ) : tar_restart_end_OCE = tar_restart_end 
    465 if wu.unDefined ( 'tar_restart_end_ICE' ) : tar_restart_end_ICE = tar_restart_end 
    466  
    467 if wu.unDefined ( 'file_ATM_beg' ) :  
     475 
     476if not tar_restart_beg_ATM : tar_restart_beg_ATM = tar_restart_beg 
     477if not tar_restart_beg_DYN : tar_restart_beg_DYN = tar_restart_beg 
     478if not tar_restart_beg_RUN : tar_restart_beg_RUN = tar_restart_beg 
     479if not tar_restart_beg_OCE : tar_restart_beg_OCE = tar_restart_beg 
     480if not tar_restart_beg_ICE : tar_restart_beg_ICE = tar_restart_beg 
     481 
     482if not tar_restart_end_ATM : tar_restart_end_ATM = tar_restart_end 
     483if not tar_restart_end_DYN : tar_restart_end_DYN = tar_restart_end 
     484if not tar_restart_end_RUN : tar_restart_end_RUN = tar_restart_end 
     485if not tar_restart_end_OCE : tar_restart_end_OCE = tar_restart_end 
     486if not tar_restart_end_ICE : tar_restart_end_ICE = tar_restart_end 
     487 
     488if SRF : 
     489    if not SRF_HIS : SRF_HIS = ATM_HIS 
     490    if not tar_restart_beg_SRF : tar_restart_beg_SRF = tar_restart_beg 
     491    if not tar_restart_end_SRF : tar_restart_end_SRF = tar_restart_end 
     492 
     493if not file_ATM_beg : 
    468494    file_ATM_beg = f'{FileDir}/ATM_{JobName}_{TarRestartDate_beg}_restartphy.nc' 
    469495    config['Files']['file_ATM_beg'] = file_ATM_beg 
    470 if wu.unDefined ( 'file_ATM_end' ) : 
     496if not file_ATM_end : 
    471497    file_ATM_end = f'{FileDir}/ATM_{JobName}_{TarRestartDate_end}_restartphy.nc' 
    472498    config['Files']['file_ATM_end'] = file_ATM_end 
     
    475501liste_end = [file_ATM_end, ] 
    476502 
    477 if wu.unDefined ( 'file_DYN_beg' ) : 
     503if not file_DYN_beg : 
    478504    if LMDZ : file_DYN_beg = f'{FileDir}/ATM_{JobName}_{TarRestartDate_beg}_restart.nc' 
    479505    if ICO  : file_DYN_beg = f'{FileDir}/ICO_{JobName}_{TarRestartDate_beg}_restart.nc' 
    480506    liste_beg.append (file_DYN_beg) 
    481507    config['Files']['file_DYN_beg'] = file_DYN_beg 
    482      
    483 if wu.unDefined ( 'file_DYN_end' ) :  
     508 
     509if not file_DYN_end : 
    484510    if LMDZ : file_DYN_end = f'{FileDir}/ATM_{JobName}_{TarRestartDate_end}_restart.nc' 
    485511    if ICO  : file_DYN_end = f'{FileDir}/ICO_{JobName}_{TarRestartDate_end}_restart.nc' 
     
    487513    config['Files']['file_DYN_end'] = file_DYN_end 
    488514 
    489 if wu.unDefined ( 'file_SRF_beg' ) : 
    490     file_SRF_beg = f'{FileDir}/SRF_{JobName}_{TarRestartDate_beg}_sechiba_rest.nc' 
    491     config['Files']['file_SRF_beg'] = file_SRF_beg 
    492 if wu.unDefined ( 'file_SRF_end' ) : 
    493     file_SRF_end = f'{FileDir}/SRF_{JobName}_{TarRestartDate_end}_sechiba_rest.nc' 
    494     config['Files']['file_SRF_end'] = file_SRF_end 
    495      
     515if SRF : 
     516    if not file_SRF_beg : 
     517        file_SRF_beg = f'{FileDir}/SRF_{JobName}_{TarRestartDate_beg}_sechiba_rest.nc' 
     518        config['Files']['file_SRF_beg'] = file_SRF_beg 
     519    if not file_SRF_end : 
     520        file_SRF_end = f'{FileDir}/SRF_{JobName}_{TarRestartDate_end}_sechiba_rest.nc' 
     521        config['Files']['file_SRF_end'] = file_SRF_end 
     522 
    496523liste_beg.append ( file_SRF_beg ) 
    497524liste_end.append ( file_SRF_end ) 
     
    501528echo ( f'{file_DYN_beg = }') 
    502529echo ( f'{file_DYN_end = }') 
    503 echo ( f'{file_SRF_beg = }') 
    504 echo ( f'{file_SRF_end = }') 
     530if SRF : 
     531    echo ( f'{file_SRF_beg = }') 
     532    echo ( f'{file_SRF_end = }') 
    505533 
    506534if ICO : 
    507     if wu.unDefined ('file_DYN_aire') : file_DYN_aire = os.path.join ( R_IN, 'ATM', 'GRID', ATM+'_grid.nc' ) 
     535    if not file_DYN_aire : file_DYN_aire = os.path.join ( R_IN, 'ATM', 'GRID', ATM+'_grid.nc' ) 
    508536    config['Files']['file_DYN_aire'] = file_DYN_aire 
    509537 
    510 if Routing == 'SIMPLE' : 
    511     if wu.unDefined ( 'file_RUN_beg' ) :  
     538if SRF and Routing == 'SIMPLE' : 
     539    if not file_RUN_beg : 
    512540        file_RUN_beg = f'{FileDir}/SRF_{JobName}_{TarRestartDate_beg}_routing_restart.nc' 
    513541        config['Files']['file_RUN_beg'] = file_RUN_beg 
    514     if wu.unDefined ( 'file_RUN_end' ) :  
     542    if not file_RUN_end : 
    515543        file_RUN_end = f'{FileDir}/SRF_{JobName}_{TarRestartDate_end}_routing_restart.nc' 
    516544        config['Files']['file_RUN_end'] = file_RUN_end 
    517          
     545 
    518546    liste_beg.append ( file_RUN_beg ) 
    519547    liste_end.append ( file_RUN_end ) 
     
    521549    echo ( f'{file_RUN_end = }' ) 
    522550 
    523 echo ('\nExtract restart files from tar : ATM, ICO and SRF') 
    524  
    525 def extract_and_rebuild ( file_name=file_ATM_beg, tar_restart=tar_restart_end, FileDirComp=FileDir, ErrorCount=ErrorCount ) : 
     551echo ('\nExtract restart files from tar : ATM, ICO', end='') 
     552if SRF : echo ( ' and SRF') 
     553else   : echo (' ') 
     554 
     555    
     556@Timer 
     557def extract ( file_name=file_ATM_beg, tar_restart=tar_restart_end, file_dir_comp=FileDir, error_count=ErrorCount ) : 
     558    ''' 
     559    Extract restart files from a tar 
     560    ''' 
    526561    echo ( f'----------') 
    527562    echo ( f'file to extract : {file_name = }' ) 
     
    532567        base_resFile = os.path.basename (file_name) 
    533568        if os.path.exists ( tar_restart ) : 
    534             command =  f'cd {FileDir} ; tar xf {tar_restart} {base_resFile}' 
     569            command =  f'cd {file_dir_comp} ; tar xf {tar_restart} {base_resFile}' 
    535570            echo ( f'{command = }' ) 
    536571            try : os.system ( command ) 
    537572            except : 
    538573                if ContinueOnError : 
    539                     ErrorCount += 1 
    540                     echo ( f'****** Command failed : {command}' ) 
    541                     echo ( f'****** Trying to continue' ) 
     574                    error_count += 1 
     575                    echo ( '****** Command failed : {command}' ) 
     576                    echo ( '****** Trying to continue' ) 
    542577                    echo ( ' ') 
    543578                else : 
    544                     raise Exception ( f'**** command failed : {command} - Stopping' ) 
     579                    raise OSError ( f'**** command failed : {command} - Stopping' ) 
    545580            else : 
    546581                echo ( f'tar done : {base_resFile}' ) 
     
    548583            echo ( f'****** Tar restart file {tar_restart = } not found ' ) 
    549584            if ContinueOnError : 
    550                 ErrorCount += 1 
    551             else :  
    552                 raise Exception ( f'****** tar file not found {tar_restart = } - Stopping' ) 
    553     return ErrorCount 
    554   
    555 ErrorCount += extract_and_rebuild ( file_name=file_ATM_beg, tar_restart=tar_restart_beg_ATM, FileDirComp=FileDir ) 
    556 ErrorCount += extract_and_rebuild ( file_name=file_DYN_beg, tar_restart=tar_restart_beg_DYN, FileDirComp=FileDir ) 
    557 ErrorCount += extract_and_rebuild ( file_name=file_SRF_beg, tar_restart=tar_restart_beg_SRF, FileDirComp=FileDir ) 
    558  
    559 ErrorCount += extract_and_rebuild ( file_name=file_ATM_end, tar_restart=tar_restart_end_ATM, FileDirComp=FileDir ) 
    560 ErrorCount += extract_and_rebuild ( file_name=file_DYN_end, tar_restart=tar_restart_end_DYN, FileDirComp=FileDir ) 
    561 ErrorCount += extract_and_rebuild ( file_name=file_SRF_end, tar_restart=tar_restart_end_SRF, FileDirComp=FileDir ) 
    562  
    563 if Routing == 'SIMPLE' : 
    564     ErrorCount += extract_and_rebuild ( file_name=file_RUN_beg, tar_restart=tar_restart_beg_RUN, FileDirComp=FileDir ) 
    565     ErrorCount += extract_and_rebuild ( file_name=file_RUN_end, tar_restart=tar_restart_end_RUN, FileDirComp=FileDir ) 
     585                error_count += 1 
     586            else : 
     587                raise OSError ( f'****** tar file not found {tar_restart = } - Stopping' ) 
     588    return error_count 
     589 
     590ErrorCount += extract ( file_name=file_ATM_beg, tar_restart=tar_restart_beg_ATM, file_dir_comp=FileDir, error_count=ErrorCount ) 
     591ErrorCount += extract ( file_name=file_DYN_beg, tar_restart=tar_restart_beg_DYN, file_dir_comp=FileDir, error_count=ErrorCount ) 
     592 
     593ErrorCount += extract ( file_name=file_ATM_end, tar_restart=tar_restart_end_ATM, file_dir_comp=FileDir, error_count=ErrorCount ) 
     594ErrorCount += extract ( file_name=file_DYN_end, tar_restart=tar_restart_end_DYN, file_dir_comp=FileDir, error_count=ErrorCount ) 
     595 
     596if SRF : 
     597    ErrorCount += extract ( file_name=file_SRF_beg, tar_restart=tar_restart_beg_SRF, file_dir_comp=FileDir, error_count=ErrorCount ) 
     598    ErrorCount += extract ( file_name=file_SRF_end, tar_restart=tar_restart_end_SRF, file_dir_comp=FileDir, error_count=ErrorCount ) 
     599 
     600    if Routing == 'SIMPLE' : 
     601        ErrorCount += extract ( file_name=file_RUN_beg, tar_restart=tar_restart_beg_RUN, file_dir_comp=FileDir, error_count=ErrorCount ) 
     602        ErrorCount += extract ( file_name=file_RUN_end, tar_restart=tar_restart_end_RUN, file_dir_comp=FileDir, error_count=ErrorCount ) 
    566603 
    567604##-- Exit in case of error in the opening file phase 
    568605if ErrorCount > 0 : 
    569606    echo ( '  ' ) 
    570     raise Exception ( f'**** Some files missing - Stopping - {ErrorCount = }' ) 
    571  
    572 ##  
     607    raise RuntimeError ( f'**** Some files missing - Stopping - {ErrorCount = }' ) 
     608 
     609## 
    573610echo ('\nOpening ATM SRF and ICO restart files') 
    574611d_ATM_beg = xr.open_dataset ( os.path.join (FileDir, file_ATM_beg), decode_times=False, decode_cf=True ).squeeze() 
    575612d_ATM_end = xr.open_dataset ( os.path.join (FileDir, file_ATM_end), decode_times=False, decode_cf=True ).squeeze() 
    576 d_SRF_beg = xr.open_dataset ( os.path.join (FileDir, file_SRF_beg), decode_times=False, decode_cf=True ).squeeze() 
    577 d_SRF_end = xr.open_dataset ( os.path.join (FileDir, file_SRF_end), decode_times=False, decode_cf=True ).squeeze() 
     613if SRF : 
     614    d_SRF_beg = xr.open_dataset ( os.path.join (FileDir, file_SRF_beg), decode_times=False, decode_cf=True ).squeeze() 
     615    d_SRF_end = xr.open_dataset ( os.path.join (FileDir, file_SRF_end), decode_times=False, decode_cf=True ).squeeze() 
    578616d_DYN_beg = xr.open_dataset ( os.path.join (FileDir, file_DYN_beg), decode_times=False, decode_cf=True ).squeeze() 
    579617d_DYN_end = xr.open_dataset ( os.path.join (FileDir, file_DYN_end), decode_times=False, decode_cf=True ).squeeze() 
    580618 
    581 for var in d_SRF_beg.variables : 
    582     d_SRF_beg[var] = d_SRF_beg[var].where ( d_SRF_beg[var]<1.e20, 0.) 
    583     d_SRF_end[var] = d_SRF_end[var].where ( d_SRF_end[var]<1.e20, 0.) 
    584  
    585 if Routing == 'SIMPLE' : 
    586     d_RUN_beg = xr.open_dataset ( os.path.join (FileDir, file_RUN_beg), decode_times=False, decode_cf=True ).squeeze() 
    587     d_RUN_end = xr.open_dataset ( os.path.join (FileDir, file_RUN_end), decode_times=False, decode_cf=True ).squeeze() 
    588  
     619if SRF : 
     620    for var in d_SRF_beg.variables : 
     621        d_SRF_beg[var] = d_SRF_beg[var].where ( d_SRF_beg[var]<1.e20, 0.) 
     622        d_SRF_end[var] = d_SRF_end[var].where ( d_SRF_end[var]<1.e20, 0.) 
     623 
     624    if Routing == 'SIMPLE' : 
     625        d_RUN_beg = xr.open_dataset ( os.path.join (FileDir, file_RUN_beg), decode_times=False, decode_cf=True ).squeeze() 
     626        d_RUN_end = xr.open_dataset ( os.path.join (FileDir, file_RUN_end), decode_times=False, decode_cf=True ).squeeze() 
     627 
     628@Timer 
    589629def to_cell ( dd, newname='cell' ) : 
    590     '''Set space dimension to 'cell' ''' 
     630    '''Set space dimension to newname 
     631    ''' 
    591632    for oldname in [ 'cell_mesh', 'y', 'points_physiques' ] : 
    592         try    : dd = dd.rename ( {oldname : newname} ) 
    593         except : pass 
     633        if oldname in dd.dims and oldname != newname : 
     634            dd = dd.rename ( {oldname : newname} ) 
    594635    return dd 
    595636 
    596637d_ATM_beg = to_cell ( d_ATM_beg ) 
    597638d_ATM_end = to_cell ( d_ATM_end ) 
    598 d_SRF_beg = to_cell ( d_SRF_beg ) 
    599 d_SRF_end = to_cell ( d_SRF_end ) 
     639if SRF : 
     640    d_SRF_beg = to_cell ( d_SRF_beg ) 
     641    d_SRF_end = to_cell ( d_SRF_end ) 
    600642d_DYN_beg = to_cell ( d_DYN_beg ) 
    601643d_DYN_end = to_cell ( d_DYN_end ) 
    602644 
    603 if Routing == 'SIMPLE' : 
     645if SRF and Routing == 'SIMPLE' : 
    604646    d_RUN_beg = to_cell ( d_RUN_beg ) 
    605647    d_RUN_end = to_cell ( d_RUN_end ) 
    606648 
    607649d_ATM_his = to_cell ( d_ATM_his ) 
    608 d_SRF_his = to_cell ( d_SRF_his ) 
    609      
     650if SRF : d_SRF_his = to_cell ( d_SRF_his ) 
     651 
    610652echo ( f'{file_ATM_beg = }' ) 
    611653echo ( f'{file_ATM_end = }' ) 
    612654echo ( f'{file_DYN_beg = }' ) 
    613655echo ( f'{file_DYN_end = }' ) 
    614 echo ( f'{file_SRF_beg = }' ) 
    615 echo ( f'{file_SRF_end = }' ) 
    616 if Routing == 'SIMPLE' : 
    617     echo ( f'{file_RUN_beg = }' ) 
    618     echo ( f'{file_RUN_end = }' ) 
     656if SRF : 
     657    echo ( f'{file_SRF_beg = }' ) 
     658    echo ( f'{file_SRF_end = }' ) 
     659    if Routing == 'SIMPLE' : 
     660        echo ( f'{file_RUN_beg = }' ) 
     661        echo ( f'{file_RUN_end = }' ) 
    619662 
    620663## Write the full configuration 
    621 config_out = open (FullIniFile, 'w') 
     664config_out = open (FullIniFile, 'w', encoding = 'utf-8') 
    622665config.write ( config_out ) 
    623666config_out.close () 
     
    626669if LMDZ : 
    627670    echo ('ATM grid with cell surfaces : LMDZ') 
    628     ATM_lat       = lmdz.geo2point (   rprec (d_ATM_his ['lat'])+0*rprec (d_ATM_his ['lon']), dim1D='cell' ) 
    629     ATM_lon       = lmdz.geo2point ( 0*rprec (d_ATM_his ['lat'])+  rprec (d_ATM_his ['lon']), dim1D='cell' ) 
    630     ATM_aire      = lmdz.geo2point ( rprec (d_ATM_his ['aire']     [0]), cumulPoles=True, dim1D='cell' ) 
    631     ATM_fter      = lmdz.geo2point ( rprec (d_ATM_his ['fract_ter'][0]), dim1D='cell' ) 
    632     ATM_foce      = lmdz.geo2point ( rprec (d_ATM_his ['fract_oce'][0]), dim1D='cell' ) 
    633     ATM_fsic      = lmdz.geo2point ( rprec (d_ATM_his ['fract_sic'][0]), dim1D='cell' ) 
    634     ATM_flic      = lmdz.geo2point ( rprec (d_ATM_his ['fract_lic'][0]), dim1D='cell' ) 
    635     SRF_lat       = lmdz.geo2point (   rprec (d_SRF_his ['lat'])+0*rprec (d_SRF_his ['lon']), dim1D='cell' ) 
    636     SRF_lon       = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat'])+  rprec (d_SRF_his ['lon']), dim1D='cell' ) 
    637     SRF_aire      = lmdz.geo2point ( rprec (d_SRF_his ['Areas']) * rprec (d_SRF_his ['Contfrac']), dim1D='cell', cumulPoles=True ) 
    638     SRF_areas     = lmdz.geo2point ( rprec (d_SRF_his ['Areas'])  ,  dim1D='cell', cumulPoles=True ) 
    639     SRF_contfrac  = lmdz.geo2point ( rprec (d_SRF_his ['Contfrac']), dim1D='cell' ) 
     671    ATM_lat       = lmdz.geo2point (   rprec (d_ATM_his ['lat'])+0*rprec (d_ATM_his ['lon']), dim1d='cell' ) 
     672    ATM_lon       = lmdz.geo2point ( 0*rprec (d_ATM_his ['lat'])+  rprec (d_ATM_his ['lon']), dim1d='cell' ) 
     673    ATM_aire      = lmdz.geo2point ( rprec (d_ATM_his ['aire']     [0]), cumul_poles=True, dim1d='cell' ) 
     674    ATM_fter      = lmdz.geo2point ( rprec (d_ATM_his ['fract_ter'][0]), dim1d='cell' ) 
     675    ATM_foce      = lmdz.geo2point ( rprec (d_ATM_his ['fract_oce'][0]), dim1d='cell' ) 
     676    ATM_fsic      = lmdz.geo2point ( rprec (d_ATM_his ['fract_sic'][0]), dim1d='cell' ) 
     677    ATM_flic      = lmdz.geo2point ( rprec (d_ATM_his ['fract_lic'][0]), dim1d='cell' ) 
     678    if SRF : 
     679        SRF_lat       = lmdz.geo2point (   rprec (d_SRF_his ['lat'])+0*rprec (d_SRF_his ['lon']), dim1d='cell' ) 
     680        SRF_lon       = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat'])+  rprec (d_SRF_his ['lon']), dim1d='cell' ) 
     681        SRF_aire      = lmdz.geo2point ( rprec (d_SRF_his ['Areas']) * rprec (d_SRF_his ['Contfrac']), dim1d='cell', cumul_poles=True ) 
     682        SRF_areas     = lmdz.geo2point ( rprec (d_SRF_his ['Areas'])  ,  dim1d='cell', cumul_poles=True ) 
     683        SRF_contfrac  = lmdz.geo2point ( rprec (d_SRF_his ['Contfrac']), dim1d='cell' ) 
    640684 
    641685if ICO : 
     
    643687        echo ( 'ATM areas and fractions on latlon grid' ) 
    644688        if 'lat_dom_out' in d_ATM_his.variables : 
    645             ATM_lat  = lmdz.geo2point (   rprec (d_ATM_his ['lat_dom_out'])+0*rprec (d_ATM_his ['lon_dom_out']), dim1D='cell' ) 
    646             ATM_lon  = lmdz.geo2point ( 0*rprec (d_ATM_his ['lat_dom_out'])+  rprec (d_ATM_his ['lon_dom_out']), dim1D='cell' ) 
     689            ATM_lat  = lmdz.geo2point (   rprec (d_ATM_his ['lat_dom_out'])+0*rprec (d_ATM_his ['lon_dom_out']), dim1d='cell' ) 
     690            ATM_lon  = lmdz.geo2point ( 0*rprec (d_ATM_his ['lat_dom_out'])+  rprec (d_ATM_his ['lon_dom_out']), dim1d='cell' ) 
    647691        else : 
    648             ATM_lat  = lmdz.geo2point (   rprec (d_ATM_his ['lat'])+0*rprec (d_ATM_his ['lon']), dim1D='cell' ) 
    649             ATM_lon  = lmdz.geo2point ( 0*rprec (d_ATM_his ['lat'])+  rprec (d_ATM_his ['lon']), dim1D='cell' ) 
    650         ATM_aire = lmdz.geo2point ( rprec (d_ATM_his ['aire'][0]).squeeze(), cumulPoles=True, dim1D='cell' ) 
    651         ATM_fter = lmdz.geo2point ( rprec (d_ATM_his ['fract_ter'][0]), dim1D='cell' ) 
    652         ATM_foce = lmdz.geo2point ( rprec (d_ATM_his ['fract_oce'][0]), dim1D='cell' ) 
    653         ATM_fsic = lmdz.geo2point ( rprec (d_ATM_his ['fract_sic'][0]), dim1D='cell' ) 
    654         ATM_flic = lmdz.geo2point ( rprec (d_ATM_his ['fract_lic'][0]), dim1D='cell' ) 
     692            ATM_lat  = lmdz.geo2point (   rprec (d_ATM_his ['lat'])+0*rprec (d_ATM_his ['lon']), dim1d='cell' ) 
     693            ATM_lon  = lmdz.geo2point ( 0*rprec (d_ATM_his ['lat'])+  rprec (d_ATM_his ['lon']), dim1d='cell' ) 
     694        ATM_aire = lmdz.geo2point ( rprec (d_ATM_his ['aire'][0]).squeeze(), cumul_poles=True, dim1d='cell' ) 
     695        ATM_fter = lmdz.geo2point ( rprec (d_ATM_his ['fract_ter'][0]), dim1d='cell' ) 
     696        ATM_foce = lmdz.geo2point ( rprec (d_ATM_his ['fract_oce'][0]), dim1d='cell' ) 
     697        ATM_fsic = lmdz.geo2point ( rprec (d_ATM_his ['fract_sic'][0]), dim1d='cell' ) 
     698        ATM_flic = lmdz.geo2point ( rprec (d_ATM_his ['fract_lic'][0]), dim1d='cell' ) 
    655699 
    656700    if ATM_HIS == 'ico' : 
     
    664708        ATM_flic =  rprec (d_ATM_his ['fract_lic'][0]) 
    665709 
    666     if SRF_HIS == 'latlon' : 
    667         echo ( 'SRF areas and fractions on latlon grid' ) 
    668         if 'lat_domain_landpoints_out' in d_SRF_his  :  
    669             SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat_domain_landpoints_out'])+0*rprec (d_SRF_his ['lon_domain_landpoints_out']), dim1D='cell' ) 
    670             SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat_domain_landpoints_out'])+  rprec (d_SRF_his ['lon_domain_landpoints_out']), dim1D='cell' ) 
    671         else :  
    672             if 'lat_domain_landpoints_out' in d_SRF_his : 
    673                 SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat_dom_out'])+0*rprec (d_SRF_his ['lon_dom_out']), dim1D='cell' ) 
    674                 SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat_dom_out'])+  rprec (d_SRF_his ['lon_dom_out']), dim1D='cell' ) 
     710    if SRF : 
     711        if SRF_HIS == 'latlon' : 
     712            echo ( 'SRF areas and fractions on latlon grid' ) 
     713            if 'lat_domain_landpoints_out' in d_SRF_his  : 
     714                SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat_domain_landpoints_out'])+0*rprec (d_SRF_his ['lon_domain_landpoints_out']), dim1d='cell' ) 
     715                SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat_domain_landpoints_out'])+  rprec (d_SRF_his ['lon_domain_landpoints_out']), dim1d='cell' ) 
    675716            else : 
    676                 SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat'])+0*rprec (d_SRF_his ['lon']), dim1D='cell' ) 
    677                 SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat'])+  rprec (d_SRF_his ['lon']), dim1D='cell' ) 
    678                  
    679         SRF_areas     = lmdz.geo2point ( rprec (d_SRF_his ['Areas']   )   , dim1D='cell', cumulPoles=True ) 
    680         SRF_areafrac  = lmdz.geo2point ( rprec (d_SRF_his ['AreaFrac'])   , dim1D='cell', cumulPoles=True ) 
    681         SRF_contfrac  = lmdz.geo2point ( rprec (d_SRF_his ['Contfrac'])   , dim1D='cell', cumulPoles=True ) 
    682         SRF_aire = SRF_areafrac 
    683   
    684     if SRF_HIS == 'ico' : 
    685         echo ( 'SRF areas and fractions on latlon grid' ) 
    686         SRF_lat       =  rprec (d_SRF_his ['lat']     ) 
    687         SRF_lon       =  rprec (d_SRF_his ['lon']     ) 
    688         SRF_areas     =  rprec (d_SRF_his ['Areas']   )  
    689         SRF_contfrac  =  rprec (d_SRF_his ['Contfrac']) 
    690         SRF_aire      =  SRF_areas * SRF_contfrac 
     717                if 'lat_domain_landpoints_out' in d_SRF_his : 
     718                    SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat_dom_out'])+0*rprec (d_SRF_his ['lon_dom_out']), dim1d='cell' ) 
     719                    SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat_dom_out'])+  rprec (d_SRF_his ['lon_dom_out']), dim1d='cell' ) 
     720                else : 
     721                    SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat'])+0*rprec (d_SRF_his ['lon']), dim1d='cell' ) 
     722                    SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat'])+  rprec (d_SRF_his ['lon']), dim1d='cell' ) 
     723 
     724            SRF_areas     = lmdz.geo2point ( rprec (d_SRF_his ['Areas']   )   , dim1d='cell', cumul_poles=True ) 
     725            SRF_areafrac  = lmdz.geo2point ( rprec (d_SRF_his ['AreaFrac'])   , dim1d='cell', cumul_poles=True ) 
     726            SRF_contfrac  = lmdz.geo2point ( rprec (d_SRF_his ['Contfrac'])   , dim1d='cell', cumul_poles=True ) 
     727            SRF_aire = SRF_areafrac 
     728 
     729        if SRF_HIS == 'ico' : 
     730            echo ( 'SRF areas and fractions on latlon grid' ) 
     731            SRF_lat       =  rprec (d_SRF_his ['lat']     ) 
     732            SRF_lon       =  rprec (d_SRF_his ['lon']     ) 
     733            SRF_areas     =  rprec (d_SRF_his ['Areas']   ) 
     734            SRF_contfrac  =  rprec (d_SRF_his ['Contfrac']) 
     735            SRF_aire      =  SRF_areas * SRF_contfrac 
    691736 
    692737ATM_fsea      = ATM_foce + ATM_fsic 
     
    702747 
    703748## Write the full configuration 
    704 config_out = open (FullIniFile, 'w') 
     749config_out = open (FullIniFile, 'w', encoding='utf-8') 
    705750config.write ( config_out ) 
    706751config_out.close () 
    707              
     752 
    708753if ICO : 
    709754    # Area on icosahedron grid 
    710755    d_DYN_aire = xr.open_dataset ( file_DYN_aire, decode_times=False ).squeeze() 
    711756 
    712     if SortIco :  
     757    if SortIco : 
    713758        # Creation d'une clef de tri pour le fichier aire 
    714759        DYN_aire_keysort = np.lexsort ( (d_DYN_aire['lat'], d_DYN_aire['lon']) ) 
    715     else :  
     760    else : 
    716761        DYN_aire_keysort = np.arange ( len ( d_DYN_aire['lat'] ) ) 
    717              
     762 
    718763    DYN_lat = d_DYN_aire['lat'] 
    719764    DYN_lon = d_DYN_aire['lon'] 
     
    725770    DYN_flic = d_ATM_beg['FLIC'] 
    726771    DYN_aire_fter = DYN_aire * DYN_fter 
    727      
     772 
    728773if LMDZ : 
    729774    # Area on lon/lat grid 
     
    736781 
    737782# Functions computing integrals and sum 
     783@Timer 
    738784def DYN_stock_int (stock) : 
    739785    '''Integrate (* surface) stock on atmosphere grid''' 
    740     DYN_stock_int  = wu.Psum ( (stock * DYN_aire).to_masked_array().ravel() )  
    741     return DYN_stock_int 
    742  
     786    return wu.Psum ( (stock * DYN_aire).to_masked_array().ravel() ) 
     787 
     788@Timer 
    743789def ATM_flux_int (flux) : 
    744790    '''Integrate (* time * surface) flux on atmosphere grid''' 
    745     ATM_flux_int  = wu.Psum ( (flux * dtime_per_sec * ATM_aire).to_masked_array().ravel() ) 
    746     return ATM_flux_int 
    747  
     791    return wu.Psum ( (flux * dtime_per_sec * ATM_aire).to_masked_array().ravel() ) 
     792 
     793@Timer 
    748794def LIC_flux_int (flux) : 
    749795    '''Integrate (* time * surface) flux on land ice grid''' 
    750     LIC_flux_int  = wu.Psum ( (flux * dtime_per_sec * ATM_aire_flic).to_masked_array().ravel() ) 
    751     return LIC_flux_int 
    752  
    753 def SRF_stock_int (stock) : 
    754     '''Integrate (* surface) stock on land grid''' 
    755     SRF_stock_int  = wu.Ksum (  ( (stock * DYN_aire_fter).to_masked_array().ravel()) ) 
    756     return SRF_stock_int 
    757  
    758 def SRF_flux_int (flux) : 
    759     '''Integrate (* time * surface) flux on land grid''' 
    760     SRF_flux_int  = wu.Psum (  (flux * dtime_per_sec * SRF_aire).to_masked_array().ravel() ) 
    761     return SRF_flux_int 
    762  
     796    return wu.Psum ( (flux * dtime_per_sec * ATM_aire_flic).to_masked_array().ravel() ) 
     797 
     798if SRF : 
     799    @Timer 
     800    def SRF_stock_int (stock) : 
     801        '''Integrate (* surface) stock on land grid''' 
     802        return wu.Ksum (  ( (stock * DYN_aire_fter).to_masked_array().ravel()) ) 
     803 
     804    @Timer 
     805    def SRF_flux_int (flux) : 
     806        '''Integrate (* time * surface) flux on land grid''' 
     807        return wu.Psum (  (flux * dtime_per_sec * SRF_aire).to_masked_array().ravel() ) 
     808 
     809@Timer 
    763810def ONE_stock_int (stock) : 
    764811    '''Sum stock ''' 
    765     ONE_stock_int  = wu.Psum ( stock.to_masked_array().ravel() ) 
    766     return ONE_stock_int 
    767  
     812    return wu.Psum ( stock.to_masked_array().ravel() ) 
     813 
     814@Timer 
    768815def ONE_flux_int (flux) : 
    769816    '''Integrate (* time) flux on area=1 grid ''' 
    770     ONE_flux_int  = wu.Psum ( (flux * dtime_per_sec ).to_masked_array().ravel() ) 
    771     return ONE_flux_int 
    772  
     817    return wu.Psum ( (flux * dtime_per_sec ).to_masked_array().ravel() ) 
     818 
     819@Timer 
    773820def Sprec ( tlist ) : 
    774821    '''Accurate sum of list of scalar elements''' 
     
    783830 
    784831DYN_aire_tot     = ONE_stock_int ( DYN_aire ) 
    785 SRF_aire_tot     = ONE_stock_int ( SRF_aire ) 
     832if SRF : SRF_aire_tot     = ONE_stock_int ( SRF_aire ) 
    786833 
    787834echo ('') 
     
    790837echo ( f'ATM HIS : Area of ter in atmosphere : {ATM_aire_ter_tot:18.9e}' ) 
    791838echo ( f'ATM HIS : Area of lic in atmosphere : {ATM_aire_lic_tot:18.9e}' ) 
    792 echo ( f'ATM SRF : Area of atmosphere        : {SRF_aire_tot:18.9e}' ) 
     839if SRF : 
     840    echo ( f'ATM SRF : Area of atmosphere        : {SRF_aire_tot:18.9e}' ) 
    793841echo ('') 
    794 echo ( 'ATM DYN : Area of atmosphere/(4pi R^2)        : {:18.9f}'.format(DYN_aire_tot/(Ra*Ra*4*np.pi) ) ) 
    795 echo ( 'ATM HIS : Area of atmosphere/(4pi R^2)        : {:18.9f}'.format(ATM_aire_tot/(Ra*Ra*4*np.pi) ) ) 
    796 echo ( 'ATM HIS : Area of ter in atmosphere/(4pi R^2) : {:18.9f}'.format(ATM_aire_ter_tot/(Ra*Ra*4*np.pi) ) ) 
    797 echo ( 'ATM SRF : Area of atmosphere/(4pi R^2)        : {:18.9f}'.format(SRF_aire_tot/(Ra*Ra*4*np.pi) ) ) 
    798 echo ('') 
    799 echo ( f'ATM SRF : Area of atmosphere (no contfrac): {ONE_stock_int (SRF_areas):18.9e}' ) 
    800  
    801  
    802 if (  np.abs (ATM_aire_tot/(Ra*Ra*4*np.pi) - 1.0) > 0.01 ) : 
    803     raise Exception ('Error of atmosphere surface interpolated on lon/lat grid') 
     842echo ( 'ATM DYN : Area of atmosphere/(4pi R^2)        : {:18.9f}'.format(DYN_aire_tot/(RA*RA*4*np.pi) ) ) 
     843echo ( 'ATM HIS : Area of atmosphere/(4pi R^2)        : {:18.9f}'.format(ATM_aire_tot/(RA*RA*4*np.pi) ) ) 
     844echo ( 'ATM HIS : Area of ter in atmosphere/(4pi R^2) : {:18.9f}'.format(ATM_aire_ter_tot/(RA*RA*4*np.pi) ) ) 
     845if SRF : 
     846    echo ( 'ATM SRF : Area of atmosphere/(4pi R^2)        : {:18.9f}'.format(SRF_aire_tot/(RA*RA*4*np.pi) ) ) 
     847    echo ('') 
     848    echo ( f'ATM SRF : Area of atmosphere (no contfrac): {ONE_stock_int (SRF_areas):18.9e}' ) 
     849 
     850 
     851if np.abs (ATM_aire_tot/(RA*RA*4*np.pi) - 1.0) > 0.01 : 
     852    raise RuntimeError ('Error of atmosphere surface interpolated on lon/lat grid') 
    804853 
    805854echo ( '\n====================================================================================' ) 
     
    817866    DYN_psol_beg = d_DYN_beg['ps'] 
    818867    DYN_psol_end = d_DYN_end['ps'] 
    819 if LMDZ :  
    820     DYN_psol_beg = lmdz.geo2point ( d_DYN_beg['ps'].isel(rlonv=slice(0,-1)), dim1D='cell' ) 
    821     DYN_psol_end = lmdz.geo2point ( d_DYN_end['ps'].isel(rlonv=slice(0,-1)), dim1D='cell' ) 
    822      
     868if LMDZ : 
     869    DYN_psol_beg = lmdz.geo2point ( d_DYN_beg['ps'].isel(rlonv=slice(0,-1)), dim1d='cell' ) 
     870    DYN_psol_end = lmdz.geo2point ( d_DYN_end['ps'].isel(rlonv=slice(0,-1)), dim1d='cell' ) 
     871 
    823872echo ( '3D Pressure at the interface layers (not scalar points)' ) 
    824873DYN_pres_beg = ATM_Ahyb + ATM_Bhyb * DYN_psol_beg 
     
    848897    echo ( f'(DYN_pres_end[-1]).min().item()              = {ind[6]}' ) 
    849898    echo ( f'(DYN_pres_end[-1]).max().item()              = {ind[7]}' ) 
    850     raise Exception 
    851      
     899    raise RuntimeError 
     900 
    852901klevp1 = ATM_Bhyb.shape[-1] 
    853902cell   = DYN_psol_beg.shape[-1] 
     
    857906DYN_mass_beg = xr.DataArray ( np.empty( (klev, cell)), dims = ('sigs', 'cell'), coords=(np.arange(klev), np.arange(cell) ) ) 
    858907DYN_mass_end = xr.DataArray ( np.empty( (klev, cell)), dims = ('sigs', 'cell'), coords=(np.arange(klev), np.arange(cell) ) ) 
    859      
     908 
    860909for k in np.arange (klev) : 
    861     DYN_mass_beg[k,:] = ( DYN_pres_beg[k,:] - DYN_pres_beg[k+1,:] ) / Grav 
    862     DYN_mass_end[k,:] = ( DYN_pres_end[k,:] - DYN_pres_end[k+1,:] ) / Grav 
     910    DYN_mass_beg[k,:] = ( DYN_pres_beg[k,:] - DYN_pres_beg[k+1,:] ) / GRAV 
     911    DYN_mass_end[k,:] = ( DYN_pres_end[k,:] - DYN_pres_end[k+1,:] ) / GRAV 
    863912 
    864913DYN_mass_beg_2D = DYN_mass_beg.sum (dim='sigs') 
     
    872921    if 'H2Ov' in d_DYN_beg.variables : 
    873922        echo ('reading LATLON : H2Ov, H2Ol, H2Oi' ) 
    874         DYN_wat_beg = lmdz.geo3point ( d_DYN_beg['H2Ov'] + d_DYN_beg['H2Ol'] + d_DYN_beg['H2Oi'].isel(rlonv=slice(0,-1) ), dim1D='cell' ) 
    875         DYN_wat_end = lmdz.geo3point ( d_DYN_end['H2Ov'] + d_DYN_end['H2Ol'] + d_DYN_end['H2Oi'].isel(rlonv=slice(0,-1) ), dim1D='cell' ) 
     923        DYN_wat_beg = lmdz.geo3point ( d_DYN_beg['H2Ov'] + d_DYN_beg['H2Ol'] + d_DYN_beg['H2Oi'].isel(rlonv=slice(0,-1) ), dim1d='cell' ) 
     924        DYN_wat_end = lmdz.geo3point ( d_DYN_end['H2Ov'] + d_DYN_end['H2Ol'] + d_DYN_end['H2Oi'].isel(rlonv=slice(0,-1) ), dim1d='cell' ) 
    876925    if 'H2Ov_g' in d_DYN_beg.variables : 
    877926        echo ('reading LATLON : H2O_g, H2O_l, H2O_s' ) 
    878         DYN_wat_beg = lmdz.geo3point ( (d_DYN_beg['H2O_g'] + d_DYN_beg['H2O_l'] + d_DYN_beg['H2O_s']).isel(rlonv=slice(0,-1) ), dim1D='cell' ) 
    879         DYN_wat_end = lmdz.geo3point ( (d_DYN_end['H2O_g'] + d_DYN_end['H2O_l'] + d_DYN_end['H2O_s']).isel(rlonv=slice(0,-1) ), dim1D='cell' ) 
     927        DYN_wat_beg = lmdz.geo3point ( (d_DYN_beg['H2O_g'] + d_DYN_beg['H2O_l'] + d_DYN_beg['H2O_s']).isel(rlonv=slice(0,-1) ), dim1d='cell' ) 
     928        DYN_wat_end = lmdz.geo3point ( (d_DYN_end['H2O_g'] + d_DYN_end['H2O_l'] + d_DYN_end['H2O_s']).isel(rlonv=slice(0,-1) ), dim1d='cell' ) 
    880929if ICO : 
    881930    if 'H2Ov_g' in d_DYN_beg.variables : 
    882931        echo ('reading ICO : H2O_g, H2O_l, H2O_s' ) 
    883         DYN_wat_beg = (d_DYN_beg['H2O_g'] + d_DYN_beg['H2O_l'] + d_DYN_beg['H2O_s']) 
    884         DYN_wat_end = (d_DYN_end['H2O_g'] + d_DYN_end['H2O_l'] + d_DYN_end['H2O_s']) 
     932        DYN_wat_beg = d_DYN_beg['H2O_g'] + d_DYN_beg['H2O_l'] + d_DYN_beg['H2O_s'] 
     933        DYN_wat_end = d_DYN_end['H2O_g'] + d_DYN_end['H2O_l'] + d_DYN_end['H2O_s'] 
    885934    elif 'H2O_g' in d_DYN_beg.variables : 
    886935        echo ('reading ICO : H2O_g, H2O_l, H2O_s' ) 
    887         DYN_wat_beg = (d_DYN_beg['H2O_g'] + d_DYN_beg['H2O_l'] + d_DYN_beg['H2O_s']) 
    888         DYN_wat_end = (d_DYN_end['H2O_g'] + d_DYN_end['H2O_l'] + d_DYN_end['H2O_s']) 
     936        DYN_wat_beg = d_DYN_beg['H2O_g'] + d_DYN_beg['H2O_l'] + d_DYN_beg['H2O_s'] 
     937        DYN_wat_end = d_DYN_end['H2O_g'] + d_DYN_end['H2O_l'] + d_DYN_end['H2O_s'] 
    889938    elif 'q' in d_DYN_beg.variables : 
    890939        echo ('reading ICO : q' ) 
    891         DYN_wat_beg = (d_DYN_beg['q'].isel(nq=0) + d_DYN_beg['q'].isel(nq=1) + d_DYN_beg['q'].isel(nq=2) ) 
    892         DYN_wat_end = (d_DYN_end['q'].isel(nq=0) + d_DYN_end['q'].isel(nq=1) + d_DYN_end['q'].isel(nq=2) ) 
    893  
    894 if 'lev' in DYN_wat_beg.dims :  
     940        DYN_wat_beg = d_DYN_beg['q'].isel(nq=0) + d_DYN_beg['q'].isel(nq=1) + d_DYN_beg['q'].isel(nq=2) 
     941        DYN_wat_end = d_DYN_end['q'].isel(nq=0) + d_DYN_end['q'].isel(nq=1) + d_DYN_end['q'].isel(nq=2) 
     942 
     943if 'lev' in DYN_wat_beg.dims : 
    895944    DYN_wat_beg = DYN_wat_beg.rename ( {'lev':'sigs'} ) 
    896945    DYN_wat_end = DYN_wat_end.rename ( {'lev':'sigs'} ) 
    897      
     946 
    898947echo ( 'Compute water content : vertical and horizontal integral' ) 
    899948 
     
    940989ATM_qs02_end     = d_ATM_end['QS02'] * d_ATM_end['FLIC'] 
    941990ATM_qs03_end     = d_ATM_end['QS03'] * d_ATM_end['FOCE'] 
    942 ATM_qs04_end     = d_ATM_end['QS04'] * d_ATM_end['FSIC']   
    943  
    944 if ICO : 
    945      ATM_sno_beg     = ATM_sno_beg     
    946      ATM_sno_end     = ATM_sno_end     
    947      ATM_qs_beg      = ATM_qs_beg      
    948      ATM_qs_end      = ATM_qs_end      
    949      ATM_qsol_beg    = ATM_qsol_beg    
    950      ATM_qs01_beg    = ATM_qs01_beg    
    951      ATM_qs02_beg    = ATM_qs02_beg    
    952      ATM_qs03_beg    = ATM_qs03_beg    
    953      ATM_qs04_beg    = ATM_qs04_beg    
    954      ATM_qsol_end    = ATM_qsol_end    
    955      ATM_qs01_end    = ATM_qs01_end    
    956      ATM_qs02_end    = ATM_qs02_end    
    957      ATM_qs03_end    = ATM_qs03_end    
    958      ATM_qs04_end    = ATM_qs04_end    
    959      LIC_sno_beg     = LIC_sno_beg     
    960      LIC_sno_end     = LIC_sno_end     
    961      LIC_runlic0_beg = LIC_runlic0_beg 
    962      LIC_runlic0_end = LIC_runlic0_end 
    963     
     991ATM_qs04_end     = d_ATM_end['QS04'] * d_ATM_end['FSIC'] 
     992 
    964993LIC_qs_beg = ATM_qs02_beg 
    965994LIC_qs_end = ATM_qs02_end 
     
    10201049prtFlux ( 'dMass (eau + neige atm) ', dDYN_mas_wat + dATM_mas_sno , 'e', True) 
    10211050 
    1022 echo ( '\n====================================================================================' ) 
    1023 echo ( f'-- SRF changes  -- {Title} ' ) 
    1024  
    1025 if Routing == 'SIMPLE' : 
    1026     RUN_mas_wat_fast_beg   = ONE_stock_int ( d_RUN_beg ['fast_reservoir']   ) 
    1027     RUN_mas_wat_slow_beg   = ONE_stock_int ( d_RUN_beg ['slow_reservoir']   ) 
    1028     RUN_mas_wat_stream_beg = ONE_stock_int ( d_RUN_beg ['stream_reservoir'] ) 
    1029      
    1030     RUN_mas_wat_flood_beg  = ONE_stock_int ( d_SRF_beg ['floodres']  ) 
    1031     RUN_mas_wat_lake_beg   = ONE_stock_int ( d_SRF_beg ['lakeres']   ) 
    1032     RUN_mas_wat_pond_beg   = ONE_stock_int ( d_SRF_beg ['pondres']   ) 
    1033      
    1034     RUN_mas_wat_fast_end   = ONE_stock_int ( d_RUN_end ['fast_reservoir']   ) 
    1035     RUN_mas_wat_slow_end   = ONE_stock_int ( d_RUN_end ['slow_reservoir']   ) 
    1036     RUN_mas_wat_stream_end = ONE_stock_int ( d_RUN_end ['stream_reservoir'] ) 
    1037      
    1038     RUN_mas_wat_flood_end  = ONE_stock_int ( d_SRF_end ['floodres']  ) 
    1039     RUN_mas_wat_lake_end   = ONE_stock_int ( d_SRF_end ['lakeres']   ) 
    1040     RUN_mas_wat_pond_end   = ONE_stock_int ( d_SRF_end ['pondres']   ) 
    1041  
    1042 if Routing == 'SECHIBA' : 
    1043     RUN_mas_wat_fast_beg   = ONE_stock_int ( d_SRF_beg ['fastres']   ) 
    1044     RUN_mas_wat_slow_beg   = ONE_stock_int ( d_SRF_beg ['slowres']   ) 
    1045     RUN_mas_wat_stream_beg = ONE_stock_int ( d_SRF_beg ['streamres'] ) 
    1046     RUN_mas_wat_flood_beg  = ONE_stock_int ( d_SRF_beg ['floodres']  ) 
    1047     RUN_mas_wat_lake_beg   = ONE_stock_int ( d_SRF_beg ['lakeres']   ) 
    1048     RUN_mas_wat_pond_beg   = ONE_stock_int ( d_SRF_beg ['pondres']   ) 
    1049      
    1050     RUN_mas_wat_fast_end   = ONE_stock_int ( d_SRF_end ['fastres']   ) 
    1051     RUN_mas_wat_slow_end   = ONE_stock_int ( d_SRF_end ['slowres']   ) 
    1052     RUN_mas_wat_stream_end = ONE_stock_int ( d_SRF_end ['streamres'] ) 
    1053     RUN_mas_wat_flood_end  = ONE_stock_int ( d_SRF_end ['floodres']  ) 
    1054     RUN_mas_wat_lake_end   = ONE_stock_int ( d_SRF_end ['lakeres']   ) 
    1055     RUN_mas_wat_pond_end   = ONE_stock_int ( d_SRF_end ['pondres']   ) 
    1056  
    1057 RUN_mas_wat_beg = Sprec ( [RUN_mas_wat_fast_beg , RUN_mas_wat_slow_beg, RUN_mas_wat_stream_beg, 
    1058                            RUN_mas_wat_flood_beg, RUN_mas_wat_lake_beg, RUN_mas_wat_pond_beg] ) 
    1059                    
    1060 RUN_mas_wat_end = Sprec ( [RUN_mas_wat_fast_end  , RUN_mas_wat_slow_end , RUN_mas_wat_stream_end, 
    1061                            RUN_mas_wat_flood_end , RUN_mas_wat_lake_end , RUN_mas_wat_pond_end] ) 
    1062  
    1063 dRUN_mas_wat_fast   = RUN_mas_wat_fast_end   - RUN_mas_wat_fast_beg 
    1064 dRUN_mas_wat_slow   = RUN_mas_wat_slow_end   - RUN_mas_wat_slow_beg 
    1065 dRUN_mas_wat_stream = RUN_mas_wat_stream_end - RUN_mas_wat_stream_beg 
    1066 dRUN_mas_wat_flood  = RUN_mas_wat_flood_end  - RUN_mas_wat_flood_beg 
    1067 dRUN_mas_wat_lake   = RUN_mas_wat_lake_end   - RUN_mas_wat_lake_beg 
    1068 dRUN_mas_wat_pond   = RUN_mas_wat_pond_end   - RUN_mas_wat_pond_beg 
    1069  
    1070 dRUN_mas_wat        = RUN_mas_wat_end        - RUN_mas_wat_beg 
    1071  
    1072 echo ( f'\nRunoff reservoirs -- {Title} ') 
    1073 echo ( f'------------------------------------------------------------------------------------' ) 
    1074 echo ( f'RUN_mas_wat_fast_beg   = {RUN_mas_wat_fast_beg  :12.6e} kg | RUN_mas_wat_fast_end   = {RUN_mas_wat_fast_end  :12.6e} kg ' ) 
    1075 echo ( f'RUN_mas_wat_slow_beg   = {RUN_mas_wat_slow_beg  :12.6e} kg | RUN_mas_wat_slow_end   = {RUN_mas_wat_slow_end  :12.6e} kg ' ) 
    1076 echo ( f'RUN_mas_wat_stream_beg = {RUN_mas_wat_stream_beg:12.6e} kg | RUN_mas_wat_stream_end = {RUN_mas_wat_stream_end:12.6e} kg ' ) 
    1077 echo ( f'RUN_mas_wat_flood_beg  = {RUN_mas_wat_flood_beg :12.6e} kg | RUN_mas_wat_flood_end  = {RUN_mas_wat_flood_end :12.6e} kg ' ) 
    1078 echo ( f'RUN_mas_wat_lake_beg   = {RUN_mas_wat_lake_beg  :12.6e} kg | RUN_mas_wat_lake_end   = {RUN_mas_wat_lake_end  :12.6e} kg ' ) 
    1079 echo ( f'RUN_mas_wat_pond_beg   = {RUN_mas_wat_pond_beg  :12.6e} kg | RUN_mas_wat_pond_end   = {RUN_mas_wat_pond_end  :12.6e} kg ' ) 
    1080 echo ( f'RUN_mas_wat_beg        = {RUN_mas_wat_beg       :12.6e} kg | RUN_mas_wat_end        = {RUN_mas_wat_end       :12.6e} kg ' ) 
    1081  
    1082 echo ( '------------------------------------------------------------------------------------' ) 
    1083  
    1084 prtFlux ( 'dMass (fast)   ', dRUN_mas_wat_fast  , 'e', True ) 
    1085 prtFlux ( 'dMass (slow)   ', dRUN_mas_wat_slow  , 'e', True ) 
    1086 prtFlux ( 'dMass (stream) ', dRUN_mas_wat_stream, 'e', True ) 
    1087 prtFlux ( 'dMass (flood)  ', dRUN_mas_wat_flood , 'e', True ) 
    1088 prtFlux ( 'dMass (lake)   ', dRUN_mas_wat_lake  , 'e', True ) 
    1089 prtFlux ( 'dMass (pond)   ', dRUN_mas_wat_pond  , 'e', True ) 
    1090 prtFlux ( 'dMass (all)    ', dRUN_mas_wat       , 'e', True ) 
    1091  
    1092 echo ( f'\nWater content in routing  -- {Title} ' ) 
    1093 echo ( '------------------------------------------------------------------------------------' ) 
    1094 echo ( f'RUN_mas_wat_beg = {RUN_mas_wat_end:12.6e} kg | RUN_mas_wat_end = {RUN_mas_wat_end:12.6e} kg' ) 
    1095 prtFlux ( 'dMass (routing) ', dRUN_mas_wat , 'e', True   ) 
    1096  
    1097 echo ( '\n====================================================================================' ) 
    1098 print (f'Reading SRF restart') 
    1099 SRF_tot_watveg_beg  = d_SRF_beg['tot_watveg_beg']  ; SRF_tot_watveg_beg  = SRF_tot_watveg_beg .where (SRF_tot_watveg_beg  < 1E15, 0.) 
    1100 SRF_tot_watsoil_beg = d_SRF_beg['tot_watsoil_beg'] ; SRF_tot_watsoil_beg = SRF_tot_watsoil_beg.where (SRF_tot_watsoil_beg < 1E15, 0.) 
    1101 SRF_snow_beg        = d_SRF_beg['snow_beg']        ; SRF_snow_beg        = SRF_snow_beg       .where (SRF_snow_beg        < 1E15, 0.) 
    1102 SRF_lakeres_beg     = d_SRF_beg['lakeres']         ; SRF_lakeres_beg     = SRF_lakeres_beg    .where (SRF_lakeres_beg     < 1E15, 0.) 
    1103  
    1104 SRF_tot_watveg_end  = d_SRF_end['tot_watveg_beg']  ; SRF_tot_watveg_end  = SRF_tot_watveg_end .where (SRF_tot_watveg_end  < 1E15, 0.) 
    1105 SRF_tot_watsoil_end = d_SRF_end['tot_watsoil_beg'] ; SRF_tot_watsoil_end = SRF_tot_watsoil_end.where (SRF_tot_watsoil_end < 1E15, 0.) 
    1106 SRF_snow_end        = d_SRF_end['snow_beg']        ; SRF_snow_end        = SRF_snow_end       .where (SRF_snow_end        < 1E15, 0.) 
    1107 SRF_lakeres_end     = d_SRF_end['lakeres']         ; SRF_lakeres_end     = SRF_lakeres_end    .where (SRF_lakeres_end     < 1E15, 0.) 
    1108  
    1109 if LMDZ : 
    1110     SRF_tot_watveg_beg  = lmdz.geo2point (SRF_tot_watveg_beg , dim1D='cell') 
    1111     SRF_tot_watsoil_beg = lmdz.geo2point (SRF_tot_watsoil_beg, dim1D='cell') 
    1112     SRF_snow_beg        = lmdz.geo2point (SRF_snow_beg       , dim1D='cell') 
    1113     SRF_lakeres_beg     = lmdz.geo2point (SRF_lakeres_beg    , dim1D='cell') 
    1114     SRF_tot_watveg_end  = lmdz.geo2point (SRF_tot_watveg_end , dim1D='cell') 
    1115     SRF_tot_watsoil_end = lmdz.geo2point (SRF_tot_watsoil_end, dim1D='cell') 
    1116     SRF_snow_end        = lmdz.geo2point (SRF_snow_end       , dim1D='cell') 
    1117     SRF_lakeres_end     = lmdz.geo2point (SRF_lakeres_end    , dim1D='cell') 
    1118  
    1119  
    1120 # Stock dSoilHum dInterce dSWE dStream dFastR dSlowR dLake dPond dFlood 
    1121  
    1122 SRF_wat_beg = SRF_tot_watveg_beg + SRF_tot_watsoil_beg + SRF_snow_beg 
    1123 SRF_wat_end = SRF_tot_watveg_end + SRF_tot_watsoil_end + SRF_snow_end 
    1124  
    1125 echo ( '\n====================================================================================' ) 
    1126 print ('Computing integrals') 
    1127  
    1128 print ( ' 1/8', end='' ) ; sys.stdout.flush () 
    1129 SRF_mas_watveg_beg   = SRF_stock_int ( SRF_tot_watveg_beg  ) 
    1130 print ( ' 2/8', end='' ) ; sys.stdout.flush () 
    1131 SRF_mas_watsoil_beg  = SRF_stock_int ( SRF_tot_watsoil_beg ) 
    1132 print ( ' 3/8', end='' ) ; sys.stdout.flush () 
    1133 SRF_mas_snow_beg     = SRF_stock_int ( SRF_snow_beg        ) 
    1134 print ( ' 4/8', end='' ) ; sys.stdout.flush () 
    1135 SRF_mas_lake_beg     = ONE_stock_int ( SRF_lakeres_beg     ) 
    1136 print ( ' 5/8', end='' ) ; sys.stdout.flush () 
    1137  
    1138 SRF_mas_watveg_end   = SRF_stock_int ( SRF_tot_watveg_end  ) 
    1139 print ( ' 6/8', end='' ) ; sys.stdout.flush () 
    1140 SRF_mas_watsoil_end  = SRF_stock_int ( SRF_tot_watsoil_end ) 
    1141 print ( ' 7/8', end='' ) ; sys.stdout.flush () 
    1142 SRF_mas_snow_end     = SRF_stock_int ( SRF_snow_end        ) 
    1143 print ( ' 8/8', end='' ) ; sys.stdout.flush () 
    1144 SRF_mas_lake_end     = ONE_stock_int ( SRF_lakeres_end     ) 
    1145  
    1146 print (' -- ') ; sys.stdout.flush () 
    1147  
    1148 dSRF_mas_watveg   = Sprec ( [SRF_mas_watveg_end , -SRF_mas_watveg_beg] ) 
    1149 dSRF_mas_watsoil  = Sprec ( [SRF_mas_watsoil_end, -SRF_mas_watsoil_beg] ) 
    1150 dSRF_mas_snow     = Sprec ( [SRF_mas_snow_end   , -SRF_mas_snow_beg] ) 
    1151 dSRF_mas_lake     = Sprec ( [SRF_mas_lake_end   , -SRF_mas_lake_beg] ) 
    1152  
    1153 echo ( '------------------------------------------------------------------------------------' ) 
    1154 echo ( f'\nSurface reservoirs  -- {Title} ') 
    1155 echo ( f'SRF_mas_watveg_beg   = {SRF_mas_watveg_beg :12.6e} kg | SRF_mas_watveg_end   = {SRF_mas_watveg_end :12.6e} kg ' ) 
    1156 echo ( f'SRF_mas_watsoil_beg  = {SRF_mas_watsoil_beg:12.6e} kg | SRF_mas_watsoil_end  = {SRF_mas_watsoil_end:12.6e} kg ' ) 
    1157 echo ( f'SRF_mas_snow_beg     = {SRF_mas_snow_beg   :12.6e} kg | SRF_mas_snow_end     = {SRF_mas_snow_end   :12.6e} kg ' ) 
    1158 echo ( f'SRF_mas_lake_beg     = {SRF_mas_lake_beg   :12.6e} kg | SRF_mas_lake_end     = {SRF_mas_lake_end   :12.6e} kg ' ) 
    1159  
    1160 prtFlux ( 'dMass (watveg) ', dSRF_mas_watveg , 'e' , True ) 
    1161 prtFlux ( 'dMass (watsoil)', dSRF_mas_watsoil, 'e' , True ) 
    1162 prtFlux ( 'dMass (snow)   ', dSRF_mas_snow   , 'e' , True ) 
    1163 prtFlux ( 'dMass (lake)   ', dSRF_mas_lake   , 'e' , True ) 
    1164  
    1165 SRF_mas_wat_beg = Sprec ( [SRF_mas_watveg_beg , SRF_mas_watsoil_beg, SRF_mas_snow_beg] ) 
    1166 SRF_mas_wat_end = Sprec ( [SRF_mas_watveg_end , SRF_mas_watsoil_end, SRF_mas_snow_end] ) 
    1167  
    1168 dSRF_mas_wat    = Sprec ( [+SRF_mas_watveg_end , +SRF_mas_watsoil_end, +SRF_mas_snow_end,  
    1169                            -SRF_mas_watveg_beg , -SRF_mas_watsoil_beg, -SRF_mas_snow_beg]  ) 
    1170  
    1171 echo ( '------------------------------------------------------------------------------------' ) 
    1172 echo ( f'Water content in surface  -- {Title} ' ) 
    1173 echo ( f'SRF_mas_wat_beg   = {SRF_mas_wat_beg:12.6e} kg | SRF_mas_wat_end  = {SRF_mas_wat_end:12.6e} kg ') 
    1174 prtFlux ( 'dMass (water srf)', dSRF_mas_wat, 'e', True ) 
    1175  
    1176 echo ( '------------------------------------------------------------------------------------' ) 
    1177 echo ( 'Water content in  ATM + SRF + RUN + LAKE' ) 
    1178 echo ( 'mas_wat_beg = {:12.6e} kg | mas_wat_end = {:12.6e} kg '. 
    1179            format (DYN_mas_wat_beg + ATM_mas_sno_beg + RUN_mas_wat_beg + SRF_mas_wat_beg + SRF_mas_lake_beg , 
    1180                    DYN_mas_wat_end + ATM_mas_sno_end + RUN_mas_wat_end + SRF_mas_wat_end + SRF_mas_lake_end ) ) 
    1181 prtFlux ( 'dMass (water atm+srf+run+lake)', dDYN_mas_wat + dATM_mas_sno + dRUN_mas_wat + dSRF_mas_wat + dSRF_mas_lake, 'e', True) 
     1051if SRF : 
     1052    echo ( '\n====================================================================================' ) 
     1053    echo ( f'-- SRF changes  -- {Title} ' ) 
     1054 
     1055    if Routing == 'SIMPLE' : 
     1056        RUN_mas_wat_fast_beg   = ONE_stock_int ( d_RUN_beg ['fast_reservoir']   ) 
     1057        RUN_mas_wat_slow_beg   = ONE_stock_int ( d_RUN_beg ['slow_reservoir']  ) 
     1058        RUN_mas_wat_stream_beg = ONE_stock_int ( d_RUN_beg ['stream_reservoir'] ) 
     1059        RUN_mas_wat_flood_beg  = ONE_stock_int ( d_SRF_beg ['floodres']  ) 
     1060        RUN_mas_wat_lake_beg   = ONE_stock_int ( d_SRF_beg ['lakeres']   ) 
     1061        RUN_mas_wat_pond_beg   = ONE_stock_int ( d_SRF_beg ['pondres']   ) 
     1062 
     1063        RUN_mas_wat_fast_end   = ONE_stock_int ( d_RUN_end ['fast_reservoir']   ) 
     1064        RUN_mas_wat_slow_end   = ONE_stock_int ( d_RUN_end ['slow_reservoir']   ) 
     1065        RUN_mas_wat_stream_end = ONE_stock_int ( d_RUN_end ['stream_reservoir'] ) 
     1066 
     1067        RUN_mas_wat_flood_end  = ONE_stock_int ( d_SRF_end ['floodres']  ) 
     1068        RUN_mas_wat_lake_end   = ONE_stock_int ( d_SRF_end ['lakeres']   ) 
     1069        RUN_mas_wat_pond_end   = ONE_stock_int ( d_SRF_end ['pondres']   ) 
     1070 
     1071    if Routing == 'SECHIBA' : 
     1072        RUN_mas_wat_fast_beg   = ONE_stock_int ( d_SRF_beg ['fastres']   ) 
     1073        RUN_mas_wat_slow_beg   = ONE_stock_int ( d_SRF_beg ['slowres']   ) 
     1074        RUN_mas_wat_stream_beg = ONE_stock_int ( d_SRF_beg ['streamres'] ) 
     1075        RUN_mas_wat_flood_beg  = ONE_stock_int ( d_SRF_beg ['floodres']  ) 
     1076        RUN_mas_wat_lake_beg   = ONE_stock_int ( d_SRF_beg ['lakeres']   ) 
     1077        RUN_mas_wat_pond_beg   = ONE_stock_int ( d_SRF_beg ['pondres']   ) 
     1078 
     1079        RUN_mas_wat_fast_end   = ONE_stock_int ( d_SRF_end ['fastres']   ) 
     1080        RUN_mas_wat_slow_end   = ONE_stock_int ( d_SRF_end ['slowres']   ) 
     1081        RUN_mas_wat_stream_end = ONE_stock_int ( d_SRF_end ['streamres'] ) 
     1082        RUN_mas_wat_flood_end  = ONE_stock_int ( d_SRF_end ['floodres']  ) 
     1083        RUN_mas_wat_lake_end   = ONE_stock_int ( d_SRF_end ['lakeres']   ) 
     1084        RUN_mas_wat_pond_end   = ONE_stock_int ( d_SRF_end ['pondres']   ) 
     1085 
     1086    RUN_mas_wat_beg = Sprec ( [RUN_mas_wat_fast_beg , RUN_mas_wat_slow_beg, RUN_mas_wat_stream_beg, 
     1087                            RUN_mas_wat_flood_beg, RUN_mas_wat_lake_beg, RUN_mas_wat_pond_beg] ) 
     1088 
     1089    RUN_mas_wat_end = Sprec ( [RUN_mas_wat_fast_end  , RUN_mas_wat_slow_end , RUN_mas_wat_stream_end, 
     1090                            RUN_mas_wat_flood_end , RUN_mas_wat_lake_end , RUN_mas_wat_pond_end] ) 
     1091 
     1092    dRUN_mas_wat_fast   = RUN_mas_wat_fast_end   - RUN_mas_wat_fast_beg 
     1093    dRUN_mas_wat_slow   = RUN_mas_wat_slow_end   - RUN_mas_wat_slow_beg 
     1094    dRUN_mas_wat_stream = RUN_mas_wat_stream_end - RUN_mas_wat_stream_beg 
     1095    dRUN_mas_wat_flood  = RUN_mas_wat_flood_end  - RUN_mas_wat_flood_beg 
     1096    dRUN_mas_wat_lake   = RUN_mas_wat_lake_end   - RUN_mas_wat_lake_beg 
     1097    dRUN_mas_wat_pond   = RUN_mas_wat_pond_end   - RUN_mas_wat_pond_beg 
     1098 
     1099    dRUN_mas_wat        = RUN_mas_wat_end        - RUN_mas_wat_beg 
     1100 
     1101    echo ( f'\nRunoff reservoirs -- {Title} ') 
     1102    echo (  '------------------------------------------------------------------------------------' ) 
     1103    echo ( f'RUN_mas_wat_fast_beg   = {RUN_mas_wat_fast_beg  :12.6e} kg | RUN_mas_wat_fast_end   = {RUN_mas_wat_fast_end  :12.6e} kg ' ) 
     1104    echo ( f'RUN_mas_wat_slow_beg   = {RUN_mas_wat_slow_beg  :12.6e} kg | RUN_mas_wat_slow_end   = {RUN_mas_wat_slow_end  :12.6e} kg ' ) 
     1105    echo ( f'RUN_mas_wat_stream_beg = {RUN_mas_wat_stream_beg:12.6e} kg | RUN_mas_wat_stream_end = {RUN_mas_wat_stream_end:12.6e} kg ' ) 
     1106    echo ( f'RUN_mas_wat_flood_beg  = {RUN_mas_wat_flood_beg :12.6e} kg | RUN_mas_wat_flood_end  = {RUN_mas_wat_flood_end :12.6e} kg ' ) 
     1107    echo ( f'RUN_mas_wat_lake_beg   = {RUN_mas_wat_lake_beg  :12.6e} kg | RUN_mas_wat_lake_end   = {RUN_mas_wat_lake_end  :12.6e} kg ' ) 
     1108    echo ( f'RUN_mas_wat_pond_beg   = {RUN_mas_wat_pond_beg  :12.6e} kg | RUN_mas_wat_pond_end   = {RUN_mas_wat_pond_end  :12.6e} kg ' ) 
     1109    echo ( f'RUN_mas_wat_beg        = {RUN_mas_wat_beg       :12.6e} kg | RUN_mas_wat_end        = {RUN_mas_wat_end       :12.6e} kg ' ) 
     1110 
     1111    echo ( '------------------------------------------------------------------------------------' ) 
     1112 
     1113    prtFlux ( 'dMass (fast)   ', dRUN_mas_wat_fast  , 'e', True ) 
     1114    prtFlux ( 'dMass (slow)   ', dRUN_mas_wat_slow  , 'e', True ) 
     1115    prtFlux ( 'dMass (stream) ', dRUN_mas_wat_stream, 'e', True ) 
     1116    prtFlux ( 'dMass (flood)  ', dRUN_mas_wat_flood , 'e', True ) 
     1117    prtFlux ( 'dMass (lake)   ', dRUN_mas_wat_lake  , 'e', True ) 
     1118    prtFlux ( 'dMass (pond)   ', dRUN_mas_wat_pond  , 'e', True ) 
     1119    prtFlux ( 'dMass (all)    ', dRUN_mas_wat       , 'e', True ) 
     1120 
     1121    echo ( f'\nWater content in routing  -- {Title} ' ) 
     1122    echo ( '------------------------------------------------------------------------------------' ) 
     1123    echo ( f'RUN_mas_wat_beg = {RUN_mas_wat_end:12.6e} kg | RUN_mas_wat_end = {RUN_mas_wat_end:12.6e} kg' ) 
     1124    prtFlux ( 'dMass (routing) ', dRUN_mas_wat , 'e', True   ) 
     1125 
     1126    echo ( '\n====================================================================================' ) 
     1127    print ( 'Reading SRF restart') 
     1128    SRF_tot_watveg_beg  = d_SRF_beg['tot_watveg_beg']  ; SRF_tot_watveg_beg  = SRF_tot_watveg_beg .where (SRF_tot_watveg_beg  < 1E15, 0.) 
     1129    SRF_tot_watsoil_beg = d_SRF_beg['tot_watsoil_beg'] ; SRF_tot_watsoil_beg = SRF_tot_watsoil_beg.where (SRF_tot_watsoil_beg < 1E15, 0.) 
     1130    SRF_snow_beg        = d_SRF_beg['snow_beg']        ; SRF_snow_beg        = SRF_snow_beg       .where (SRF_snow_beg        < 1E15, 0.) 
     1131    SRF_lakeres_beg     = d_SRF_beg['lakeres']         ; SRF_lakeres_beg     = SRF_lakeres_beg    .where (SRF_lakeres_beg     < 1E15, 0.) 
     1132 
     1133    SRF_tot_watveg_end  = d_SRF_end['tot_watveg_beg']  ; SRF_tot_watveg_end  = SRF_tot_watveg_end .where (SRF_tot_watveg_end  < 1E15, 0.) 
     1134    SRF_tot_watsoil_end = d_SRF_end['tot_watsoil_beg'] ; SRF_tot_watsoil_end = SRF_tot_watsoil_end.where (SRF_tot_watsoil_end < 1E15, 0.) 
     1135    SRF_snow_end        = d_SRF_end['snow_beg']        ; SRF_snow_end        = SRF_snow_end       .where (SRF_snow_end        < 1E15, 0.) 
     1136    SRF_lakeres_end     = d_SRF_end['lakeres']         ; SRF_lakeres_end     = SRF_lakeres_end    .where (SRF_lakeres_end     < 1E15, 0.) 
     1137 
     1138    if LMDZ : 
     1139        SRF_tot_watveg_beg  = lmdz.geo2point (SRF_tot_watveg_beg , dim1d='cell') 
     1140        SRF_tot_watsoil_beg = lmdz.geo2point (SRF_tot_watsoil_beg, dim1d='cell') 
     1141        SRF_snow_beg        = lmdz.geo2point (SRF_snow_beg       , dim1d='cell') 
     1142        SRF_lakeres_beg     = lmdz.geo2point (SRF_lakeres_beg    , dim1d='cell') 
     1143        SRF_tot_watveg_end  = lmdz.geo2point (SRF_tot_watveg_end , dim1d='cell') 
     1144        SRF_tot_watsoil_end = lmdz.geo2point (SRF_tot_watsoil_end, dim1d='cell') 
     1145        SRF_snow_end        = lmdz.geo2point (SRF_snow_end       , dim1d='cell') 
     1146        SRF_lakeres_end     = lmdz.geo2point (SRF_lakeres_end    , dim1d='cell') 
     1147 
     1148 
     1149    # Stock dSoilHum dInterce dSWE dStream dFastR dSlowR dLake dPond dFlood 
     1150 
     1151    SRF_wat_beg = SRF_tot_watveg_beg + SRF_tot_watsoil_beg + SRF_snow_beg 
     1152    SRF_wat_end = SRF_tot_watveg_end + SRF_tot_watsoil_end + SRF_snow_end 
     1153 
     1154    echo ( '\n====================================================================================' ) 
     1155    print ('Computing integrals') 
     1156 
     1157    print ( ' 1/8', end='' ) ; sys.stdout.flush () 
     1158    SRF_mas_watveg_beg   = SRF_stock_int ( SRF_tot_watveg_beg  ) 
     1159    print ( ' 2/8', end='' ) ; sys.stdout.flush () 
     1160    SRF_mas_watsoil_beg  = SRF_stock_int ( SRF_tot_watsoil_beg ) 
     1161    print ( ' 3/8', end='' ) ; sys.stdout.flush () 
     1162    SRF_mas_snow_beg     = SRF_stock_int ( SRF_snow_beg        ) 
     1163    print ( ' 4/8', end='' ) ; sys.stdout.flush () 
     1164    SRF_mas_lake_beg     = ONE_stock_int ( SRF_lakeres_beg     ) 
     1165    print ( ' 5/8', end='' ) ; sys.stdout.flush () 
     1166 
     1167    SRF_mas_watveg_end   = SRF_stock_int ( SRF_tot_watveg_end  ) 
     1168    print ( ' 6/8', end='' ) ; sys.stdout.flush () 
     1169    SRF_mas_watsoil_end  = SRF_stock_int ( SRF_tot_watsoil_end ) 
     1170    print ( ' 7/8', end='' ) ; sys.stdout.flush () 
     1171    SRF_mas_snow_end     = SRF_stock_int ( SRF_snow_end        ) 
     1172    print ( ' 8/8', end='' ) ; sys.stdout.flush () 
     1173    SRF_mas_lake_end     = ONE_stock_int ( SRF_lakeres_end     ) 
     1174 
     1175    print (' -- ') ; sys.stdout.flush () 
     1176 
     1177    dSRF_mas_watveg   = Sprec ( [SRF_mas_watveg_end , -SRF_mas_watveg_beg] ) 
     1178    dSRF_mas_watsoil  = Sprec ( [SRF_mas_watsoil_end, -SRF_mas_watsoil_beg] ) 
     1179    dSRF_mas_snow     = Sprec ( [SRF_mas_snow_end   , -SRF_mas_snow_beg] ) 
     1180    dSRF_mas_lake     = Sprec ( [SRF_mas_lake_end   , -SRF_mas_lake_beg] ) 
     1181 
     1182    echo ( '------------------------------------------------------------------------------------' ) 
     1183    echo ( f'\nSurface reservoirs  -- {Title} ') 
     1184    echo ( f'SRF_mas_watveg_beg   = {SRF_mas_watveg_beg :12.6e} kg | SRF_mas_watveg_end   = {SRF_mas_watveg_end :12.6e} kg ' ) 
     1185    echo ( f'SRF_mas_watsoil_beg  = {SRF_mas_watsoil_beg:12.6e} kg | SRF_mas_watsoil_end  = {SRF_mas_watsoil_end:12.6e} kg ' ) 
     1186    echo ( f'SRF_mas_snow_beg     = {SRF_mas_snow_beg   :12.6e} kg | SRF_mas_snow_end     = {SRF_mas_snow_end   :12.6e} kg ' ) 
     1187    echo ( f'SRF_mas_lake_beg     = {SRF_mas_lake_beg   :12.6e} kg | SRF_mas_lake_end     = {SRF_mas_lake_end   :12.6e} kg ' ) 
     1188 
     1189    prtFlux ( 'dMass (watveg) ', dSRF_mas_watveg , 'e' , True ) 
     1190    prtFlux ( 'dMass (watsoil)', dSRF_mas_watsoil, 'e' , True ) 
     1191    prtFlux ( 'dMass (snow)   ', dSRF_mas_snow   , 'e' , True ) 
     1192    prtFlux ( 'dMass (lake)   ', dSRF_mas_lake   , 'e' , True ) 
     1193 
     1194    SRF_mas_wat_beg = Sprec ( [SRF_mas_watveg_beg , SRF_mas_watsoil_beg, SRF_mas_snow_beg] ) 
     1195    SRF_mas_wat_end = Sprec ( [SRF_mas_watveg_end , SRF_mas_watsoil_end, SRF_mas_snow_end] ) 
     1196 
     1197    dSRF_mas_wat    = Sprec ( [+SRF_mas_watveg_end , +SRF_mas_watsoil_end, +SRF_mas_snow_end, 
     1198                               -SRF_mas_watveg_beg , -SRF_mas_watsoil_beg, -SRF_mas_snow_beg]  ) 
     1199 
     1200    echo ( '------------------------------------------------------------------------------------' ) 
     1201    echo ( f'Water content in surface  -- {Title} ' ) 
     1202    echo ( f'SRF_mas_wat_beg   = {SRF_mas_wat_beg:12.6e} kg | SRF_mas_wat_end  = {SRF_mas_wat_end:12.6e} kg ') 
     1203    prtFlux ( 'dMass (water srf)', dSRF_mas_wat, 'e', True ) 
     1204 
     1205    echo ( '------------------------------------------------------------------------------------' ) 
     1206    echo ( 'Water content in  ATM + SRF + RUN + LAKE' ) 
     1207    echo ( 'mas_wat_beg = {:12.6e} kg | mas_wat_end = {:12.6e} kg '. 
     1208            format (DYN_mas_wat_beg + ATM_mas_sno_beg + RUN_mas_wat_beg + SRF_mas_wat_beg + SRF_mas_lake_beg , 
     1209                    DYN_mas_wat_end + ATM_mas_sno_end + RUN_mas_wat_end + SRF_mas_wat_end + SRF_mas_lake_end ) ) 
     1210    prtFlux ( 'dMass (water atm+srf+run+lake)', dDYN_mas_wat + dATM_mas_sno + dRUN_mas_wat + dSRF_mas_wat + dSRF_mas_lake, 'e', True) 
    11821211 
    11831212echo ( '\n====================================================================================' ) 
     
    11861215if ATM_HIS == 'latlon' : 
    11871216    echo ( ' latlon case' ) 
    1188     ATM_wbilo_oce   = lmdz.geo2point ( rprec (d_ATM_his ['wbilo_oce']), dim1D='cell' ) 
    1189     ATM_wbilo_sic   = lmdz.geo2point ( rprec (d_ATM_his ['wbilo_sic']), dim1D='cell' ) 
    1190     ATM_wbilo_ter   = lmdz.geo2point ( rprec (d_ATM_his ['wbilo_ter']), dim1D='cell' ) 
    1191     ATM_wbilo_lic   = lmdz.geo2point ( rprec (d_ATM_his ['wbilo_lic']), dim1D='cell' ) 
    1192     ATM_runofflic   = lmdz.geo2point ( rprec (d_ATM_his ['runofflic']), dim1D='cell' ) 
    1193     ATM_fqcalving   = lmdz.geo2point ( rprec (d_ATM_his ['fqcalving']), dim1D='cell' ) 
    1194     ATM_fqfonte     = lmdz.geo2point ( rprec (d_ATM_his ['fqfonte']  ), dim1D='cell' ) 
    1195     ATM_precip      = lmdz.geo2point ( rprec (d_ATM_his ['precip']   ), dim1D='cell' ) 
    1196     ATM_snowf       = lmdz.geo2point ( rprec (d_ATM_his ['snow']     ), dim1D='cell' ) 
    1197     ATM_evap        = lmdz.geo2point ( rprec (d_ATM_his ['evap']     ), dim1D='cell' ) 
    1198     ATM_wevap_ter   = lmdz.geo2point ( rprec (d_ATM_his ['wevap_ter']), dim1D='cell' ) 
    1199     ATM_wevap_oce   = lmdz.geo2point ( rprec (d_ATM_his ['wevap_oce']), dim1D='cell' ) 
    1200     ATM_wevap_lic   = lmdz.geo2point ( rprec (d_ATM_his ['wevap_lic']), dim1D='cell' ) 
    1201     ATM_wevap_sic   = lmdz.geo2point ( rprec (d_ATM_his ['wevap_sic']), dim1D='cell' ) 
    1202     ATM_wrain_ter   = lmdz.geo2point ( rprec (d_ATM_his ['wrain_ter']), dim1D='cell' ) 
    1203     ATM_wrain_oce   = lmdz.geo2point ( rprec (d_ATM_his ['wrain_oce']), dim1D='cell' ) 
    1204     ATM_wrain_lic   = lmdz.geo2point ( rprec (d_ATM_his ['wrain_lic']), dim1D='cell' ) 
    1205     ATM_wrain_sic   = lmdz.geo2point ( rprec (d_ATM_his ['wrain_sic']), dim1D='cell' ) 
    1206     ATM_wsnow_ter   = lmdz.geo2point ( rprec (d_ATM_his ['wsnow_ter']), dim1D='cell' ) 
    1207     ATM_wsnow_oce   = lmdz.geo2point ( rprec (d_ATM_his ['wsnow_oce']), dim1D='cell' ) 
    1208     ATM_wsnow_lic   = lmdz.geo2point ( rprec (d_ATM_his ['wsnow_lic']), dim1D='cell' ) 
    1209     ATM_wsnow_sic   = lmdz.geo2point ( rprec (d_ATM_his ['wsnow_sic']), dim1D='cell' ) 
    1210     ATM_runofflic   = lmdz.geo2point ( rprec (d_ATM_his ['runofflic']), dim1D='cell' ) 
    1211     echo ( f'End of LATLON case') 
    1212      
     1217    ATM_wbilo_oce   = lmdz.geo2point ( rprec (d_ATM_his ['wbilo_oce']), dim1d='cell' ) 
     1218    ATM_wbilo_sic   = lmdz.geo2point ( rprec (d_ATM_his ['wbilo_sic']), dim1d='cell' ) 
     1219    ATM_wbilo_ter   = lmdz.geo2point ( rprec (d_ATM_his ['wbilo_ter']), dim1d='cell' ) 
     1220    ATM_wbilo_lic   = lmdz.geo2point ( rprec (d_ATM_his ['wbilo_lic']), dim1d='cell' ) 
     1221    ATM_runofflic   = lmdz.geo2point ( rprec (d_ATM_his ['runofflic']), dim1d='cell' ) 
     1222    ATM_fqcalving   = lmdz.geo2point ( rprec (d_ATM_his ['fqcalving']), dim1d='cell' ) 
     1223    ATM_fqfonte     = lmdz.geo2point ( rprec (d_ATM_his ['fqfonte']  ), dim1d='cell' ) 
     1224    ATM_precip      = lmdz.geo2point ( rprec (d_ATM_his ['precip']   ), dim1d='cell' ) 
     1225    ATM_snowf       = lmdz.geo2point ( rprec (d_ATM_his ['snow']     ), dim1d='cell' ) 
     1226    ATM_evap        = lmdz.geo2point ( rprec (d_ATM_his ['evap']     ), dim1d='cell' ) 
     1227    ATM_wevap_ter   = lmdz.geo2point ( rprec (d_ATM_his ['wevap_ter']), dim1d='cell' ) 
     1228    ATM_wevap_oce   = lmdz.geo2point ( rprec (d_ATM_his ['wevap_oce']), dim1d='cell' ) 
     1229    ATM_wevap_lic   = lmdz.geo2point ( rprec (d_ATM_his ['wevap_lic']), dim1d='cell' ) 
     1230    ATM_wevap_sic   = lmdz.geo2point ( rprec (d_ATM_his ['wevap_sic']), dim1d='cell' ) 
     1231    ATM_wrain_ter   = lmdz.geo2point ( rprec (d_ATM_his ['wrain_ter']), dim1d='cell' ) 
     1232    ATM_wrain_oce   = lmdz.geo2point ( rprec (d_ATM_his ['wrain_oce']), dim1d='cell' ) 
     1233    ATM_wrain_lic   = lmdz.geo2point ( rprec (d_ATM_his ['wrain_lic']), dim1d='cell' ) 
     1234    ATM_wrain_sic   = lmdz.geo2point ( rprec (d_ATM_his ['wrain_sic']), dim1d='cell' ) 
     1235    ATM_wsnow_ter   = lmdz.geo2point ( rprec (d_ATM_his ['wsnow_ter']), dim1d='cell' ) 
     1236    ATM_wsnow_oce   = lmdz.geo2point ( rprec (d_ATM_his ['wsnow_oce']), dim1d='cell' ) 
     1237    ATM_wsnow_lic   = lmdz.geo2point ( rprec (d_ATM_his ['wsnow_lic']), dim1d='cell' ) 
     1238    ATM_wsnow_sic   = lmdz.geo2point ( rprec (d_ATM_his ['wsnow_sic']), dim1d='cell' ) 
     1239    ATM_runofflic   = lmdz.geo2point ( rprec (d_ATM_his ['runofflic']), dim1d='cell' ) 
     1240    echo ( 'End of LATLON case') 
     1241 
    12131242if ATM_HIS == 'ico' : 
    12141243    echo (' ico case') 
     
    12401269    ATM_wsnow_lic   = rprec (d_ATM_his ['wsnow_lic']) 
    12411270    ATM_wsnow_sic   = rprec (d_ATM_his ['wsnow_sic']) 
    1242     echo ( f'End of ico case ') 
     1271    echo ( 'End of ico case ') 
    12431272 
    12441273echo ( 'ATM wprecip_oce' ) 
     
    12681297ATM_wemp_sea    = ATM_wevap_sic - ATM_wprecip_oce 
    12691298 
    1270 if RUN_HIS == 'latlon' : 
    1271     echo ( f'RUN costalflow Grille LATLON' ) 
    1272     if TestInterp : 
    1273          echo ( f'RUN runoff TestInterp' ) 
    1274          RUN_runoff      = lmdz.geo2point ( rprec (d_RUN_his ['runoff_contfrac_interp']  )   , dim1D='cell' ) 
    1275          RUN_drainage    = lmdz.geo2point ( rprec (d_RUN_his ['drainage_contfrac_interp'])   , dim1D='cell' ) 
    1276     else :  
    1277         echo ( f'RUN runoff' ) 
    1278         RUN_runoff      = lmdz.geo2point ( rprec (d_RUN_his ['runoff']         ), dim1D='cell' ) 
    1279         RUN_drainage    = lmdz.geo2point ( rprec (d_RUN_his ['drainage']       ), dim1D='cell' ) 
    1280          
    1281     RUN_coastalflow     = lmdz.geo2point ( rprec (d_RUN_his ['coastalflow']    ), dim1D='cell' )  
    1282     RUN_riverflow       = lmdz.geo2point ( rprec (d_RUN_his ['riverflow']      ), dim1D='cell' ) 
    1283     RUN_riversret       = lmdz.geo2point ( rprec (d_RUN_his ['riversret']      ), dim1D='cell' ) 
    1284     RUN_coastalflow_cpl = lmdz.geo2point ( rprec (d_RUN_his ['coastalflow_cpl']), dim1D='cell' )  
    1285     RUN_riverflow_cpl   = lmdz.geo2point ( rprec (d_RUN_his ['riverflow_cpl']  ), dim1D='cell' ) 
    1286  
    1287 if RUN_HIS == 'ico' : 
    1288     echo ( f'RUN costalflow Grille ICO' ) 
    1289     RUN_coastalflow =  rprec (d_RUN_his ['coastalflow']) 
    1290     RUN_riverflow   =  rprec (d_RUN_his ['riverflow']  ) 
    1291     RUN_runoff      =  rprec (d_RUN_his ['runoff']     ) 
    1292     RUN_drainage    =  rprec (d_RUN_his ['drainage']   ) 
    1293     RUN_riversret   =  rprec (d_RUN_his ['riversret']  ) 
    1294      
    1295     RUN_coastalflow_cpl = rprec (d_RUN_his ['coastalflow_cpl']) 
    1296     RUN_riverflow_cpl   = rprec (d_RUN_his ['riverflow_cpl']  ) 
    1297  
    1298 Step = 0 
    1299  
    1300 if SRF_HIS == 'latlon' : 
    1301     if TestInterp : 
    1302          echo ( f'SRF rain TestInterp' ) 
    1303          SRF_rain     = lmdz.geo2point ( rprec (d_SRF_his ['rain_contfrac_interp'] ), dim1D='cell') 
    1304          SRF_evap     = lmdz.geo2point ( rprec (d_SRF_his ['evap_contfrac_interp'] ), dim1D='cell') 
    1305          SRF_snowf    = lmdz.geo2point ( rprec (d_SRF_his ['snow_contfrac_interp'] ), dim1D='cell') 
    1306          SRF_subli    = lmdz.geo2point ( rprec (d_SRF_his ['subli_contfrac_interp']), dim1D='cell') 
    1307          SRF_transpir = lmdz.geo2point ( rprec (d_SRF_his ['transpir_contfrac_interp']).sum(dim='veget'), dim1D='cell' ) 
    1308          #SRF_rain.attrs.update     ( d_SRF_his ['rain_contfrac_interp'].attrs ) 
    1309          #SRF_evap.attrs.update     ( d_SRF_his ['evap_contfrac_interp'].attrs ) 
    1310          #SRF_snowf.attrs.update    ( d_SRF_his ['snow_contfrac_interp'].attrs ) 
    1311          #SRF_subli.attrs.update    ( d_SRF_his ['subli_contfrac_interp'].attrs ) 
    1312          #SRF_transpir.attrs.update ( d_SRF_his ['transpir_contfrac_interp'].attrs ) 
    1313     else :  
    1314         echo ( f'SRF rain' ) 
    1315         SRF_rain     = lmdz.geo2point ( rprec (d_SRF_his ['rain'] ) , dim1D='cell') 
    1316         SRF_evap     = lmdz.geo2point ( rprec (d_SRF_his ['evap'] ) , dim1D='cell') 
    1317         SRF_snowf    = lmdz.geo2point ( rprec (d_SRF_his ['snowf']) , dim1D='cell') 
    1318         SRF_subli    = lmdz.geo2point ( rprec (d_SRF_his ['subli']) , dim1D='cell') 
    1319         SRF_transpir = lmdz.geo2point ( rprec (d_SRF_his ['transpir']).sum(dim='veget'), dim1D='cell' ) 
    1320  
    1321 if SRF_HIS == 'ico' : 
    1322     echo ( f'SRF rain') 
    1323     SRF_rain     = rprec (d_SRF_his ['rain'] ) 
    1324     SRF_evap     = rprec (d_SRF_his ['evap'] ) 
    1325     SRF_snowf    = rprec (d_SRF_his ['snowf']) 
    1326     SRF_subli    = rprec (d_SRF_his ['subli']) 
    1327     SRF_transpir = rprec (d_SRF_his ['transpir']).sum(dim='veget') 
    1328  
    1329 echo ( f'SRF emp' ) 
    1330 SRF_transpir.attrs['units'] = d_SRF_his ['transpir'].attrs['units'] 
    1331 SRF_emp      = SRF_evap - SRF_rain - SRF_snowf ; SRF_emp.attrs['units'] = SRF_rain.attrs['units'] 
    1332      
    1333 ## Correcting units of SECHIBA variables 
    1334 def mmd2SI ( Var ) : 
    1335     '''Change unit from mm/d or m^3/s to kg/s if needed''' 
    1336     if 'units' in VarT.attrs :  
    1337         if VarT.attrs['units'] in ['m^3/s', 'm3/s', 'm3.s-1',] : 
    1338             VarT.values = VarT.values  * ATM_rho                 ;  VarT.attrs['units'] = 'kg/s' 
    1339         if VarT.attrs['units'] == 'mm/d' : 
    1340             VarT.values = VarT.values  * ATM_rho * (1e-3/86400.) ;  VarT.attrs['units'] = 'kg/s' 
    1341         if VarT.attrs['units'] in ['m^3', 'm3', ] : 
    1342             VarT.values = VarT.values  * ATM_rho                 ;  VarT.attrs['units'] = 'kg' 
    1343              
    1344 for var in [ 'runoff', 'drainage', 'riversret', 'coastalflow', 'riverflow', 'coastalflow_cpl', 'riverflow_cpl' ] : 
    1345     VarT = locals()['RUN_' + var] 
    1346     mmd2SI (VarT) 
    1347  
    1348 for var in ['evap', 'snowf', 'subli', 'transpir', 'rain', 'emp' ] : 
    1349     VarT = locals()['SRF_' + var] 
    1350     mmd2SI (VarT) 
    1351  
    1352 echo ( f'RUN input' ) 
    1353 RUN_input  = RUN_runoff      + RUN_drainage 
    1354 RUN_output = RUN_coastalflow + RUN_riverflow 
    1355  
    1356 echo ( f'ATM flw_wbilo' ) 
     1299if SRF : 
     1300    if RUN_HIS == 'latlon' : 
     1301        echo ( 'RUN costalflow Grille LATLON' ) 
     1302        if TestInterp : 
     1303            echo ( 'RUN runoff TestInterp' ) 
     1304            RUN_runoff      = lmdz.geo2point ( rprec (d_RUN_his ['runoff_contfrac_interp']  )   , dim1d='cell' ) 
     1305            RUN_drainage    = lmdz.geo2point ( rprec (d_RUN_his ['drainage_contfrac_interp'])   , dim1d='cell' ) 
     1306        else : 
     1307            echo ( 'RUN runoff' ) 
     1308            RUN_runoff      = lmdz.geo2point ( rprec (d_RUN_his ['runoff']         ), dim1d='cell' ) 
     1309            RUN_drainage    = lmdz.geo2point ( rprec (d_RUN_his ['drainage']       ), dim1d='cell' ) 
     1310 
     1311        RUN_coastalflow     = lmdz.geo2point ( rprec (d_RUN_his ['coastalflow']    ), dim1d='cell' ) 
     1312        RUN_riverflow       = lmdz.geo2point ( rprec (d_RUN_his ['riverflow']      ), dim1d='cell' ) 
     1313        RUN_riversret       = lmdz.geo2point ( rprec (d_RUN_his ['riversret']      ), dim1d='cell' ) 
     1314        RUN_coastalflow_cpl = lmdz.geo2point ( rprec (d_RUN_his ['coastalflow_cpl']), dim1d='cell' ) 
     1315        RUN_riverflow_cpl   = lmdz.geo2point ( rprec (d_RUN_his ['riverflow_cpl']  ), dim1d='cell' ) 
     1316 
     1317    if RUN_HIS == 'ico' : 
     1318        echo ( 'RUN costalflow Grille ICO' ) 
     1319        RUN_coastalflow =  rprec (d_RUN_his ['coastalflow']) 
     1320        RUN_riverflow   =  rprec (d_RUN_his ['riverflow']  ) 
     1321        RUN_runoff      =  rprec (d_RUN_his ['runoff']     ) 
     1322        RUN_drainage    =  rprec (d_RUN_his ['drainage']   ) 
     1323        RUN_riversret   =  rprec (d_RUN_his ['riversret']  ) 
     1324 
     1325        RUN_coastalflow_cpl = rprec (d_RUN_his ['coastalflow_cpl']) 
     1326        RUN_riverflow_cpl   = rprec (d_RUN_his ['riverflow_cpl']  ) 
     1327 
     1328    Step = 0 
     1329 
     1330    if SRF_HIS == 'latlon' : 
     1331        if TestInterp : 
     1332            echo ( 'SRF rain TestInterp' ) 
     1333            SRF_rain     = lmdz.geo2point ( rprec (d_SRF_his ['rain_contfrac_interp'] ), dim1d='cell') 
     1334            SRF_evap     = lmdz.geo2point ( rprec (d_SRF_his ['evap_contfrac_interp'] ), dim1d='cell') 
     1335            SRF_snowf    = lmdz.geo2point ( rprec (d_SRF_his ['snow_contfrac_interp'] ), dim1d='cell') 
     1336            SRF_subli    = lmdz.geo2point ( rprec (d_SRF_his ['subli_contfrac_interp']), dim1d='cell') 
     1337            SRF_transpir = lmdz.geo2point ( rprec (d_SRF_his ['transpir_contfrac_interp']).sum(dim='veget'), dim1d='cell' ) 
     1338            #SRF_rain.attrs.update     ( d_SRF_his ['rain_contfrac_interp'].attrs ) 
     1339            #SRF_evap.attrs.update     ( d_SRF_his ['evap_contfrac_interp'].attrs ) 
     1340            #SRF_snowf.attrs.update    ( d_SRF_his ['snow_contfrac_interp'].attrs ) 
     1341            #SRF_subli.attrs.update    ( d_SRF_his ['subli_contfrac_interp'].attrs ) 
     1342            #SRF_transpir.attrs.update ( d_SRF_his ['transpir_contfrac_interp'].attrs ) 
     1343        else : 
     1344            echo ( 'SRF rain' ) 
     1345            SRF_rain     = lmdz.geo2point ( rprec (d_SRF_his ['rain'] ) , dim1d='cell') 
     1346            SRF_evap     = lmdz.geo2point ( rprec (d_SRF_his ['evap'] ) , dim1d='cell') 
     1347            SRF_snowf    = lmdz.geo2point ( rprec (d_SRF_his ['snowf']) , dim1d='cell') 
     1348            SRF_subli    = lmdz.geo2point ( rprec (d_SRF_his ['subli']) , dim1d='cell') 
     1349            SRF_transpir = lmdz.geo2point ( rprec (d_SRF_his ['transpir']).sum(dim='veget'), dim1d='cell' ) 
     1350 
     1351    if SRF_HIS == 'ico' : 
     1352        echo ( 'SRF rain') 
     1353        SRF_rain     = rprec (d_SRF_his ['rain'] ) 
     1354        SRF_evap     = rprec (d_SRF_his ['evap'] ) 
     1355        SRF_snowf    = rprec (d_SRF_his ['snowf']) 
     1356        SRF_subli    = rprec (d_SRF_his ['subli']) 
     1357        SRF_transpir = rprec (d_SRF_his ['transpir']).sum(dim='veget') 
     1358 
     1359    echo ( 'SRF emp' ) 
     1360    SRF_transpir.attrs['units'] = d_SRF_his ['transpir'].attrs['units'] 
     1361    SRF_emp      = SRF_evap - SRF_rain - SRF_snowf ; SRF_emp.attrs['units'] = SRF_rain.attrs['units'] 
     1362 
     1363    ## Correcting units of SECHIBA variables 
     1364    def mmd2si ( pvar ) : 
     1365        '''Change unit from mm/d or m^3/s to kg/s if needed''' 
     1366        if 'units' in pvar.attrs : 
     1367            if pvar.attrs['units'] in ['m^3/s', 'm3/s', 'm3.s-1',] : 
     1368                pvar.values = pvar.values  * ATM_RHO                    ;  pvar.attrs['units'] = 'kg/s' 
     1369            if pvar.attrs['units'] == 'mm/d' : 
     1370                pvar.values = pvar.values  * ATM_RHO * (1e-3/lmdz.RDAY) ;  pvar.attrs['units'] = 'kg/s' 
     1371            if pvar.attrs['units'] in ['m^3', 'm3', ] : 
     1372                pvar.values = pvar.values  * ATM_RHO                    ;  pvar.attrs['units'] = 'kg' 
     1373 
     1374    for var in [ 'runoff', 'drainage', 'riversret', 'coastalflow', 'riverflow', 'coastalflow_cpl', 'riverflow_cpl' ] : 
     1375        zvar = locals()['RUN_' + var] 
     1376        mmd2si (zvar) 
     1377 
     1378    for var in ['evap', 'snowf', 'subli', 'transpir', 'rain', 'emp' ] : 
     1379        zvar = locals()['SRF_' + var] 
     1380        mmd2si (zvar) 
     1381 
     1382    echo ( 'RUN input' ) 
     1383    RUN_input  = RUN_runoff      + RUN_drainage 
     1384    RUN_output = RUN_coastalflow + RUN_riverflow 
     1385 
     1386echo ( 'ATM flw_wbilo' ) 
    13571387ATM_flx_wbilo       = ATM_flux_int ( ATM_wbilo      ) 
    13581388ATM_flx_wevap       = ATM_flux_int ( ATM_wevap      ) 
     
    13671397ATM_flx_wbilo_sic   = ATM_flux_int ( ATM_wbilo_sic  ) 
    13681398ATM_flx_wbilo_ter   = ATM_flux_int ( ATM_wbilo_ter  ) 
     1399# Type d'integration a verifier 
    13691400ATM_flx_calving     = ATM_flux_int ( ATM_fqcalving  ) 
    13701401ATM_flx_fqfonte     = ATM_flux_int ( ATM_fqfonte    ) 
     
    13731404LIC_flx_fqfonte     = LIC_flux_int ( ATM_fqfonte    ) 
    13741405 
    1375 echo ( f'ATM flx precip' ) 
     1406echo ( 'ATM flx precip' ) 
    13761407ATM_flx_precip      = ATM_flux_int ( ATM_precip     ) 
    13771408ATM_flx_snowf       = ATM_flux_int ( ATM_snowf      ) 
     
    13841415LIC_flx_runlic      = LIC_flux_int ( ATM_runofflic  ) 
    13851416 
    1386 echo ( f'ATM flx_wrain_ter' ) 
     1417echo ( 'ATM flx_wrain_ter' ) 
    13871418ATM_flx_wrain_ter    = ATM_flux_int ( ATM_wrain_ter ) 
    13881419ATM_flx_wrain_oce    = ATM_flux_int ( ATM_wrain_oce ) 
     
    13971428ATM_flx_wsnow_sea    = ATM_flux_int ( ATM_wsnow_sea ) 
    13981429 
    1399 echo ( f'ATM flx_evap_ter' )  
     1430echo ( 'ATM flx_evap_ter' ) 
    14001431ATM_flx_wevap_ter    = ATM_flux_int ( ATM_wevap_ter ) 
    14011432ATM_flx_wevap_oce    = ATM_flux_int ( ATM_wevap_oce ) 
     
    14161447ATM_flx_emp          = ATM_flux_int ( ATM_emp ) 
    14171448 
    1418 echo ( f'RUN flx_coastal' ) 
    1419 RUN_flx_coastal     = ONE_flux_int ( RUN_coastalflow) 
    1420 echo ( f'RUN flx_river' ) 
    1421 RUN_flx_river       = ONE_flux_int ( RUN_riverflow  ) 
    1422 echo ( f'RUN flx_coastal_cpl' ) 
    1423 RUN_flx_coastal_cpl = ONE_flux_int ( RUN_coastalflow_cpl) 
    1424 echo ( f'RUN flx_river_cpl' ) 
    1425 RUN_flx_river_cpl   = ONE_flux_int ( RUN_riverflow_cpl  ) 
    1426 echo ( f'RUN flx_drainage' ) 
    1427 RUN_flx_drainage    = SRF_flux_int ( RUN_drainage   ) 
    1428 echo ( f'RUN flx_riversset' ) 
    1429 RUN_flx_riversret   = SRF_flux_int ( RUN_riversret  ) 
    1430 echo ( f'RUN flx_runoff' ) 
    1431 RUN_flx_runoff      = SRF_flux_int ( RUN_runoff     ) 
    1432 echo ( f'RUN flx_input' ) 
    1433 RUN_flx_input       = SRF_flux_int ( RUN_input      ) 
    1434 echo ( f'RUN flx_output' ) 
    1435 RUN_flx_output      = ONE_flux_int ( RUN_output     ) 
    1436  
    1437 echo ( f'RUN flx_bil' ) ; Step += 1 
    1438 #RUN_flx_bil    = RUN_flx_input   - RUN_flx_output 
    1439 #RUN_flx_rivcoa = RUN_flx_coastal + RUN_flx_river 
    1440  
    1441 RUN_flx_bil    = ONE_flux_int ( RUN_input       - RUN_output) 
    1442 RUN_flx_rivcoa = ONE_flux_int ( RUN_coastalflow + RUN_riverflow) 
    1443  
    1444 prtFlux ('wbilo_oce            ', ATM_flx_wbilo_oce     , 'f' )           
    1445 prtFlux ('wbilo_sic            ', ATM_flx_wbilo_sic     , 'f' )           
    1446 prtFlux ('wbilo_sic+oce        ', ATM_flx_wbilo_sea     , 'f' )           
    1447 prtFlux ('wbilo_ter            ', ATM_flx_wbilo_ter     , 'f' )           
    1448 prtFlux ('wbilo_lic            ', ATM_flx_wbilo_lic     , 'f' )           
    1449 prtFlux ('Sum wbilo_*          ', ATM_flx_wbilo         , 'f', True)   
    1450 prtFlux ('E-P                  ', ATM_flx_emp           , 'f', True)   
    1451 prtFlux ('calving              ', ATM_flx_calving       , 'f' )  
    1452 prtFlux ('fqfonte              ', ATM_flx_fqfonte       , 'f' )        
    1453 prtFlux ('precip               ', ATM_flx_precip        , 'f' )        
    1454 prtFlux ('snowf                ', ATM_flx_snowf         , 'f' )         
     1449if SRF : 
     1450    echo ( 'RUN flx_coastal' ) 
     1451    RUN_flx_coastal     = ONE_flux_int ( RUN_coastalflow) 
     1452    echo ( 'RUN flx_river' ) 
     1453    RUN_flx_river       = ONE_flux_int ( RUN_riverflow  ) 
     1454    echo ( 'RUN flx_coastal_cpl' ) 
     1455    RUN_flx_coastal_cpl = ONE_flux_int ( RUN_coastalflow_cpl) 
     1456    echo ( 'RUN flx_river_cpl' ) 
     1457    RUN_flx_river_cpl   = ONE_flux_int ( RUN_riverflow_cpl  ) 
     1458    echo ( 'RUN flx_drainage' ) 
     1459    RUN_flx_drainage    = SRF_flux_int ( RUN_drainage   ) 
     1460    echo ( 'RUN flx_riversset' ) 
     1461    RUN_flx_riversret   = SRF_flux_int ( RUN_riversret  ) 
     1462    echo ( 'RUN flx_runoff' ) 
     1463    RUN_flx_runoff      = SRF_flux_int ( RUN_runoff     ) 
     1464    echo ( 'RUN flx_input' ) 
     1465    RUN_flx_input       = SRF_flux_int ( RUN_input      ) 
     1466    echo ( 'RUN flx_output' ) 
     1467    RUN_flx_output      = ONE_flux_int ( RUN_output     ) 
     1468 
     1469    echo ( 'RUN flx_bil' ) ; Step += 1 
     1470    #RUN_flx_bil    = RUN_flx_input   - RUN_flx_output 
     1471    #RUN_flx_rivcoa = RUN_flx_coastal + RUN_flx_river 
     1472 
     1473    RUN_flx_bil    = ONE_flux_int ( RUN_input       - RUN_output) 
     1474    RUN_flx_rivcoa = ONE_flux_int ( RUN_coastalflow + RUN_riverflow) 
     1475 
     1476prtFlux ('wbilo_oce            ', ATM_flx_wbilo_oce     , 'f' ) 
     1477prtFlux ('wbilo_sic            ', ATM_flx_wbilo_sic     , 'f' ) 
     1478prtFlux ('wbilo_sic+oce        ', ATM_flx_wbilo_sea     , 'f' ) 
     1479prtFlux ('wbilo_ter            ', ATM_flx_wbilo_ter     , 'f' ) 
     1480prtFlux ('wbilo_lic            ', ATM_flx_wbilo_lic     , 'f' ) 
     1481prtFlux ('Sum wbilo_*          ', ATM_flx_wbilo         , 'f', True) 
     1482prtFlux ('E-P                  ', ATM_flx_emp           , 'f', True) 
     1483prtFlux ('calving              ', ATM_flx_calving       , 'f' ) 
     1484prtFlux ('fqfonte              ', ATM_flx_fqfonte       , 'f' ) 
     1485prtFlux ('precip               ', ATM_flx_precip        , 'f' ) 
     1486prtFlux ('snowf                ', ATM_flx_snowf         , 'f' ) 
    14551487prtFlux ('evap                 ', ATM_flx_evap          , 'f' ) 
    14561488prtFlux ('runoff lic           ', ATM_flx_runlic        , 'f' ) 
     
    14671499prtFlux ('ERROR emp            ', ATM_flx_wemp    - ATM_flx_emp   , 'e', True ) 
    14681500 
    1469  
    1470 echo ( '\n====================================================================================' ) 
    1471 echo ( f'-- RUNOFF Fluxes  -- {Title} ' ) 
    1472 prtFlux ('coastalflow   ', RUN_flx_coastal    , 'f' )  
    1473 prtFlux ('riverflow     ', RUN_flx_river      , 'f' )         
    1474 prtFlux ('coastal_cpl   ', RUN_flx_coastal_cpl, 'f' )   
    1475 prtFlux ('riverf_cpl    ', RUN_flx_river_cpl  , 'f' )     
    1476 prtFlux ('river+coastal ', RUN_flx_rivcoa     , 'f' )    
    1477 prtFlux ('drainage      ', RUN_flx_drainage   , 'f' )    
    1478 prtFlux ('riversret     ', RUN_flx_riversret  , 'f' )    
    1479 prtFlux ('runoff        ', RUN_flx_runoff     , 'f' )    
    1480 prtFlux ('river in      ', RUN_flx_input      , 'f' )    
    1481 prtFlux ('river out     ', RUN_flx_output     , 'f' )    
    1482 prtFlux ('river bil     ', RUN_flx_bil        , 'f' )    
     1501if SRF : 
     1502    echo ( '\n====================================================================================' ) 
     1503    echo ( f'-- RUNOFF Fluxes  -- {Title} ' ) 
     1504    prtFlux ('coastalflow   ', RUN_flx_coastal    , 'f' ) 
     1505    prtFlux ('riverflow     ', RUN_flx_river      , 'f' ) 
     1506    prtFlux ('coastal_cpl   ', RUN_flx_coastal_cpl, 'f' ) 
     1507    prtFlux ('riverf_cpl    ', RUN_flx_river_cpl  , 'f' ) 
     1508    prtFlux ('river+coastal ', RUN_flx_rivcoa     , 'f' ) 
     1509    prtFlux ('drainage      ', RUN_flx_drainage   , 'f' ) 
     1510    prtFlux ('riversret     ', RUN_flx_riversret  , 'f' ) 
     1511    prtFlux ('runoff        ', RUN_flx_runoff     , 'f' ) 
     1512    prtFlux ('river in      ', RUN_flx_input      , 'f' ) 
     1513    prtFlux ('river out     ', RUN_flx_output     , 'f' ) 
     1514    prtFlux ('river bil     ', RUN_flx_bil        , 'f' ) 
    14831515 
    14841516ATM_flx_budget = -ATM_flx_wbilo + ATM_flx_calving + ATM_flx_runlic #+ ATM_flx_fqfonte + RUN_flx_river 
     
    15421574echo ( 'LIC error (-wbilo_lic - runofflic*frac_lic)                   = {:12.4e} (rel) '.format ( (LIC_flx_budget3-dLIC_mas_wat)/dLIC_mas_wat) ) 
    15431575 
    1544 echo ( '\n====================================================================================' ) 
    1545 echo ( f'-- SECHIBA fluxes  -- {Title} ' ) 
    1546  
    1547 SRF_flx_rain     = SRF_flux_int ( SRF_rain     ) 
    1548 SRF_flx_evap     = SRF_flux_int ( SRF_evap     ) 
    1549 SRF_flx_snowf    = SRF_flux_int ( SRF_snowf    ) 
    1550 SRF_flx_subli    = SRF_flux_int ( SRF_subli    ) 
    1551 SRF_flx_transpir = SRF_flux_int ( SRF_transpir ) 
    1552 SRF_flx_emp      = SRF_flux_int ( SRF_emp      ) 
    1553  
    1554 RUN_flx_torouting   = SRF_flux_int  ( RUN_runoff       + RUN_drainage) 
    1555 RUN_flx_fromrouting = ONE_flux_int  ( RUN_coastalflow + RUN_riverflow ) 
    1556  
    1557 SRF_flx_all =  SRF_flux_int  ( SRF_rain + SRF_snowf - SRF_evap - RUN_runoff - RUN_drainage ) 
    1558  
    1559 prtFlux ('rain         ', SRF_flx_rain       , 'f' ) 
    1560 prtFlux ('evap         ', SRF_flx_evap       , 'f' ) 
    1561 prtFlux ('snowf        ', SRF_flx_snowf      , 'f' ) 
    1562 prtFlux ('E-P          ', SRF_flx_emp        , 'f' ) 
    1563 prtFlux ('subli        ', SRF_flx_subli      , 'f' ) 
    1564 prtFlux ('transpir     ', SRF_flx_transpir   , 'f' ) 
    1565 prtFlux ('to routing   ', RUN_flx_torouting  , 'f' ) 
    1566 prtFlux ('budget       ', SRF_flx_all        , 'f', small=True ) 
    1567  
    1568 echo ( '\n------------------------------------------------------------------------------------' ) 
    1569 echo ( 'Water content in surface ' ) 
    1570 echo ( f'SRF_mas_wat_beg  = {SRF_mas_wat_beg:12.6e} kg | SRF_mas_wat_end  = {SRF_mas_wat_end:12.6e} kg ' ) 
    1571 prtFlux ( 'dMass (water srf)', dSRF_mas_wat, 'e', small=True) 
    1572 prtFlux ( 'Error            ',  SRF_flx_all-dSRF_mas_wat, 'e', small=True ) 
    1573 echo ( 'dMass (water srf) = {:12.4e} (rel)   '.format ( (SRF_flx_all-dSRF_mas_wat)/dSRF_mas_wat) ) 
    1574  
    1575 echo ( '\n====================================================================================' ) 
    1576 echo ( f'-- Check ATM vs. SRF -- {Title} ' ) 
    1577 prtFlux ('E-P ATM       ', ATM_flx_wemp_ter   , 'f' ) 
    1578 prtFlux ('wbilo ter     ', ATM_flx_wbilo_ter  , 'f' ) 
    1579 prtFlux ('E-P SRF       ', SRF_flx_emp        , 'f' ) 
    1580 prtFlux ('SRF/ATM error ', ATM_flx_wbilo_ter - SRF_flx_emp, 'e', True) 
    1581 echo ( 'SRF/ATM error {:12.3e} (rel)  '.format ( (ATM_flx_wbilo_ter - SRF_flx_emp)/SRF_flx_emp ) ) 
    1582  
    1583 echo ('') 
    1584 echo ( '\n====================================================================================' ) 
    1585 echo ( f'-- RUNOFF fluxes  -- {Title} ' ) 
    1586 RUN_flx_all = RUN_flx_torouting - RUN_flx_river - RUN_flx_coastal 
    1587 prtFlux ('runoff    ', RUN_flx_runoff      , 'f' )  
    1588 prtFlux ('drainage  ', RUN_flx_drainage    , 'f' )  
    1589 prtFlux ('run+drain ', RUN_flx_torouting   , 'f' )  
    1590 prtFlux ('river     ', RUN_flx_river       , 'f' )  
    1591 prtFlux ('coastal   ', RUN_flx_coastal     , 'f' )  
    1592 prtFlux ('riv+coa   ', RUN_flx_fromrouting , 'f' )  
    1593 prtFlux ('budget    ', RUN_flx_all         , 'f' , small=True) 
    1594  
    1595 echo ( '\n------------------------------------------------------------------------------------' ) 
    1596 echo ( f'Water content in routing+lake  -- {Title} ' ) 
    1597 echo ( f'RUN_mas_wat_beg  = {RUN_mas_wat_beg:12.6e} kg | RUN_mas_wat_end = {RUN_mas_wat_end:12.6e} kg ' ) 
    1598 prtFlux ( 'dMass (routing)  ', dRUN_mas_wat+dSRF_mas_lake, 'f', small=True) 
    1599 prtFlux ( 'Routing error    ', RUN_flx_all+dSRF_mas_lake-dRUN_mas_wat, 'e', small=True ) 
    1600 echo ( 'Routing error : {:12.3e} (rel)'.format ( (RUN_flx_all-dSRF_mas_lake-dRUN_mas_wat)/(dRUN_mas_wat+dSRF_mas_lake) ) ) 
    1601  
    1602 echo ( '\n------------------------------------------------------------------------------------' ) 
    1603 echo ( f'Water content in routing  -- {Title} ' ) 
    1604 echo ( f'RUN_mas_wat_beg  = {RUN_mas_wat_beg:12.6e} kg | RUN_mas_wat_end = {RUN_mas_wat_end:12.6e} kg ' ) 
    1605 prtFlux ( 'dMass (routing) ', dRUN_mas_wat, 'f', small=True  ) 
    1606 prtFlux ( 'Routing error   ', RUN_flx_all-dRUN_mas_wat, 'e', small=True) 
    1607 echo ( 'Routing error : {:12.3e} (rel)'.format ( (RUN_flx_all-dRUN_mas_wat)/dRUN_mas_wat ) ) 
     1576if SRF : 
     1577    echo ( '\n====================================================================================' ) 
     1578    echo ( f'-- SECHIBA fluxes  -- {Title} ' ) 
     1579 
     1580    SRF_flx_rain     = SRF_flux_int ( SRF_rain     ) 
     1581    SRF_flx_evap     = SRF_flux_int ( SRF_evap     ) 
     1582    SRF_flx_snowf    = SRF_flux_int ( SRF_snowf    ) 
     1583    SRF_flx_subli    = SRF_flux_int ( SRF_subli    ) 
     1584    SRF_flx_transpir = SRF_flux_int ( SRF_transpir ) 
     1585    SRF_flx_emp      = SRF_flux_int ( SRF_emp      ) 
     1586 
     1587    RUN_flx_torouting   = SRF_flux_int  ( RUN_runoff       + RUN_drainage) 
     1588    RUN_flx_fromrouting = ONE_flux_int  ( RUN_coastalflow + RUN_riverflow ) 
     1589 
     1590    SRF_flx_all =  SRF_flux_int  ( SRF_rain + SRF_snowf - SRF_evap - RUN_runoff - RUN_drainage ) 
     1591 
     1592    prtFlux ('rain         ', SRF_flx_rain       , 'f' ) 
     1593    prtFlux ('evap         ', SRF_flx_evap       , 'f' ) 
     1594    prtFlux ('snowf        ', SRF_flx_snowf      , 'f' ) 
     1595    prtFlux ('E-P          ', SRF_flx_emp        , 'f' ) 
     1596    prtFlux ('subli        ', SRF_flx_subli      , 'f' ) 
     1597    prtFlux ('transpir     ', SRF_flx_transpir   , 'f' ) 
     1598    prtFlux ('to routing   ', RUN_flx_torouting  , 'f' ) 
     1599    prtFlux ('budget       ', SRF_flx_all        , 'f', small=True ) 
     1600 
     1601    echo ( '\n------------------------------------------------------------------------------------' ) 
     1602    echo ( 'Water content in surface ' ) 
     1603    echo ( f'SRF_mas_wat_beg  = {SRF_mas_wat_beg:12.6e} kg | SRF_mas_wat_end  = {SRF_mas_wat_end:12.6e} kg ' ) 
     1604    prtFlux ( 'dMass (water srf)', dSRF_mas_wat, 'e', small=True) 
     1605    prtFlux ( 'Error            ',  SRF_flx_all-dSRF_mas_wat, 'e', small=True ) 
     1606    echo ( 'dMass (water srf) = {:12.4e} (rel)   '.format ( (SRF_flx_all-dSRF_mas_wat)/dSRF_mas_wat) ) 
     1607 
     1608    echo ( '\n====================================================================================' ) 
     1609    echo ( f'-- Check ATM vs. SRF -- {Title} ' ) 
     1610    prtFlux ('E-P ATM       ', ATM_flx_wemp_ter   , 'f' ) 
     1611    prtFlux ('wbilo ter     ', ATM_flx_wbilo_ter  , 'f' ) 
     1612    prtFlux ('E-P SRF       ', SRF_flx_emp        , 'f' ) 
     1613    prtFlux ('SRF/ATM error ', ATM_flx_wbilo_ter - SRF_flx_emp, 'e', True) 
     1614    echo ( 'SRF/ATM error {:12.3e} (rel)  '.format ( (ATM_flx_wbilo_ter - SRF_flx_emp)/SRF_flx_emp ) ) 
     1615 
     1616    echo ('') 
     1617    echo ( '\n====================================================================================' ) 
     1618    echo ( f'-- RUNOFF fluxes  -- {Title} ' ) 
     1619    RUN_flx_all = RUN_flx_torouting - RUN_flx_river - RUN_flx_coastal 
     1620    prtFlux ('runoff    ', RUN_flx_runoff      , 'f' ) 
     1621    prtFlux ('drainage  ', RUN_flx_drainage    , 'f' ) 
     1622    prtFlux ('run+drain ', RUN_flx_torouting   , 'f' ) 
     1623    prtFlux ('river     ', RUN_flx_river       , 'f' ) 
     1624    prtFlux ('coastal   ', RUN_flx_coastal     , 'f' ) 
     1625    prtFlux ('riv+coa   ', RUN_flx_fromrouting , 'f' ) 
     1626    prtFlux ('budget    ', RUN_flx_all         , 'f' , small=True) 
     1627 
     1628    echo ( '\n------------------------------------------------------------------------------------' ) 
     1629    echo ( f'Water content in routing+lake  -- {Title} ' ) 
     1630    echo ( f'RUN_mas_wat_beg  = {RUN_mas_wat_beg:12.6e} kg | RUN_mas_wat_end = {RUN_mas_wat_end:12.6e} kg ' ) 
     1631    prtFlux ( 'dMass (routing)  ', dRUN_mas_wat+dSRF_mas_lake, 'f', small=True) 
     1632    prtFlux ( 'Routing error    ', RUN_flx_all+dSRF_mas_lake-dRUN_mas_wat, 'e', small=True ) 
     1633    echo ( 'Routing error : {:12.3e} (rel)'.format ( (RUN_flx_all-dSRF_mas_lake-dRUN_mas_wat)/(dRUN_mas_wat+dSRF_mas_lake) ) ) 
     1634 
     1635    echo ( '\n------------------------------------------------------------------------------------' ) 
     1636    echo ( f'Water content in routing  -- {Title} ' ) 
     1637    echo ( f'RUN_mas_wat_beg  = {RUN_mas_wat_beg:12.6e} kg | RUN_mas_wat_end = {RUN_mas_wat_end:12.6e} kg ' ) 
     1638    prtFlux ( 'dMass (routing) ', dRUN_mas_wat, 'f', small=True  ) 
     1639    prtFlux ( 'Routing error   ', RUN_flx_all-dRUN_mas_wat, 'e', small=True) 
     1640    echo ( 'Routing error : {:12.3e} (rel)'.format ( (RUN_flx_all-dRUN_mas_wat)/dRUN_mas_wat ) ) 
    16081641 
    16091642echo ( ' ' ) 
     
    16111644 
    16121645echo ( 'SVN Information' ) 
    1613 for clef in SVN.keys () : echo ( SVN[clef] ) 
     1646for kk in SVN.keys(): 
     1647    print ( SVN[kk] ) 
  • TOOLS/WATER_BUDGET/CPL_waterbudget.py

    r6651 r6665  
    4242import numpy as np, xarray as xr 
    4343 
    44 # Check python version 
    45 if sys.version_info < (3, 8, 0) : 
    46     print ( f'Python version : {platform.python_version()}' )  
    47     raise Exception ( "Minimum Python version is 3.8" ) 
    48  
    4944## Import local modules 
    5045import WaterUtils as wu 
     
    5247import nemo, lmdz 
    5348 
    54 from WaterUtils import VarInt, Rho, Ra, Grav, ICE_rho_ice, ICE_rho_sno, OCE_rho_liq, ATM_rho, SRF_rho, RUN_rho, ICE_rho_pnd, YearLength 
     49from WaterUtils import RA, GRAV, ICE_RHO_ICE, ICE_RHO_SNO, OCE_RHO_LIQ, \ 
     50                       ATM_RHO, SRF_RHO, RUN_RHO, ICE_RHO_PND, YEAR_LENGTH 
    5551 
    5652## Creates parser for reading .ini input file 
     
    6662YearBegin=None ; YearEnd=None ; DateBegin=None ; DateEnd=None 
    6763 
     64Timer=False ; Debug=False 
    6865## 
    6966ARCHIVE=None ; STORAGE=None ; SCRATCHDIR=None ; R_IN=None ; rebuild=None ; TmpDir=None 
    70 FileDir=None ; FileOut=None 
     67FileDir=None ; FileOut=None ; R_OUT=None ; R_FIG=None ; R_FIGR=None ; R_BUFR=None ; R_SAVE=None 
     68R_BUF_KSH=None ; REBUILD_DIR=None ; POST_DIR=None ; L_EXP=None 
     69 
    7170dir_ATM_his=None ; dir_SRF_his=None ; dir_OCE_his=None ; dir_ICE_his=None 
    7271FileCommon=None ; file_ATM_his=None ; file_SRF_his=None ; file_RUN_his=None 
     
    7776file_ICE_beg=None ; file_OCE_beg=None 
    7877file_OCE_end=None ; file_ICE_beg=None ; file_OCE_end=None ; file_ICE_end=None 
     78TarRestartDate_beg=None ; TarRestartDate_end=None 
     79file_DYN_aire=None 
    7980tar_restart_beg_ATM=None ; tar_restart_beg_DYN=None ; tar_restart_beg_SRF=None 
    8081tar_restart_beg_RUN=None ; tar_restart_beg_OCE=None ; tar_restart_beg_ICE=None 
     
    8283tar_restart_end_RUN=None ; tar_restart_end_OCE=None ; tar_restart_end_ICE=None 
    8384ContinueOnError=False ; ErrorCount=0 
     85FileDirOCE=None ; FileDirATM=None ; FileDirICE=None ; FileDirSRF=None ; FileDirRUN=None 
    8486 
    8587## 
     
    8789## --------------------------------- 
    8890# Default is float (full precision). Degrade the precision by using np.float32 
    89 # Restart file are always read at the full precision 
     91# Restart files are always read at the full precision 
    9092readPrec=float 
    9193 
     
    148150## Reading config file 
    149151## ------------------- 
    150 for Section in ['Config', 'Experiment', 'libIGCM', 'Files', 'Physics' ] : 
    151    if Section in config.keys () :  
    152         print ( f'\nReading [{Section}]' ) 
    153         for VarName in config[Section].keys() : 
    154             locals()[VarName] = config[Section][VarName] 
    155             exec  ( f'{VarName} = wu.setBool ({VarName})' ) 
    156             exec  ( f'{VarName} = wu.setNum  ({VarName})' ) 
    157             exec  ( f'{VarName} = wu.setNone ({VarName})' ) 
    158             exec  ( f'wu.{VarName} = {VarName}' ) 
    159             print ( f'    {VarName:21} set to : {locals()[VarName]}' ) 
    160             #exec ( f'del {VarName}' ) 
     152# Each entry in the .ini file will create a Python variable with the same name 
     153for Section in config.keys () :  
     154    print ( f'\nReading [{Section}]' ) 
     155    for VarName in config[Section].keys() : 
     156        locals()[VarName] = config[Section][VarName] 
     157        exec  ( f'{VarName} = wu.setBool ({VarName})' ) 
     158        exec  ( f'{VarName} = wu.setNum  ({VarName})' ) 
     159        exec  ( f'{VarName} = wu.setNone ({VarName})' ) 
     160        exec  ( f'wu.{VarName} = {VarName}' ) 
     161        print ( f'    {VarName:21} set to : {locals()[VarName]}' ) 
    161162 
    162163print ( f'\nConfig file readed : {IniFile} ' ) 
     
    164165## 
    165166## Reading prec 
    166 if wu.unDefined ( 'readPrec' )  : 
     167if not readPrec  : 
    167168    readPrec = np.float64 
    168169else : 
     
    171172    if readPrec in [         "float16", "r2", "half"  , "<class 'numpy.float16'>" ] : readPrec = np.float16 
    172173     
    173 ## Some physical constants 
     174# Some physical constants 
    174175## ======================= 
    175 if wu.unDefined ( 'Ra' )           : Ra          = wu.Ra           #-- Earth Radius (m) 
    176 if wu.unDefined ( 'Grav' )         : Grav        = wu.Grav         #-- Gravity (m^2/s 
    177 if wu.unDefined ( 'ICE_rho_ice' )  : ICE_rho_ice = wu.ICE_rho_ice  #-- Ice volumic mass (kg/m3) in LIM3 
    178 if wu.unDefined ( 'ICE_rho_sno')   : ICE_rho_sno = wu.ICE_rho_sno  #-- Snow volumic mass (kg/m3) in LIM3 
    179 if wu.unDefined ( 'OCE_rho_liq' )  : OCE_rho_liq = wu.OCE_rho_liq  #-- Ocean water volumic mass (kg/m3) in NEMO 
    180 if wu.unDefined ( 'ATM_rho' )      : ATM_rho     = wu.ATM_rho      #-- Water volumic mass in atmosphere (kg/m^3) 
    181 if wu.unDefined ( 'SRF_rho' )      : SRF_rho     = wu.SRF_rho      #-- Water volumic mass in surface reservoir (kg/m^3) 
    182 if wu.unDefined ( 'RUN_rho' )      : RUN_rho     = wu.RUN_rho      #-- Water volumic mass of rivers (kg/m^3) 
    183 if wu.unDefined ( 'ICE_rho_pnd' )  : ICE_rho_pnd = wu.ICE_rho_pnd  #-- Water volumic mass in ice ponds (kg/m^3) 
    184 if wu.unDefined ( 'YearLength' )   : YearLength  = wu.YearLength   #-- Year length (s) 
    185  
    186 ## Set libIGCM and machine dependant values 
    187 ## ---------------------------------------- 
    188 if not 'Files' in config.keys () : config['Files'] = {} 
    189  
    190 config['Physics'] = { 'Ra':str(Ra), 'Grav':str(Grav), 'ICE_rho_ice':str(ICE_rho_ice), 'ICE_rho_sno':str(ICE_rho_sno), 
    191                       'OCE_rho_liq':str(OCE_rho_liq), 'ATM_rho':str(ATM_rho), 'SRF_rho':str(SRF_rho), 'RUN_rho':str(RUN_rho)} 
    192  
    193 config['Config'] = { 'ContinueOnError':str(ContinueOnError), 'TestInterp':str(TestInterp), 'readPrec':str(readPrec) } 
     176if not RA           : RA          = wu.RA           #-- Earth Radius (m) 
     177if not GRAV         : GRAV        = wu.GRAV         #-- Gravity (m^2/s 
     178if not ICE_RHO_ICE  : ICE_RHO_ICE = wu.ICE_RHO_ICE  #-- Ice volumic mass (kg/m3) in LIM3 
     179if not ICE_RHO_SNO  : ICE_RHO_SNO = wu.ICE_RHO_SNO  #-- Snow volumic mass (kg/m3) in LIM3 
     180if not OCE_RHO_LIQ  : OCE_RHO_LIQ = wu.OCE_RHO_LIQ  #-- Ocean water volumic mass (kg/m3) in NEMO 
     181if not ATM_RHO      : ATM_RHO     = wu.ATM_RHO      #-- Water volumic mass in atmosphere (kg/m^3) 
     182if not SRF_RHO      : SRF_RHO     = wu.SRF_RHO      #-- Water volumic mass in surface reservoir (kg/m^3) 
     183if not RUN_RHO      : RUN_RHO     = wu.RUN_RHO      #-- Water volumic mass of rivers (kg/m^3) 
     184if not ICE_RHO_PND  : ICE_RHO_PND = wu.ICE_RHO_PND  #-- Water volumic mass in ice ponds (kg/m^3) 
     185if not YEAR_LENGTH   : YEAR_LENGTH  = wu.YEAR_LENGTH   #-- Year length (s) 
     186 
     187if not 'Files'   in config.keys () : config['Files']   = {} 
     188if not 'Physics' in config.keys () : config['Physics'] = {} 
     189if not 'Config'  in config.keys () : config['Physics'] = {} 
     190     
     191 
     192config['Physics'].update ( { 'RA':str(RA), 'GRAV':str(GRAV), 'ICE_RHO_ICE':str(ICE_RHO_ICE), 'ICE_RHO_SNO':str(ICE_RHO_SNO), 
     193                      'OCE_RHO_LIQ':str(OCE_RHO_LIQ), 'ATM_RHO':str(ATM_RHO), 'SRF_RHO':str(SRF_RHO), 'RUN_RHO':str(RUN_RHO)} ) 
     194 
     195config['Config'].update ( { 'ContinueOnError':str(ContinueOnError), 'TestInterp':str(TestInterp), 'readPrec':str(readPrec), 
     196                            'Debug':str(Debug), 'Timer':str(Timer) } ) 
    194197 
    195198## -------------------------- 
     
    198201 
    199202mm = libIGCM_sys.config ( TagName=TagName, SpaceName=SpaceName, ExperimentName=ExperimentName, JobName=JobName, User=User, Group=Group, 
    200              ARCHIVE=None, SCRATCHDIR=None, STORAGE=None, R_IN=None, R_OUT=None, R_FIG=None, rebuild=None, TmpDir=None,  
    201              R_SAVE=None, R_FIGR=None, R_BUFR=None, R_BUF_KSH=None, REBUILD_DIR=None, POST_DIR=None ) 
     203             ARCHIVE=ARCHIVE, SCRATCHDIR=SCRATCHDIR, STORAGE=STORAGE, R_IN=R_IN, R_OUT=R_OUT, R_FIG=R_FIG, rebuild=rebuild, TmpDir=TmpDir,  
     204             R_SAVE=R_SAVE, R_FIGR=R_FIGR, R_BUFR=R_BUFR, R_BUF_KSH=R_BUF_KSH, REBUILD_DIR=REBUILD_DIR, POST_DIR=POST_DIR, L_EXP=L_EXP ) 
    202205globals().update(mm) 
    203206 
    204207config['Files']['TmpDir'] = TmpDir 
    205 config['libIGCM'] = { 'ARCHIVE':ARCHIVE, 'STORAGE':STORAGE, 'TmpDir':TmpDir, 'R_IN':R_IN, 'rebuild':rebuild } 
    206      
     208if not 'libIGCM'  in config.keys () : config['libIGCM'] = {} 
     209config['libIGCM'].update ( { 'ARCHIVE':str(ARCHIVE), 'STORAGE':str(STORAGE), 'TmpDir':str(TmpDir), 'R_IN':str(R_IN), 'rebuild':str(rebuild) } ) 
     210 
     211## Debuging and timer 
     212Timer = wu.functools.partial (wu.Timer, debug=Debug, timer=Timer) 
     213 
    207214## Defines begining and end of experiment 
    208215## -------------------------------------- 
    209 if wu.unDefined ( 'DateBegin' ) : 
     216if not DateBegin : 
    210217    DateBegin = f'{YearBegin}0101' 
    211218    config['Experiment']['DateBegin'] = str(DateBegin) 
     
    215222    config['Experiment']['YearBegin'] = str(YearBegin) 
    216223 
    217 if wu.unDefined ( 'DateEnd' )  : 
     224if not DateEnd : 
    218225    DateEnd   = f'{YearEnd}1231' 
    219226    config['Experiment']['DateEnd'] = str(DateEnd) 
     
    223230    config['Experiment']['DateEnd'] = str(DateEnd) 
    224231 
    225 if wu.unDefined ( 'PackFrequency' ) : 
     232if not PackFrequency :  
    226233    PackFrequency = YearEnd - YearBegin + 1 
    227234    config['Experiment']['PackFrequency']   = f'{PackFrequency}' 
     
    234241## Output file with water budget diagnostics 
    235242## ----------------------------------------- 
    236 if wu.unDefined ( 'FileOut' ) : 
     243if not FileOut : 
    237244    FileOut = f'CPL_waterbudget_{JobName}_{YearBegin}_{YearEnd}' 
    238245    if ICO :  
     
    248255## Useful functions 
    249256## ---------------- 
    250 if readPrec == float : 
    251     def rprec (tab) : return tab 
    252 else :  
    253     def rprec (tab) : return tab.astype(readPrec).astype(float) 
    254      
    255 def kg2Sv    (val, rho=ATM_rho) : 
     257if repr(readPrec) == "<class 'numpy.float64'>" or readPrec == float : 
     258    def rprec (ptab) : 
     259        '''This version does nothing 
     260 
     261        rprec may be use to reduce floating precision when reading history files 
     262        ''' 
     263        return ptab 
     264else                 : 
     265    def rprec (ptab) : 
     266        '''Returns float with a different precision''' 
     267        return ptab.astype(readPrec).astype(float) 
     268     
     269def kg2Sv    (val, rho=ATM_RHO) : 
    256270    '''From kg to Sverdrup''' 
    257271    return val/dtime_sec*1.0e-6/rho 
    258272 
    259 def kg2myear (val, rho=ATM_rho) : 
     273def kg2myear (val, rho=ATM_RHO) : 
    260274    '''From kg to m/year''' 
    261275    return val/ATM_aire_sea_tot/rho/NbYear 
    262276 
    263 def var2prt (var, small=False, rho=ATM_rho) : 
     277def var2prt (var, small=False, rho=ATM_RHO) : 
     278    '''Formats value for printing''' 
    264279    if small :  return var , kg2Sv(var, rho=rho)*1000., kg2myear(var, rho=rho)*1000 
    265280    else     :  return var , kg2Sv(var, rho=rho)      , kg2myear(var, rho=rho) 
    266281 
    267 def prtFlux (Desc, var, Form='F', small=False, rho=ATM_rho, width=15) : 
     282def prtFlux (Desc, var, Form='F', small=False, rho=ATM_RHO, width=15) : 
     283    '''Pretty print of formattd value''' 
    268284    if small : 
    269285        if Form in ['f', 'F'] : ff=" {:14.6e} kg | {:12.4f} mSv | {:12.4f} mm/year " 
     
    308324## Set libIGCM directories 
    309325## ----------------------- 
    310 if wu.unDefined ('R_OUT'      ) : R_OUT       = os.path.join ( ARCHIVE   , 'IGCM_OUT' ) 
    311 if wu.unDefined ('R_BUF'      ) : R_BUF       = os.path.join ( SCRATCHDIR, 'IGCM_OUT' ) 
    312 if wu.unDefined ('L_EXP'      ) : L_EXP       = os.path.join (TagName, SpaceName, ExperimentName, JobName) 
    313 if wu.unDefined ('R_SAVE'     ) : R_SAVE      = os.path.join ( R_OUT, L_EXP ) 
    314 if wu.unDefined ('R_BUFR'     ) : R_BUFR      = os.path.join ( R_BUF, L_EXP ) 
    315 if wu.unDefined ('POST_DIR'   ) : POST_DIR    = os.path.join ( R_BUFR, 'Out' ) 
    316 if wu.unDefined ('REBUILD_DIR') : REBUILD_DIR = os.path.join ( R_BUFR, 'REBUILD' ) 
    317 if wu.unDefined ('R_BUF_KSH'  ) : R_BUF_KSH   = os.path.join ( R_BUFR, 'Out' ) 
    318 if wu.unDefined ('R_FIGR'     ) : R_FIGR      = os.path.join ( STORAGE, 'IGCM_OUT', L_EXP ) 
    319  
    320 config['libIGCM'].update ( { 'R_OUT':R_OUT, 'R_BUF':R_BUF, 'L_EXP':L_EXP, 'R_BUFR':R_BUFR, 'POST_DIR':POST_DIR, 
    321                       'REBUILD_DIR':REBUILD_DIR, 'R_BUF_KSH':R_BUF_KSH, 'R_FIGR':R_FIGR, 'rebuild':rebuild } ) 
     326if not R_OUT       : R_OUT       = os.path.join ( ARCHIVE   , 'IGCM_OUT' ) 
     327if not R_BUF       : R_BUF       = os.path.join ( SCRATCHDIR, 'IGCM_OUT' ) 
     328if not L_EXP       : L_EXP       = os.path.join (TagName, SpaceName, ExperimentName, JobName) 
     329if not R_SAVE      : R_SAVE      = os.path.join ( R_OUT, L_EXP ) 
     330if not R_BUFR      : R_BUFR      = os.path.join ( R_BUF, L_EXP ) 
     331if not POST_DIR    : POST_DIR    = os.path.join ( R_BUFR, 'Out' ) 
     332if not REBUILD_DIR : REBUILD_DIR = os.path.join ( R_BUFR, 'REBUILD' ) 
     333if not R_BUF_KSH   : R_BUF_KSH   = os.path.join ( R_BUFR, 'Out' ) 
     334if not R_FIGR      : R_FIGR      = os.path.join ( STORAGE, 'IGCM_OUT', L_EXP ) 
     335 
     336config['libIGCM'].update ( { 'R_OUT':R_OUT, 'R_BUF':R_BUF, 'L_EXP':L_EXP, 'R_BUFR':R_BUFR, 'R_SAVE':R_SAVE, 'POST_DIR':POST_DIR, 
     337                             'REBUILD_DIR':REBUILD_DIR, 'R_BUF_KSH':R_BUF_KSH, 'R_FIGR':R_FIGR, 'rebuild':rebuild, 
     338                             'YEAR_LENGTH':str(YEAR_LENGTH)} ) 
    322339 
    323340## Set directory to extract files 
    324341## ------------------------------ 
    325 if wu.unDefined ( 'FileDir' ) : FileDir = os.path.join ( TmpDir, f'WATER_{JobName}' ) 
     342if not FileDir : FileDir = os.path.join ( TmpDir, f'WATER_{JobName}' ) 
    326343config['Files']['FileDir'] = FileDir 
    327344 
     
    329346 
    330347##- Set directories to rebuild ocean and ice restart files 
    331 if wu.unDefined ( 'FileDirOCE' ) : FileDirOCE = os.path.join ( FileDir, 'OCE' ) 
    332 if wu.unDefined ( 'FileDirICE' ) : FileDirICE = os.path.join ( FileDir, 'ICE' ) 
     348if not FileDirOCE : FileDirOCE = os.path.join ( FileDir, 'OCE' ) 
     349if not FileDirICE : FileDirICE = os.path.join ( FileDir, 'ICE' ) 
    333350if not os.path.exists ( FileDirOCE ) : os.mkdir ( FileDirOCE ) 
    334351if not os.path.exists ( FileDirICE ) : os.mkdir ( FileDirICE ) 
     
    358375    dir_ATM_his = os.path.join ( R_SAVE, "ATM", FreqDir ) 
    359376    config['Files']['dir_ATM_his'] = dir_ATM_his 
    360 if dir_SRF_his == None :  
    361     dir_SRF_his = os.path.join ( R_SAVE, "SRF", FreqDir ) 
    362     config['Files']['dir_SRF_his'] = dir_SRF_his 
     377if SRF :  
     378    if dir_SRF_his == None :  
     379        dir_SRF_his = os.path.join ( R_SAVE, "SRF", FreqDir ) 
     380        config['Files']['dir_SRF_his'] = dir_SRF_his 
    363381if dir_OCE_his == None : 
    364382    dir_OCE_his = os.path.join ( R_SAVE, "OCE", FreqDir ) 
     
    372390echo ( f'{dir_OCE_his}' ) 
    373391echo ( f'{dir_ICE_his}' ) 
    374 echo ( f'{dir_SRF_his}' ) 
     392if SRF :  
     393    echo ( f'{dir_SRF_his}' ) 
    375394 
    376395##-- Creates files names 
    377 if wu.unDefined ( 'Period' ) : 
     396if not Period : 
    378397    if Freq == 'MO' : Period = f'{DateBegin}_{DateEnd}_1M' 
    379398    if Freq == 'SE' : Period = f'SE_{DateBegin}_{DateEnd}_1M' 
     
    385404echo ( f'Period   : {Period}' ) 
    386405 
    387 if wu.unDefined ( 'FileCommon' ) : 
     406if not FileCommon : 
    388407    FileCommon = f'{JobName}_{Period}' 
    389408    config['Files']['FileCommon'] = FileCommon 
    390409 
    391 if wu.unDefined ( 'Title' ) : 
     410if not Title : 
    392411    Title = f'{JobName} : {Freq} : {DateBegin} - {DateEnd}' 
    393412    config['Files']['Title'] = Title 
    394413echo ('\nOpen history files' ) 
    395 if wu.unDefined ( 'file_ATM_his' ) : 
     414if not file_ATM_his : 
    396415    if ATM_HIS == 'latlon' : 
    397416        file_ATM_his = os.path.join ( dir_ATM_his, f'{FileCommon}_histmth.nc' ) 
     
    399418        file_ATM_his = os.path.join ( dir_ATM_his, f'{FileCommon}_histmth_ico.nc' ) 
    400419    config['Files']['file_ATM_his'] = file_ATM_his 
    401 if wu.unDefined ( 'file_SRF_his' ) : 
    402     if ATM_HIS == 'latlon' : 
    403         file_SRF_his = os.path.join ( dir_SRF_his, f'{FileCommon}_sechiba_history.nc' ) 
    404     if ATM_HIS == 'ico' : 
    405         file_SRF_his = os.path.join ( dir_SRF_his, f'{FileCommon}_sechiba_history_ico.nc' ) 
    406     config['Files']['file_SRF_his'] = file_SRF_his 
    407  
    408 if Routing == 'SIMPLE' : 
    409     if file_RUN_his == None : 
     420if SRF :  
     421    if not file_SRF_his : 
    410422        if ATM_HIS == 'latlon' : 
    411             file_RUN_his = os.path.join ( dir_SRF_his, f'{FileCommon}_sechiba_history.nc' ) 
     423            file_SRF_his = os.path.join ( dir_SRF_his, f'{FileCommon}_sechiba_history.nc' ) 
    412424        if ATM_HIS == 'ico' : 
    413             file_RUN_his = os.path.join ( dir_SRF_his, f'{FileCommon}_sechiba_history_ico.nc' ) 
    414         config['Files']['file_RUN_his'] = file_RUN_his 
     425            file_SRF_his = os.path.join ( dir_SRF_his, f'{FileCommon}_sechiba_history_ico.nc' ) 
     426        config['Files']['file_SRF_his'] = file_SRF_his 
     427 
     428    if Routing == 'SIMPLE' : 
     429        if file_RUN_his == None : 
     430            if ATM_HIS == 'latlon' : 
     431                file_RUN_his = os.path.join ( dir_SRF_his, f'{FileCommon}_sechiba_history.nc' ) 
     432            if ATM_HIS == 'ico' : 
     433                file_RUN_his = os.path.join ( dir_SRF_his, f'{FileCommon}_sechiba_history_ico.nc' ) 
     434            config['Files']['file_RUN_his'] = file_RUN_his 
    415435 
    416436echo ( f'{file_ATM_his = }' ) 
    417 echo ( f'{file_SRF_his = }' ) 
    418 if Routing == 'SIMPLE' : echo ( f'{file_RUN_his = }' ) 
     437if SRF :  
     438    echo ( f'{file_SRF_his = }' ) 
     439    if Routing == 'SIMPLE' : echo ( f'{file_RUN_his = }' ) 
    419440         
    420441d_ATM_his = xr.open_dataset ( file_ATM_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
    421 d_SRF_his = xr.open_dataset ( file_SRF_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
    422 if Routing == 'SECHIBA' : d_RUN_his = d_SRF_his 
    423 if Routing == 'SIMPLE'  : d_RUN_his = xr.open_dataset ( file_RUN_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
    424      
    425 if wu.unDefined ('file_OCE_his' ) : 
     442if SRF :  
     443    d_SRF_his = xr.open_dataset ( file_SRF_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
     444    if Routing == 'SECHIBA' : d_RUN_his = d_SRF_his 
     445    if Routing == 'SIMPLE'  : d_RUN_his = xr.open_dataset ( file_RUN_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
     446     
     447if not file_OCE_his : 
    426448    file_OCE_his = os.path.join ( dir_OCE_his, f'{FileCommon}_grid_T.nc' ) 
    427449    file_OCE_his = file_OCE_his 
    428 if wu.unDefined ('file_OCE_sca' ) :     
     450if not file_OCE_sca :     
    429451    file_OCE_sca = os.path.join ( dir_OCE_his, f'{FileCommon}_scalar.nc' ) 
    430452    config['Files']['file_OCE_sca'] = file_OCE_sca 
    431 if wu.unDefined ('file_OCE_srf' ) :     
     453if not file_OCE_srf :     
    432454    file_OCE_srf = os.path.join ( dir_OCE_his, f'{FileCommon}_sbc.nc' ) 
    433455    config['Files']['file_OCE_srf'] = file_OCE_srf 
    434 if wu.unDefined ( 'file_ICE_hi' ) :  
     456if not file_ICE_his :  
    435457    file_ICE_his = os.path.join ( dir_ICE_his, f'{FileCommon}_icemod.nc' ) 
    436458    config['Files']['file_ICE_his'] = file_ICE_his 
     
    440462#d_OCE_srf = xr.open_dataset ( file_OCE_srf, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
    441463d_ICE_his = xr.open_dataset ( file_ICE_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
    442 if NEMO == '3.6' :d_ICE_his = d_ICE_his.rename ( {'y_grid_T':'y', 'x_grid_T':'x'} ) 
     464if NEMO == '3.6' : d_ICE_his = d_ICE_his.rename ( {'y_grid_T':'y', 'x_grid_T':'x'} ) 
    443465 
    444466echo ( f'{file_OCE_his = }' ) 
     
    461483 
    462484# Number of years 
    463 NbYear = dtime_sec / YearLength 
     485NbYear = dtime_sec / YEAR_LENGTH 
    464486 
    465487## Write the full configuration 
     
    478500    ATM_fsic      = lmdz.geo2point ( rprec (d_ATM_his ['fract_sic'][0]), dim1D='cell' ) 
    479501    ATM_flic      = lmdz.geo2point ( rprec (d_ATM_his ['fract_lic'][0]), dim1D='cell' ) 
    480     SRF_lat       = lmdz.geo2point (   rprec (d_SRF_his ['lat'])+0*rprec (d_SRF_his ['lon']), dim1D='cell' ) 
    481     SRF_lon       = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat'])+  rprec (d_SRF_his ['lon']), dim1D='cell' ) 
    482     SRF_aire      = lmdz.geo2point ( rprec (d_SRF_his ['Areas']) * rprec (d_SRF_his ['Contfrac']), dim1D='cell', cumulPoles=True ) 
    483     SRF_areas     = lmdz.geo2point ( rprec (d_SRF_his ['Areas'])  ,  dim1D='cell', cumulPoles=True ) 
    484     SRF_contfrac  = lmdz.geo2point ( rprec (d_SRF_his ['Contfrac']), dim1D='cell' ) 
     502    if SRF :  
     503        SRF_lat       = lmdz.geo2point (   rprec (d_SRF_his ['lat'])+0*rprec (d_SRF_his ['lon']), dim1D='cell' ) 
     504        SRF_lon       = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat'])+  rprec (d_SRF_his ['lon']), dim1D='cell' ) 
     505        SRF_aire      = lmdz.geo2point ( rprec (d_SRF_his ['Areas']) * rprec (d_SRF_his ['Contfrac']), dim1D='cell', cumulPoles=True ) 
     506        SRF_areas     = lmdz.geo2point ( rprec (d_SRF_his ['Areas'])  ,  dim1D='cell', cumulPoles=True ) 
     507        SRF_contfrac  = lmdz.geo2point ( rprec (d_SRF_his ['Contfrac']), dim1D='cell' ) 
     508         
    485509if ICO : 
    486510    if ATM_HIS == 'latlon' : 
     
    508532        ATM_flic =  rprec (d_ATM_his ['fract_lic'][0]) 
    509533 
    510     if SRF_HIS == 'latlon' : 
    511         echo ( 'SRF areas and fractions on latlon grid' ) 
    512         if 'lat_domain_landpoints_out' in d_SRF_his  :  
    513             SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat_domain_landpoints_out'])+0*rprec (d_SRF_his ['lon_domain_landpoints_out']), dim1D='cell' ) 
    514             SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat_domain_landpoints_out'])+  rprec (d_SRF_his ['lon_domain_landpoints_out']), dim1D='cell' ) 
    515         else :  
    516             if 'lat_domain_landpoints_out' in d_SRF_his : 
    517                 SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat_dom_out'])+0*rprec (d_SRF_his ['lon_dom_out']), dim1D='cell' ) 
    518                 SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat_dom_out'])+  rprec (d_SRF_his ['lon_dom_out']), dim1D='cell' ) 
    519             else : 
    520                 SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat'])+0*rprec (d_SRF_his ['lon']), dim1D='cell' ) 
    521                 SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat'])+  rprec (d_SRF_his ['lon']), dim1D='cell' ) 
    522                  
    523         SRF_areas     = lmdz.geo2point ( rprec (d_SRF_his ['Areas']   )   , dim1D='cell', cumulPoles=True ) 
    524         SRF_areafrac  = lmdz.geo2point ( rprec (d_SRF_his ['AreaFrac'])   , dim1D='cell', cumulPoles=True ) 
    525         SRF_contfrac  = lmdz.geo2point ( rprec (d_SRF_his ['Contfrac'])   , dim1D='cell', cumulPoles=True ) 
    526         SRF_aire = SRF_areafrac 
     534    if SRF :  
     535        if SRF_HIS == 'latlon' : 
     536            echo ( 'SRF areas and fractions on latlon grid' ) 
     537            if 'lat_domain_landpoints_out' in d_SRF_his  :  
     538                SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat_domain_landpoints_out'])+0*rprec (d_SRF_his ['lon_domain_landpoints_out']), dim1D='cell' ) 
     539                SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat_domain_landpoints_out'])+  rprec (d_SRF_his ['lon_domain_landpoints_out']), dim1D='cell' ) 
     540            else :  
     541                if 'lat_domain_landpoints_out' in d_SRF_his : 
     542                    SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat_dom_out'])+0*rprec (d_SRF_his ['lon_dom_out']), dim1D='cell' ) 
     543                    SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat_dom_out'])+  rprec (d_SRF_his ['lon_dom_out']), dim1D='cell' ) 
     544                else : 
     545                    SRF_lat  = lmdz.geo2point (   rprec (d_SRF_his ['lat'])+0*rprec (d_SRF_his ['lon']), dim1D='cell' ) 
     546                    SRF_lon  = lmdz.geo2point ( 0*rprec (d_SRF_his ['lat'])+  rprec (d_SRF_his ['lon']), dim1D='cell' ) 
     547                     
     548            SRF_areas     = lmdz.geo2point ( rprec (d_SRF_his ['Areas']   )   , dim1D='cell', cumulPoles=True ) 
     549            SRF_areafrac  = lmdz.geo2point ( rprec (d_SRF_his ['AreaFrac'])   , dim1D='cell', cumulPoles=True ) 
     550            SRF_contfrac  = lmdz.geo2point ( rprec (d_SRF_his ['Contfrac'])   , dim1D='cell', cumulPoles=True ) 
     551            SRF_aire = SRF_areafrac 
    527552  
    528     if SRF_HIS == 'ico' : 
    529         echo ( 'SRF areas and fractions on latlon grid' ) 
    530         SRF_lat       =  rprec (d_SRF_his ['lat']     ) 
    531         SRF_lon       =  rprec (d_SRF_his ['lon']     ) 
    532         SRF_areas     =  rprec (d_SRF_his ['Areas']   )  
    533         SRF_contfrac  =  rprec (d_SRF_his ['Contfrac']) 
    534         SRF_aire      =  SRF_areas * SRF_contfrac 
     553        if SRF_HIS == 'ico' : 
     554            echo ( 'SRF areas and fractions on latlon grid' ) 
     555            SRF_lat       =  rprec (d_SRF_his ['lat']     ) 
     556            SRF_lon       =  rprec (d_SRF_his ['lon']     ) 
     557            SRF_areas     =  rprec (d_SRF_his ['Areas']   )  
     558            SRF_contfrac  =  rprec (d_SRF_his ['Contfrac']) 
     559            SRF_aire      =  SRF_areas * SRF_contfrac 
     560             
    535561ATM_fsea      = ATM_foce + ATM_fsic 
    536562ATM_flnd      = ATM_fter + ATM_flic 
     
    592618    return SRF_flux_int 
    593619 
    594 def LIC_flux_int (flux) : 
    595     '''Integrate (* time * surface) flux on land ice grid''' 
    596     LIC_flux_int  = wu.Psum ( (flux * dtime_per_sec * ATM_aire_flic).to_masked_array().ravel() ) 
    597     return LIC_flux_int 
     620# def LIC_flux_int (flux) : 
     621#     '''Integrate (* time * surface) flux on land ice grid''' 
     622#     LIC_flux_int  = wu.Psum ( (flux * dtime_per_sec * ATM_aire_flic).to_masked_array().ravel() ) 
     623#     return LIC_flux_int 
    598624 
    599625# def OCE_stock_int (stock) : 
     
    628654 
    629655ATM_aire_tot = ONE_stock_int (ATM_aire) 
    630 SRF_aire_tot = ONE_stock_int (SRF_aire) 
     656if SRF :  
     657    SRF_aire_tot = ONE_stock_int (SRF_aire) 
    631658OCE_aire_tot = ONE_stock_int (OCE_aire) 
    632659ICE_aire_tot = ONE_stock_int (ICE_aire) 
     
    724751ATM_wemp_sea    = ATM_wevap_sic - ATM_wprecip_oce 
    725752 
    726 if RUN_HIS == 'latlon' : 
    727     echo ( f'RUN costalflow Grille LATLON' ) 
    728     if TestInterp : 
    729         echo ( f'RUN runoff TestInterp' ) 
    730         RUN_runoff      = lmdz.geo2point ( rprec (d_RUN_his ['runoff_contfrac_interp']  )   , dim1D='cell' ) 
    731         RUN_drainage    = lmdz.geo2point ( rprec (d_RUN_his ['drainage_contfrac_interp'])   , dim1D='cell' ) 
    732     else :  
    733         echo ( f'RUN runoff' ) 
    734         RUN_runoff      = lmdz.geo2point ( rprec (d_RUN_his ['runoff']         ), dim1D='cell' ) 
    735         RUN_drainage    = lmdz.geo2point ( rprec (d_RUN_his ['drainage']       ), dim1D='cell' ) 
     753if SRF :  
     754    if RUN_HIS == 'latlon' : 
     755        echo ( f'RUN costalflow Grille LATLON' ) 
     756        if TestInterp : 
     757            echo ( f'RUN runoff TestInterp' ) 
     758            RUN_runoff      = lmdz.geo2point ( rprec (d_RUN_his ['runoff_contfrac_interp']  )   , dim1D='cell' ) 
     759            RUN_drainage    = lmdz.geo2point ( rprec (d_RUN_his ['drainage_contfrac_interp'])   , dim1D='cell' ) 
     760        else :  
     761            echo ( f'RUN runoff' ) 
     762            RUN_runoff      = lmdz.geo2point ( rprec (d_RUN_his ['runoff']         ), dim1D='cell' ) 
     763            RUN_drainage    = lmdz.geo2point ( rprec (d_RUN_his ['drainage']       ), dim1D='cell' ) 
     764             
     765        RUN_coastalflow     = lmdz.geo2point ( rprec (d_RUN_his ['coastalflow']    ), dim1D='cell' )  
     766        RUN_riverflow       = lmdz.geo2point ( rprec (d_RUN_his ['riverflow']      ), dim1D='cell' ) 
     767        RUN_riversret       = lmdz.geo2point ( rprec (d_RUN_his ['riversret']      ), dim1D='cell' ) 
     768        RUN_coastalflow_cpl = lmdz.geo2point ( rprec (d_RUN_his ['coastalflow_cpl']), dim1D='cell' )  
     769        RUN_riverflow_cpl   = lmdz.geo2point ( rprec (d_RUN_his ['riverflow_cpl']  ), dim1D='cell' ) 
    736770         
    737     RUN_coastalflow     = lmdz.geo2point ( rprec (d_RUN_his ['coastalflow']    ), dim1D='cell' )  
    738     RUN_riverflow       = lmdz.geo2point ( rprec (d_RUN_his ['riverflow']      ), dim1D='cell' ) 
    739     RUN_riversret       = lmdz.geo2point ( rprec (d_RUN_his ['riversret']      ), dim1D='cell' ) 
    740     RUN_coastalflow_cpl = lmdz.geo2point ( rprec (d_RUN_his ['coastalflow_cpl']), dim1D='cell' )  
    741     RUN_riverflow_cpl   = lmdz.geo2point ( rprec (d_RUN_his ['riverflow_cpl']  ), dim1D='cell' ) 
    742  
    743 if RUN_HIS == 'ico' : 
    744     echo ( f'RUN costalflow Grille ICO' ) 
    745     RUN_coastalflow =  rprec (d_RUN_his ['coastalflow']) 
    746     RUN_riverflow   =  rprec (d_RUN_his ['riverflow']  ) 
    747     RUN_runoff      =  rprec (d_RUN_his ['runoff']     ) 
    748     RUN_drainage    =  rprec (d_RUN_his ['drainage']   ) 
    749     RUN_riversret   =  rprec (d_RUN_his ['riversret']  ) 
    750      
    751     RUN_coastalflow_cpl = rprec (d_RUN_his ['coastalflow_cpl']) 
    752     RUN_riverflow_cpl   = rprec (d_RUN_his ['riverflow_cpl']  ) 
    753  
    754 ## Correcting units of SECHIBA variables 
    755 def mmd2SI ( Var ) : 
    756     '''Change unit from mm/d or m^3/s to kg/s if needed''' 
    757     if 'units' in VarT.attrs :  
    758         if VarT.attrs['units'] in ['m^3/s', 'm3/s', 'm3.s-1',] : 
    759             VarT.values = VarT.values  * ATM_rho                 ;  VarT.attrs['units'] = 'kg/s' 
    760         if VarT.attrs['units'] == 'mm/d' : 
    761             VarT.values = VarT.values  * ATM_rho * (1e-3/86400.) ;  VarT.attrs['units'] = 'kg/s' 
    762         if VarT.attrs['units'] in ['m^3', 'm3', ] : 
    763             VarT.values = VarT.values  * ATM_rho                 ;  VarT.attrs['units'] = 'kg' 
    764              
    765 for var in [ 'runoff', 'drainage', 'riversret', 'coastalflow', 'riverflow', 'coastalflow_cpl', 'riverflow_cpl' ] : 
    766     VarT = locals()['RUN_' + var] 
    767     mmd2SI (VarT) 
    768  
    769 #for var in ['evap', 'snowf', 'subli', 'transpir', 'rain', 'emp' ] : 
    770 #    VarT = locals()['SRF_' + var] 
    771 #    mmd2SI (VarT) 
    772 echo ( f'RUN input' ) 
    773 RUN_input  = RUN_runoff      + RUN_drainage 
    774 RUN_output = RUN_coastalflow + RUN_riverflow 
    775  
     771    if RUN_HIS == 'ico' : 
     772        echo ( f'RUN costalflow Grille ICO' ) 
     773        RUN_coastalflow =  rprec (d_RUN_his ['coastalflow']) 
     774        RUN_riverflow   =  rprec (d_RUN_his ['riverflow']  ) 
     775        RUN_runoff      =  rprec (d_RUN_his ['runoff']     ) 
     776        RUN_drainage    =  rprec (d_RUN_his ['drainage']   ) 
     777        RUN_riversret   =  rprec (d_RUN_his ['riversret']  ) 
     778         
     779        RUN_coastalflow_cpl = rprec (d_RUN_his ['coastalflow_cpl']) 
     780        RUN_riverflow_cpl   = rprec (d_RUN_his ['riverflow_cpl']  ) 
     781         
     782        ## Correcting units of SECHIBA variables 
     783    def mmd2SI ( Var ) : 
     784        '''Change unit from mm/d or m^3/s to kg/s if needed''' 
     785        if 'units' in VarT.attrs :  
     786            if VarT.attrs['units'] in ['m^3/s', 'm3/s', 'm3.s-1',] : 
     787                VarT.values = VarT.values  * ATM_RHO                 ;  VarT.attrs['units'] = 'kg/s' 
     788            if VarT.attrs['units'] == 'mm/d' : 
     789                VarT.values = VarT.values  * ATM_RHO * (1e-3/86400.) ;  VarT.attrs['units'] = 'kg/s' 
     790            if VarT.attrs['units'] in ['m^3', 'm3', ] : 
     791                VarT.values = VarT.values  * ATM_RHO                 ;  VarT.attrs['units'] = 'kg' 
     792                 
     793    for var in [ 'runoff', 'drainage', 'riversret', 'coastalflow', 'riverflow', 'coastalflow_cpl', 'riverflow_cpl' ] : 
     794        VarT = locals()['RUN_' + var] 
     795        mmd2SI (VarT) 
     796         
     797    #for var in ['evap', 'snowf', 'subli', 'transpir', 'rain', 'emp' ] : 
     798    #    VarT = locals()['SRF_' + var] 
     799    #    mmd2SI (VarT) 
     800    echo ( f'RUN input' ) 
     801    RUN_input  = RUN_runoff      + RUN_drainage 
     802    RUN_output = RUN_coastalflow + RUN_riverflow 
     803     
    776804echo ( f'ATM flw_wbilo' ) 
    777805ATM_flx_wbilo       = ATM_flux_int ( ATM_wbilo      ) 
     
    790818ATM_flx_fqfonte     = ATM_flux_int ( ATM_fqfonte    ) 
    791819 
    792 LIC_flx_calving     = LIC_flux_int ( ATM_fqcalving  ) 
    793 LIC_flx_fqfonte     = LIC_flux_int ( ATM_fqfonte    ) 
     820LIC_flx_calving     = ATM_flux_int ( ATM_fqcalving  ) 
     821LIC_flx_fqfonte     = ATM_flux_int ( ATM_fqfonte    ) 
    794822 
    795823ATM_flx_precip      = ATM_flux_int ( ATM_precip     ) 
     
    798826ATM_flx_runlic      = ATM_flux_int ( ATM_runofflic  ) 
    799827 
    800 LIC_flx_precip      = LIC_flux_int ( ATM_precip     ) 
    801 LIC_flx_snowf       = LIC_flux_int ( ATM_snowf      ) 
    802 LIC_flx_evap        = LIC_flux_int ( ATM_evap       ) 
    803 LIC_flx_runlic      = LIC_flux_int ( ATM_runofflic  ) 
     828#LIC_flx_precip      = LIC_flux_int ( ATM_precip     ) 
     829#LIC_flx_snowf       = LIC_flux_int ( ATM_snowf      ) 
     830#LIC_flx_evap        = LIC_flux_int ( ATM_evap       ) 
     831#LIC_flx_runlic      = LIC_flux_int ( ATM_runofflic  ) 
    804832 
    805833ATM_flx_wrain_ter   = ATM_flux_int ( ATM_wrain_ter ) 
     
    833861ATM_flx_emp          = ATM_flux_int ( ATM_emp ) 
    834862 
    835 RUN_flx_coastal     = ONE_flux_int ( RUN_coastalflow) 
    836 RUN_flx_river       = ONE_flux_int ( RUN_riverflow  ) 
    837 RUN_flx_coastal_cpl = ONE_flux_int ( RUN_coastalflow_cpl) 
    838 RUN_flx_river_cpl   = ONE_flux_int ( RUN_riverflow_cpl  ) 
    839 RUN_flx_drainage    = SRF_flux_int ( RUN_drainage   ) 
    840 RUN_flx_riversret   = SRF_flux_int ( RUN_riversret  ) 
    841 RUN_flx_runoff      = SRF_flux_int ( RUN_runoff     ) 
    842 RUN_flx_input       = SRF_flux_int ( RUN_input      ) 
    843 RUN_flx_output      = ONE_flux_int ( RUN_output     ) 
    844  
    845 RUN_flx_bil    = ONE_flux_int ( RUN_input       - RUN_output) 
    846 RUN_flx_rivcoa = ONE_flux_int ( RUN_coastalflow + RUN_riverflow) 
    847  
     863if SRF :  
     864    RUN_flx_coastal     = ONE_flux_int ( RUN_coastalflow) 
     865    RUN_flx_river       = ONE_flux_int ( RUN_riverflow  ) 
     866    RUN_flx_coastal_cpl = ONE_flux_int ( RUN_coastalflow_cpl) 
     867    RUN_flx_river_cpl   = ONE_flux_int ( RUN_riverflow_cpl  ) 
     868    RUN_flx_drainage    = SRF_flux_int ( RUN_drainage   ) 
     869    RUN_flx_riversret   = SRF_flux_int ( RUN_riversret  ) 
     870    RUN_flx_runoff      = SRF_flux_int ( RUN_runoff     ) 
     871    RUN_flx_input       = SRF_flux_int ( RUN_input      ) 
     872    RUN_flx_output      = ONE_flux_int ( RUN_output     ) 
     873     
     874    RUN_flx_bil    = ONE_flux_int ( RUN_input       - RUN_output) 
     875    RUN_flx_rivcoa = ONE_flux_int ( RUN_coastalflow + RUN_riverflow) 
     876     
    848877prtFlux ('wbilo_oce            ', ATM_flx_wbilo_oce     , 'f' )           
    849878prtFlux ('wbilo_sic            ', ATM_flx_wbilo_sic     , 'f' )           
     
    871900prtFlux ('ERROR emp            ', ATM_flx_wemp    - ATM_flx_emp   , 'e', True ) 
    872901 
    873  
    874 echo ( '\n====================================================================================' ) 
    875 echo ( f'-- RUNOFF Fluxes  -- {Title} ' ) 
    876 prtFlux ('coastalflow   ', RUN_flx_coastal    , 'f' )  
    877 prtFlux ('riverflow     ', RUN_flx_river      , 'f' )         
    878 prtFlux ('coastal_cpl   ', RUN_flx_coastal_cpl, 'f' )   
    879 prtFlux ('riverf_cpl    ', RUN_flx_river_cpl  , 'f' )     
    880 prtFlux ('river+coastal ', RUN_flx_rivcoa     , 'f' )    
    881 prtFlux ('drainage      ', RUN_flx_drainage   , 'f' )    
    882 prtFlux ('riversret     ', RUN_flx_riversret  , 'f' )    
    883 prtFlux ('runoff        ', RUN_flx_runoff     , 'f' )    
    884 prtFlux ('river in      ', RUN_flx_input      , 'f' )    
    885 prtFlux ('river out     ', RUN_flx_output     , 'f' )    
    886 prtFlux ('river bil     ', RUN_flx_bil        , 'f' )  
     902if SRF :  
     903    echo ( '\n====================================================================================' ) 
     904    echo ( f'-- RUNOFF Fluxes  -- {Title} ' ) 
     905    prtFlux ('coastalflow   ', RUN_flx_coastal    , 'f' )  
     906    prtFlux ('riverflow     ', RUN_flx_river      , 'f' )         
     907    prtFlux ('coastal_cpl   ', RUN_flx_coastal_cpl, 'f' )   
     908    prtFlux ('riverf_cpl    ', RUN_flx_river_cpl  , 'f' )     
     909    prtFlux ('river+coastal ', RUN_flx_rivcoa     , 'f' )    
     910    prtFlux ('drainage      ', RUN_flx_drainage   , 'f' )    
     911    prtFlux ('riversret     ', RUN_flx_riversret  , 'f' )    
     912    prtFlux ('runoff        ', RUN_flx_runoff     , 'f' )    
     913    prtFlux ('river in      ', RUN_flx_input      , 'f' )    
     914    prtFlux ('river out     ', RUN_flx_output     , 'f' )    
     915    prtFlux ('river bil     ', RUN_flx_bil        , 'f' )  
    887916     
    888917echo ( '\n====================================================================================' ) 
     
    904933    OCE_wfxsub     = rprec (d_OCE_his['vfxsub']) ; OCE_mas_wfxsub   = OCE_flux_int ( OCE_wfxsub ) 
    905934if NEMO == 3.6 : 
    906     OCE_wfxice     = rprec (d_OCE_his['vfxice'])/86400.*ICE_rho_ice ; OCE_mas_wfxice   = OCE_flux_int ( OCE_wfxice ) 
    907     OCE_wfxsnw     = rprec (d_OCE_his['vfxsnw'])/86400.*ICE_rho_sno ; OCE_mas_wfxsnw   = OCE_flux_int ( OCE_wfxsnw ) 
    908     OCE_wfxsub     = rprec (d_OCE_his['vfxsub'])/86400.*ICE_rho_sno ; OCE_mas_wfxsub   = OCE_flux_int ( OCE_wfxsub ) 
     935    OCE_wfxice     = rprec (d_OCE_his['vfxice'])/86400.*ICE_RHO_ICE ; OCE_mas_wfxice   = OCE_flux_int ( OCE_wfxice ) 
     936    OCE_wfxsnw     = rprec (d_OCE_his['vfxsnw'])/86400.*ICE_RHO_SNO ; OCE_mas_wfxsnw   = OCE_flux_int ( OCE_wfxsnw ) 
     937    OCE_wfxsub     = rprec (d_OCE_his['vfxsub'])/86400.*ICE_RHO_SNO ; OCE_mas_wfxsub   = OCE_flux_int ( OCE_wfxsub ) 
    909938# Additional checks 
    910939OCE_evap_oce   = rprec (d_OCE_his['evap_ao_cea']) ; OCE_mas_evap_oce   = OCE_flux_int ( OCE_evap_oce ) 
     
    920949if NEMO == 3.6 : 
    921950    ICE_wfxpnd = 0.0 ; ICE_mas_wfxpnd = 0.0 
    922     ICE_wfxsnw_sub = rprec (d_ICE_his['vfxsub'])/86400.*ICE_rho_sno  ; ICE_mas_wfxsnw_sub = OCE_flux_int ( ICE_wfxsnw_sub ) 
    923     ICE_wfxsnw_pre = rprec (d_ICE_his['vfxspr'])/86400.*ICE_rho_sno  ; ICE_mas_wfxsnw_pre = OCE_flux_int ( ICE_wfxsnw_pre     ) 
     951    ICE_wfxsnw_sub = rprec (d_ICE_his['vfxsub'])/86400.*ICE_RHO_SNO  ; ICE_mas_wfxsnw_sub = OCE_flux_int ( ICE_wfxsnw_sub ) 
     952    ICE_wfxsnw_pre = rprec (d_ICE_his['vfxspr'])/86400.*ICE_RHO_SNO  ; ICE_mas_wfxsnw_pre = OCE_flux_int ( ICE_wfxsnw_pre     ) 
    924953 
    925954OCE_wfcorr    = rprec (d_OCE_his['wfcorr']) ; OCE_mas_wfcorr  = OCE_flux_int ( OCE_wfcorr ) 
     
    9741003 
    9751004prtFlux ( 'wbilo sea  ', ATM_flux_int (ATM_wbilo_sea), 'e',   ) 
    976 prtFlux ( 'costalflow ', ONE_flux_int (RUN_coastalflow), 'e',   ) 
    977 prtFlux ( 'riverflow  ', RUN_flx_river  , 'e',   ) 
    978 prtFlux ( 'costalflow ', RUN_flx_coastal, 'e',   ) 
    979 prtFlux ( 'runoff     ', RUN_flx_river+RUN_flx_coastal, 'e',   ) 
    980  
    981 ATM_to_OCE   =  ATM_flux_int (ATM_wbilo_sea) - RUN_flx_river - RUN_flx_coastal - ATM_flx_calving 
     1005if SRF :  
     1006    prtFlux ( 'costalflow ', ONE_flux_int (RUN_coastalflow), 'e',   ) 
     1007    prtFlux ( 'riverflow  ', RUN_flx_river  , 'e',   ) 
     1008    prtFlux ( 'costalflow ', RUN_flx_coastal, 'e',   ) 
     1009    prtFlux ( 'runoff     ', RUN_flx_river+RUN_flx_coastal, 'e',   ) 
     1010 
     1011#ATM_to_OCE   =  ATM_flux_int (ATM_wbilo_sea) - RUN_flx_river - RUN_flx_coastal - ATM_flx_calving 
     1012ATM_to_OCE   =  ATM_flux_int (ATM_wbilo_sea) - ATM_flx_river - ATM_flx_coastal - ATM_flx_calving 
    9821013#OCE_from_ATM = -OCE_mas_emp_oce - OCE_mas_emp_ice + OCE_mas_runoffs + OCE_mas_iceberg + OCE_mas_calving + OCE_mas_iceshelf 
    9831014OCE_from_ATM = OCE_mas_all 
     
    9851016prtFlux ( 'ATM_to_OCE  ', ATM_to_OCE  , 'e', True ) 
    9861017prtFlux ( 'OCE_from_ATM', OCE_from_ATM, 'e', True ) 
     1018 
     1019echo ( ' ' ) 
     1020echo ( f'{Title = }' ) 
     1021 
     1022echo ( 'SVN Information' ) 
     1023for kk in SVN.keys(): 
     1024    print ( SVN[kk] ) 
  • TOOLS/WATER_BUDGET/OCE_waterbudget.py

    r6651 r6665  
    2222### 
    2323## Import system modules 
    24 import sys, os, shutil#, subprocess, platform 
    25 import configparser, re 
     24import sys 
     25import os 
     26import subprocess 
     27import configparser 
    2628from pathlib import Path 
    2729 
    2830## Import needed scientific modules 
    29 import numpy as np, xarray as xr 
    30  
    31 # Check python version 
    32 if sys.version_info < (3, 8, 0) : 
    33     print ( f'Python version : {platform.python_version()}' )  
    34     raise Exception ( "Minimum Python version is 3.8" ) 
     31import numpy as np 
     32import xarray as xr 
    3533 
    3634## Import local module 
    3735import WaterUtils as wu 
    3836import libIGCM_sys 
    39 import nemo, lmdz 
    40  
    41 from WaterUtils import VarInt, Rho, Ra, Grav, ICE_rho_ice, ICE_rho_sno, OCE_rho_liq, ATM_rho, SRF_rho, RUN_rho, ICE_rho_pnd, YearLength 
     37import nemo 
     38 
     39from WaterUtils import RA, GRAV, ICE_RHO_ICE, ICE_RHO_SNO, OCE_RHO_LIQ, ATM_RHO, \ 
     40                       SRF_RHO, RUN_RHO, ICE_RHO_PND, YEAR_LENGTH 
    4241 
    4342## Creates parser for reading .ini input file 
     
    4847## Experiment parameters 
    4948## --------------------- 
    50 ATM=None ; ATM_HIS='latlon' ; SRF_HIS='latlon' ; RUN_HIS='latlon' ; ORCA=None ; NEMO=None ; OCE_relax=False 
    51 OCE_icb=False ; Coupled=False ; Routing=None ; TestInterp=None 
    52 TarRestartPeriod_beg=None ; TarRestartPeriod_end=None ; Comment=None ; Period=None ; Title=None 
     49JobName=None ; TagName=None ; ExperimentName=None ; SpaceName=None 
     50SRF=True ; RUN=True 
     51ATM=None ; ATM_HIS='latlon' ; SRF_HIS='latlon' ; RUN_HIS='latlon' ; ORCA=None 
     52NEMO=None ; OCE_relax=False 
     53OCE_icb=False ; Coupled=False ; Rsouting=None ; TestInterp=None 
     54TarRestartPeriod_beg=None ; TarRestartPeriod_end=None ; Comment=None 
     55Period=None ; Title=None 
    5356YearBegin=None ; YearEnd=None ; DateBegin=None ; DateEnd=None 
     57Freq=None ; libIGCM=None ; User=None; Group=None ; Routing=None 
     58PackFrequency = None ; FreqDir=None 
     59 
     60Timer=False ; Debug=False 
    5461 
    5562## 
    56 ARCHIVE=None ; STORAGE=None ; SCRATCHDIR=None ; R_IN=None ; rebuild=None ; TmpDir=None 
    57 FileDir=None ; FileOut=None 
     63ARCHIVE=None ; STORAGE=None ; SCRATCHDIR=None ; R_IN=None 
     64TmpDir=None ; FileDir=None ; FileOut=None ; R_OUT=None ; R_FIG=None 
     65R_FIGR=None ; R_BUF=None ; R_BUFR=None ; R_SAVE=None 
     66R_BUF_KSH=None ; POST_DIR=None ; L_EXP=None 
     67 
    5868dir_ATM_his=None ; dir_SRF_his=None ; dir_OCE_his=None ; dir_ICE_his=None 
    5969FileCommon=None ; file_ATM_his=None ; file_SRF_his=None ; file_RUN_his=None 
    6070file_OCE_his=None ;  file_ICE_his=None ; file_OCE_sca=None 
    61 tar_restart_beg=None ; tar_restart_end=None ; file_ATM_beg=None ; file_ATM_end=None ; file_DYN_beg=None 
     71tar_restart_beg=None ; tar_restart_end=None ; file_ATM_beg=None 
     72file_ATM_end=None ; file_DYN_beg=None 
    6273file_DYN_end=None ; file_SRF_beg=None ; file_SRF_end=None 
    6374file_RUN_beg=None ; file_RUN_end=None ; file_RUN_end=None ; file_OCE_beg=None 
    6475file_ICE_beg=None ; file_OCE_beg=None 
    6576file_OCE_end=None ; file_ICE_beg=None ; file_OCE_end=None ; file_ICE_end=None 
     77TarRestartDate_beg=None ; TarRestartDate_end=None 
     78file_DYN_aire=None 
    6679tar_restart_beg_ATM=None ; tar_restart_beg_DYN=None ; tar_restart_beg_SRF=None 
    6780tar_restart_beg_RUN=None ; tar_restart_beg_OCE=None ; tar_restart_beg_ICE=None 
    6881tar_restart_end_ATM=None ; tar_restart_end_DYN=None ; tar_restart_end_SRF=None 
    6982tar_restart_end_RUN=None ; tar_restart_end_OCE=None ; tar_restart_end_ICE=None 
    70 ContinueOnError=False ; ErrorCount=0 
     83ContinueOnError=False ; ErrorCount=0 ; SortIco = False 
     84 
     85d_OCE_beg=None ; d_OCE_end=None 
     86 
     87FileDirOCE=None ; FileDirATM=None ; FileDirICE=None ; FileDirSRF=None ; FileDirRUN=None 
     88 
     89rebuild=None ;  REBUILD_DIR=None 
    7190 
    7291## 
     
    7493## --------------------------------- 
    7594# Default is float (full precision). Degrade the precision by using np.float32 
    76 # Restart file are always read at the full precision 
     95# Restart files are always read at the full precision 
    7796readPrec=float 
    7897 
     
    88107if 'full' in IniFile : FullIniFile = IniFile 
    89108else                 : FullIniFile = 'full_' + IniFile 
    90      
     109 
    91110print ("Input file : ", IniFile ) 
    92111config.read (IniFile) 
     
    109128        MyReader = configparser.ConfigParser (interpolation=configparser.ExtendedInterpolation() ) 
    110129        MyReader.optionxform = str # To keep capitals 
    111          
     130 
    112131        MyReader.read (ConfigCard) 
    113132 
     
    120139                exec  ( f'wu.{VarName} = {VarName}' ) 
    121140                print ( f'    {VarName:21} set to : {locals()[VarName]:}' ) 
    122                  
     141 
    123142        for VarName in ['PackFrequency'] : 
    124143            if VarName in MyReader['Post'].keys() : 
     
    134153## Reading config file 
    135154## ------------------- 
    136 for Section in ['Config', 'Experiment', 'libIGCM', 'Files', 'Physics' ] : 
    137    if Section in config.keys () :  
    138         print ( f'\nReading [{Section}]' ) 
    139         for VarName in config[Section].keys() : 
    140             locals()[VarName] = config[Section][VarName] 
    141             exec ( f'{VarName} = wu.setBool ({VarName})' ) 
    142             exec ( f'{VarName} = wu.setNum  ({VarName})' ) 
    143             exec ( f'{VarName} = wu.setNone ({VarName})' ) 
    144             exec ( f'wu.{VarName} = {VarName}' ) 
    145             print ( f'    {VarName:21} set to : {locals()[VarName]}' ) 
     155# Each entry in the .ini file will create a Python variable with the same name 
     156for Section in config.keys () : 
     157    print ( f'\nReading [{Section}]' ) 
     158    for VarName in config[Section].keys() : 
     159        locals()[VarName] = config[Section][VarName] 
     160        exec ( f'{VarName} = wu.setBool ({VarName})' ) 
     161        exec ( f'{VarName} = wu.setNum  ({VarName})' ) 
     162        exec ( f'{VarName} = wu.setNone ({VarName})' ) 
     163        exec ( f'wu.{VarName} = {VarName}' ) 
     164        print ( f'    {VarName:21} set to : {locals()[VarName]}' ) 
    146165 
    147166print ( f'\nConfig file readed : {IniFile} ' ) 
     
    149168## 
    150169## Reading prec 
    151 if wu.unDefined ( 'readPrec' )  : 
     170if not readPrec  : 
    152171    readPrec = np.float64 
    153172else : 
     
    155174    if readPrec in [         "float32", "r4", "single", "<class 'numpy.float32'>" ] : readPrec = np.float32 
    156175    if readPrec in [         "float16", "r2", "half"  , "<class 'numpy.float16'>" ] : readPrec = np.float16 
    157                
     176 
    158177## Some physical constants 
    159178## ======================= 
    160 if wu.unDefined ( 'Ra' )           : Ra          = wu.Ra           #-- Earth Radius (m) 
    161 if wu.unDefined ( 'Grav' )         : Grav        = wu.Grav         #-- Gravity (m^2/s 
    162 if wu.unDefined ( 'ICE_rho_ice' )  : ICE_rho_ice = wu.ICE_rho_ice  #-- Ice volumic mass (kg/m3) in LIM3 
    163 if wu.unDefined ( 'ICE_rho_sno')   : ICE_rho_sno = wu.ICE_rho_sno  #-- Snow volumic mass (kg/m3) in LIM3 
    164 if wu.unDefined ( 'OCE_rho_liq' )  : OCE_rho_liq = wu.OCE_rho_liq  #-- Ocean water volumic mass (kg/m3) in NEMO 
    165 if wu.unDefined ( 'ATM_rho' )      : ATM_rho     = wu.ATM_rho      #-- Water volumic mass in atmosphere (kg/m^3) 
    166 if wu.unDefined ( 'SRF_rho' )      : SRF_rho     = wu.SRF_rho      #-- Water volumic mass in surface reservoir (kg/m^3) 
    167 if wu.unDefined ( 'RUN_rho' )      : RUN_rho     = wu.RUN_rho      #-- Water volumic mass of rivers (kg/m^3) 
    168 if wu.unDefined ( 'ICE_rho_pnd' )  : ICE_rho_pnd = wu.ICE_rho_pnd  #-- Water volumic mass in ice ponds (kg/m^3) 
    169 if wu.unDefined ( 'YearLength' )   : YearLength  = wu.YearLength   #-- Year length (s) 
     179if not RA           : RA          = wu.RA           #-- Earth Radius (m) 
     180if not GRAV         : GRAV        = wu.GRAV         #-- Gravity (m^2/s 
     181if not ICE_RHO_ICE  : ICE_RHO_ICE = wu.ICE_RHO_ICE  #-- Ice volumic mass (kg/m3) in LIM3 
     182if not ICE_RHO_SNO  : ICE_RHO_SNO = wu.ICE_RHO_SNO  #-- Snow volumic mass (kg/m3) in LIM3 
     183if not OCE_RHO_LIQ  : OCE_RHO_LIQ = wu.OCE_RHO_LIQ  #-- Ocean water volumic mass (kg/m3) in NEMO 
     184if not ATM_RHO      : ATM_RHO     = wu.ATM_RHO      #-- Water volumic mass in atmosphere (kg/m^3) 
     185if not SRF_RHO      : SRF_RHO     = wu.SRF_RHO      #-- Water volumic mass in surface reservoir (kg/m^3) 
     186if not RUN_RHO      : RUN_RHO     = wu.RUN_RHO      #-- Water volumic mass of rivers (kg/m^3) 
     187if not ICE_RHO_PND  : ICE_RHO_PND = wu.ICE_RHO_PND  #-- Water volumic mass in ice ponds (kg/m^3) 
     188if not YEAR_LENGTH   : YEAR_LENGTH  = wu.YEAR_LENGTH   #-- Year length (s) 
    170189 
    171190## Set libIGCM and machine dependant values 
    172191## ---------------------------------------- 
    173 if not 'Files' in config.keys () : config['Files'] = {} 
    174  
    175 config['Physics'] = { 'Ra':str(Ra), 'Grav':str(Grav), 'ICE_rho_ice':str(ICE_rho_ice), 'ICE_rho_sno':str(ICE_rho_sno), 
    176                       'OCE_rho_liq':str(OCE_rho_liq), 'ATM_rho':str(ATM_rho), 'SRF_rho':str(SRF_rho), 'RUN_rho':str(RUN_rho)} 
    177  
    178 config['Config'] = { 'ContinueOnError':ContinueOnError, 'TestInterp':str(TestInterp), 'readPrec':str(readPrec) } 
     192if 'Files'   not in config.keys () : config['Files']   = {} 
     193if 'Physics' not in config.keys () : config['Physics'] = {} 
     194if 'Config'  not in config.keys () : config['Physics'] = {} 
     195 
     196config['Physics'].update ( { 'RA':str(RA), 'GRAV':str(GRAV), 'ICE_RHO_ICE':str(ICE_RHO_ICE), 'ICE_RHO_SNO':str(ICE_RHO_SNO), 
     197                      'OCE_RHO_LIQ':str(OCE_RHO_LIQ), 'ATM_RHO':str(ATM_RHO), 'SRF_RHO':str(SRF_RHO), 'RUN_RHO':str(RUN_RHO)} ) 
     198 
     199config['Config'].update ( { 'ContinueOnError':str(ContinueOnError), 'TestInterp':str(TestInterp), 'readPrec':str(readPrec), 
     200                            'Debug':str(Debug), 'Timer':str(Timer)} ) 
     201 
     202Timer = wu.functools.partial (wu.Timer, debug=False, timer=True) 
     203 
    179204 
    180205## -------------------------- 
    181 ICO  = ( 'ICO' in wu.ATM ) 
    182 LMDZ = ( 'LMD' in wu.ATM ) 
     206ICO  = ( 'ICO' in ATM ) 
     207LMDZ = ( 'LMD' in ATM ) 
    183208 
    184209mm = libIGCM_sys.config ( TagName=TagName, SpaceName=SpaceName, ExperimentName=ExperimentName, JobName=JobName, User=User, Group=Group, 
    185              ARCHIVE=None, SCRATCHDIR=None, STORAGE=None, R_IN=None, R_OUT=None, R_FIG=None, rebuild=None, TmpDir=None,  
    186              R_SAVE=None, R_FIGR=None, R_BUFR=None, R_BUF_KSH=None, REBUILD_DIR=None, POST_DIR=None ) 
     210             ARCHIVE=ARCHIVE, SCRATCHDIR=SCRATCHDIR, STORAGE=STORAGE, R_IN=R_IN, R_OUT=R_OUT, R_FIG=R_FIG, rebuild=rebuild, TmpDir=TmpDir, 
     211             R_SAVE=R_SAVE, R_FIGR=R_FIGR, R_BUFR=R_BUFR, R_BUF_KSH=R_BUF_KSH, REBUILD_DIR=REBUILD_DIR, POST_DIR=POST_DIR, L_EXP=L_EXP ) 
    187212globals().update(mm) 
    188213 
    189214config['Files']['TmpDir'] = TmpDir 
    190 config['libIGCM'] = { 'ARCHIVE':ARCHIVE, 'STORAGE':STORAGE, 'TmpDir':TmpDir, 'R_IN':R_IN, 'rebuild':rebuild } 
     215 
     216if 'libIGCM' not in config.keys () : config['libIGCM'] = {} 
     217config['libIGCM'].update ( { 'ARCHIVE':str(ARCHIVE), 'STORAGE':str(STORAGE), 'TmpDir':str(TmpDir), 'R_IN':str(R_IN), 'rebuild':str(rebuild) } ) 
     218 
     219## Debuging and timer 
     220Timer = wu.functools.partial (wu.Timer, debug=Debug, timer=Timer) 
    191221 
    192222## Defines begining and end of experiment 
    193223## -------------------------------------- 
    194 if wu.unDefined ( 'DateBegin' ) : 
     224if not DateBegin : 
    195225    DateBegin = f'{YearBegin}0101' 
    196226    config['Experiment']['DateBegin'] = DateBegin 
     
    200230    config['Experiment']['YearBegin'] = str(YearBegin) 
    201231 
    202 if wu.unDefined ( 'DateEnd' )   : 
     232if not DateEnd   : 
    203233    DateEnd   = f'{YearEnd}1231' 
    204234    config['Experiment']['DateEnd']   = str(DateEnd) 
     
    208238    config['Experiment']['DateEnd']   = str(DateEnd) 
    209239 
    210 if wu.unDefined ( 'PackFrequency' ) : 
     240if not PackFrequency : 
    211241    PackFrequency = YearEnd - YearBegin +1 
    212242    config['Experiment']['PackFrequency']   = f'{PackFrequency}' 
    213243 
    214 if type ( PackFrequency ) == str :  
    215     if 'Y' in PackFrequency : PackFrequency = PackFrequency.replace ( 'Y', '')  
     244if isinstance ( PackFrequency, str) : 
     245    if 'Y' in PackFrequency : PackFrequency = PackFrequency.replace ( 'Y', '') 
    216246    if 'M' in PackFrequency : PackFrequency = PackFrequency.replace ( 'M', '') 
    217247    PackFrequency = int ( PackFrequency ) 
     
    220250print ( f'{YearEnd  =} {DateEnd  =}' ) 
    221251print ( f'{PackFrequency=}' ) 
    222      
     252 
    223253## Output file with water budget diagnostics 
    224254## ----------------------------------------- 
    225 if wu.unDefined ( 'FileOut' ) : 
     255if not FileOut : 
    226256    FileOut = f'OCE_waterbudget_{JobName}_{YearBegin}_{YearEnd}' 
    227257    if readPrec == np.float32 : FileOut = f'{FileOut}_float32' 
     
    230260    config['Files']['FileOut'] = FileOut 
    231261 
    232 f_out = open ( FileOut, mode = 'w' ) 
     262f_out = open ( FileOut, mode = 'w', encoding='utf-8' ) 
    233263 
    234264## Useful functions 
    235265## ---------------- 
    236266 
    237 # Degrades precision  
    238 if readPrec == float : 
    239     def rprec (tab) : return tab 
    240 else :  
    241     def rprec (tab) : return tab.astype(readPrec).astype(float) 
    242          
    243 def kg2Sv  (val, rho=ATM_rho) : 
     267# Degrades precision 
     268if repr(readPrec) == "<class 'numpy.float64'>" or readPrec == float : 
     269    def rprec (ptab) : 
     270        '''This version does nothing 
     271 
     272        rprec may be use to reduce floating precision when reading history files 
     273        ''' 
     274        return ptab 
     275else                 : 
     276    def rprec (ptab) : 
     277        '''Return float with a different precision''' 
     278        return ptab.astype(readPrec).astype(float) 
     279 
     280def kg2Sv  (val, rho=ATM_RHO) : 
    244281    '''From kg to Sverdrup''' 
    245282    return val/dtime_sec*1.0e-6/rho 
    246283 
    247 def kg2myear (val, rho=ATM_rho) : 
     284def kg2myear (val, rho=ATM_RHO) : 
    248285    '''From kg to m/year''' 
    249286    return val/OCE_aire_tot/rho/NbYear 
    250287 
    251 def var2prt (var, small=False, rho=ATM_rho) : 
     288def var2prt (var, small=False, rho=ATM_RHO) : 
     289    '''Formats value for printing''' 
    252290    if small :  return var , kg2Sv(var, rho=rho)*1000., kg2myear(var, rho=rho)*1000. 
    253291    else     :  return var , kg2Sv(var, rho=rho)      , kg2myear(var, rho=rho) 
    254292 
    255 def prtFlux (Desc, var, Form='F', small=False, rho=ATM_rho, width=15) : 
     293def prtFlux (Desc, var, Form='F', small=False, rho=ATM_RHO, width=15) : 
     294    '''Pretty print of formattd value''' 
    256295    if small : 
    257296        if Form in ['f', 'F'] : ff=" {:14.6e} kg | {:12.4f} mSv | {:12.4f} mm/year " 
     
    261300        if Form in ['e', 'E'] : ff=" {:14.6e} kg | {:12.4e} Sv  | {:12.4e} m/year  " 
    262301    echo ( (' {:>{width}} = ' +ff).format (Desc, *var2prt(var, small, rho=rho), width=width ) ) 
    263     return None 
    264302 
    265303def echo (string, end='\n') : 
     
    269307    f_out.write ( str(string) + end ) 
    270308    f_out.flush () 
    271     return None 
    272      
    273     
     309 
     310 
    274311## Set libIGCM directories 
    275312## ----------------------- 
    276 if wu.unDefined ('R_OUT'      ) : R_OUT       = os.path.join ( ARCHIVE   , 'IGCM_OUT' ) 
    277 if wu.unDefined ('R_BUF'      ) : R_BUF       = os.path.join ( SCRATCHDIR, 'IGCM_OUT' ) 
    278 if wu.unDefined ('L_EXP'      ) : L_EXP       = os.path.join (TagName, SpaceName, ExperimentName, JobName) 
    279 if wu.unDefined ('R_SAVE'     ) : R_SAVE      = os.path.join ( R_OUT, L_EXP ) 
    280 if wu.unDefined ('R_BUFR'     ) : R_BUFR      = os.path.join ( R_BUF, L_EXP ) 
    281 if wu.unDefined ('POST_DIR'   ) : POST_DIR    = os.path.join ( R_BUFR, 'Out' ) 
    282 if wu.unDefined ('REBUILD_DIR') : REBUILD_DIR = os.path.join ( R_BUFR, 'REBUILD' ) 
    283 if wu.unDefined ('R_BUF_KSH'  ) : R_BUF_KSH   = os.path.join ( R_BUFR, 'Out' ) 
    284 if wu.unDefined ('R_FIGR'     ) : R_FIGR      = os.path.join ( STORAGE, 'IGCM_OUT', L_EXP ) 
    285  
    286 config['libIGCM'].update ( { 'R_OUT':R_OUT, 'R_BUF':R_BUF, 'L_EXP':L_EXP, 'R_BUFR':R_BUFR, 'POST_DIR':POST_DIR, 
    287                       'REBUILD_DIR':REBUILD_DIR, 'R_BUF_KSH':R_BUF_KSH, 'R_FIGR':R_FIGR, 'rebuild':rebuild } ) 
     313if not R_OUT       : R_OUT       = os.path.join ( ARCHIVE   , 'IGCM_OUT' ) 
     314if not R_BUF       : R_BUF       = os.path.join ( SCRATCHDIR, 'IGCM_OUT' ) 
     315if not L_EXP       : L_EXP       = os.path.join (TagName, SpaceName, ExperimentName, JobName) 
     316if not R_SAVE      : R_SAVE      = os.path.join ( R_OUT, L_EXP ) 
     317if not R_BUFR      : R_BUFR      = os.path.join ( R_BUF, L_EXP ) 
     318if not POST_DIR    : POST_DIR    = os.path.join ( R_BUFR, 'Out' ) 
     319if not REBUILD_DIR : REBUILD_DIR = os.path.join ( R_BUFR, 'REBUILD' ) 
     320if not R_BUF_KSH   : R_BUF_KSH   = os.path.join ( R_BUFR, 'Out' ) 
     321if not R_FIGR      : R_FIGR      = os.path.join ( STORAGE, 'IGCM_OUT', L_EXP ) 
     322 
     323config['libIGCM'].update ( { 'R_OUT':R_OUT, 'R_BUF':R_BUF, 'L_EXP':L_EXP, 'R_BUFR':R_BUFR, 'R_SAVE':R_SAVE, 'POST_DIR':POST_DIR, 
     324                             'REBUILD_DIR':REBUILD_DIR, 'R_BUF_KSH':R_BUF_KSH, 'R_FIGR':R_FIGR, 'rebuild':rebuild, 
     325                             'YEAR_LENGTH':str(YEAR_LENGTH)} ) 
    288326 
    289327## Set directory to extract files 
    290328## ------------------------------ 
    291 if wu.unDefined ( 'FileDir' ) : FileDir = os.path.join ( TmpDir, f'WATER_{JobName}' ) 
     329if not FileDir : FileDir = os.path.join ( TmpDir, f'WATER_{JobName}' ) 
    292330config['Files']['FileDir'] = FileDir 
    293331 
     
    295333 
    296334##- Set directories to rebuild ocean and ice restart files 
    297 if wu.unDefined ( 'FileDirOCE' ) : FileDirOCE = os.path.join ( FileDir, 'OCE' ) 
    298 if wu.unDefined ( 'FileDirICE' ) : FileDirICE = os.path.join ( FileDir, 'ICE' ) 
     335if not FileDirOCE : FileDirOCE = os.path.join ( FileDir, 'OCE' ) 
     336if not FileDirICE : FileDirICE = os.path.join ( FileDir, 'ICE' ) 
    299337if not os.path.exists ( FileDirOCE ) : os.mkdir ( FileDirOCE ) 
    300338if not os.path.exists ( FileDirICE ) : os.mkdir ( FileDirICE ) 
     
    314352if Freq == "MO" : FreqDir = os.path.join ( 'Output' , 'MO' ) 
    315353if Freq == "SE" : FreqDir = os.path.join ( 'Analyse', 'SE' ) 
    316 if wu.unDefined ( 'dir_OCE_his' ) : 
     354if not dir_OCE_his : 
    317355    dir_OCE_his = os.path.join ( R_SAVE, "OCE", FreqDir ) 
    318356    config['Files']['dir_OCE_his'] = dir_OCE_his 
    319 if wu.unDefined ( 'dir_ICE_his' ) : 
     357if not dir_ICE_his : 
    320358    dir_ICE_his = os.path.join ( R_SAVE, "ICE", FreqDir ) 
    321359    config['Files']['dir_OCE_his'] = dir_OCE_his 
    322   
    323 echo ( f'The analysis relies on files from the following model output directories : ' ) 
     360 
     361echo (  'The analysis relies on files from the following model output directories : ' ) 
    324362echo ( f'{dir_OCE_his}' ) 
    325363echo ( f'{dir_ICE_his}' ) 
    326364 
    327365#-- Creates files names 
    328 if wu.unDefined ( 'Period ' ) : 
     366if not Period : 
    329367    if Freq == 'MO' : Period = f'{DateBegin}_{DateEnd}_1M' 
    330368    if Freq == 'SE' : Period = f'SE_{DateBegin}_{DateEnd}_1M' 
     
    333371config['Files']['DateBegin'] = DateBegin 
    334372config['Files']['DateBegin'] = DateEnd 
    335         
     373 
    336374echo ( f'Period   : {Period}' ) 
    337375 
    338 if wu.unDefined ( 'FileCommon' ) : 
     376if not FileCommon : 
    339377    FileCommon = f'{JobName}_{Period}' 
    340378    config['Files']['FileCommon'] = FileCommon 
    341379 
    342 if wu.unDefined ( 'Title' ) : 
     380if not Title : 
    343381    Title = f'{JobName} : {Freq} : {DateBegin} - {DateEnd}' 
    344382    config['Files']['Title'] = Title 
    345          
     383 
    346384echo ('\nOpen history files' ) 
    347 if wu.unDefined ('file_OCE_his' ) : 
     385if not file_OCE_his : 
    348386    file_OCE_his = os.path.join ( dir_OCE_his, f'{FileCommon}_grid_T.nc' ) 
    349     file_OCE_his = file_OCE_his 
    350 if wu.unDefined ('file_OCE_sca' ) :     
     387    config['Files']['file_OCE_his'] = file_OCE_his 
     388if not file_OCE_sca : 
    351389    file_OCE_sca = os.path.join ( dir_OCE_his, f'{FileCommon}_scalar.nc' ) 
    352390    config['Files']['file_OCE_sca'] = file_OCE_sca 
    353 if wu.unDefined ( 'file_ICE_hi' ) :  
     391if not file_ICE_his : 
    354392    file_ICE_his = os.path.join ( dir_ICE_his, f'{FileCommon}_icemod.nc' ) 
    355393    config['Files']['file_ICE_his'] = file_ICE_his 
     
    358396d_OCE_sca = xr.open_dataset ( file_OCE_sca, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
    359397d_ICE_his = xr.open_dataset ( file_ICE_his, use_cftime=True, decode_times=True, decode_cf=True ).squeeze() 
    360 if NEMO == 3.6 :d_ICE_his = d_ICE_his.rename ( {'y_grid_T':'y', 'x_grid_T':'x'} ) 
     398 
     399udims = udims={'y':'y', 'x':'x'} 
     400d_OCE_his = nemo.unify_dims ( d_OCE_his, **udims, verbose=False ) 
     401d_OCE_sca = nemo.unify_dims ( d_OCE_sca, **udims, verbose=False ) 
     402d_ICE_his = nemo.unify_dims ( d_ICE_his, **udims, verbose=False ) 
    361403 
    362404echo ( f'{file_OCE_his = }' ) 
     
    367409## ------------------ 
    368410dtime = ( d_OCE_his.time_counter_bounds.max() - d_OCE_his.time_counter_bounds.min() ) 
    369 echo ( f'\nRun length : {(dtime/np.timedelta64(1, "D")).values:8.2f} days' ) 
     411echo ( '\nRun length : {(dtime/np.timedelta64(1, "D")).values:8.2f} days' ) 
    370412dtime_sec = (dtime/np.timedelta64(1, "s")).values.item() # Convert in seconds 
    371413 
     
    373415## ----------------------------- 
    374416dtime_per = ( d_OCE_his.time_counter_bounds[:,-1] - d_OCE_his.time_counter_bounds[:,0] ) 
    375 echo ( f'\nPeriods lengths (days) : ') 
     417echo (  '\nPeriods lengths (days) : ') 
    376418echo ( f' {(dtime_per/np.timedelta64(1, "D")).values}' ) 
    377419dtime_per_sec = (dtime_per/np.timedelta64(1, "s")).values # In seconds 
     
    380422 
    381423## Number of years 
    382 NbYear = dtime_sec / YearLength 
     424NbYear = dtime_sec / YEAR_LENGTH 
    383425 
    384426##-- Extract restart files from tar 
     
    387429if wu.unDefined ('TarRestartDate_end' ) : TarRestartDate_end = wu.FormatToGregorian ( DateEnd ) 
    388430 
    389 if wu.unDefined ( 'TarRestartPeriod_beg' ) : 
     431if not TarRestartPeriod_beg : 
    390432 
    391433    TarRestartPeriod_beg_DateEnd = TarRestartDate_beg 
    392434    TarRestartPeriod_beg_DateBeg = wu.DateAddYear ( TarRestartPeriod_beg_DateEnd, -PackFrequency ) 
    393435    TarRestartPeriod_beg_DateBeg = wu.DatePlusOneDay ( TarRestartPeriod_beg_DateBeg ) 
    394      
     436 
    395437    TarRestartPeriod_beg = f'{TarRestartPeriod_beg_DateBeg}_{TarRestartPeriod_beg_DateEnd}' 
    396438    echo (f'Tar period for initial restart : {TarRestartPeriod_beg}') 
    397439    config['Files']['TarRestartPeriod_beg'] = TarRestartPeriod_beg 
    398440 
    399 if wu.unDefined ( 'TarRestartPeriod_end' ) : 
     441if not TarRestartPeriod_end : 
    400442 
    401443    TarRestartPeriod_end_DateEnd = TarRestartDate_end 
    402444    TarRestartPeriod_end_DateBeg = wu.DateAddYear ( TarRestartPeriod_end_DateEnd, -PackFrequency ) 
    403445    TarRestartPeriod_end_DateBeg = wu.DatePlusOneDay ( TarRestartPeriod_end_DateBeg ) 
    404       
     446 
    405447    TarRestartPeriod_end = f'{TarRestartPeriod_end_DateBeg}_{TarRestartPeriod_end_DateEnd}' 
    406448    echo (f'Tar period for final restart : {TarRestartPeriod_end}') 
     
    409451echo (f'Restart dates - Start : {TarRestartPeriod_beg}  /  End : {TarRestartPeriod_end}') 
    410452 
    411 if wu.unDefined ( 'tar_restart_beg' ) : 
     453if not tar_restart_beg : 
    412454    tar_restart_beg = os.path.join ( R_SAVE, 'RESTART', f'{JobName}_{TarRestartPeriod_beg}_restart.tar' ) 
    413455    config['Files']['tar_restart_beg'] = tar_restart_beg 
    414 if wu.unDefined ( 'tar_restart_end' ) : 
     456if not tar_restart_end : 
    415457    tar_restart_end = os.path.join ( R_SAVE, 'RESTART', f'{JobName}_{TarRestartPeriod_end}_restart.tar' ) 
    416458    config['Files']['tar_restart_end'] = tar_restart_end 
     
    418460echo ( f'{tar_restart_beg = }' ) 
    419461echo ( f'{tar_restart_end = }' ) 
    420      
     462 
    421463# 
    422 if wu.unDefined ('tar_restart_beg_ATM' ) : tar_restart_beg_ATM = tar_restart_beg 
    423 if wu.unDefined ('tar_restart_beg_DYN' ) : tar_restart_beg_DYN = tar_restart_beg 
    424 if wu.unDefined ('tar_restart_beg_SRF' ) : tar_restart_beg_SRF = tar_restart_beg 
    425 if wu.unDefined ('tar_restart_beg_RUN' ) : tar_restart_beg_RUN = tar_restart_beg 
    426 if wu.unDefined ('tar_restart_beg_OCE' ) : tar_restart_beg_OCE = tar_restart_beg 
    427 if wu.unDefined ('tar_restart_beg_ICE' ) : tar_restart_beg_ICE = tar_restart_beg 
    428  
    429 if wu.unDefined ('tar_restart_end_ATM' ) : tar_restart_end_ATM = tar_restart_end 
    430 if wu.unDefined ('tar_restart_end_DYN' ) : tar_restart_end_DYN = tar_restart_end 
    431 if wu.unDefined ('tar_restart_end_SRF' ) : tar_restart_end_SRF = tar_restart_end 
    432 if wu.unDefined ('tar_restart_end_RUN' ) : tar_restart_end_RUN = tar_restart_end 
    433 if wu.unDefined ('tar_restart_end_OCE' ) : tar_restart_end_OCE = tar_restart_end 
    434 if wu.unDefined ('tar_restart_end_ICE' ) : tar_restart_end_ICE = tar_restart_end 
    435  
    436 if wu.unDefined ( 'file_OCE_beg' ) :  
     464if not tar_restart_beg_ATM : tar_restart_beg_ATM = tar_restart_beg 
     465if not tar_restart_beg_DYN : tar_restart_beg_DYN = tar_restart_beg 
     466if not tar_restart_beg_RUN : tar_restart_beg_RUN = tar_restart_beg 
     467if not tar_restart_beg_OCE : tar_restart_beg_OCE = tar_restart_beg 
     468if not tar_restart_beg_ICE : tar_restart_beg_ICE = tar_restart_beg 
     469 
     470if not tar_restart_end_ATM : tar_restart_end_ATM = tar_restart_end 
     471if not tar_restart_end_DYN : tar_restart_end_DYN = tar_restart_end 
     472if not tar_restart_end_RUN : tar_restart_end_RUN = tar_restart_end 
     473if not tar_restart_end_OCE : tar_restart_end_OCE = tar_restart_end 
     474if not tar_restart_end_ICE : tar_restart_end_ICE = tar_restart_end 
     475 
     476if not file_OCE_beg : 
    437477    file_OCE_beg = f'{FileDir}/OCE_{JobName}_{TarRestartDate_beg}_restart.nc' 
    438478    config['Files']['file_OCE_beg'] = file_OCE_beg 
    439 if wu.unDefined ( 'file_OCE_end' ) : 
     479if not file_OCE_end : 
    440480    file_OCE_end = f'{FileDir}/OCE_{JobName}_{TarRestartDate_end}_restart.nc' 
    441481    config['Files']['file_OCE_end'] = file_OCE_end 
    442 if wu.unDefined ( 'file_ICE_beg' ) : 
     482if not file_ICE_beg : 
    443483    file_ICE_beg = f'{FileDir}/ICE_{JobName}_{TarRestartDate_beg}_restart_icemod.nc' 
    444484    config['Files']['file_ICE_beg'] = file_ICE_beg 
    445 if wu.unDefined ( 'file_ICE_end' ) :  
     485if not file_ICE_end : 
    446486    file_ICE_end = f'{FileDir}/ICE_{JobName}_{TarRestartDate_end}_restart_icemod.nc' 
    447487    config['Files']['file_ICE_end'] = file_ICE_end 
     
    463503    return int (ndomain_opa) 
    464504 
    465 def extract_and_rebuild ( file_name=file_OCE_beg, tar_restart=tar_restart_end, FileDirComp=FileDirOCE, ErrorCount=ErrorCount ) : 
     505@Timer 
     506def extract_and_rebuild ( file_name=file_OCE_beg, tar_restart=tar_restart_end, file_dir_comp=FileDirOCE, error_count=ErrorCount ) : 
    466507    '''Extract restart file from tar. Rebuild ocean files if needed''' 
    467     echo ( f'----------') 
     508    echo ( '----------') 
    468509    if os.path.exists ( file_name ) : 
    469510        echo ( f'-- File ready : {file_name = }' ) 
    470     else :  
     511    else : 
    471512        echo ( f'-- Extracting {file_name = }' ) 
    472513        base_resFile = Path (file_name).stem # basename, and remove suffix 
    473514        # Try to extract the rebuilded file 
    474515        if os.path.exists ( tar_restart ) : 
    475             command =  f'cd {FileDirComp} ; tar xf {tar_restart} {base_resFile}.nc' 
     516            command =  f'cd {file_dir_comp} ; tar xf {tar_restart} {base_resFile}.nc' 
    476517            echo ( command ) 
    477             try :  
     518            try : 
    478519                os.system ( command ) 
    479520            except : 
    480521                if not os.path.exists ( os.path.join (FileDir, f'{base_resFile}_0000.nc') ): 
    481                     command =  f'cd {FileDirComp} ; tar xf {tar_restart_end} {base_file}_*.nc' 
     522                    command =  f'cd {file_dir_comp} ; tar xf {tar_restart_end} {base_resFile}_*.nc' 
    482523                    echo ( command ) 
    483524                    ierr = os.system ( command ) 
    484525                    if ierr == 0 : echo ( f'tar done : {base_resFile}.nc') 
    485                     else         : raise Exception ( f'command failed : {command}' ) 
    486                     echo ( f'extract ndomain' ) 
    487                 ndomain_opa = get_ndomain ( os.path.join (FileDir, f'{base_file}') ) 
    488                 command = f'cd {FileDirComp} ; {rebuild} {base_resFile} {ndomain_opa} ; mv {base_resFile}.nc {FileDir}' 
     526                    else         : raise OSError ( f'command failed : {command}' ) 
     527                    echo ( 'extract ndomain' ) 
     528                ndomain_opa = get_ndomain ( os.path.join (FileDir, f'{base_resFile}') ) 
     529                command = f'cd {file_dir_comp} ; {rebuild} {base_resFile} {ndomain_opa} ; mv {base_resFile}.nc {FileDir}' 
    489530                echo ( command ) 
    490531                ierr = os.system ( command ) 
    491532                if ierr == 0 : echo ( f'Rebuild done : {base_resFile}.nc') 
    492                 else         : raise Exception ( f'command failed : {command}' ) 
    493             else :  
     533                else         : raise OSError ( f'command failed : {command}' ) 
     534            else : 
    494535                echo ( f'tar done : {base_resFile}') 
    495                 command = f'cd {FileDirComp} ; mv {base_resFile}.nc {FileDir}' 
     536                command = f'cd {file_dir_comp} ; mv {base_resFile}.nc {FileDir}' 
    496537                ierr = os.system ( command ) 
    497538                if ierr == 0 : echo ( f'command done : {command}' ) 
    498                 else         : raise Exception ( f'command failed : {command = }' )                    
     539                else         : raise OSError ( f'command failed : {command = }' ) 
    499540        else : 
    500541            echo ( f'****** Tar restart file {tar_restart = } not found ' ) 
    501542            if ContinueOnError : 
    502                 ErrorCount += 1 
    503             else :  
    504                 raise Exception ( f'****** tar file not found {tar_restart = } - Stopping' ) 
    505     return ErrorCount 
    506  
    507              
    508 ErrorCount += extract_and_rebuild ( file_name=file_OCE_beg, tar_restart=tar_restart_beg, FileDirComp=FileDirOCE ) 
    509 ErrorCount += extract_and_rebuild ( file_name=file_OCE_end, tar_restart=tar_restart_end, FileDirComp=FileDirOCE ) 
    510 ErrorCount += extract_and_rebuild ( file_name=file_ICE_beg, tar_restart=tar_restart_beg, FileDirComp=FileDirICE ) 
    511 ErrorCount += extract_and_rebuild ( file_name=file_ICE_end, tar_restart=tar_restart_end, FileDirComp=FileDirICE ) 
     543                error_count += 1 
     544            else : 
     545                raise OSError ( f'****** tar file not found {tar_restart = } - Stopping' ) 
     546    return error_count 
     547 
     548ErrorCount += extract_and_rebuild ( file_name=file_OCE_beg, tar_restart=tar_restart_beg, file_dir_comp=FileDirOCE, error_count=ErrorCount ) 
     549ErrorCount += extract_and_rebuild ( file_name=file_OCE_end, tar_restart=tar_restart_end, file_dir_comp=FileDirOCE, error_count=ErrorCount ) 
     550ErrorCount += extract_and_rebuild ( file_name=file_ICE_beg, tar_restart=tar_restart_beg, file_dir_comp=FileDirICE, error_count=ErrorCount ) 
     551ErrorCount += extract_and_rebuild ( file_name=file_ICE_end, tar_restart=tar_restart_end, file_dir_comp=FileDirICE, error_count=ErrorCount ) 
    512552 
    513553echo ('Opening OCE and ICE restart files') 
    514 if NEMO == 3.6 :  
     554if NEMO == 3.6 : 
    515555    d_OCE_beg = xr.open_dataset ( os.path.join (FileDir, file_OCE_beg), decode_times=False, decode_cf=True, drop_variables=['y', 'x']).squeeze() 
    516556    d_OCE_end = xr.open_dataset ( os.path.join (FileDir, file_OCE_end), decode_times=False, decode_cf=True).squeeze() 
    517557    d_ICE_beg = xr.open_dataset ( os.path.join (FileDir, file_ICE_beg), decode_times=False, decode_cf=True).squeeze() 
    518558    d_ICE_end = xr.open_dataset ( os.path.join (FileDir, file_ICE_end), decode_times=False, decode_cf=True).squeeze() 
    519 if NEMO == 4.0 or NEMO == 4.2 :  
     559if NEMO in [ 4.0, 4.2 ] : 
    520560    d_OCE_beg = xr.open_dataset ( os.path.join (FileDir, file_OCE_beg), decode_times=False, decode_cf=True, drop_variables=['y', 'x']).squeeze() 
    521561    d_OCE_end = xr.open_dataset ( os.path.join (FileDir, file_OCE_end), decode_times=False, decode_cf=True, drop_variables=['y', 'x']).squeeze() 
     
    524564 
    525565## Write the full configuration 
    526 config_out = open (FullIniFile, 'w') 
     566config_out = open (FullIniFile, 'w', encoding='utf-8') 
    527567config.write (config_out ) 
    528568config_out.close () 
    529      
     569 
    530570# Get mask and surfaces 
    531571sos = d_OCE_his ['sos'][0].squeeze() 
     
    539579ICE_aire = OCE_aire 
    540580 
     581@Timer 
    541582def OCE_stock_int (stock) : 
    542583    '''Integrate stock on ocean grid''' 
    543     OCE_stock_int = wu.Psum (  (stock * OCE_aire ).to_masked_array().ravel() ) 
    544     return OCE_stock_int 
    545  
     584    return wu.Psum (  (stock * OCE_aire ).to_masked_array().ravel() ) 
     585 
     586@Timer 
    546587def ONE_stock_int (stock) : 
    547588    '''Sum stock''' 
    548     ONE_stock_int = wu.Psum ( stock.to_masked_array().ravel() ) 
    549     return ONE_stock_int 
    550  
     589    return wu.Psum ( stock.to_masked_array().ravel() ) 
     590 
     591@Timer 
    551592def OCE_flux_int (flux) : 
    552593    '''Integrate flux on oce grid''' 
    553     OCE_flux_int = wu.Psum  ( (flux * OCE_aire * dtime_per_sec).to_masked_array().ravel() ) 
    554     return OCE_flux_int 
    555  
     594    return wu.Psum  ( (flux * OCE_aire * dtime_per_sec).to_masked_array().ravel() ) 
     595 
     596@Timer 
    556597def ONE_flux_int (flux) : 
    557598    '''Integrate flux on oce grid''' 
    558     OCE_flux_int =  wu.Psum ( (flux * dtime_per_sec).to_masked_array().ravel() ) 
    559     return OCE_flux_int 
     599    return wu.Psum ( (flux * dtime_per_sec).to_masked_array().ravel() ) 
    560600 
    561601OCE_aire_tot = ONE_stock_int ( OCE_aire ) 
    562602ICE_aire_tot = ONE_stock_int ( ICE_aire ) 
    563      
     603 
    564604echo ( '\n------------------------------------------------------------------------------------' ) 
    565605echo ( '-- NEMO change in stores (for the records)' ) 
     
    582622 
    583623echo ( f'OCE_sum_ssh_beg = {OCE_sum_ssh_beg:12.6e} m^3  - OCE_sum_ssh_end = {OCE_sum_ssh_end:12.6e} m^3' ) 
    584 dOCE_ssh_vol = ( OCE_sum_ssh_end - OCE_sum_ssh_beg ) 
    585 dOCE_ssh_mas = dOCE_ssh_vol * OCE_rho_liq 
     624dOCE_ssh_vol = OCE_sum_ssh_end - OCE_sum_ssh_beg 
     625dOCE_ssh_mas = dOCE_ssh_vol * OCE_RHO_LIQ 
    586626 
    587627if NEMO == 3.6 : 
    588628    echo ( f'OCE_sum_e3tn_beg = {OCE_sum_e3tn_beg:12.6e} m^3  - OCE_sum_e3tn_end = {OCE_sum_e3tn_end:12.6e} m^3' ) 
    589     dOCE_e3tn_vol = ( OCE_sum_e3tn_end - OCE_sum_e3tn_beg ) 
    590     dOCE_e3tn_mas = dOCE_e3tn_vol * OCE_rho_liq 
     629    dOCE_e3tn_vol = OCE_sum_e3tn_end - OCE_sum_e3tn_beg 
     630    dOCE_e3tn_mas = dOCE_e3tn_vol * OCE_RHO_LIQ 
    591631 
    592632dOCE_vol_wat = dOCE_ssh_vol ; dOCE_mas_wat = dOCE_ssh_mas 
     
    601641 
    602642## Glace et neige 
    603 if NEMO == 3.6 :         
     643if NEMO == 3.6 : 
    604644    ICE_ice_beg = d_ICE_beg['v_i_htc1']+d_ICE_beg['v_i_htc2']+d_ICE_beg['v_i_htc3']+d_ICE_beg['v_i_htc4']+d_ICE_beg['v_i_htc5'] 
    605645    ICE_ice_end = d_ICE_end['v_i_htc1']+d_ICE_end['v_i_htc2']+d_ICE_end['v_i_htc3']+d_ICE_end['v_i_htc4']+d_ICE_end['v_i_htc5'] 
     
    607647    ICE_sno_beg = d_ICE_beg['v_s_htc1']+d_ICE_beg['v_s_htc2']+d_ICE_beg['v_s_htc3']+d_ICE_beg['v_s_htc4']+d_ICE_beg['v_s_htc5'] 
    608648    ICE_sno_end = d_ICE_end['v_s_htc1']+d_ICE_end['v_s_htc2']+d_ICE_end['v_s_htc3']+d_ICE_end['v_s_htc4']+d_ICE_end['v_s_htc5'] 
    609      
     649 
    610650    ICE_pnd_beg = 0.0 ; ICE_pnd_end = 0.0 ; ICE_fzl_beg = 0.0 ; ICE_fzl_end = 0.0 
    611651 
    612     ICE_mas_wat_beg = ICE_ice_beg*ICE_rho_ice + ICE_sno_beg*ICE_rho_sno 
    613     ICE_mas_wat_end = ICE_ice_end*ICE_rho_ice + ICE_sno_end*ICE_rho_sno 
    614      
    615 if NEMO == 4.0 or NEMO == 4.2 : 
     652    ICE_mas_wat_beg = ICE_ice_beg*ICE_RHO_ICE + ICE_sno_beg*ICE_RHO_SNO 
     653    ICE_mas_wat_end = ICE_ice_end*ICE_RHO_ICE + ICE_sno_end*ICE_RHO_SNO 
     654 
     655if NEMO in [ 4.0, 4.2 ] : 
    616656    ICE_ice_beg = d_ICE_beg['v_i']  ; ICE_ice_end = d_ICE_end['v_i'] 
    617     ICE_sno_beg = d_ICE_beg['v_s']  ; ICE_sno_end = d_ICE_end['v_s']  
     657    ICE_sno_beg = d_ICE_beg['v_s']  ; ICE_sno_end = d_ICE_end['v_s'] 
    618658    ICE_pnd_beg = d_ICE_beg['v_ip'] ; ICE_pnd_end = d_ICE_end['v_ip'] # Ice ponds 
    619659    ICE_fzl_beg = d_ICE_beg['v_il'] ; ICE_fzl_end = d_ICE_end['v_il'] # Frozen Ice Ponds 
    620      
     660 
    621661    ICE_mas_wat_beg =  OCE_stock_int ( d_ICE_beg['snwice_mass'] ) 
    622662    ICE_mas_wat_end =  OCE_stock_int ( d_ICE_end['snwice_mass'] ) 
    623      
     663 
    624664ICE_vol_ice_beg = OCE_stock_int ( ICE_ice_beg ) 
    625665ICE_vol_ice_end = OCE_stock_int ( ICE_ice_end ) 
     
    636676#-- Converting to freswater volume 
    637677dICE_vol_ice = ICE_vol_ice_end - ICE_vol_ice_beg 
    638 dICE_mas_ice = dICE_vol_ice * ICE_rho_ice 
     678dICE_mas_ice = dICE_vol_ice * ICE_RHO_ICE 
    639679 
    640680dICE_vol_sno = ICE_vol_sno_end - ICE_vol_sno_beg 
    641 dICE_mas_sno = dICE_vol_sno * ICE_rho_sno 
     681dICE_mas_sno = dICE_vol_sno * ICE_RHO_SNO 
    642682 
    643683dICE_vol_pnd = ICE_vol_pnd_end - ICE_vol_pnd_beg 
    644 dICE_mas_pnd = dICE_vol_pnd * ICE_rho_pnd 
     684dICE_mas_pnd = dICE_vol_pnd * ICE_RHO_PND 
    645685 
    646686dICE_vol_fzl= ICE_vol_fzl_end - ICE_vol_fzl_beg 
    647 dICE_mas_fzl = dICE_vol_fzl * ICE_rho_pnd 
     687dICE_mas_fzl = dICE_vol_fzl * ICE_RHO_PND 
    648688 
    649689if NEMO == 3.6 : 
    650     dICE_mas_wat = dICE_mas_ice + dICE_mas_sno   
     690    dICE_mas_wat = dICE_mas_ice + dICE_mas_sno 
    651691    dSEA_mas_wat = dOCE_mas_wat + dICE_mas_ice + dICE_mas_sno 
    652692 
    653 if NEMO == 4.0 or NEMO == 4.2 : 
     693if NEMO in [4.0, 4.2 ] : 
    654694    dICE_mas_wat = ICE_mas_wat_end - ICE_mas_wat_beg 
    655695    dSEA_mas_wat = dOCE_mas_wat + dICE_mas_wat 
     
    664704echo ( f'dICE_vol_pnd   = {dICE_vol_pnd:12.3e} m^3' ) 
    665705echo ( f'dICE_mas_ice   = {dICE_mas_ice:12.3e} m^3' ) 
    666 echo ( f'dICE_mas_sno   = {dICE_mas_sno:12.3e} m^3' )   
    667 echo ( f'dICE_mas_pnd   = {dICE_mas_pnd:12.3e} m^3' )   
    668 echo ( f'dICE_mas_fzl   = {dICE_mas_fzl:12.3e} m^3' )   
     706echo ( f'dICE_mas_sno   = {dICE_mas_sno:12.3e} m^3' ) 
     707echo ( f'dICE_mas_pnd   = {dICE_mas_pnd:12.3e} m^3' ) 
     708echo ( f'dICE_mas_fzl   = {dICE_mas_fzl:12.3e} m^3' ) 
    669709 
    670710echo ( '\n------------------------------------------------------------') 
     
    704744OCE_friver     = rprec (d_OCE_his['friver']  )    ; OCE_mas_friver   = OCE_flux_int ( OCE_friver   ) 
    705745OCE_runoffs    = rprec (d_OCE_his['runoffs'] )    ; OCE_mas_runoffs  = OCE_flux_int ( OCE_runoffs  ) 
    706 if NEMO == 4.0 or NEMO == 4.2 : 
     746if NEMO in [ 4.0, 4.2 ] : 
    707747    OCE_wfxice     = rprec (d_OCE_his['vfxice']) ; OCE_mas_wfxice   = OCE_flux_int ( OCE_wfxice ) 
    708748    OCE_wfxsnw     = rprec (d_OCE_his['vfxsnw']) ; OCE_mas_wfxsnw   = OCE_flux_int ( OCE_wfxsnw ) 
    709749    OCE_wfxsub     = rprec (d_OCE_his['vfxsub']) ; OCE_mas_wfxsub   = OCE_flux_int ( OCE_wfxsub ) 
    710750if NEMO == 3.6 : 
    711     OCE_wfxice     = rprec (d_OCE_his['vfxice'])/86400.*ICE_rho_ice ; OCE_mas_wfxice   = OCE_flux_int ( OCE_wfxice ) 
    712     OCE_wfxsnw     = rprec (d_OCE_his['vfxsnw'])/86400.*ICE_rho_sno ; OCE_mas_wfxsnw   = OCE_flux_int ( OCE_wfxsnw ) 
    713     OCE_wfxsub     = rprec (d_OCE_his['vfxsub'])/86400.*ICE_rho_sno ; OCE_mas_wfxsub   = OCE_flux_int ( OCE_wfxsub ) 
     751    OCE_wfxice     = rprec (d_OCE_his['vfxice'])/nemo.RDAY*ICE_RHO_ICE ; OCE_mas_wfxice   = OCE_flux_int ( OCE_wfxice ) 
     752    OCE_wfxsnw     = rprec (d_OCE_his['vfxsnw'])/nemo.RDAY*ICE_RHO_SNO ; OCE_mas_wfxsnw   = OCE_flux_int ( OCE_wfxsnw ) 
     753    OCE_wfxsub     = rprec (d_OCE_his['vfxsub'])/nemo.RDAY*ICE_RHO_SNO ; OCE_mas_wfxsub   = OCE_flux_int ( OCE_wfxsub ) 
    714754# Additional checks 
    715755OCE_evap_oce   = rprec (d_OCE_his['evap_ao_cea']) ; OCE_mas_evap_oce   = OCE_flux_int ( OCE_evap_oce ) 
     
    719759OCE_rain       = rprec (d_OCE_his['rain']       ) ; OCE_mas_rain       = OCE_flux_int ( OCE_rain     ) 
    720760ICE_wfxsub_err = rprec (d_ICE_his['vfxsub_err'] ) ; ICE_mas_wfxsub_err = OCE_flux_int ( ICE_wfxsub_err ) 
    721 if NEMO == 4.0 or NEMO == 4.2 : 
     761if NEMO in [ 4.0, 4.2 ] : 
    722762    ICE_wfxpnd     = rprec (d_ICE_his['vfxpnd']    ) ; ICE_mas_wfxpnd     = OCE_flux_int ( ICE_wfxpnd     ) 
    723763    ICE_wfxsnw_sub = rprec (d_ICE_his['vfxsnw_sub']) ; ICE_mas_wfxsnw_sub = OCE_flux_int ( ICE_wfxsnw_sub ) 
     
    725765if NEMO == 3.6 : 
    726766    ICE_wfxpnd = 0.0 ; ICE_mas_wfxpnd = 0.0 
    727     ICE_wfxsnw_sub = rprec (d_ICE_his['vfxsub'])/86400.*ICE_rho_sno  ; ICE_mas_wfxsnw_sub = OCE_flux_int ( ICE_wfxsnw_sub ) 
    728     ICE_wfxsnw_pre = rprec (d_ICE_his['vfxspr'])/86400.*ICE_rho_sno  ; ICE_mas_wfxsnw_pre = OCE_flux_int ( ICE_wfxsnw_pre    ) 
     767    ICE_wfxsnw_sub = rprec (d_ICE_his['vfxsub'])/nemo.RDAY*ICE_RHO_SNO  ; ICE_mas_wfxsnw_sub = OCE_flux_int ( ICE_wfxsnw_sub ) 
     768    ICE_wfxsnw_pre = rprec (d_ICE_his['vfxspr'])/nemo.RDAY*ICE_RHO_SNO  ; ICE_mas_wfxsnw_pre = OCE_flux_int ( ICE_wfxsnw_pre ) 
    729769 
    730770OCE_wfcorr    = rprec (d_OCE_his['wfcorr']) ; OCE_mas_wfcorr  = OCE_flux_int ( OCE_wfcorr ) 
     
    733773    OCE_vflx_fwb = rprec (d_OCE_his['vflx_fwb']) ; OCE_mas_vflx_fwb   = OCE_flux_int ( OCE_vflx_fwb ) 
    734774    OCE_vflx_ssr = rprec (d_OCE_his['vflx_ssr']) ; OCE_mas_vflx_ssr   = OCE_flux_int ( OCE_vflx_ssr ) 
    735 else :  
     775else : 
    736776    OCE_fwb = 0.0 ; OCE_mas_fwb = 0.0 
    737777    OCE_ssr = 0.0 ; OCE_mas_ssr = 0.0 
     
    746786OCE_mas_all = OCE_mas_emp_oce + OCE_mas_emp_ice - OCE_mas_runoffs - OCE_mas_iceshelf 
    747787 
    748 echo ('\n-- Fields:' )  
     788echo ('\n-- Fields:' ) 
    749789prtFlux ('OCE+ICE budget ', OCE_mas_all       , 'e', True) 
    750790prtFlux ('  EMPMR        ', OCE_mas_empmr     , 'e', True) 
     
    756796prtFlux ('  ICESHELF     ', OCE_mas_iceshelf  , 'e', True) 
    757797prtFlux ('  CALVING      ', OCE_mas_calving   , 'e', True) 
    758 prtFlux ('  FRIVER       ', OCE_mas_friver    , 'e', True)   
     798prtFlux ('  FRIVER       ', OCE_mas_friver    , 'e', True) 
    759799prtFlux ('  RUNOFFS      ', OCE_mas_runoffs   , 'e', True) 
    760800prtFlux ('  WFXICE       ', OCE_mas_wfxice    , 'e', True) 
     
    783823 
    784824 
    785 echo     ('\n===>  Comparing ===>' )  
     825echo     ('\n===>  Comparing ===>' ) 
    786826echo     ('  WFX OCE                     = -empmr + iceshelf                                            = {:12.5e} (kg) '.format ( -OCE_mas_empmr + OCE_mas_iceshelf) ) 
    787827echo     ('     versus d OCE                                                                            = {:12.5e} (kg) '.format ( dOCE_mas_wat) ) 
    788828echo     ('  WFX ICE+SNW+PND 1           = emp_ice - wfxice - wfxsnw - wfxpnd - wfxsub_err              = {:12.5e} (kg) '.format ( -OCE_mas_emp_ice - OCE_mas_wfxice - OCE_mas_wfxsnw - ICE_mas_wfxpnd - ICE_mas_wfxsub_err) ) 
    789 echo     ('  WFX ICE+SNW+PND 2           = -emp_ice + empmr - emp_oce + runoffs                         = {:12.5e} (kg) '.format ( -OCE_mas_emp_ice + OCE_mas_empmr - OCE_mas_emp_oce + OCE_mas_runoffs ))  
     829echo     ('  WFX ICE+SNW+PND 2           = -emp_ice + empmr - emp_oce + runoffs                         = {:12.5e} (kg) '.format ( -OCE_mas_emp_ice + OCE_mas_empmr - OCE_mas_emp_oce + OCE_mas_runoffs )) 
    790830echo     ('     versus d ICE+SNW+PND                                                                    = {:12.5e} (kg) '.format ( dICE_mas_wat))  # Manque PND ? 
    791 if Coupled :  
     831if Coupled : 
    792832    echo ('  WFX OCE+ICE+SNW+PND         = -emp_oce - emp_ice + runoffs + iceshelf                      = {:12.5e} (kg) '.format ( -OCE_mas_emp_oce - OCE_mas_emp_ice + OCE_mas_runoffs + OCE_mas_iceshelf)) 
    793833else : 
     
    796836 
    797837echo ('\n===> Leaks ===>') 
    798 echo ('   Leak OCE             = dOCE_mas_wat + empmr - iceshelf                                                 = {:12.3e} (kg) '.format ( dOCE_mas_wat + OCE_mas_empmr - OCE_mas_iceshelf) )  
     838echo ('   Leak OCE             = dOCE_mas_wat + empmr - iceshelf                                                 = {:12.3e} (kg) '.format ( dOCE_mas_wat + OCE_mas_empmr - OCE_mas_iceshelf) ) 
    799839echo ('                        = (dOCE_mas_wat + empmr - iceshelf)/abs(dOCE_mas_wat)                             = {:12.1e} (-)  '.format ( (dOCE_mas_wat + OCE_mas_empmr - OCE_mas_iceshelf )  / abs (dOCE_mas_wat)  ) ) 
    800840echo ('   Leak ICE+SNW+PND 1   = dICE_mas_wat + emp_ice + wfxice + wfxsnw + wfxpnd + wfxsub_err                  = {:12.3e} (kg) '.format ( dICE_mas_wat + OCE_mas_emp_ice + OCE_mas_wfxice + OCE_mas_wfxsnw + ICE_mas_wfxpnd + ICE_mas_wfxsub_err ) ) 
     
    817857echo     ('\n===> Checks ===>' ) 
    818858echo     ('   Check EMPMR           = empmr - emp_oce + runoffs + wfxice + wfxsnw + wfxpnd + wfxsub_err = {:12.5e} (kg) '.format ( OCE_mas_empmr - OCE_mas_emp_oce + OCE_mas_runoffs + OCE_mas_wfxice + OCE_mas_wfxsnw + ICE_mas_wfxpnd + ICE_mas_wfxsub_err )) 
    819 if Coupled :  
     859if Coupled : 
    820860    echo ('   Check EMP_OCE         = emp_oce + fwb + ssr - evap_oce + rain + snow_oce + calving        = {:12.5e} (kg) '.format ( OCE_mas_emp_oce + OCE_mas_fwb + OCE_mas_ssr - OCE_mas_evap_oce + OCE_mas_rain + OCE_mas_snow_oce + OCE_mas_calving )) 
    821861else : 
     
    836876echo ( 'Freshwater flux at the interface ocean-atm         = emp_oce + calving - vfxsub_err                                  = {:12.5e} (kg) '.format ( OCE_mas_emp_oce + OCE_mas_calving - ICE_mas_wfxsub_err )) 
    837877 
    838 echo ( "scsshtot   : global_average_sea_level_change                            = {:12.3e} (m) ".format ( np.sum (d_OCE_sca['scsshtot']  ).values  ) ) 
    839 echo ( "scsshtot   : global_average_sea_level_change                            = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['scsshtot']  ).values * OCE_aire_tot*OCE_rho_liq  ) ) 
    840 echo ( "bgvolssh   : drift in global mean ssh volume wrt timestep 1             = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['bgvolssh']  ).values * 1e9 * OCE_rho_liq  ) ) 
    841 echo ( "bgvole3t   : drift in global mean volume variation (e3t) wrt timestep 1 = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['bgvole3t']  ).values * 1e9 * OCE_rho_liq  ) ) 
    842 echo ( "bgfrcvol   : global mean volume from forcing                            = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['bgfrcvol']  ).values * 1e9 * OCE_rho_liq  ) ) 
    843 echo ( "ibgvol_tot : global mean ice volume                                     = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['ibgvol_tot']).values * 1e9 * OCE_rho_liq  ) ) 
    844 echo ( "sbgvol_tot : global mean snow volume                                    = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['sbgvol_tot']).values * 1e9 * OCE_rho_liq  ) ) 
    845 echo ( "ibgvolume  : drift in ice/snow volume (equivalent ocean volume)         = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['ibgvolume'] ).values * 1e9 * OCE_rho_liq  ) ) 
    846  
     878echo ( "scsshtot   : global_average_sea_level_change                            = {:12.3e} (m) ".format ( np.sum (d_OCE_sca['scsshtot']  )  ) ) 
     879echo ( "scsshtot   : global_average_sea_level_change                            = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['scsshtot']  ) * OCE_aire_tot*OCE_RHO_LIQ  ) ) 
     880echo ( "bgvolssh   : drift in global mean ssh volume wrt timestep 1             = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['bgvolssh']  ) * 1e9 * OCE_RHO_LIQ  ) ) 
     881echo ( "bgvole3t   : drift in global mean volume variation (e3t) wrt timestep 1 = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['bgvole3t']  ) * 1e9 * OCE_RHO_LIQ  ) ) 
     882echo ( "bgfrcvol   : global mean volume from forcing                            = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['bgfrcvol']  ) * 1e9 * OCE_RHO_LIQ  ) ) 
     883echo ( "ibgvol_tot : global mean ice volume                                     = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['ibgvol_tot']) * 1e9 * OCE_RHO_LIQ  ) ) 
     884echo ( "sbgvol_tot : global mean snow volume                                    = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['sbgvol_tot']) * 1e9 * OCE_RHO_LIQ  ) ) 
     885echo ( "ibgvolume  : drift in ice/snow volume (equivalent ocean volume)         = {:12.3e} (kg)".format ( np.sum (d_OCE_sca['ibgvolume'] ) * 1e9 * OCE_RHO_LIQ  ) ) 
     886 
     887echo ( ' ' ) 
     888echo ( f'{Title = }' ) 
     889 
     890echo ( 'SVN Information' ) 
     891for kk in SVN.keys(): 
     892    print ( SVN[kk] ) 
  • TOOLS/WATER_BUDGET/WaterUtils.py

    r6647 r6665  
    22''' 
    33  Script to check water conservation in the IPSL coupled model 
    4   
     4 
    55  Here, some common utilities to all scripts 
    6     
     6 
    77  Warning, to install, configure, run, use any of included software or 
    88  to read the associated documentation you'll need at least one (1) 
     
    1818 $Date$ 
    1919 $Revision$ 
    20  $Id: ATM_waterbudget.py 6277 2022-12-08 09:24:05Z omamce $ 
     20 $Id: $ 
    2121 $HeadURL$ 
    2222''' 
    2323 
     24import functools 
     25import time 
     26import configparser, re 
    2427import numpy as np 
    25 import configparser, re 
    26  
    27 VarInt      = 10 
    28 Rho         = 1000.0 
    29 Ra          = 6366197.7236758135 #-- Earth Radius (m) 
    30 Grav        = 9.81               #-- Gravity (m^2/s 
    31 ICE_rho_ice = 917.0              #-- Ice volumic mass (kg/m3) in LIM3 
    32 ICE_rho_sno = 330.0              #-- Snow volumic mass (kg/m3) in LIM3 
    33 OCE_rho_liq = 1026.0             #-- Ocean water volumic mass (kg/m3) in NEMO 
    34 ATM_rho     = 1000.0             #-- Water volumic mass in atmosphere (kg/m^3) 
    35 SRF_rho     = 1000.0             #-- Water volumic mass in surface reservoir (kg/m^3) 
    36 RUN_rho     = 1000.0             #-- Water volumic mass of rivers (kg/m^3) 
    37 ICE_rho_pnd = 1000.              #-- Water volumic mass in ice ponds (kg/m^3) 
    38 YearLength  = 365.25 * 24. * 60. * 60. #-- Year length (s) 
     28 
     29VAR_INT     = 10 
     30RHO         = 1000.0 
     31RA          = 6366197.7236758135 #-- Earth Radius (m) 
     32GRAV        = 9.81               #-- Gravity (m^2/s 
     33ICE_RHO_ICE = 917.0              #-- Ice volumic mass (kg/m3) in LIM3 
     34ICE_RHO_SNO = 330.0              #-- Snow volumic mass (kg/m3) in LIM3 
     35OCE_RHO_LIQ = 1026.0             #-- Ocean water volumic mass (kg/m3) in NEMO 
     36ATM_RHO     = 1000.0             #-- Water volumic mass in atmosphere (kg/m^3) 
     37SRF_RHO     = 1000.0             #-- Water volumic mass in surface reservoir (kg/m^3) 
     38RUN_RHO     = 1000.0             #-- Water volumic mass of rivers (kg/m^3) 
     39ICE_RHO_PND = 1000.              #-- Water volumic mass in ice ponds (kg/m^3) 
     40YEAR_LENGTH = 365.25 * 24. * 60. * 60. #-- Year length (s) 
    3941 
    4042def setBool (chars) : 
    4143    '''Convert specific char string in boolean if possible''' 
    42     setBool = chars 
    43     if type (chars) == str : 
     44    z_set_bool = chars 
     45    if isinstance (chars, str) : 
    4446        for key in configparser.ConfigParser.BOOLEAN_STATES.keys () : 
    45             if chars.lower() == key : setBool = configparser.ConfigParser.BOOLEAN_STATES[key] 
    46     return setBool 
     47            if chars.lower() == key : 
     48                z_set_bool = configparser.ConfigParser.BOOLEAN_STATES[key] 
     49    return z_set_bool 
    4750 
    4851def setNum (chars) : 
    4952    '''Convert specific char string in integer or real if possible''' 
    50     if type (chars) == str : 
    51         realnum  = re.compile ("^[-+]?[0-9]*\.?[0-9]+(e[-+]?[0-9]+)?$") 
    52         isNumber = realnum.match(chars.strip()) != None 
    53         isInt    = chars.strip().isdigit() 
    54         #print (chars , isNumber , isInt) 
    55         if isNumber : 
    56             if isInt : setNum = int  (chars) 
    57             else     : setNum = float (chars) 
    58         else : setNum = chars 
    59     else : setNum = chars 
    60     return setNum 
     53    if isinstance (chars, str) : 
     54        realnum   = re.compile ("^[-+]?[0-9]*\.?[0-9]+(e[-+]?[0-9]+)?$") 
     55        is_number = realnum.match(chars.strip()) != None 
     56        is_int    = chars.strip().isdigit() 
     57        if is_number : 
     58            if is_int : zset_num = int   (chars) 
     59            else      : zset_num = float (chars) 
     60        else : zset_num = chars 
     61    else : 
     62        zset_num = chars 
     63    return zset_num 
    6164 
    6265def setNone (chars) : 
    6366    '''Convert specific char string to None if possible''' 
    64     if type (chars) == str : 
    65         if chars in ['None', 'NONE', 'none'] : setNone = None 
    66         else : setNone = chars 
    67     else : setNone = chars 
    68     return setNone 
     67    if isinstance (chars, str) : 
     68        if chars in ['None', 'NONE', 'none'] : zset_none = None 
     69        else : zset_none = chars 
     70    else : zset_none = chars 
     71    return zset_none 
    6972 
    7073def unDefined (char) : 
    7174    '''True if a variable is not defined, or set to None''' 
    7275    if char in globals () : 
    73         if globals()[char] == None : 
    74                 unDefined = True 
    75         else            : unDefined = False 
    76     else                : unDefined = True 
    77     return unDefined 
     76        if globals()[char] is None : 
     77            zun_defined = True 
     78        else : zun_defined = False 
     79    else :     zun_defined = True 
     80    return zun_defined 
    7881 
    7982def Defined (char) : 
    8083    '''True if a variable is defined and not equal to None''' 
    8184    if char in globals () : 
    82         if globals()[char] == None : 
    83                 Defined = False 
    84         else            : Defined = True 
    85     else                : Defined = False 
    86     return Defined 
     85        if globals()[char] is None : 
     86            zdefined = False 
     87        else            : zdefined = True 
     88    else                : zdefined = False 
     89    return zdefined 
    8790 
    8891def Ksum (tab) : 
    89     ''' 
    90     Kahan summation algorithm, also known as compensated summation 
     92    '''Kahan summation algorithm, also known as compensated summation 
     93 
    9194    https://en.wikipedia.org/wiki/Kahan_summation_algorithm 
    9295    ''' 
    93     Ksum = 0.0                   # Prepare the accumulator. 
    94     comp = 0.0                   # A running compensation for lost low-order bits. 
    95     
    96     for xx in np.where ( np.isnan(tab), 0., tab ) :  
    97         yy = xx - comp           # comp is zero the first time around. 
    98         tt = Ksum + yy           # Alas, sum is big, y small, so low-order digits of y are lost. 
    99         comp = (tt - Ksum) - yy  # (tt - Ksum) cancels the high-order part of y; subtracting y recovers negative (low part of yy) 
    100         Ksum = tt                # Algebraically, comp should always be zero. Beware overly-aggressive optimizing compilers ! 
    101                                  # Next time around, the lost low part will be added to y in a fresh attempt. 
    102     return Ksum 
     96    # Prepare the accumulator. 
     97    ksum = 0.0 
     98    # A running compensation for lost low-order bits. 
     99    comp = 0.0 
     100 
     101    for xx in np.where ( np.isnan(tab), 0., tab ) : 
     102        # comp is zero the first time around. 
     103        yy = xx - comp 
     104        # Alas, sum is big, y small, so low-order digits of y are lost. 
     105        tt = ksum + yy 
     106        # (tt - Ksum) cancels the high-order part of y; subtracting y recovers negative (low part of yy) 
     107        comp = (tt - ksum) - yy 
     108        # Algebraically, comp should always be zero. Beware overly-aggressive optimizing compilers ! 
     109        ksum = tt 
     110        # Next time around, the lost low part will be added to y in a fresh attempt. 
     111 
     112    return ksum 
    103113 
    104114def Ssum (tab) : 
    105     ''' 
    106     Precision summation by sorting by absolute values 
    107     ''' 
    108     Ssum = np.sum ( tab[np.argsort(np.abs(tab))] ) 
    109     return Ssum 
     115    '''Precision summation by sorting by absolute values''' 
     116    ssum = np.sum ( tab[np.argsort(np.abs(tab))] ) 
     117    return ssum 
    110118 
    111119def KSsum (tab) : 
    112     ''' 
    113     Precision summation by sorting by absolute value, and applying Kahan summation 
    114     ''' 
    115     KSsum = Ksum ( tab[np.argsort(np.abs(tab))] ) 
    116     return KSsum 
     120    '''Precision summation by sorting by absolute value, and applying Kahan summation''' 
     121    kssum = Ksum ( tab[np.argsort(np.abs(tab))] ) 
     122    return kssum 
    117123 
    118124# Choosing algorithm for precise summation 
    119125Psum = KSsum 
    120126 
    121 def IsLeapYear ( Year, CalendarType="Gregorian" ) : 
    122     ''' True is Year is a leap year '''  
     127def IsLeapYear ( year, CalendarType="Gregorian" ) : 
     128    '''True is Year is a leap year''' 
     129    year = int ( year ) 
     130    zis_leap_year = None 
    123131 
    124132    # What is the calendar : 
    125     if CalendarType in [ '360d', '360_day', 'noleap', '365_day'] :  
    126         IsLeapYear = False 
    127         return IsLeapYear 
    128  
    129     if CalendarType in [ 'all_leap', '366_day' ] :  
    130         IsLeapYear = True 
    131         return IsLeapYear 
    132      
    133     Year = int ( Year ) 
    134    
     133    if CalendarType in [ '360d', '360_day', 'noleap', '365_day'] : 
     134        zis_leap_year = False 
     135 
     136    if CalendarType in [ 'all_leap', '366_day' ] : 
     137        zis_leap_year = True 
     138 
    135139    # a year is a leap year if it is even divisible by 4 
    136140    # but not evenly divisible by 100 
     
    138142 
    139143    # if it is evenly divisible by 400 it must be a leap year 
    140     if np.mod ( Year, 400 ) == 0 :  
    141         IsLeapYear = True 
    142         return IsLeapYear 
    143          
     144    if not zis_leap_year and np.mod ( year, 400 ) == 0 : 
     145        zis_leap_year = True 
     146 
    144147    # if it is evenly divisible by 100 it must not be a leap year 
    145     if np.mod ( Year, 100 ) == 0 : 
    146         IsLeapYear = False 
    147         return IsLeapYear 
     148    if not zis_leap_year and np.mod ( year, 100 ) == 0 : 
     149        zis_leap_year = False 
    148150 
    149151    # if it is evenly divisible by 4 it must be a leap year 
    150     if np.mod ( Year, 4 ) == 0 : 
    151         IsLeapYear = True 
    152         return IsLeapYear 
    153  
    154     IsLeapYear = False 
    155     return IsLeapYear 
    156  
    157 def DateFormat ( Date ) : 
    158     ''' 
    159     Get date format : 
     152    if not zis_leap_year and np.mod ( year, 4 ) == 0 : 
     153        zis_leap_year = True 
     154 
     155    if not zis_leap_year : 
     156        zis_leap_year = False 
     157 
     158    return zis_leap_year 
     159 
     160def DateFormat ( date ) : 
     161    '''Get date format : 
     162 
    160163      [yy]yymmdd   is Gregorian 
    161164      [yy]yy-mm-dd is Human 
    162165    ''' 
    163     if type (Date) == str : 
    164         if '-' in Date :  
    165             DateFormat = 'Human' 
    166         else :  
    167             DateFormat = 'Gregorian' 
    168     if type (Date) == int : DateFormat = 'Gregorian' 
    169     return DateFormat 
    170  
    171 def PrintDate ( YE, MO, DA, Format ) : 
    172     '''Return a date in the requested format''' 
    173     if Format == 'Human'     : PrintDate = f'{YE:04d}-{MO:02d}-{DA:02d}' 
    174     if Format == 'Gregorian' : PrintDate = f'{YE:04d}{MO:02d}{DA:02d}' 
    175     return PrintDate 
    176          
    177 def FormatToGregorian ( Date ) : 
    178     ''' from a yyyy-mm-dd or yyymmdd date format returns 
     166    if isinstance (date, str) : 
     167        if '-' in date : 
     168            zdate_format = 'Human' 
     169        else : 
     170            zdate_format = 'Gregorian' 
     171    if isinstance (date, int) : zdate_format = 'Gregorian' 
     172    return zdate_format 
     173 
     174def PrintDate ( ye, mo, da, pformat ) : 
     175    '''Return a date in the requested format 
     176    ''' 
     177    if pformat == 'Human'     : zPrintDate = f'{ye:04d}-{mo:02d}-{da:02d}' 
     178    if pformat == 'Gregorian' : zPrintDate = f'{ye:04d}{mo:02d}{da:02d}' 
     179    return zPrintDate 
     180 
     181def FormatToGregorian ( date ) : 
     182    '''From a yyyy-mm-dd or yyymmdd date format returns 
    179183        a yyymmdd date format 
    180184    ''' 
    181     YE, MO, DA = SplitDate ( Date ) 
    182     FormatToGregorian = f'{YE:04d}{MO:02d}{DA:02d}' 
    183     return FormatToGregorian 
    184    
    185 def FormatToHuman ( Date ) : 
    186     ''' From a yyyymmdd or yyymmdd date format returns 
     185    ye, mo, da = SplitDate ( date ) 
     186    return f'{ye:04d}{mo:02d}{da:02d}' 
     187 
     188def FormatToHuman ( date ) : 
     189    '''From a yyyymmdd or yyymmdd date format returns 
    187190        a yyy-mm-dd date format 
    188191    ''' 
    189     YE, MO, DA = SplitDate ( Date ) 
    190     FormatToHuman =  f'{YE_new:04d}-{MO:02d}-{DA:02d}' 
    191     return FormatToHuman 
    192  
    193 def SplitDate  ( Date, Out='int' ) : 
    194     ''' Split Date in format [yy]yymmdd or [yy]yy-mm-dd 
    195         to yy, mm, dd ''' 
    196     if type (Date) == str : 
    197         if '-' in Date :  
    198             Dash = True 
    199             YE, MO, DA = Date.split ('-') 
    200         else :  
    201             Dash = False 
    202             YE = Date[:-4] ; MO = Date[-4:-2] ; DA = Date[-2:] 
    203             YearDigits = len (YE) 
    204     if type (Date) == int : 
    205         DA = np.mod ( Date, 100)  
    206         MO = np.mod ( Date//100, 100) 
    207         YE = Date // 10000 
     192    ye, mo, da = SplitDate ( date ) 
     193    return f'{ye:04d}-{mo:02d}-{da:02d}' 
     194 
     195def SplitDate  ( date ) : 
     196    '''Split Date in format [yy]yymmdd or [yy]yy-mm-dd 
     197       to yy, mm, dd ''' 
     198    if isinstance (date, str) : 
     199        if '-' in date : 
     200            ye, mo, da = date.split ('-') 
     201        else : 
     202            ye, mo, da = date[:-4], date[-4:-2], date[-2:] 
     203    if isinstance (date, int) : 
     204        da = np.mod ( date, 100) 
     205        mo = np.mod ( date//100, 100) 
     206        ye = date // 10000 
     207 
     208    ye = int(ye) ; mo = int(mo) ; da=int(da) 
     209    return ye, mo, da 
     210 
     211def DateAddYear ( date, year_inc=1 ) : 
     212    '''Add on year(s) to date in format [yy]yymmdd or [yy]yy-mm-dd''' 
     213    zformat = DateFormat ( date ) 
     214    ye, mo, da = SplitDate ( date ) 
     215    ye_new = ye + year_inc 
     216    return PrintDate ( ye_new, mo, da, zformat) 
     217 
     218def DateMinusOneDay ( date ) : 
     219    '''Substracts one day to date in format [yy]yymmdd or [yy]yy-mm-dd''' 
     220    zformat = DateFormat ( date ) 
     221    mth_length = np.array ( [31, 28, 31,  30,  31,  30,  31,  31,  30,  31,  30,  31] ) 
     222    ye, mo, da = SplitDate ( date ) 
     223    if IsLeapYear ( ye) : mth_length[1] += 1 
     224 
     225    ye = int(ye) ; mo = int(mo) ; da=int(da) 
     226    if da ==  1 : 
     227        if mo == 1 : 
     228            da_new, mo_new, ye_new = mth_length[-1  ], 12    , ye - 1 
     229        else       : 
     230            da_new, mo_new, ye_new = mth_length[mo-2], mo - 1, ye 
     231    else : 
     232        da_new, mo_new, ye_new = da - 1, mo, ye 
     233 
     234    return PrintDate ( ye_new, mo_new, da_new, zformat) 
     235 
     236def DatePlusOneDay ( date ) : 
     237    '''Add one day to date in format [yy]yymmdd or [yy]yy-mm-dd''' 
     238    zformat = DateFormat ( date ) 
     239    mth_length = np.array ( [31, 28, 31,  30,  31,  30,  31,  31,  30,  31,  30,  31] ) 
     240    ye, mo, da = SplitDate ( date ) 
     241    if IsLeapYear ( ye ) : mth_length[1] += 1 
     242 
     243    ye_new = ye 
     244    mo_new = mo 
     245    da_new = da+1 
     246    if da_new > mth_length [mo_new-1] : 
     247        da_new = 1 
     248        mo_new = mo_new + 1 
     249        if mo_new == 13 : 
     250            mo_new =  1 
     251            ye_new += 1 
     252 
     253    return PrintDate ( ye_new, mo_new, da_new, zformat ) 
     254 
     255class Timer : 
     256    '''Measures execution time of a function''' 
     257    def __str__(self): 
     258        return str(self.__class__) 
    208259     
    209     YE = int(YE) ; MO = int(MO) ; DA=int(DA) 
    210     return YE, MO, DA 
    211  
    212 def DateAddYear ( Date, YearInc=1 ) : 
    213     ''' Add on year to date in format [yy]yymmdd or [yy]yy-mm-dd''' 
    214     Format = DateFormat ( Date ) 
    215     YE, MO, DA = SplitDate ( Date ) 
    216     YE_new = YE + YearInc 
    217     DateAddYear = PrintDate ( YE_new, MO, DA, Format) 
    218     return DateAddYear  
    219  
    220 def DateMinusOneDay ( Date ) : 
    221     ''' Substracts one day to date in format [yy]yymmdd or [yy]yy-mm-dd''' 
    222     Format = DateFormat ( Date ) 
    223     mth_length = np.array ( [31, 28, 31,  30,  31,  30,  31,  31,  30,  31,  30,  31] ) 
    224     YE, MO, DA = SplitDate ( Date ) 
    225     if IsLeapYear ( YE) : mth_length[1] += 1 
     260    def __name__(self): 
     261        return self.__class__.__name__ 
     262 
     263    def __init__ (self, func, debug=False, timer=True) : 
     264        functools.update_wrapper (self, func) 
     265        self.func       = func 
     266        self.num_calls  = 0 
     267        self.cumul_time = 0. 
     268        self.debug      = debug 
     269        self.timer      = timer 
     270 
     271    def __call__ (self, *args, **kwargs) : 
     272        self.num_calls += 1 
     273        if self.debug : 
     274            print ( f'>-- Calling {self.__name__} --------------------------------------------------' ) 
     275            args_repr   = [f"{repr (a)}" for a in args] 
     276            kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items ()] 
     277            signature   = ", ".join (args_repr + kwargs_repr) 
     278            print ( f"Signature : ({signature}") 
     279        start_time = time.perf_counter ()      
     280        values     = self.func (*args, **kwargs) 
     281        end_time   = time.perf_counter () 
     282        run_time   = end_time - start_time 
     283        self.cumul_time += run_time 
     284        if self.timer :  
     285            print ( f"--> Calling {self.__name__!r} : {run_time:.3f} secs / cumul {self.cumul_time:.3f} # {self.num_calls:2d} calls") 
     286        if self.debug : 
     287            print ( '<------------------------------------------------------------' ) 
     288        return values 
    226289     
    227     YE = int(YE) ; MO = int(MO) ; DA=int(DA) 
    228     if DA ==  1 :  
    229         if MO == 1 : DA_new = mth_length[-1]   ; MO_new = 12     ; YE_new = YE - 1 
    230         else       : DA_new = mth_length[MO-2] ; MO_new = MO - 1 ; YE_new = YE 
    231     else        :    DA_new = DA - 1           ; MO_new = MO     ; YE_new = YE 
    232  
    233     DateMinusOneDay = PrintDate ( YE_new, MO_new, DA_new, Format) 
    234     return DateMinusOneDay 
    235  
    236 def DatePlusOneDay ( Date ) : 
    237     ''' Add one day to date in format [yy]yymmdd or [yy]yy-mm-dd''' 
    238     Format = DateFormat ( Date ) 
    239     mth_length = np.array ( [31, 28, 31,  30,  31,  30,  31,  31,  30,  31,  30,  31] ) 
    240     YE, MO, DA = SplitDate ( Date ) 
    241     if IsLeapYear ( YE ) : mth_length[1] += 1 
    242      
    243     YE_new = YE ; MO_new=MO ; DA_new=DA+1 
    244     if DA_new > mth_length [MO_new-1] : 
    245         DA_new = 1 ; MO_new = MO_new + 1 
    246         if MO_new == 13 :  
    247             MO_new = 1 ; YE_new = YE_new+1 
    248  
    249     DatePlusOneDay = PrintDate ( YE_new, MO_new, DA_new, Format ) 
    250     return DatePlusOneDay 
  • TOOLS/WATER_BUDGET/lmdz.py

    r6647 r6665  
    2121Utilities for LMDZ grid 
    2222 
    23 olivier.marti@lsce.ipsl.fr 
    24 ''' 
     23- Lots of tests for xarray object 
     24- Not much tested for numpy objects 
     25 
     26Author: olivier.marti@lsce.ipsl.fr 
    2527 
    2628## SVN information 
     
    3032__Id__       = "$Id: $" 
    3133__HeadURL    = "$HeadURL$" 
     34''' 
    3235 
    3336import numpy as np 
    34  
    35 try    : import xarray as xr 
    36 except ImportError : pass 
    37  
    38 try    : import numba 
    39 except ImportError : pass 
    40  
    41 rpi = np.pi ; rad = np.deg2rad (1.0) ; dar = np.rad2deg (1.0) 
    42  
    43  
    44 def __mmath__ (tab) : 
    45     ''' 
    46     Determines the type of tab : i.e. numpy or xarray 
    47     ''' 
    48     math = None 
    49     try :  
    50         if type (tab) == xr.core.dataarray.DataArray : math = xr 
    51     except : 
    52         pass 
    53  
    54     try : 
    55         if type (tab) == np.ndarray : math = np 
    56     except : 
    57         pass 
    58              
    59     return math 
     37import xarray as xr 
     38 
     39RPI   = np.pi 
     40RAD   = np.deg2rad (1.0) 
     41DAR   = np.rad2deg (1.0) 
     42REPSI = np.finfo (1.0).eps 
     43 
     44RAAMO    =      12          # Number of months in one year 
     45RJJHH    =      24          # Number of hours in one day 
     46RHHMM    =      60          # Number of minutes in one hour 
     47RMMSS    =      60          # Number of seconds in one minute 
     48RA       = 6371229.0        # Earth radius                                  [m] 
     49GRAV     =       9.80665    # Gravity                                       [m/s2] 
     50RT0      =     273.15       # Freezing point of fresh water                 [Kelvin] 
     51RAU0     =    1026.0        # Volumic mass of sea water                     [kg/m3] 
     52RLEVAP   =       2.5e+6     # Latent heat of evaporation (water)            [J/K] 
     53VKARMN   =       0.4        # Von Karman constant 
     54STEFAN   =       5.67e-8    # Stefan-Boltzmann constant                     [W/m2/K4] 
     55#RHOS     =     330.         # Volumic mass of snow                          [kg/m3] 
     56 
     57RDAY     = RJJHH * RHHMM * RMMSS                # Day length               [s] 
     58RSIYEA   = 365.25 * RDAY * 2. * RPI / 6.283076  # Sideral year length      [s] 
     59RSIDAY   = RDAY / (1. + RDAY / RSIYEA)          # Sideral day length       [s] 
     60ROMEGA   = 2. * RPI / RSIDAY                    # Earth rotation parameter [s-1] 
     61 
     62def __mmath__ (ptab, default=None) : 
     63    '''Determines the type of tab : xarray, numpy or numpy.ma object ? 
     64 
     65    Returns type 
     66    ''' 
     67    mmath = default 
     68    if isinstance (ptab, xr.core.dataarray.DataArray) : 
     69        mmath = xr 
     70    if isinstance (ptab, np.ndarray) : 
     71        mmath = np 
     72    if isinstance (ptab, np.ma.MaskType) : 
     73        mmath = np.ma 
     74 
     75    return mmath 
     76 
    6077# 
    6178def extend (tab, Lon=False, jplus=25, jpi=None, lonplus=360.0) : 
    62     ''' 
    63     Returns extended field eastward to have better plots, and box average crossing the boundary 
     79    '''Returns extended field eastward to have better plots, and box average crossing the boundary 
     80 
    6481    Works only for xarray and numpy data (?) 
    6582 
     
    6986        size of the field != jpi (avoid to extend several times) 
    7087    jplus (optional, default=25) : number of points added on the east side of the field 
     88    ''' 
    7189     
    72     ''' 
    7390    math = __mmath__ (tab) 
    74     if tab.shape[-1] == 1 : extend = tab 
    75  
    76     else : 
    77         if jpi == None : jpi = tab.shape[-1] 
    78  
    79         if Lon : xplus =  lonplus 
    80         else   : xplus =    0.0 
     91    if tab.shape[-1] == 1 : 
     92        ztab = tab 
     93 
     94    else : 
     95        if jpi is None : 
     96            jpi = tab.shape[-1] 
     97 
     98        if Lon : 
     99            xplus =  lonplus 
     100        else   : 
     101            xplus =    0.0 
    81102 
    82103        if tab.shape[-1] > jpi : 
    83             extend = tab 
     104            ztab = tab 
    84105        else : 
    85             istart = 0 ; le=jpi+1 ; la=0 
     106            istart = 0 
     107            le     = jpi+1 
     108            la     = 0 
    86109            if math == xr : 
    87110                lon = tab.dims[-1] 
    88                 extend         = xr.concat      ((tab.isel(lon=slice(istart   ,istart+le      )), 
    89                                                   tab.isel(lon=slice(istart+la,istart+la+jplus))+xplus  ), dim=lon) 
    90                 try : 
    91                     extend_lon = xr.concat      ((tab.coords[lon].isel(lon=slice(istart   ,istart+le      )), 
    92                                                   tab.coords[lon].isel(lon=slice(istart+la,istart+la+jplus))+lonplus), dim=lon) 
    93                     extend = extend.assign_coords ( {tab.dims[-1]:extend_lon} )    
    94                 except : 
    95                     pass 
     111                ztab         = xr.concat      (( 
     112                    tab.isel (lon=slice(istart   ,istart+le      )), 
     113                    tab.isel (lon=slice(istart+la,istart+la+jplus))+xplus  ), dim=lon) 
     114                if 'lon' in tab.dims : 
     115                    extend_lon = xr.concat      (( 
     116                        tab.coords[lon].isel(lon=slice(istart   ,istart+le      )), 
     117                        tab.coords[lon].isel(lon=slice(istart+la,istart+la+jplus))+lonplus), dim=lon) 
     118                    ztab = ztab.assign_coords ( {tab.dims[-1]:extend_lon} ) 
     119                #except : 
     120                #    pass 
    96121            if math == np : 
    97                 extend = np.concatenate ((tab    [..., istart:istart+le], tab    [..., istart+la:jplus]+xplus  ), axis=-1) 
    98                  
    99     return extend 
     122                ztab = np.concatenate ((tab    [..., istart:istart+le], 
     123                                        tab    [..., istart+la:jplus]+xplus  ), axis=-1) 
     124 
     125    return ztab 
    100126 
    101127def interp1d (x, xp, yp, zdim='presnivs', units=None, verbose=False, method='linear') : 
    102     ''' 
    103     One-dimensionnal interpolation of a multi-dimensionnal field 
     128    '''One-dimensionnal interpolation of a multi-dimensionnal field 
    104129 
    105130    Intended to interpolate on standard pressure level 
    106      
     131 
    107132    All inputs shoud be xarray data arrays 
    108133 
    109     Input :  
     134    Input : 
    110135       x      : levels at wich we want to interpolate (i.e. standard pressure levels) 
    111136       xp     : position of the input points (i.e. pressure) 
     
    117142           nearest : nearest neighbor 
    118143 
    119        \!/ xp should be decreasing values along zdim axis \!/ 
     144           Warning : xp should be decreasing values along zdim axis 
    120145    ''' 
    121146    # Get the number of dimension with dim==zdim 
    122147    axis = list(xp.dims).index(zdim) 
    123      
     148 
    124149    # Get the number of levels in each arrays 
    125     nk_in = xp.shape[axis] 
    126150    nk_ou = len (x) 
    127      
     151 
    128152    # Define the result array 
    129153    in_shape       = np.array (xp.shape) 
    130     if verbose : print ( f'{in_shape=}' ) 
     154    if verbose : 
     155        print ( f'{in_shape=}' ) 
    131156    ou_shape       = np.array (in_shape) 
    132     if verbose : print ( f'{ou_shape=}' ) 
     157    if verbose : 
     158        print ( f'{ou_shape=}' ) 
    133159    ou_shape[axis] = nk_ou 
    134      
     160 
    135161    in_dims        = list (yp.dims) 
    136     if verbose : print ( f'{in_dims=}' ) 
     162    if verbose : 
     163        print ( f'{in_dims=}' ) 
    137164    ou_dims        = in_dims 
    138    
     165 
    139166    pdim           = x.dims[0] 
    140167    ou_dims[axis]  = pdim 
     
    144171        if dim == zdim : 
    145172            ou_dims[i] = x.dims[0] 
    146             if units != None : yp[dim].attrs['units'] = units 
     173            if units is not None : 
     174                yp[dim].attrs['units'] = units 
    147175            new_coords.append (x             .values) 
    148176        else : 
    149177            new_coords.append (yp.coords[dim].values) 
    150     
     178 
    151179    if verbose : 
    152180        print ( f'{ou_dims   =}'     ) 
    153181        print ( f'{new_coords=}' ) 
    154          
     182 
    155183    ou_tab = xr.DataArray (np.empty (ou_shape), dims=ou_dims, coords=new_coords) 
    156184 
    157185    if 'log' in method : 
    158         yp_min = yp.min() ; yp_max = yp.max() 
    159         indic = yp_min * yp_max 
     186        yp_min = yp.min() 
     187        yp_max = yp.max() 
     188        indic  = yp_min * yp_max 
    160189        if indic <= 0. : 
    161             print ('Input data have a change of sign') 
    162             print ('Error : logarithmic method is available only for') 
    163             print ('positive or negative input values. ') 
    164             raise Exception 
     190            print ( 'Input data have a change of sign') 
     191            print ( 'Error: logarithmic method is available only for') 
     192            print ( 'positive or negative input values. ') 
     193            raise ValueError 
    165194 
    166195    # Optimized (pre-compiled) interpolation loop 
    167196    #@numba.jit (nopython=True) 
    168     def __interp (nk_ou, x, xp, yp) : 
     197    def __interp (x, xp, yp) : 
    169198        # Interpolate 
    170199        # Find index of the just above level 
     
    172201        idk2 = idk1 - 1 
    173202        idk2 = np.maximum (idk2, 0) 
    174          
     203 
    175204        x1   = xp[{zdim:idk1}] 
    176205        x2   = xp[{zdim:idk2}] 
    177          
     206 
    178207        dx1  = x  - x1 
    179208        dx2  = x2 - x 
    180209        dx   = x2 - x1 
    181         dx1  = dx1/dx ; dx2 = dx2/dx 
    182          
     210        dx1  = dx1/dx 
     211        dx2  = dx2/dx 
     212 
    183213        y1   = yp[{zdim:idk1}] 
    184214        y2   = yp[{zdim:idk2}] 
    185          
    186         #print ( f'{k=} {idk1=} {idk2=} {x1=} {x2=} {dx=1} {dx2=} {y1=} {y2}' ) 
    187          
    188         if 'linear'  in method :  
    189             result = (dx1*y2 + dx2*y1) 
     215 
     216        if 'linear'  in method : 
     217            result = dx1*y2 + dx2*y1 
    190218        if 'log'     in method : 
    191             if yp_min > 0. :  
     219            if yp_min > 0. : 
    192220                result = np.power(y2, dx1) * np.power(y1, dx2) 
    193221            if yp_max < 0. : 
     
    195223        if 'nearest' in method : 
    196224            result = xr.where ( dx2>=dx1, y1, y2) 
    197                  
     225 
    198226        return result 
    199227 
    200228    for k in np.arange (nk_ou) : 
    201         result = __interp  (nk_ou, x[{pdim:k}], xp, yp) 
    202             
     229        result = __interp  (x[{pdim:k}], xp, yp) 
     230 
    203231        # Put result in the final array 
    204232        ou_tab [{pdim:k}] = result 
     
    207235 
    208236def fixed_lon (lon, center_lon=0.0) : 
    209     ''' 
    210     Returns corrected longitudes for nicer plots 
     237    '''Returns corrected longitudes for nicer plots 
    211238 
    212239    lon        : longitudes of the grid. At least 1D. 
     
    216243    ''' 
    217244    mmath = __mmath__ (lon) 
    218      
    219     fixed_lon = lon.copy () 
    220  
    221     fixed_lon = mmath.where (fixed_lon > center_lon+180., fixed_lon-360.0, fixed_lon) 
    222     fixed_lon = mmath.where (fixed_lon < center_lon-180., fixed_lon+360.0, fixed_lon) 
    223      
    224     start = np.argmax (np.abs (np.diff (fixed_lon, axis=-1)) > 180., axis=-1) 
    225     fixed_lon [start+1:] += 360. 
    226  
    227     return fixed_lon 
    228  
    229 def nord2sud (p2D) : 
    230     ''' 
    231     Swap north to south a 2D field 
    232     ''' 
    233     pout = p2D [..., -1::-1, : ] 
     245 
     246    zfixed_lon = lon.copy () 
     247 
     248    zfixed_lon = mmath.where (zfixed_lon > center_lon+180., zfixed_lon-360.0, fixed_lon) 
     249    zfixed_lon = mmath.where (zfixed_lon < center_lon-180., zfixed_lon+360.0, fixed_lon) 
     250 
     251    start = np.argmax (np.abs (np.diff (zfixed_lon, axis=-1)) > 180., axis=-1) 
     252    zfixed_lon [start+1:] += 360. 
     253 
     254    return zfixed_lon 
     255 
     256def nord2sud (p2d) : 
     257    '''Swap north to south a 2D field 
     258    ''' 
     259    pout = p2d [..., -1::-1, : ] 
    234260 
    235261    return pout 
    236262 
    237 def point2geo (p1D) : 
    238     ''' 
    239     From 1D (restart type) to 2D 
    240     ''' 
    241     math = __mmath__ (p1D) 
     263def point2geo (p1d) : 
     264    '''From 1D (restart type) to 2D 
     265    ''' 
     266    math = __mmath__ (p1d) 
    242267 
    243268    # Get the dimensions 
    244     jpn = p1D.shape[-1] 
    245      
    246     if len (p1D.shape) > 1 : 
    247         jpt = p1D.shape[0] 
     269    jpn = p1d.shape[-1] 
     270 
     271    if len (p1d.shape) > 1 : 
     272        jpt = p1d.shape[0] 
    248273    else : 
    249274        jpt = 0 
    250          
    251     if jpn ==  9026 : jpi =  96 ; jpj =  96 
    252     if jpn == 17858 : jpi = 144 ; jpj = 144 
    253     if jpn == 20306 : jpi = 144 ; jpj = 143 
     275 
     276    if jpn ==  9026 : 
     277        jpi, jpj =  96, 96 
     278    if jpn == 17858 : 
     279        jpi, jpj = 144, 144 
     280    if jpn == 20306 : 
     281        jpi, jpj = 144, 143 
    254282 
    255283    if jpt > 0 : 
    256         p2D = np.zeros ( (jpt, jpj, jpi) ) 
    257         p2D [:, 1:jpj-1, :] = np.reshape (p1D [:,1:jpn-1], (jpt, jpj-2, jpi) ) 
    258         p2D [:, 0    , : ] = p1D[:,   0  ] 
    259         p2D [:, jpj-1, : ] = p1D[:, jpn-1] 
    260  
    261     else : 
    262         p2D = np.zeros ( (jpj, jpi) ) 
    263         p2D [1:jpj-1, :] = np.reshape (np.float64 (p1D [1:jpn-1]), (jpj-2, jpi) ) 
    264         p2D [0    , : ] = p1D[   0 ] 
    265         p2D [jpj-1, : ] = p1D[jpn-1] 
     284        p2d = np.zeros ( (jpt, jpj, jpi) ) 
     285        p2d [:, 1:jpj-1, :] = np.reshape (p1d [:,1:jpn-1], (jpt, jpj-2, jpi) ) 
     286        p2d [:, 0    , : ] = p1d[:,   0  ] 
     287        p2d [:, jpj-1, : ] = p1d[:, jpn-1] 
     288 
     289    else : 
     290        p2d = np.zeros ( (jpj, jpi) ) 
     291        p2d [1:jpj-1, :] = np.reshape (np.float64 (p1d [1:jpn-1]), (jpj-2, jpi) ) 
     292        p2d [0    , : ] = p1d[   0 ] 
     293        p2d [jpj-1, : ] = p1d[jpn-1] 
    266294 
    267295    if math == xr : 
    268         p2D = xr.DataArray (p2D) 
    269         for attr in p1D.attrs :  
    270             p2D.attrs[attr] = p1D.attrs[attr] 
    271         p2D = p2D.rename ( {p2D.dims[0]:p1D.dims[0], p2D.dims[-1]:'x', p2D.dims[-2]:'y'} ) 
    272          
    273     return p2D 
    274  
    275 def geo2point ( p2D, cumulPoles=False, dim1D='points_physiques' ) :  
    276     ''' 
    277     From 2D (lat, lon) to 1D (points_phyiques) 
    278     ''' 
    279     math = __mmath__ (p2D) 
     296        p2d = xr.DataArray (p2d) 
     297        p2d.attrs.update ( p1d.attrs ) 
     298        p2d = p2d.rename ( {p2d.dims[0]:p1d.dims[0], p2d.dims[-1]:'x', p2d.dims[-2]:'y'} ) 
     299 
     300    return p2d 
     301 
     302def geo2point ( p2d, cumul_poles=False, dim1d='points_physiques' ) : 
     303    '''From 2D (lat, lon) to 1D (points_phyiques) 
     304    ''' 
     305    math = __mmath__ (p2d) 
    280306    # 
    281307    # Get the dimension 
    282      
    283     (jpj, jpi) = p2D.shape[-2:] 
    284       
    285     if len (p2D.shape) > 2 : 
    286         jpt = p2D.shape[0] 
    287     else :  
     308 
     309    (jpj, jpi) = p2d.shape[-2:] 
     310 
     311    if len (p2d.shape) > 2 : 
     312        jpt = p2d.shape[0] 
     313    else : 
    288314        jpt = -1 
    289315 
     
    291317 
    292318    if jpt == -1 : 
    293         p1D = np.zeros ( (jpn,) ) 
    294         p1D[1:-1] = np.float64(p2D[1:-1, :]).ravel() 
    295         p1D[ 0]   = p2D[ 0, 0] 
    296         p1D[-1]   = p2D[-1, 0] 
    297  
    298     else :  
    299         p1D = np.zeros ( (jpt, jpn) ) 
     319        p1d = np.zeros ( (jpn,) ) 
     320        p1d[1:-1] = np.float64(p2d[1:-1, :]).ravel() 
     321        p1d[ 0]   = p2d[ 0, 0] 
     322        p1d[-1]   = p2d[-1, 0] 
     323 
     324    else : 
     325        p1d = np.zeros ( (jpt, jpn) ) 
    300326        if math == xr : 
    301             p1D[:, 1:-1] = np.reshape ( np.float64 (p2D[:, 1:-1, :].values).ravel(), (jpt, jpn-2) ) 
     327            p1d[:, 1:-1] = np.reshape ( np.float64 (p2d[:, 1:-1, :].values).ravel(), (jpt, jpn-2) ) 
    302328        else : 
    303             p1D[:, 1:-1] = np.reshape ( np.float64 (p2D[:, 1:-1, :]       ).ravel(), (jpt, jpn-2) ) 
    304         p1D[:,  0  ] = p2D[:,  0, 0] 
    305         p1D[:, -1  ] = p2D[:, -1, 0] 
    306       
     329            p1d[:, 1:-1] = np.reshape ( np.float64 (p2d[:, 1:-1, :]       ).ravel(), (jpt, jpn-2) ) 
     330        p1d[:,  0  ] = p2d[:,  0, 0] 
     331        p1d[:, -1  ] = p2d[:, -1, 0] 
     332 
    307333    if math == xr : 
    308         p1D       = xr.DataArray (p1D) 
    309         for attr in p2D.attrs :  
    310             p1D.attrs[attr] = p2D.attrs[attr] 
    311         p1D       = p1D.rename ( {p1D.dims[0]:p2D.dims[0], p1D.dims[-1]:dim1D} ) 
    312  
    313     if cumulPoles : 
    314         p1D[...,  0] = np.sum ( p2D[...,  0, :] ) 
    315         p1D[..., -1] = np.sum ( p2D[..., -1, :] ) 
    316          
    317     return p1D 
    318  
    319 def geo3point ( p3D, cumulPoles=False, dim1D='points_physiques' ) :  
    320     ''' 
    321     From 3D (lev, lat, lon) to 2D (lev, points_phyiques) 
    322     ''' 
    323     math = __mmath__ (p3D) 
     334        p1d = xr.DataArray (p1d) 
     335        p1d.attrs.update ( p2d.attrs ) 
     336        p1d = p1d.rename ( {p1d.dims[0]:p2d.dims[0], p1d.dims[-1]:dim1d} ) 
     337 
     338    if cumul_poles : 
     339        p1d[...,  0] = np.sum ( p2d[...,  0, :] ) 
     340        p1d[..., -1] = np.sum ( p2d[..., -1, :] ) 
     341 
     342    return p1d 
     343 
     344def geo3point ( p3d, cumul_poles=False, dim1d='points_physiques' ) : 
     345    '''From 3D (lev, lat, lon) to 2D (lev, points_phyiques) 
     346    ''' 
     347    math = __mmath__ (p3d) 
    324348    # 
    325349    # Get the dimensions 
    326      
    327     (jpk, jpj, jpi) = p3D.shape[-3:] 
    328       
    329     if len (p3D.shape) > 3 : 
    330         jpt = p3D.shape[0] 
    331     else :  
     350 
     351    (jpk, jpj, jpi) = p3d.shape[-3:] 
     352 
     353    if len (p3d.shape) > 3 : 
     354        jpt = p3d.shape[0] 
     355    else : 
    332356        jpt = -1 
    333357 
     
    335359 
    336360    if jpt == -1 : 
    337         p2D = np.zeros ( (jpk, jpn,) ) 
     361        p2d = np.zeros ( (jpk, jpn,) ) 
    338362        for jk in np.arange (jpk) : 
    339             p2D [jk, :] = geo2point ( p3D [jk,:,:], cumulPoles, dim1D ) 
    340     else : 
    341         p2D = np.zeros ( (jpt, jpk, jpn) ) 
     363            p2d [jk, :] = geo2point ( p3d [jk,:,:], cumul_poles, dim1d ) 
     364    else : 
     365        p2d = np.zeros ( (jpt, jpk, jpn) ) 
    342366        for jk in np.arange (jpk) : 
    343             p2D [:, jk, :] = geo2point ( p3D [:, jk,:,:], cumulPoles, dim1D  ) 
     367            p2d [:, jk, :] = geo2point ( p3d [:, jk,:,:], cumul_poles, dim1d  ) 
    344368 
    345369    if math == xr : 
    346         p2D       = xr.DataArray (p2D) 
    347         for attr in p2D.attrs :  
    348             p2D.attrs[attr] = p3D.attrs[attr] 
    349         p2D       = p2D.rename ( {p2D.dims[-1]:dim1D, p2D.dims[-2]:p3D.dims[-3]} ) 
    350          
    351     return p2D   
    352  
    353 def geo2en (pxx, pyy, pzz, glam, gphi) :  
    354     ''' 
    355     Change vector from geocentric to east/north 
     370        p2d       = xr.DataArray (p2d) 
     371        p2d.attrs.update ( p3d.attrs ) 
     372        p2d       = p2d.rename ( {p2d.dims[-1]:dim1d, p2d.dims[-2]:p3d.dims[-3]} ) 
     373 
     374    return p2d 
     375 
     376def geo2en (pxx, pyy, pzz, glam, gphi) : 
     377    '''Change vector from geocentric to east/north 
    356378 
    357379    Inputs : 
     
    360382    ''' 
    361383 
    362     gsinlon = np.sin (rad * glam) 
    363     gcoslon = np.cos (rad * glam) 
    364     gsinlat = np.sin (rad * gphi) 
    365     gcoslat = np.cos (rad * gphi) 
    366            
     384    gsinlon = np.sin (RAD * glam) 
     385    gcoslon = np.cos (RAD * glam) 
     386    gsinlat = np.sin (RAD * gphi) 
     387    gcoslat = np.cos (RAD * gphi) 
     388 
    367389    pte = - pxx * gsinlon            + pyy * gcoslon 
    368390    ptn = - pxx * gcoslon * gsinlat  - pyy * gsinlon * gsinlat + pzz * gcoslat 
     
    371393 
    372394def en2geo (pte, ptn, glam, gphi) : 
    373     ''' 
    374     Change vector from east/north to geocentric 
    375  
    376     Inputs :  
     395    '''Change vector from east/north to geocentric 
     396 
     397    Inputs : 
    377398        pte, ptn : eastward/northward components 
    378399        glam, gphi : longitude and latitude of the points 
    379400    ''' 
    380      
    381     gsinlon = np.sin (rad * glam) 
    382     gcoslon = np.cos (rad * glam) 
    383     gsinlat = np.sin (rad * gphi) 
    384     gcoslat = np.cos (rad * gphi) 
     401 
     402    gsinlon = np.sin (RAD * glam) 
     403    gcoslon = np.cos (RAD * glam) 
     404    gsinlat = np.sin (RAD * gphi) 
     405    gcoslat = np.cos (RAD * gphi) 
    385406 
    386407    pxx = - pte * gsinlon - ptn * gcoslon * gsinlat 
    387408    pyy =   pte * gcoslon - ptn * gsinlon * gsinlat 
    388409    pzz =   ptn * gcoslat 
    389      
     410 
    390411    return pxx, pyy, pzz 
    391412 
  • TOOLS/WATER_BUDGET/nemo.py

    r6647 r6665  
    1919## =========================================================================== 
    2020''' 
    21 Utilities to plot NEMO ORCA fields 
    22 Periodicity and other stuff 
     21Utilities to plot NEMO ORCA fields, 
     22Handles periodicity and other stuff 
    2323 
    2424- Lots of tests for xarray object 
    25 - Not much testerd for numpy objects 
    26  
    27 olivier.marti@lsce.ipsl.fr 
     25- Not much tested for numpy objects 
     26 
     27Author: olivier.marti@lsce.ipsl.fr 
    2828 
    2929## SVN information 
     
    3636 
    3737import numpy as np 
    38 try    : import xarray as xr 
    39 except ImportError : pass 
    40  
    41 #try    : import f90nml 
    42 #except : pass 
    43  
    44 #try : from sklearn.impute import SimpleImputer 
    45 #except : pass 
    46  
    47 rpi = np.pi ; rad = np.deg2rad (1.0) ; dar = np.rad2deg (1.0) 
    48  
    49 nperio_valid_range = [0, 1, 4, 4.2, 5, 6, 6.2] 
    50  
    51 rday   = 24.*60.*60.     # Day length [s] 
    52 rsiyea = 365.25 * rday * 2. * rpi / 6.283076 # Sideral year length [s] 
    53 rsiday = rday / (1. + rday / rsiyea) 
    54 raamo  =  12.        # Number of months in one year 
    55 rjjhh  =  24.        # Number of hours in one day 
    56 rhhmm  =  60.        # Number of minutes in one hour 
    57 rmmss  =  60.        # Number of seconds in one minute 
    58 omega  = 2. * rpi / rsiday # Earth rotation parameter [s-1] 
    59 ra     = 6371229.    # Earth radius [m] 
    60 grav   = 9.80665     # Gravity [m/s2] 
    61 repsi  = np.finfo (1.0).eps 
     38import xarray as xr 
     39 
     40try : 
     41    from sklearn.impute import SimpleImputer 
     42except ImportError as err : 
     43    print ("Import error of sklearn.impute.SimpleImputer :", err) 
     44    SimpleImputer = None 
     45 
     46try : 
     47    import f90nml 
     48except ImportError as err : 
     49    print ("Import error of f90nml :", err) 
     50    f90nml = None 
     51 
     52 
     53RPI   = np.pi 
     54RAD   = np.deg2rad (1.0) 
     55DAR   = np.rad2deg (1.0) 
     56REPSI = np.finfo (1.0).eps 
     57 
     58NPERIO_VALID_RANGE = [0, 1, 4, 4.2, 5, 6, 6.2] 
     59 
     60RAAMO    =      12          # Number of months in one year 
     61RJJHH    =      24          # Number of hours in one day 
     62RHHMM    =      60          # Number of minutes in one hour 
     63RMMSS    =      60          # Number of seconds in one minute 
     64RA       = 6371229.0        # Earth radius                                  [m] 
     65GRAV     =       9.80665    # Gravity                                       [m/s2] 
     66RT0      =     273.15       # Freezing point of fresh water                 [Kelvin] 
     67RAU0     =    1026.0        # Volumic mass of sea water                     [kg/m3] 
     68SICE     =       6.0        # Salinity of ice (for pisces)                  [psu] 
     69SOCE     =      34.7        # Salinity of sea (for pisces and isf)          [psu] 
     70RLEVAP   =       2.5e+6     # Latent heat of evaporation (water)            [J/K] 
     71VKARMN   =       0.4        # Von Karman constant 
     72STEFAN   =       5.67e-8    # Stefan-Boltzmann constant                     [W/m2/K4] 
     73RHOS     =     330.         # Volumic mass of snow                          [kg/m3] 
     74RHOI     =     917.         # Volumic mass of sea ice                       [kg/m3] 
     75RHOW     =    1000.         # Volumic mass of freshwater in melt ponds      [kg/m3] 
     76RCND_I   =       2.034396   # Thermal conductivity of fresh ice             [W/m/K] 
     77RCPI     =    2067.0        # Specific heat of fresh ice                    [J/kg/K] 
     78RLSUB    =       2.834e+6   # Pure ice latent heat of sublimation           [J/kg] 
     79RLFUS    =       0.334e+6   # Latent heat of fusion of fresh ice            [J/kg] 
     80RTMLT    =       0.054      # Decrease of seawater meltpoint with salinity 
     81 
     82RDAY     = RJJHH * RHHMM * RMMSS                # Day length               [s] 
     83RSIYEA   = 365.25 * RDAY * 2. * RPI / 6.283076  # Sideral year length      [s] 
     84RSIDAY   = RDAY / (1. + RDAY / RSIYEA)          # Sideral day length       [s] 
     85OMEGA    = 2. * RPI / RSIDAY                    # Earth rotation parameter [s-1] 
    6286 
    6387## Default names of dimensions 
    64 dim_names = {'x':'xx', 'y':'yy', 'z':'olevel', 't':None} 
     88UDIMS = {'x':'x', 'y':'y', 'z':'olevel', 't':'time_counter'} 
    6589 
    6690## All possibles name of dimensions in Nemo files 
    67 xName = [ 'x', 'X', 'X1', 'xx', 'XX', 'x_grid_T', 'x_grid_U', 'x_grid_V', 'x_grid_F', 'x_grid_W', 'lon', 'nav_lon', 'longitude', 'X1', 'x_c', 'x_f', ] 
    68 yName = [ 'y', 'Y', 'Y1', 'yy', 'YY', 'y_grid_T', 'y_grid_U', 'y_grid_V', 'y_grid_F', 'y_grid_W', 'lat', 'nav_lat', 'latitude' , 'Y1', 'y_c', 'y_f', ] 
    69 zName = [ 'z', 'Z', 'Z1', 'zz', 'ZZ', 'depth', 'tdepth', 'udepth', 'vdepth', 'wdepth', 'fdepth', 'deptht', 'depthu', 'depthv', 'depthw', 'depthf', 'olevel', 'z_c', 'z_f', ] 
    70 tName = [ 't', 'T', 'tt', 'TT', 'time', 'time_counter', 'time_centered', ] 
     91XNAME = [ 'x', 'X', 'X1', 'xx', 'XX', 
     92              'x_grid_T', 'x_grid_U', 'x_grid_V', 'x_grid_F', 'x_grid_W', 
     93              'lon', 'nav_lon', 'longitude', 'X1', 'x_c', 'x_f', ] 
     94YNAME = [ 'y', 'Y', 'Y1', 'yy', 'YY', 
     95              'y_grid_T', 'y_grid_U', 'y_grid_V', 'y_grid_F', 'y_grid_W', 
     96              'lat', 'nav_lat', 'latitude' , 'Y1', 'y_c', 'y_f', ] 
     97ZNAME = [ 'z', 'Z', 'Z1', 'zz', 'ZZ', 'depth', 'tdepth', 'udepth', 
     98              'vdepth', 'wdepth', 'fdepth', 'deptht', 'depthu', 
     99              'depthv', 'depthw', 'depthf', 'olevel', 'z_c', 'z_f', ] 
     100TNAME = [ 't', 'T', 'tt', 'TT', 'time', 'time_counter', 'time_centered', ] 
    71101 
    72102## All possibles name of units of dimensions in Nemo files 
    73 xUnit = [ 'degrees_east', ] 
    74 yUnit = [ 'degrees_north', ] 
    75 zUnit = [ 'm', 'meter', ] 
    76 tUnit = [ 'second', 'minute', 'hour', 'day', 'month', 'year', ] 
     103XUNIT = [ 'degrees_east', ] 
     104YUNIT = [ 'degrees_north', ] 
     105ZUNIT = [ 'm', 'meter', ] 
     106TUNIT = [ 'second', 'minute', 'hour', 'day', 'month', 'year', ] 
    77107 
    78108## All possibles size of dimensions in Orca files 
    79 xLength = [ 180, 182, 360, 362 ] 
    80 yLength = [ 148, 149, 331, 332 ] 
    81 zLength = [31, 75] 
     109XLENGTH = [ 180, 182, 360, 362, 1440 ] 
     110YLENGTH = [ 148, 149, 331, 332 ] 
     111ZLENGTH = [ 31, 75] 
    82112 
    83113## =========================================================================== 
    84 def __mmath__ (tab, default=None) : 
    85     ''' 
    86     Determines the type of tab : xarray or numpy object ? 
     114def __mmath__ (ptab, default=None) : 
     115    '''Determines the type of tab : xarray, numpy or numpy.ma object ? 
     116 
     117    Returns type 
    87118    ''' 
    88119    mmath = default 
    89     try    : 
    90         if type (tab) == xr.core.dataarray.DataArray : mmath = xr 
    91     except : pass 
    92  
    93     try    : 
    94         if type (tab) == np.ndarray : mmath = np 
    95     except : pass 
    96              
     120    if isinstance (ptab, xr.core.dataarray.DataArray) : 
     121        mmath = xr 
     122    if isinstance (ptab, np.ndarray) : 
     123        mmath = np 
     124    if isinstance (ptab, np.ma.MaskType) : 
     125        mmath = np.ma 
     126 
    97127    return mmath 
    98128 
    99 def __guessNperio__ (jpj, jpi, nperio=None, out='nperio') : 
    100     ''' 
    101     Tries to guess the value of nperio (periodicity parameter. See NEMO documentation for details) 
    102      
     129def __guess_nperio__ (jpj, jpi, nperio=None, out='nperio') : 
     130    '''Tries to guess the value of nperio (periodicity parameter. 
     131 
     132    See NEMO documentation for details) 
    103133    Inputs 
    104134    jpj    : number of latitudes 
     
    106136    nperio : periodicity parameter 
    107137    ''' 
    108     if nperio == None : 
    109         nperio = __guessConfig__ (jpj, jpi, nperio=None, out='nperio') 
    110      
     138    if nperio is None : 
     139        nperio = __guess_config__ (jpj, jpi, nperio=None, out=out) 
    111140    return nperio 
    112141 
    113 def __guessConfig__ (jpj, jpi, nperio=None, config=None, out='nperio') : 
    114     ''' 
    115     Tries to guess the value of nperio (periodicity parameter. See NEMO documentation for details) 
    116  
     142def __guess_config__ (jpj, jpi, nperio=None, config=None, out='nperio') : 
     143    '''Tries to guess the value of nperio (periodicity parameter). 
     144 
     145    See NEMO documentation for details) 
    117146    Inputs 
    118147    jpj    : number of latitudes 
     
    121150    ''' 
    122151    print ( jpi, jpj) 
    123     if nperio == None : 
     152    if nperio is None : 
    124153        ## Values for NEMO version < 4.2 
    125         if (jpj ==  149 and jpi == 182) or (jpj == None and jpi == 182) or (jpj == 149 or jpi == None) : 
    126             config = 'ORCA2.3' 
    127             nperio = 4   # ORCA2. We choose legacy orca2. 
    128             Iperio = 1 ; Jperio = 0 ; NFold = 1 ; NFtype = 'T' 
    129         if (jpj == 332 and jpi == 362) or (jpj == None and jpi == 362) or (jpj ==  332 and jpi == None) : # eORCA1. 
    130             config = 'eORCA1.2' 
    131             nperio = 6   
    132             Iperio = 1 ; Jperio = 0 ; NFold = 1 ; NFtype = 'F' 
     154        if ( (jpj == 149 and jpi == 182) or (jpj is None and jpi == 182) or 
     155             (jpj == 149 or jpi is None) ) : 
     156            # ORCA2. We choose legacy orca2. 
     157            config, nperio, iperio, jperio, nfold, nftype = 'ORCA2.3' , 4, 1, 0, 1, 'T' 
     158        if ((jpj == 332 and jpi == 362) or (jpj is None and jpi == 362) or 
     159            (jpj ==  332 and jpi is None) ) : # eORCA1. 
     160            config, nperio, iperio, jperio, nfold, nftype = 'eORCA1.2', 6, 1, 0, 1, 'F' 
    133161        if jpi == 1442 :  # ORCA025. 
    134             config = 'ORCA025' 
    135             nperio = 6  
    136             Iperio = 1 ; Jperio = 0 ; NFold = 1 ; NFtype = 'F' 
     162            config, nperio, iperio, jperio, nfold, nftype = 'ORCA025' , 6, 1, 0, 1, 'F' 
    137163        if jpj ==  294 : # ORCA1 
    138             config = 'ORCA1' 
    139             nperio = 6 
    140             Iperio = 1 ; Jperio = 0 ; NFold = 1 ; NFtype = 'F' 
    141              
     164            config, nperio, iperio, jperio, nfold, nftype = 'ORCA1'   , 6, 1, 0, 1, 'F' 
     165 
    142166        ## Values for NEMO version >= 4.2. No more halo points 
    143         if (jpj == 148 and jpi == 180) or (jpj == None and jpi == 180) or (jpj == 148 and jpi == None) : 
    144             config = 'ORCA2.4' 
    145             nperio = 4.2 # ORCA2. We choose legacy orca2. 
    146             Iperio = 1 ; Jperio = 0 ; NFold = 1 ; NFtype = 'F' 
    147         if (jpj == 331 and jpi == 360) or (jpj == None and jpi == 360) or (jpj == 331 and jpi == None) : # eORCA1. 
    148             config = 'eORCA1.4' 
    149             nperio = 6.2 
    150             Iperio = 1 ; Jperio = 0 ; NFold = 1 ; NFtype = 'F' 
     167        if  (jpj == 148 and jpi == 180) or (jpj is None and jpi == 180) or \ 
     168            (jpj == 148 and jpi is None) :  # ORCA2. We choose legacy orca2. 
     169            config, nperio, iperio, jperio, nfold, nftype = 'ORCA2.4' , 4.2, 1, 0, 1, 'F' 
     170        if  (jpj == 331 and jpi == 360) or (jpj is None and jpi == 360) or \ 
     171            (jpj == 331 and jpi is None) : # eORCA1. 
     172            config, nperio, iperio, jperio, nfold, nftype = 'eORCA1.4', 6.2, 1, 0, 1, 'F' 
    151173        if jpi == 1440 : # ORCA025. 
    152             config = 'ORCA025' 
    153             nperio = 6.2 
    154             Iperio = 1 ; Jperio = 0 ; NFold = 1 ; NFtype = 'F' 
    155              
    156         if nperio == None : 
    157             raise Exception  ('in nemo module : nperio not found, and cannot by guessed') 
     174            config, nperio, iperio, jperio, nfold, nftype = 'ORCA025' , 6.2, 1, 0, 1, 'F' 
     175 
     176        if nperio is None : 
     177            raise ValueError ('in nemo module : nperio not found, and cannot by guessed') 
     178 
     179        if nperio in NPERIO_VALID_RANGE : 
     180            print ( f'nperio set as {nperio} (deduced from {jpj=} and {jpi=})' ) 
    158181        else : 
    159             if nperio in nperio_valid_range : 
    160                 print ( f'nperio set as {nperio} (deduced from {jpj=} and {jpi=})' ) 
    161             else :  
    162                 raise ValueError ( f'nperio set as {nperio} (deduced from {jpi=} and {jpj=}) : nemo.py is not ready for this value' ) 
    163  
    164     if out == 'nperio' : return nperio 
    165     if out == 'config' : return config 
    166     if out == 'perio'  : return Iperio, Jperio, NFold, NFtype 
    167     if out in ['full', 'all'] : return {'nperio':nperio, 'Iperio':Iperio, 'Jperio':Jperio, 'NFold':NFold, 'NFtype':NFtype} 
    168          
    169 def __guessPoint__ (ptab) : 
    170     ''' 
    171     Tries to guess the grid point (periodicity parameter. See NEMO documentation for details) 
    172      
     182            raise ValueError ( f'nperio set as {nperio} (deduced from {jpi=} and {jpj=}) : \n'+ 
     183                                'nemo.py is not ready for this value' ) 
     184 
     185    if out == 'nperio' : 
     186        return nperio 
     187    if out == 'config' : 
     188        return config 
     189    if out == 'perio'  : 
     190        return iperio, jperio, nfold, nftype 
     191    if out in ['full', 'all'] : 
     192        return {'nperio':nperio, 'iperio':iperio, 'jperio':jperio, 'nfold':nfold, 'nftype':nftype} 
     193 
     194def __guess_point__ (ptab) : 
     195    '''Tries to guess the grid point (periodicity parameter. 
     196 
     197    See NEMO documentation for details) 
    173198    For array conforments with xgcm requirements 
    174199 
     
    178203    Credits : who is the original author ? 
    179204    ''' 
    180      
    181     gP = None 
     205 
     206    gp = None 
    182207    mmath = __mmath__ (ptab) 
    183208    if mmath == xr : 
    184         if 'x_c' in ptab.dims and 'y_c' in ptab.dims                        : gP = 'T' 
    185         if 'x_f' in ptab.dims and 'y_c' in ptab.dims                        : gP = 'U' 
    186         if 'x_c' in ptab.dims and 'y_f' in ptab.dims                        : gP = 'V' 
    187         if 'x_f' in ptab.dims and 'y_f' in ptab.dims                        : gP = 'F' 
    188         if 'x_c' in ptab.dims and 'y_c' in ptab.dims and 'z_c' in ptab.dims : gP = 'T' 
    189         if 'x_c' in ptab.dims and 'y_c' in ptab.dims and 'z_f' in ptab.dims : gP = 'W' 
    190         if 'x_f' in ptab.dims and 'y_c' in ptab.dims and 'z_f' in ptab.dims : gP = 'U' 
    191         if 'x_c' in ptab.dims and 'y_f' in ptab.dims and 'z_f' in ptab.dims : gP = 'V' 
    192         if 'x_f' in ptab.dims and 'y_f' in ptab.dims and 'z_f' in ptab.dims : gP = 'F' 
    193               
    194         if gP == None : 
    195             raise Exception ('in nemo module : cd_type not found, and cannot by guessed') 
    196         else : 
    197             print ( f'Grid set as {gP} deduced from dims {ptab.dims}' ) 
    198             return gP 
     209        if ('x_c' in ptab.dims and 'y_c' in ptab.dims ) : 
     210            gp = 'T' 
     211        if ('x_f' in ptab.dims and 'y_c' in ptab.dims ) : 
     212            gp = 'U' 
     213        if ('x_c' in ptab.dims and 'y_f' in ptab.dims ) : 
     214            gp = 'V' 
     215        if ('x_f' in ptab.dims and 'y_f' in ptab.dims ) : 
     216            gp = 'F' 
     217        if ('x_c' in ptab.dims and 'y_c' in ptab.dims 
     218              and 'z_c' in ptab.dims )                : 
     219            gp = 'T' 
     220        if ('x_c' in ptab.dims and 'y_c' in ptab.dims 
     221                and 'z_f' in ptab.dims )                : 
     222            gp = 'W' 
     223        if ('x_f' in ptab.dims and 'y_c' in ptab.dims 
     224                and 'z_f' in ptab.dims )                : 
     225            gp = 'U' 
     226        if ('x_c' in ptab.dims and 'y_f' in ptab.dims 
     227                and 'z_f' in ptab.dims ) : 
     228            gp = 'V' 
     229        if ('x_f' in ptab.dims and 'y_f' in ptab.dims 
     230                and 'z_f' in ptab.dims ) : 
     231            gp = 'F' 
     232 
     233        if gp is None : 
     234            raise AttributeError ('in nemo module : cd_type not found, and cannot by guessed') 
     235        print ( f'Grid set as {gp} deduced from dims {ptab.dims}' ) 
     236        return gp 
    199237    else : 
    200          raise Exception  ('in nemo module : cd_type not found, input is not an xarray data') 
     238        raise AttributeError  ('in nemo module : cd_type not found, input is not an xarray data') 
    201239 
    202240def get_shape ( ptab ) : 
    203     ''' 
    204     Get shape of ptab :  
    205     shape main contain X, Y, Z or T 
     241    '''Get shape of ptab return a string with axes names 
     242 
     243    shape may contain X, Y, Z or T 
    206244    Y is missing for a latitudinal slice 
    207245    X is missing for on longitudinal slice 
    208246    etc ... 
    209247    ''' 
    210      
    211     get_shape = '' 
    212     ix, ax = __findAxis__ (ptab, 'x') 
    213     jy, ay = __findAxis__ (ptab, 'y') 
    214     kz, az = __findAxis__ (ptab, 'z') 
    215     lt, at = __findAxis__ (ptab, 't') 
    216     if ax : get_shape = 'X' 
    217     if ay : get_shape = 'Y' + get_shape 
    218     if az : get_shape = 'Z' + get_shape 
    219     if at : get_shape = 'T' + get_shape 
    220     return get_shape 
    221       
     248 
     249    g_shape = '' 
     250    if __find_axis__ (ptab, 'x')[0] : 
     251        g_shape = 'X' 
     252    if __find_axis__ (ptab, 'y')[0] : 
     253        g_shape = 'Y' + g_shape 
     254    if __find_axis__ (ptab, 'z')[0] : 
     255        g_shape = 'Z' + g_shape 
     256    if __find_axis__ (ptab, 't')[0] : 
     257        g_shape = 'T' + g_shape 
     258    return g_shape 
     259 
    222260def lbc_diag (nperio) : 
    223     lperio = nperio ; aperio = False 
     261    '''Useful to switch between field with and without halo''' 
     262    lperio, aperio = nperio, False 
    224263    if nperio == 4.2 : 
    225         lperio = 4 ; aperio = True 
     264        lperio, aperio = 4, True 
    226265    if nperio == 6.2 : 
    227         lperio = 6 ; aperio = True 
    228          
     266        lperio, aperio = 6, True 
    229267    return lperio, aperio 
    230268 
    231 def __findAxis__ (tab, axis='z') : 
    232     ''' 
    233     Find order and name of the requested axis 
    234     ''' 
    235     mmath = __mmath__ (tab) 
    236     ix = None ; ax = None 
    237  
    238     if axis in xName : axName = xName ; unList = xUnit ; Length = xLength 
    239     if axis in yName : axName = yName ; unList = yUnit ; Length = yLength 
    240     if axis in zName : axName = zName ; unList = zUnit ; Length = zLength 
    241     if axis in tName : axName = tName ; unList = tUnit ; Length = None 
    242      
     269def __find_axis__ (ptab, axis='z', back=True) : 
     270    '''Returns name and name of the requested axis''' 
     271    mmath = __mmath__ (ptab) 
     272    ax, ix = None, None 
     273 
     274    if axis in XNAME : 
     275        ax_name, unit_list, length = XNAME, XUNIT, XLENGTH 
     276    if axis in YNAME : 
     277        ax_name, unit_list, length = YNAME, YUNIT, YLENGTH 
     278    if axis in ZNAME : 
     279        ax_name, unit_list, length = ZNAME, ZUNIT, ZLENGTH 
     280    if axis in TNAME : 
     281        ax_name, unit_list, length = TNAME, TUNIT, None 
     282 
    243283    if mmath == xr : 
    244         for Name in axName : 
    245             try    : 
    246                 ix = tab.dims.index (Name) 
    247                 ax = Name 
    248             except : pass 
    249  
    250         for i, dim in enumerate (tab.dims) : 
    251             if 'units' in tab.coords[dim].attrs.keys() : 
    252                 for name in unList : 
    253                     if name in tab.coords[dim].attrs['units'] : 
    254                         ix = i ; ax = dim 
    255     else : 
    256         #if axis in xName : ix=-1 
    257         #if axis in yName : 
    258         #    if len(tab.shape) >= 2 : ix=-2 
    259         #if axis in zName : 
    260         #    if len(tab.shape) >= 3 : ix=-3 
    261         #if axis in tName : 
    262         #    if len(tab.shape) >=3  : ix=-3 
    263         #    if len(tab.shape) >=4  : ix=-4 
    264  
    265         l_shape = tab.shape 
    266         for nn in np.arange ( len(l_shape)) : 
    267             if l_shape[nn] in Length : ix = nn 
    268         
    269     return ix, ax 
    270  
    271 def findAxis ( tab, axis= 'z' ) : 
    272   ix, xx = __findAxis__ (tab, axis) 
    273   return xx 
    274  
    275 def fixed_lon (lon, center_lon=0.0) : 
    276     ''' 
    277     Returns corrected longitudes for nicer plots 
     284        # Try by name 
     285        for dim in ax_name : 
     286            if dim in ptab.dims : 
     287                ix, ax = ptab.dims.index (dim), dim 
     288 
     289        # If not found, try by axis attributes 
     290        if not ix : 
     291            for i, dim in enumerate (ptab.dims) : 
     292                if 'axis' in ptab.coords[dim].attrs.keys() : 
     293                    l_axis = ptab.coords[dim].attrs['axis'] 
     294                    if axis in ax_name and l_axis == 'X' : 
     295                        ix, ax = (i, dim) 
     296                    if axis in ax_name and l_axis == 'Y' : 
     297                        ix, ax = (i, dim) 
     298                    if axis in ax_name and l_axis == 'Z' : 
     299                        ix, ax = (i, dim) 
     300                    if axis in ax_name and l_axis == 'T' : 
     301                        ix, ax = (i, dim) 
     302 
     303        # If not found, try by units 
     304        if not ix : 
     305            for i, dim in enumerate (ptab.dims) : 
     306                if 'units' in ptab.coords[dim].attrs.keys() : 
     307                    for name in unit_list : 
     308                        if name in ptab.coords[dim].attrs['units'] : 
     309                            ix, ax = i, dim 
     310 
     311    # If numpy array or dimension not found, try by length 
     312    if mmath != xr or not ix : 
     313        if length : 
     314            l_shape = ptab.shape 
     315            for nn in np.arange ( len(l_shape) ) : 
     316                if l_shape[nn] in length : 
     317                    ix = nn 
     318 
     319    if ix and back : 
     320        ix -= len(ptab.shape) 
     321 
     322    return ax, ix 
     323 
     324def find_axis ( ptab, axis='z', back=True ) : 
     325    '''Version of find_axis with no __''' 
     326    ix, xx = __find_axis__ (ptab, axis, back) 
     327    return xx, ix 
     328 
     329def fixed_lon (plon, center_lon=0.0) : 
     330    '''Returns corrected longitudes for nicer plots 
    278331 
    279332    lon        : longitudes of the grid. At least 2D. 
    280333    center_lon : center longitude. Default=0. 
    281334 
    282     Designed by Phil Pelson. See https://gist.github.com/pelson/79cf31ef324774c97ae7 
    283     ''' 
    284     mmath = __mmath__ (lon) 
     335    Designed by Phil Pelson. 
     336    See https://gist.github.com/pelson/79cf31ef324774c97ae7 
     337    ''' 
     338    mmath = __mmath__ (plon) 
     339 
     340    f_lon = plon.copy () 
     341 
     342    f_lon = mmath.where (f_lon > center_lon+180., f_lon-360.0, f_lon) 
     343    f_lon = mmath.where (f_lon < center_lon-180., f_lon+360.0, f_lon) 
     344 
     345    for i, start in enumerate (np.argmax (np.abs (np.diff (f_lon, axis=-1)) > 180., axis=-1)) : 
     346        f_lon [..., i, start+1:] += 360. 
     347 
     348    # Special case for eORCA025 
     349    if f_lon.shape [-1] == 1442 : 
     350        f_lon [..., -2, :] = f_lon [..., -3, :] 
     351    if f_lon.shape [-1] == 1440 : 
     352        f_lon [..., -1, :] = f_lon [..., -2, :] 
     353 
     354    if f_lon.min () > center_lon : 
     355        f_lon += -360.0 
     356    if f_lon.max () < center_lon : 
     357        f_lon +=  360.0 
     358 
     359    if f_lon.min () < center_lon-360.0 : 
     360        f_lon +=  360.0 
     361    if f_lon.max () > center_lon+360.0 : 
     362        f_lon += -360.0 
     363 
     364    return f_lon 
     365 
     366def bounds_clolon ( pbounds_lon, plon, rad=False, deg=True) : 
     367    '''Choose closest to lon0 longitude, adding/substacting 360° if needed 
     368    ''' 
     369 
     370    if rad : 
     371        lon_range = 2.0*np.pi 
     372    if deg : 
     373        lon_range = 360.0 
     374    b_clolon = pbounds_lon.copy () 
     375 
     376    b_clolon = xr.where ( b_clolon < plon-lon_range/2., 
     377                          b_clolon+lon_range, 
     378                          b_clolon ) 
     379    b_clolon = xr.where ( b_clolon > plon+lon_range/2., 
     380                          b_clolon-lon_range, 
     381                          b_clolon ) 
     382    return b_clolon 
     383 
     384def unify_dims ( dd, x='x', y='y', z='olevel', t='time_counter', verbose=False ) : 
     385    '''Rename dimensions to unify them between NEMO versions 
     386    ''' 
     387    for xx in XNAME : 
     388        if xx in dd.dims and xx != x : 
     389            if verbose : 
     390                print ( f"{xx} renamed to {x}" ) 
     391            dd = dd.rename ( {xx:x}) 
     392 
     393    for yy in YNAME : 
     394        if yy in dd.dims and yy != y  : 
     395            if verbose : 
     396                print ( f"{yy} renamed to {y}" ) 
     397            dd = dd.rename ( {yy:y} ) 
     398 
     399    for zz in ZNAME : 
     400        if zz in dd.dims and zz != z : 
     401            if verbose : 
     402                print ( f"{zz} renamed to {z}" ) 
     403            dd = dd.rename ( {zz:z} ) 
     404 
     405    for tt in TNAME  : 
     406        if tt in dd.dims and tt != t : 
     407            if verbose : 
     408                print ( f"{tt} renamed to {t}" ) 
     409            dd = dd.rename ( {tt:t} ) 
     410 
     411    return dd 
     412 
     413 
     414if SimpleImputer :  
     415  def fill_empty (ptab, sval=np.nan, transpose=False) : 
     416        '''Fill empty values 
     417 
     418        Useful when NEMO has run with no wet points options : 
     419        some parts of the domain, with no ocean points, have no 
     420        values 
     421        ''' 
     422        mmath = __mmath__ (ptab) 
     423 
     424        imp = SimpleImputer (missing_values=sval, strategy='mean') 
     425        if transpose : 
     426            imp.fit (ptab.T) 
     427            ztab = imp.transform (ptab.T).T 
     428        else : 
     429            imp.fit (ptab) 
     430            ztab = imp.transform (ptab) 
     431 
     432        if mmath == xr : 
     433            ztab = xr.DataArray (ztab, dims=ztab.dims, coords=ztab.coords) 
     434            ztab.attrs.update (ptab.attrs) 
     435 
     436        return ztab 
     437 
    285438     
    286     fixed_lon = lon.copy () 
    287          
    288     fixed_lon = mmath.where (fixed_lon > center_lon+180., fixed_lon-360.0, fixed_lon) 
    289     fixed_lon = mmath.where (fixed_lon < center_lon-180., fixed_lon+360.0, fixed_lon) 
    290      
    291     for i, start in enumerate (np.argmax (np.abs (np.diff (fixed_lon, axis=-1)) > 180., axis=-1)) : 
    292         fixed_lon [..., i, start+1:] += 360. 
    293  
    294     # Special case for eORCA025 
    295     if fixed_lon.shape [-1] == 1442 : fixed_lon [..., -2, :] = fixed_lon [..., -3, :] 
    296     if fixed_lon.shape [-1] == 1440 : fixed_lon [..., -1, :] = fixed_lon [..., -2, :] 
    297  
    298     if fixed_lon.min () > center_lon : fixed_lon += -360.0 
    299     if fixed_lon.max () < center_lon : fixed_lon +=  360.0 
    300          
    301     if fixed_lon.min () < center_lon-360.0 : fixed_lon +=  360.0 
    302     if fixed_lon.max () > center_lon+360.0 : fixed_lon += -360.0 
    303                  
    304     return fixed_lon 
    305  
    306 def bounds_clolon ( bounds_lon, lon, rad=False, deg=True) : 
    307     '''Choose closest to lon0 longitude, adding or substacting 360° if needed''' 
    308  
    309     if rad : lon_range = 2.0*np.pi 
    310     if deg : lon_range = 360.0 
    311     bounds_clolon = bounds_lon.copy () 
    312  
    313     bounds_clolon = xr.where ( bounds_clolon < lon-lon_range/2., bounds_clolon+lon_range, bounds_clolon ) 
    314     bounds_clolon = xr.where ( bounds_clolon > lon+lon_range/2., bounds_clolon-lon_range, bounds_clolon ) 
    315  
    316     return bounds_clolon 
    317  
    318 def UnifyDims ( dd, udims=dim_names, verbose=False ) : 
    319     ''' 
    320     Rename dimensions to unify them between NEMO versions 
    321     ''' 
    322      
    323     if udims['x'] : 
    324         for xx in xName : 
    325             if xx in dd.dims and xx != udims['x'] : 
    326                 if verbose : print ( f"{xx} renamed to {udims['x']}" ) 
    327                 dd = dd.rename ( {xx:udims['x']}) 
    328     if udims['y'] : 
    329         for yy in yName : 
    330             if yy in dd.dims and yy != udims['y']  : 
    331                 if verbose : print ( f"{yy} renamed to {udims['y']}" ) 
    332                 dd = dd.rename ( {yy:udims['y']} ) 
    333     if udims['z'] : 
    334         for zz in zName : 
    335             if zz in dd.dims and zz != udims['z'] : 
    336                 if verbose : print ( f"{zz} renamed to {udims['z']}" ) 
    337                 dd = dd.rename ( {zz:udims['z']} ) 
    338     if udims['t'] : 
    339         for tt in tName  : 
    340             if tt in dd.dims and tt != udims['t'] : 
    341                 if verbose : print ( f"{tt} renamed to {udims['t']}" ) 
    342                 dd = dd.rename ( {tt:udims['t']} ) 
    343  
    344     return dd 
    345  
    346 def fill_empty (ztab, sval=np.nan, transpose=False) : 
    347     ''' 
    348     Fill values 
    349  
    350     Useful when NEMO has run with no wet points options :  
    351     some parts of the domain, with no ocean points, have no 
    352     values 
    353     ''' 
    354     from sklearn.impute import SimpleImputer 
    355     mmath = __mmath__ (ztab) 
    356  
    357     imp = SimpleImputer (missing_values=sval, strategy='mean') 
    358     if transpose : 
    359         imp.fit (ztab.T) 
    360         ptab = imp.transform (ztab.T).T 
    361     else :  
    362         imp.fit (ztab) 
    363         ptab = imp.transform (ztab) 
    364     
    365     if mmath == xr : 
    366         ptab = xr.DataArray (ptab, dims=ztab.dims, coords=ztab.coords) 
    367         ptab.attrs = ztab.attrs 
    368          
    369     return ptab 
    370  
    371 def fill_lonlat (lon, lat, sval=-1) : 
    372     ''' 
    373     Fill longitude/latitude values 
    374  
    375     Useful when NEMO has run with no wet points options :  
     439else :  
     440    print ("Import error of sklearn.impute.SimpleImputer") 
     441    def fill_empty (ptab, sval=np.nan, transpose=False) : 
     442        '''Void version of fill_empy, because module sklearn.impute.SimpleImputer is not available 
     443 
     444        fill_empty :  
     445          Fill values 
     446 
     447          Useful when NEMO has run with no wet points options : 
     448          some parts of the domain, with no ocean points, have no 
     449          values 
     450        ''' 
     451        print ( 'Error : module sklearn.impute.SimpleImputer not found' ) 
     452        print ( 'Can not call fill_empty' ) 
     453        print ( 'Call arguments where : ' ) 
     454        print ( f'{ptab.shape=} {sval=} {transpose=}' ) 
     455   
     456def fill_lonlat (plon, plat, sval=-1) : 
     457    '''Fill longitude/latitude values 
     458 
     459    Useful when NEMO has run with no wet points options : 
    376460    some parts of the domain, with no ocean points, have no 
    377461    lon/lat values 
    378462    ''' 
    379463    from sklearn.impute import SimpleImputer 
    380     mmath = __mmath__ (lon) 
     464    mmath = __mmath__ (plon) 
    381465 
    382466    imp = SimpleImputer (missing_values=sval, strategy='mean') 
    383     imp.fit (lon) 
    384     plon = imp.transform (lon) 
    385     imp.fit (lat.T) 
    386     plat = imp.transform (lat.T).T 
     467    imp.fit (plon) 
     468    zlon = imp.transform (plon) 
     469    imp.fit (plat.T) 
     470    zlat = imp.transform (plat.T).T 
    387471 
    388472    if mmath == xr : 
    389         plon = xr.DataArray (plon, dims=lon.dims, coords=lon.coords) 
    390         plat = xr.DataArray (plat, dims=lat.dims, coords=lat.coords) 
    391         plon.attrs = lon.attrs ; plat.attrs = lat.attrs 
    392          
    393     plon = fixed_lon (plon) 
    394      
    395     return plon, plat 
    396  
    397 def fill_bounds_lonlat (bounds_lon, bounds_lat, sval=-1) : 
    398     ''' 
    399     Fill longitude/latitude bounds values 
    400  
    401     Useful when NEMO has run with no wet points options :  
     473        zlon = xr.DataArray (zlon, dims=plon.dims, coords=plon.coords) 
     474        zlat = xr.DataArray (zlat, dims=plat.dims, coords=plat.coords) 
     475        zlon.attrs.update (plon.attrs) 
     476        zlat.attrs.update (plat.attrs) 
     477 
     478    zlon = fixed_lon (zlon) 
     479 
     480    return zlon, zlat 
     481 
     482def fill_bounds_lonlat (pbounds_lon, pbounds_lat, sval=-1) : 
     483    '''Fill longitude/latitude bounds values 
     484 
     485    Useful when NEMO has run with no wet points options : 
    402486    some parts of the domain, with no ocean points, as no 
    403487    lon/lat values 
    404488    ''' 
    405     mmath = __mmath__ (bounds_lon) 
    406  
    407     p_bounds_lon = np.empty ( bounds_lon.shape ) 
    408     p_bounds_lat = np.empty ( bounds_lat.shape ) 
     489    mmath = __mmath__ (pbounds_lon) 
     490 
     491    z_bounds_lon = np.empty ( pbounds_lon.shape ) 
     492    z_bounds_lat = np.empty ( pbounds_lat.shape ) 
    409493 
    410494    imp = SimpleImputer (missing_values=sval, strategy='mean') 
    411      
    412     for n in np.arange (4) :  
    413         imp.fit (bounds_lon[:,:,n]) 
    414         p_bounds_lon[:,:,n] = imp.transform (bounds_lon[:,:,n]) 
    415         imp.fit (bounds_lat[:,:,n].T) 
    416         p_bounds_lat[:,:,n] = imp.transform (bounds_lat[:,:,n].T).T 
    417          
     495 
     496    for n in np.arange (4) : 
     497        imp.fit (pbounds_lon[:,:,n]) 
     498        z_bounds_lon[:,:,n] = imp.transform (pbounds_lon[:,:,n]) 
     499        imp.fit (pbounds_lat[:,:,n].T) 
     500        z_bounds_lat[:,:,n] = imp.transform (pbounds_lat[:,:,n].T).T 
     501 
    418502    if mmath == xr : 
    419         p_bounds_lon = xr.DataArray (bounds_lon, dims=bounds_lon.dims, coords=bounds_lon.coords) 
    420         p_bounds_lat = xr.DataArray (bounds_lat, dims=bounds_lat.dims, coords=bounds_lat.coords) 
    421         p_bounds_lon.attrs = bounds_lat.attrs ; p_bounds_lat.attrs = bounds_lat.attrs 
    422          
    423     return p_bounds_lon, p_bounds_lat 
    424  
    425 def jeq (lat) : 
    426     ''' 
    427     Returns j index of equator in the grid 
    428      
     503        z_bounds_lon = xr.DataArray (pbounds_lon, dims=pbounds_lon.dims, 
     504                                         coords=pbounds_lon.coords) 
     505        z_bounds_lat = xr.DataArray (pbounds_lat, dims=pbounds_lat.dims, 
     506                                         coords=pbounds_lat.coords) 
     507        z_bounds_lon.attrs.update (pbounds_lat.attrs) 
     508        z_bounds_lat.attrs.update (pbounds_lat.attrs) 
     509 
     510    return z_bounds_lon, z_bounds_lat 
     511 
     512def jeq (plat) : 
     513    '''Returns j index of equator in the grid 
     514 
    429515    lat : latitudes of the grid. At least 2D. 
    430516    ''' 
    431     mmath = __mmath__ (lat) 
    432     ix, ax = __findAxis__ (lat, 'x') 
    433     jy, ay = __findAxis__ (lat, 'y') 
     517    mmath = __mmath__ (plat) 
     518    jy = __find_axis__ (plat, 'y')[-1] 
    434519 
    435520    if mmath == xr : 
    436         jeq = int ( np.mean ( np.argmin (np.abs (np.float64 (lat)), axis=jy) ) ) 
    437     else :  
    438         jeq = np.argmin (np.abs (np.float64 (lat[...,:, 0]))) 
    439     return jeq 
    440  
    441 def lon1D (lon, lat=None) : 
    442     ''' 
    443     Returns 1D longitude for simple plots. 
    444      
    445     lon : longitudes of the grid 
    446     lat (optionnal) : latitudes of the grid 
    447     ''' 
    448     mmath = __mmath__ (lon) 
    449     jpj, jpi  = lon.shape [-2:] 
    450     if np.max (lat) : 
    451         je    = jeq (lat) 
    452         #lon1D = lon.copy() [..., je, :] 
    453         lon0 = lon [..., je, 0].copy() 
    454         dlon = lon [..., je, 1].copy() - lon [..., je, 0].copy() 
    455         lon1D = np.linspace ( start=lon0, stop=lon0+360.+2*dlon, num=jpi ) 
     521        jj = int ( np.mean ( np.argmin (np.abs (np.float64 (plat)), 
     522                                                axis=jy) ) ) 
    456523    else : 
    457         lon0 = lon [..., jpj//3, 0].copy() 
    458         dlon = lon [..., jpj//3, 1].copy() - lon [..., jpj//3, 0].copy() 
    459         lon1D = np.linspace ( start=lon0, stop=lon0+360.+2*dlon, num=jpi ) 
     524        jj = np.argmin (np.abs (np.float64 (plat[...,:, 0]))) 
     525 
     526    return jj 
     527 
     528def lon1d (plon, plat=None) : 
     529    '''Returns 1D longitude for simple plots. 
     530 
     531    plon : longitudes of the grid 
     532    plat (optionnal) : latitudes of the grid 
     533    ''' 
     534    mmath = __mmath__ (plon) 
     535    jpj, jpi  = plon.shape [-2:] 
     536    if np.max (plat) : 
     537        je    = jeq (plat) 
     538        lon0 = plon [..., je, 0].copy() 
     539        dlon = plon [..., je, 1].copy() - plon [..., je, 0].copy() 
     540        lon_1d = np.linspace ( start=lon0, stop=lon0+360.+2*dlon, num=jpi ) 
     541    else : 
     542        lon0 = plon [..., jpj//3, 0].copy() 
     543        dlon = plon [..., jpj//3, 1].copy() - plon [..., jpj//3, 0].copy() 
     544        lon_1d = np.linspace ( start=lon0, stop=lon0+360.+2*dlon, num=jpi ) 
    460545 
    461546    #start = np.argmax (np.abs (np.diff (lon1D, axis=-1)) > 180.0, axis=-1) 
     
    463548 
    464549    if mmath == xr : 
    465         lon1D = xr.DataArray( lon1D, dims=('lon',), coords=(lon1D,)) 
    466         lon1D.attrs = lon.attrs 
    467         lon1D.attrs['units']         = 'degrees_east' 
    468         lon1D.attrs['standard_name'] = 'longitude' 
    469         lon1D.attrs['long_name :']   = 'Longitude' 
    470          
    471     return lon1D 
    472  
    473 def latreg (lat, diff=0.1) : 
    474     ''' 
    475     Returns maximum j index where gridlines are along latitudes in the northern hemisphere 
    476      
     550        lon_1d = xr.DataArray( lon_1d, dims=('lon',), coords=(lon_1d,)) 
     551        lon_1d.attrs.update (plon.attrs) 
     552        lon_1d.attrs['units']         = 'degrees_east' 
     553        lon_1d.attrs['standard_name'] = 'longitude' 
     554        lon_1d.attrs['long_name :']   = 'Longitude' 
     555 
     556    return lon_1d 
     557 
     558def latreg (plat, diff=0.1) : 
     559    '''Returns maximum j index where gridlines are along latitudes 
     560    in the northern hemisphere 
     561 
    477562    lat : latitudes of the grid (2D) 
    478563    diff [optional] : tolerance 
    479564    ''' 
    480     mmath = __mmath__ (lat) 
    481     if diff == None : 
    482         dy   = np.float64 (np.mean (np.abs (lat - np.roll (lat,shift=1,axis=-2, roll_coords=False)))) 
     565    #mmath = __mmath__ (plat) 
     566    if diff is None : 
     567        dy = np.float64 (np.mean (np.abs (plat - 
     568                        np.roll (plat,shift=1,axis=-2, roll_coords=False)))) 
    483569        print ( f'{dy=}' ) 
    484570        diff = dy/100. 
    485571 
    486     je     = jeq (lat) 
    487     jreg   = np.where (lat[...,je:,:].max(axis=-1) - lat[...,je:,:].min(axis=-1)< diff)[-1][-1] + je 
    488     latreg = np.float64 (lat[...,jreg,:].mean(axis=-1)) 
    489     JREG   = jreg 
    490  
    491     return jreg, latreg 
    492  
    493 def lat1D (lat) : 
    494     ''' 
    495     Returns 1D latitudes for zonal means and simple plots. 
    496  
    497     lat : latitudes of the grid (2D) 
    498     ''' 
    499     mmath = __mmath__ (lat) 
    500     jpj, jpi = lat.shape[-2:] 
    501  
    502     dy     = np.float64 (np.mean (np.abs (lat - np.roll (lat, shift=1,axis=-2)))) 
    503     je     = jeq (lat) 
    504     lat_eq = np.float64 (lat[...,je,:].mean(axis=-1)) 
    505       
    506     jreg, lat_reg = latreg (lat) 
    507     lat_ave = np.mean (lat, axis=-1) 
    508  
    509     #print ( f'{dy=} {jpj=} {je=} {lat_eq=} {jreg=} ' ) 
    510      
    511     if (np.abs (lat_eq) < dy/100.) : # T, U or W grid 
    512         if jpj-1 > jreg : dys = (90.-lat_reg) / (jpj-jreg-1)*0.5 
    513         else            : dys = (90.-lat_reg) / 2.0 
    514         yrange = (90.-dys-lat_reg) 
     572    je     = jeq (plat) 
     573    jreg   = np.where (plat[...,je:,:].max(axis=-1) - 
     574                       plat[...,je:,:].min(axis=-1)< diff)[-1][-1] + je 
     575    lareg  = np.float64 (plat[...,jreg,:].mean(axis=-1)) 
     576 
     577    return jreg, lareg 
     578 
     579def lat1d (plat) : 
     580    '''Returns 1D latitudes for zonal means and simple plots. 
     581 
     582    plat : latitudes of the grid (2D) 
     583    ''' 
     584    mmath = __mmath__ (plat) 
     585    iy = __find_axis__ (plat, 'y')[-1] 
     586    jpj = plat.shape[iy] 
     587 
     588    dy     = np.float64 (np.mean (np.abs (plat - np.roll (plat, shift=1,axis=-2)))) 
     589    je     = jeq (plat) 
     590    lat_eq = np.float64 (plat[...,je,:].mean(axis=-1)) 
     591 
     592    jreg, lat_reg = latreg (plat) 
     593    lat_ave = np.mean (plat, axis=-1) 
     594 
     595    if np.abs (lat_eq) < dy/100. : # T, U or W grid 
     596        if jpj-1 > jreg : 
     597            dys = (90.-lat_reg) / (jpj-jreg-1)*0.5 
     598        else            : 
     599            dys = (90.-lat_reg) / 2.0 
     600        yrange = 90.-dys-lat_reg 
    515601    else                           :  # V or F grid 
    516602        yrange = 90.-lat_reg 
    517603 
    518604    if jpj-1 > jreg : 
    519         lat1D = mmath.where (lat_ave<lat_reg, lat_ave, lat_reg + yrange * (np.arange(jpj)-jreg)/(jpj-jreg-1) ) 
     605        lat_1d = mmath.where (lat_ave<lat_reg, 
     606                 lat_ave, 
     607                 lat_reg + yrange * (np.arange(jpj)-jreg)/(jpj-jreg-1) ) 
    520608    else : 
    521         lat1D = lat_ave 
    522     lat1D[-1] = 90.0 
     609        lat_1d = lat_ave 
     610    lat_1d[-1] = 90.0 
    523611 
    524612    if mmath == xr : 
    525         lat1D = xr.DataArray( lat1D.values, dims=('lat',), coords=(lat1D,)) 
    526         lat1D.attrs = lat.attrs 
    527         lat1D.attrs ['units']         = 'degrees_north' 
    528         lat1D.attrs ['standard_name'] = 'latitude' 
    529         lat1D.attrs ['long_name :']   = 'Latitude' 
    530          
    531     return lat1D 
    532  
    533 def latlon1D (lat, lon) : 
    534     ''' 
    535     Returns simple latitude and longitude (1D) for simple plots. 
    536  
    537     lat, lon : latitudes and longitudes of the grid (2D) 
    538     ''' 
    539     return lat1D (lat),  lon1D (lon, lat) 
     613        lat_1d = xr.DataArray( lat_1d.values, dims=('lat',), coords=(lat_1d,)) 
     614        lat_1d.attrs.update (plat.attrs) 
     615        lat_1d.attrs ['units']         = 'degrees_north' 
     616        lat_1d.attrs ['standard_name'] = 'latitude' 
     617        lat_1d.attrs ['long_name :']   = 'Latitude' 
     618 
     619    return lat_1d 
     620 
     621def latlon1d (plat, plon) : 
     622    '''Returns simple latitude and longitude (1D) for simple plots. 
     623 
     624    plat, plon : latitudes and longitudes of the grid (2D) 
     625    ''' 
     626    return lat1d (plat),  lon1d (plon, plat) 
     627 
     628def ff (plat) : 
     629    '''Returns Coriolis factor 
     630    ''' 
     631    zff   = np.sin (RAD * plat) * OMEGA 
     632    return zff 
     633 
     634def beta (plat) : 
     635    '''Return Beta factor (derivative of Coriolis factor) 
     636    ''' 
     637    zbeta = np.cos (RAD * plat) * OMEGA / RA 
     638    return zbeta 
    540639 
    541640def mask_lonlat (ptab, x0, x1, y0, y1, lon, lat, sval=np.nan) : 
     641    '''Returns masked values outside a lat/lon box 
     642    ''' 
    542643    mmath = __mmath__ (ptab) 
    543     try : 
     644    if mmath == xr : 
    544645        lon = lon.copy().to_masked_array() 
    545646        lat = lat.copy().to_masked_array() 
    546     except : pass 
    547              
    548     mask = np.logical_and (np.logical_and(lat>y0, lat<y1),  
    549             np.logical_or (np.logical_or (np.logical_and(lon>x0, lon<x1), np.logical_and(lon+360>x0, lon+360<x1)), 
    550                                       np.logical_and(lon-360>x0, lon-360<x1))) 
    551     tab = mmath.where (mask, ptab, np.nan) 
    552      
     647 
     648    mask = np.logical_and (np.logical_and(lat>y0, lat<y1), 
     649            np.logical_or (np.logical_or ( 
     650                np.logical_and(lon>x0, lon<x1), 
     651                np.logical_and(lon+360>x0, lon+360<x1)), 
     652                np.logical_and(lon-360>x0, lon-360<x1))) 
     653    tab = mmath.where (mask, ptab, sval) 
     654 
    553655    return tab 
    554656 
    555 def extend (tab, Lon=False, jplus=25, jpi=None, nperio=4) : 
    556     ''' 
    557     Returns extended field eastward to have better plots, and box average crossing the boundary 
     657def extend (ptab, blon=False, jplus=25, jpi=None, nperio=4) : 
     658    '''Returns extended field eastward to have better plots, 
     659    and box average crossing the boundary 
     660 
    558661    Works only for xarray and numpy data (?) 
    559  
    560     Useful for vertical sections in OCE and ATM. 
    561  
    562     tab : field to extend. 
    563     Lon : (optional, default=False) : if True, add 360 in the extended parts of the field 
    564     jpi : normal longitude dimension of the field. exrtend does nothing it the actual 
    565         size of the field != jpi (avoid to extend several times) 
    566     jplus (optional, default=25) : number of points added on the east side of the field 
    567      
    568     ''' 
    569     mmath = __mmath__ (tab) 
    570      
    571     if tab.shape[-1] == 1 : extend = tab 
     662    Useful for plotting vertical sections in OCE and ATM. 
     663 
     664    ptab : field to extend. 
     665    blon  : (optional, default=False) : if True, add 360 in the extended 
     666          parts of the field 
     667    jpi   : normal longitude dimension of the field. extend does nothing 
     668          if the actual size of the field != jpi 
     669          (avoid to extend several times in notebooks) 
     670    jplus (optional, default=25) : number of points added on 
     671          the east side of the field 
     672 
     673    ''' 
     674    mmath = __mmath__ (ptab) 
     675 
     676    if ptab.shape[-1] == 1 : 
     677        tabex = ptab 
    572678 
    573679    else : 
    574         if jpi == None : jpi = tab.shape[-1] 
    575  
    576         if Lon : xplus = -360.0 
    577         else   : xplus =    0.0 
    578  
    579         if tab.shape[-1] > jpi : 
    580             extend = tab 
     680        if jpi is None : 
     681            jpi = ptab.shape[-1] 
     682 
     683        if blon : 
     684            xplus = -360.0 
     685        else   : 
     686            xplus =    0.0 
     687 
     688        if ptab.shape[-1] > jpi : 
     689            tabex = ptab 
    581690        else : 
    582             if nperio == 0 or nperio == 4.2 : 
    583                 istart = 0 ; le=jpi+1 ; la=0 
     691            if nperio in [ 0, 4.2 ] : 
     692                istart, le, la = 0, jpi+1, 0 
    584693            if nperio == 1 : 
    585                 istart = 0 ; le=jpi+1 ; la=0 
    586             if nperio == 4 or nperio == 6 : # OPA case with two halo points for periodicity 
    587                 istart = 1 ; le=jpi-2 ; la=1  # Perfect, except at the pole that should be masked by lbc_plot 
    588             
     694                istart, le, la = 0, jpi+1, 0 
     695            if nperio in [4, 6] : # OPA case with two halo points for periodicity 
     696                # Perfect, except at the pole that should be masked by lbc_plot 
     697                istart, le, la = 1, jpi-2, 1 
    589698            if mmath == xr : 
    590                 extend = np.concatenate ((tab.values[..., istart   :istart+le+1    ] + xplus, 
    591                                           tab.values[..., istart+la:istart+la+jplus]         ), axis=-1) 
    592                 lon    = tab.dims[-1] 
     699                tabex = np.concatenate ( 
     700                     (ptab.values[..., istart   :istart+le+1    ] + xplus, 
     701                      ptab.values[..., istart+la:istart+la+jplus]         ), 
     702                      axis=-1) 
     703                lon    = ptab.dims[-1] 
    593704                new_coords = [] 
    594                 for coord in tab.dims : 
    595                     if coord == lon : new_coords.append ( np.arange( extend.shape[-1])) 
    596                     else            : new_coords.append ( tab.coords[coord].values) 
    597                 extend = xr.DataArray ( extend, dims=tab.dims, coords=new_coords ) 
    598             else :  
    599                 extend = np.concatenate ((tab [..., istart   :istart+le+1    ] + xplus, 
    600                                           tab [..., istart+la:istart+la+jplus]          ), axis=-1) 
    601     return extend 
    602  
    603 def orca2reg (ff, lat_name='nav_lat', lon_name='nav_lon', y_name='y', x_name='x') : 
    604     ''' 
    605     Assign an ORCA dataset on a regular grid. 
     705                for coord in ptab.dims : 
     706                    if coord == lon : 
     707                        new_coords.append ( np.arange( tabex.shape[-1])) 
     708                    else            : 
     709                        new_coords.append ( ptab.coords[coord].values) 
     710                tabex = xr.DataArray ( tabex, dims=ptab.dims, 
     711                                           coords=new_coords ) 
     712            else : 
     713                tabex = np.concatenate ( 
     714                    (ptab [..., istart   :istart+le+1    ] + xplus, 
     715                     ptab [..., istart+la:istart+la+jplus]          ), 
     716                     axis=-1) 
     717    return tabex 
     718 
     719def orca2reg (dd, lat_name='nav_lat', lon_name='nav_lon', 
     720                  y_name='y', x_name='x') : 
     721    '''Assign an ORCA dataset on a regular grid. 
     722 
    606723    For use in the tropical region. 
    607      
    608     Inputs :  
     724    Inputs : 
    609725      ff : xarray dataset 
    610726      lat_name, lon_name : name of latitude and longitude 2D field in ff 
    611727      y_name, x_name     : namex of dimensions in ff 
    612        
     728 
    613729      Returns : xarray dataset with rectangular grid. Incorrect above 20°N 
    614730    ''' 
    615731    # Compute 1D longitude and latitude 
    616     (lat, lon) = latlon1D (ff[lat_name], ff[lon_name]) 
    617  
     732    (zlat, zlon) = latlon1d ( dd[lat_name], dd[lon_name]) 
     733 
     734    zdd = dd 
    618735    # Assign lon and lat as dimensions of the dataset 
    619     if y_name in ff.dims :  
    620         lat = xr.DataArray (lat, coords=[lat,], dims=['lat',])      
    621         ff  = ff.rename_dims ({y_name: "lat",}).assign_coords (lat=lat) 
    622     if x_name in ff.dims : 
    623         lon = xr.DataArray (lon, coords=[lon,], dims=['lon',]) 
    624         ff  = ff.rename_dims ({x_name: "lon",}).assign_coords (lon=lon) 
     736    if y_name in zdd.dims : 
     737        zlat = xr.DataArray (zlat, coords=[zlat,], dims=['lat',]) 
     738        zdd  = zdd.rename_dims ({y_name: "lat",}).assign_coords (lat=zlat) 
     739    if x_name in zdd.dims : 
     740        zlon = xr.DataArray (zlon, coords=[zlon,], dims=['lon',]) 
     741        zdd  = zdd.rename_dims ({x_name: "lon",}).assign_coords (lon=zlon) 
    625742    # Force dimensions to be in the right order 
    626743    coord_order = ['lat', 'lon'] 
    627744    for dim in [ 'depthw', 'depthv', 'depthu', 'deptht', 'depth', 'z', 
    628                  'time_counter', 'time', 'tbnds',  
     745                 'time_counter', 'time', 'tbnds', 
    629746                 'bnds', 'axis_nbounds', 'two2', 'two1', 'two', 'four',] : 
    630         if dim in ff.dims : coord_order.insert (0, dim) 
    631          
    632     ff = ff.transpose (*coord_order) 
    633     return ff 
     747        if dim in zdd.dims : 
     748            coord_order.insert (0, dim) 
     749 
     750    zdd = zdd.transpose (*coord_order) 
     751    return zdd 
    634752 
    635753def lbc_init (ptab, nperio=None) : 
    636     ''' 
    637     Prepare for all lbc calls 
    638      
     754    '''Prepare for all lbc calls 
     755 
    639756    Set periodicity on input field 
    640757    nperio    : Type of periodicity 
     
    648765    See NEMO documentation for further details 
    649766    ''' 
    650     jpi = None ; jpj = None 
    651     ix, ax = __findAxis__ (ptab, 'x') 
    652     jy, ay = __findAxis__ (ptab, 'y') 
    653     if ax : jpi = ptab.shape[ix] 
    654     if ay : jpj = ptab.shape[jy] 
    655          
    656     if nperio == None : nperio = __guessNperio__ (jpj, jpi, nperio) 
    657      
    658     if nperio not in nperio_valid_range : 
    659         raise Exception ( f'{nperio=} is not in the valid range {nperio_valid_range}' ) 
     767    jpi, jpj = None, None 
     768    ax, ix = __find_axis__ (ptab, 'x') 
     769    ay, jy = __find_axis__ (ptab, 'y') 
     770    if ax : 
     771        jpi = ptab.shape[ix] 
     772    if ay : 
     773        jpj = ptab.shape[jy] 
     774 
     775    if nperio is None : 
     776        nperio = __guess_nperio__ (jpj, jpi, nperio) 
     777 
     778    if nperio not in NPERIO_VALID_RANGE : 
     779        raise AttributeError ( f'{nperio=} is not in the valid range {NPERIO_VALID_RANGE}' ) 
    660780 
    661781    return jpj, jpi, nperio 
    662          
    663 def lbc (ptab, nperio=None, cd_type='T', psgn=1.0, nemo_4U_bug=False) : 
    664     ''' 
    665     Set periodicity on input field 
     782 
     783def lbc (ptab, nperio=None, cd_type='T', psgn=1.0, nemo_4u_bug=False) : 
     784    '''Set periodicity on input field 
     785 
    666786    ptab      : Input array (works for rank 2 at least : ptab[...., lat, lon]) 
    667787    nperio    : Type of periodicity 
    668788    cd_type   : Grid specification : T, U, V or F 
    669789    psgn      : For change of sign for vector components (1 for scalars, -1 for vector components) 
    670      
     790 
    671791    See NEMO documentation for further details 
    672792    ''' 
    673     jpj, jpi, nperio = lbc_init (ptab, nperio) 
    674     ix, ax = __findAxis__ (ptab, 'x') 
    675     jy, ay = __findAxis__ (ptab, 'y') 
     793    jpi, nperio = lbc_init (ptab, nperio)[1:] 
     794    ax = __find_axis__ (ptab, 'x')[0] 
     795    ay = __find_axis__ (ptab, 'y')[0] 
    676796    psgn   = ptab.dtype.type (psgn) 
    677     mmath = __mmath__ (ptab) 
    678      
    679     if mmath == xr : ztab = ptab.values.copy () 
    680     else           : ztab = ptab.copy () 
    681          
    682     if ax :  
     797    mmath  = __mmath__ (ptab) 
     798 
     799    if mmath == xr : 
     800        ztab = ptab.values.copy () 
     801    else           : 
     802        ztab = ptab.copy () 
     803 
     804    if ax : 
    683805        # 
    684806        #> East-West boundary conditions 
     
    689811            ztab [..., -1] = ztab [...,  1] 
    690812 
    691         if ay :  
     813        if ay : 
    692814            # 
    693815            #> North-South boundary conditions 
     
    698820                    ztab [..., -1, 0        ] = psgn * ztab [..., -3, 2            ] 
    699821                    ztab [..., -2, jpi//2:  ] = psgn * ztab [..., -2, jpi//2:0:-1  ] 
    700                      
     822 
    701823                if cd_type == 'U' : 
    702                     ztab [..., -1, 0:-1     ] = psgn * ztab [..., -3, -1:0:-1      ]        
     824                    ztab [..., -1, 0:-1     ] = psgn * ztab [..., -3, -1:0:-1      ] 
    703825                    ztab [..., -1,  0       ] = psgn * ztab [..., -3,  1           ] 
    704826                    ztab [..., -1, -1       ] = psgn * ztab [..., -3, -2           ] 
    705                      
    706                     if nemo_4U_bug : 
     827 
     828                    if nemo_4u_bug : 
    707829                        ztab [..., -2, jpi//2+1:-1] = psgn * ztab [..., -2, jpi//2-2:0:-1] 
    708830                        ztab [..., -2, jpi//2-1   ] = psgn * ztab [..., -2, jpi//2       ] 
    709831                    else : 
    710832                        ztab [..., -2, jpi//2-1:-1] = psgn * ztab [..., -2, jpi//2:0:-1] 
    711                          
    712                 if cd_type == 'V' :  
     833 
     834                if cd_type == 'V' : 
    713835                    ztab [..., -2, 1:       ] = psgn * ztab [..., -3, jpi-1:0:-1   ] 
    714                     ztab [..., -1, 1:       ] = psgn * ztab [..., -4, -1:0:-1      ]    
     836                    ztab [..., -1, 1:       ] = psgn * ztab [..., -4, -1:0:-1      ] 
    715837                    ztab [..., -1, 0        ] = psgn * ztab [..., -4, 2            ] 
    716                      
     838 
    717839                if cd_type == 'F' : 
    718840                    ztab [..., -2, 0:-1     ] = psgn * ztab [..., -3, -1:0:-1      ] 
     
    720842                    ztab [..., -1,  0       ] = psgn * ztab [..., -4,  1           ] 
    721843                    ztab [..., -1, -1       ] = psgn * ztab [..., -4, -2           ] 
    722                  
     844 
    723845            if nperio in [4.2] :  # North fold T-point pivot 
    724846                if cd_type in [ 'T', 'W' ] : # T-, W-point 
    725847                    ztab [..., -1, jpi//2:  ] = psgn * ztab [..., -1, jpi//2:0:-1  ] 
    726                      
     848 
    727849                if cd_type == 'U' : 
    728850                    ztab [..., -1, jpi//2-1:-1] = psgn * ztab [..., -1, jpi//2:0:-1] 
    729                      
    730                 if cd_type == 'V' :  
     851 
     852                if cd_type == 'V' : 
    731853                    ztab [..., -1, 1:       ] = psgn * ztab [..., -2, jpi-1:0:-1   ] 
    732                      
     854 
    733855                if cd_type == 'F' : 
    734856                    ztab [..., -1, 0:-1     ] = psgn * ztab [..., -2, -1:0:-1      ] 
    735                  
    736             if nperio in [5, 6] :            #  North fold F-point pivot   
     857 
     858            if nperio in [5, 6] :            #  North fold F-point pivot 
    737859                if cd_type in ['T', 'W']  : 
    738860                    ztab [..., -1, 0:       ] = psgn * ztab [..., -2, -1::-1       ] 
    739                      
     861 
    740862                if cd_type == 'U' : 
    741                     ztab [..., -1, 0:-1     ] = psgn * ztab [..., -2, -2::-1       ]        
     863                    ztab [..., -1, 0:-1     ] = psgn * ztab [..., -2, -2::-1       ] 
    742864                    ztab [..., -1, -1       ] = psgn * ztab [..., -2, 0            ] # Bug ? 
    743                      
     865 
    744866                if cd_type == 'V' : 
    745867                    ztab [..., -1, 0:       ] = psgn * ztab [..., -3, -1::-1       ] 
    746868                    ztab [..., -2, jpi//2:  ] = psgn * ztab [..., -2, jpi//2-1::-1 ] 
    747                      
     869 
    748870                if cd_type == 'F' : 
    749871                    ztab [..., -1, 0:-1     ] = psgn * ztab [..., -3, -2::-1       ] 
    750872                    ztab [..., -1, -1       ] = psgn * ztab [..., -3, 0            ] 
    751873                    ztab [..., -2, jpi//2:-1] = psgn * ztab [..., -2, jpi//2-2::-1 ] 
    752                      
     874 
    753875            # 
    754876            #> East-West boundary conditions 
     
    762884        ztab = xr.DataArray ( ztab, dims=ptab.dims, coords=ptab.coords ) 
    763885        ztab.attrs = ptab.attrs 
    764          
     886 
    765887    return ztab 
    766888 
    767889def lbc_mask (ptab, nperio=None, cd_type='T', sval=np.nan) : 
    768     # 
    769     ''' 
    770     Mask fields on duplicated points 
     890    '''Mask fields on duplicated points 
     891 
    771892    ptab      : Input array. Rank 2 at least : ptab [...., lat, lon] 
    772893    nperio    : Type of periodicity 
    773894    cd_type   : Grid specification : T, U, V or F 
    774      
     895 
    775896    See NEMO documentation for further details 
    776897    ''' 
    777     jpj, jpi, nperio = lbc_init (ptab, nperio) 
    778     ix, ax = __findAxis__ (ptab, 'x') 
    779     jy, ay = __findAxis__ (ptab, 'y') 
     898    jpi, nperio = lbc_init (ptab, nperio)[1:] 
     899    ax = __find_axis__ (ptab, 'x')[0] 
     900    ay = __find_axis__ (ptab, 'y')[0] 
    780901    ztab = ptab.copy () 
    781902 
    782     if ax :  
     903    if ax : 
    783904        # 
    784905        #> East-West boundary conditions 
     
    789910            ztab [..., -1] = sval 
    790911 
    791         if ay :  
     912        if ay : 
    792913            # 
    793914            #> South (in which nperio cases ?) 
     
    795916            if nperio in [1, 3, 4, 5, 6] : 
    796917                ztab [..., 0, :] = sval 
    797          
     918 
    798919            # 
    799920            #> North-South boundary conditions 
     
    803924                    ztab [..., -1,  :         ] = sval 
    804925                    ztab [..., -2, :jpi//2  ] = sval 
    805                  
     926 
    806927                if cd_type == 'U' : 
    807                     ztab [..., -1,  :         ] = sval   
     928                    ztab [..., -1,  :         ] = sval 
    808929                    ztab [..., -2, jpi//2+1:  ] = sval 
    809                  
     930 
    810931                if cd_type == 'V' : 
    811932                    ztab [..., -2, :       ] = sval 
    812                     ztab [..., -1, :       ] = sval    
     933                    ztab [..., -1, :       ] = sval 
    813934 
    814935                if cd_type == 'F' : 
     
    823944                    ztab [..., -1, jpi//2-1:-1] = sval 
    824945 
    825                 if cd_type == 'V' :  
     946                if cd_type == 'V' : 
    826947                    ztab [..., -1, 1:       ] = sval 
    827948 
     
    834955 
    835956                if cd_type == 'U' : 
    836                     ztab [..., -1, 0:-1     ] = sval        
     957                    ztab [..., -1, 0:-1     ] = sval 
    837958                    ztab [..., -1, -1       ] = sval 
    838959 
     
    849970 
    850971def lbc_plot (ptab, nperio=None, cd_type='T', psgn=1.0, sval=np.nan) : 
    851     ''' 
    852     Set periodicity on input field, adapted for plotting for any cartopy projection 
     972    '''Set periodicity on input field, for plotting for any cartopy projection 
     973 
     974      Points at the north fold are masked 
     975      Points for zonal periodicity are kept 
    853976    ptab      : Input array. Rank 2 at least : ptab[...., lat, lon] 
    854977    nperio    : Type of periodicity 
    855978    cd_type   : Grid specification : T, U, V or F 
    856     psgn      : For change of sign for vector components (1 for scalars, -1 for vector components) 
    857      
     979    psgn      : For change of sign for vector components 
     980           (1 for scalars, -1 for vector components) 
     981 
    858982    See NEMO documentation for further details 
    859983    ''' 
    860     jpj, jpi, nperio = lbc_init (ptab, nperio) 
    861     ix, ax = __findAxis__ (ptab, 'x') 
    862     jy, ay = __findAxis__ (ptab, 'y') 
     984    jpi, nperio = lbc_init (ptab, nperio)[1:] 
     985    ax = __find_axis__ (ptab, 'x')[0] 
     986    ay = __find_axis__ (ptab, 'y')[0] 
    863987    psgn   = ptab.dtype.type (psgn) 
    864988    ztab   = ptab.copy () 
    865989 
    866     if ax :  
     990    if ax : 
    867991        # 
    868992        #> East-West boundary conditions 
     
    873997            ztab [..., :, -1] = ztab [..., :,  1] 
    874998 
    875         if ay :  
     999        if ay : 
    8761000            #> Masks south 
    8771001            # ------------ 
    878             if nperio in [4, 6] : ztab [..., 0, : ] = sval 
     1002            if nperio in [4, 6] : 
     1003                ztab [..., 0, : ] = sval 
    8791004 
    8801005            # 
     
    8891014                    ztab [..., -1, : ] = sval 
    8901015 
    891                 if cd_type == 'V' :  
     1016                if cd_type == 'V' : 
    8921017                    ztab [..., -2, : ] = sval 
    8931018                    ztab [..., -1, : ] = sval 
     
    9041029                    ztab [..., -1, jpi//2-1:-1] = sval 
    9051030 
    906                 if cd_type == 'V' :  
     1031                if cd_type == 'V' : 
    9071032                    ztab [..., -1, 1:       ] = sval 
    9081033 
     
    9101035                    ztab [..., -1, 0:-1     ] = sval 
    9111036 
    912             if nperio in [5, 6] :            #  North fold F-point pivot   
     1037            if nperio in [5, 6] :            #  North fold F-point pivot 
    9131038                if cd_type in ['T', 'W']  : 
    9141039                    ztab [..., -1, : ] = sval 
    9151040 
    9161041                if cd_type == 'U' : 
    917                     ztab [..., -1, : ] = sval       
     1042                    ztab [..., -1, : ] = sval 
    9181043 
    9191044                if cd_type == 'V' : 
     
    9271052    return ztab 
    9281053 
    929 def lbc_add (ptab, nperio=None, cd_type=None, psgn=1, sval=None) : 
    930     ''' 
    931     Handles NEMO domain changes between NEMO 4.0 to NEMO 4.2 
    932       Peridodicity halo has been removed 
     1054def lbc_add (ptab, nperio=None, cd_type=None, psgn=1) : 
     1055    '''Handles NEMO domain changes between NEMO 4.0 to NEMO 4.2 
     1056 
     1057    Periodicity and north fold halos has been removed in NEMO 4.2 
    9331058    This routine adds the halos if needed 
    9341059 
    935     ptab      : Input array (works  
     1060    ptab      : Input array (works 
    9361061      rank 2 at least : ptab[...., lat, lon] 
    9371062    nperio    : Type of periodicity 
    938   
     1063 
    9391064    See NEMO documentation for further details 
    9401065    ''' 
    941     mmath = __mmath__ (ptab)  
    942     jpj, jpi, nperio = lbc_init (ptab, nperio) 
     1066    mmath = __mmath__ (ptab) 
     1067    nperio = lbc_init (ptab, nperio)[-1] 
    9431068    lshape = get_shape (ptab) 
    944     ix, ax = __findAxis__ (ptab, 'x') 
    945     jy, ay = __findAxis__ (ptab, 'y') 
     1069    ix = __find_axis__ (ptab, 'x')[-1] 
     1070    jy = __find_axis__ (ptab, 'y')[-1] 
    9461071 
    9471072    t_shape = np.array (ptab.shape) 
    9481073 
    949     if nperio == 4.2 or nperio == 6.2 : 
    950        
     1074    if nperio in [4.2, 6.2] : 
     1075 
    9511076        ext_shape = t_shape.copy() 
    952         if 'X' in lshape : ext_shape[ix] = ext_shape[ix] + 2 
    953         if 'Y' in lshape : ext_shape[jy] = ext_shape[jy] + 1 
     1077        if 'X' in lshape : 
     1078            ext_shape[ix] = ext_shape[ix] + 2 
     1079        if 'Y' in lshape : 
     1080            ext_shape[jy] = ext_shape[jy] + 1 
    9541081 
    9551082        if mmath == xr : 
     
    9581085                ptab_ext.values[..., :-1, 1:-1] = ptab.values.copy () 
    9591086            else : 
    960                 if 'X' in lshape     : ptab_ext.values[...,      1:-1] = ptab.values.copy () 
    961                 if 'Y' in lshape     : ptab_ext.values[..., :-1      ] = ptab.values.copy () 
     1087                if 'X' in lshape     : 
     1088                    ptab_ext.values[...,      1:-1] = ptab.values.copy () 
     1089                if 'Y' in lshape     : 
     1090                    ptab_ext.values[..., :-1      ] = ptab.values.copy () 
    9621091        else           : 
    9631092            ptab_ext =               np.zeros (ext_shape) 
    964             if 'X' in lshape and 'Y' in lshape : ptab_ext       [..., :-1, 1:-1] = ptab.copy () 
     1093            if 'X' in lshape and 'Y' in lshape : 
     1094                ptab_ext       [..., :-1, 1:-1] = ptab.copy () 
    9651095            else : 
    966                 if 'X' in lshape     : ptab_ext       [...,      1:-1] = ptab.copy () 
    967                 if 'Y' in lshape     : ptab_ext       [..., :-1      ] = ptab.copy ()             
    968  
    969         if nperio == 4.2 : ptab_ext = lbc (ptab_ext, nperio=4, cd_type=cd_type, psgn=psgn) 
    970         if nperio == 6.2 : ptab_ext = lbc (ptab_ext, nperio=6, cd_type=cd_type, psgn=psgn) 
    971          
     1096                if 'X' in lshape     : 
     1097                    ptab_ext       [...,      1:-1] = ptab.copy () 
     1098                if 'Y' in lshape     : 
     1099                    ptab_ext       [..., :-1      ] = ptab.copy () 
     1100 
     1101        if nperio == 4.2 : 
     1102            ptab_ext = lbc (ptab_ext, nperio=4, cd_type=cd_type, psgn=psgn) 
     1103        if nperio == 6.2 : 
     1104            ptab_ext = lbc (ptab_ext, nperio=6, cd_type=cd_type, psgn=psgn) 
     1105 
    9721106        if mmath == xr : 
    9731107            ptab_ext.attrs = ptab.attrs 
    974             kz, az = __findAxis__ (ptab, 'z') 
    975             it, at = __findAxis__ (ptab, 't') 
    976             if az : ptab_ext = ptab_ext.assign_coords ( {az:ptab.coords[az]} ) 
    977             if at : ptab_ext = ptab_ext.assign_coords ( {at:ptab.coords[at]} ) 
     1108            az = __find_axis__ (ptab, 'z')[0] 
     1109            at = __find_axis__ (ptab, 't')[0] 
     1110            if az : 
     1111                ptab_ext = ptab_ext.assign_coords ( {az:ptab.coords[az]} ) 
     1112            if at : 
     1113                ptab_ext = ptab_ext.assign_coords ( {at:ptab.coords[at]} ) 
    9781114 
    9791115    else : ptab_ext = lbc (ptab, nperio=nperio, cd_type=cd_type, psgn=psgn) 
    980          
     1116 
    9811117    return ptab_ext 
    9821118 
    9831119def lbc_del (ptab, nperio=None, cd_type='T', psgn=1) : 
    984     ''' 
    985     Handles NEMO domain changes between NEMO 4.0 to NEMO 4.2 
    986       Periodicity halo has been removed 
     1120    '''Handles NEMO domain changes between NEMO 4.0 to NEMO 4.2 
     1121 
     1122    Periodicity and north fold halos has been removed in NEMO 4.2 
    9871123    This routine removes the halos if needed 
    9881124 
    989     ptab      : Input array (works  
     1125    ptab      : Input array (works 
    9901126      rank 2 at least : ptab[...., lat, lon] 
    9911127    nperio    : Type of periodicity 
    992   
     1128 
    9931129    See NEMO documentation for further details 
    9941130    ''' 
    995     jpj, jpi, nperio = lbc_init (ptab, nperio) 
    996     lshape = get_shape (ptab) 
    997     ix, ax = __findAxis__ (ptab, 'x') 
    998     jy, ay = __findAxis__ (ptab, 'y') 
    999  
    1000     if nperio == 4.2 or nperio == 6.2 : 
    1001         if ax or ay :  
    1002             if ax and ay :  
    1003                 return lbc (ptab[..., :-1, 1:-1], nperio=nperio, cd_type=cd_type, psgn=psgn) 
    1004             else :  
     1131    nperio = lbc_init (ptab, nperio)[-1] 
     1132    #lshape = get_shape (ptab) 
     1133    ax = __find_axis__ (ptab, 'x')[0] 
     1134    ay = __find_axis__ (ptab, 'y')[0] 
     1135 
     1136    if nperio in [4.2, 6.2] : 
     1137        if ax or ay : 
     1138            if ax and ay : 
     1139                ztab = lbc (ptab[..., :-1, 1:-1], 
     1140                            nperio=nperio, cd_type=cd_type, psgn=psgn) 
     1141            else : 
    10051142                if ax : 
    1006                     return lbc (ptab[...,      1:-1], nperio=nperio, cd_type=cd_type, psgn=psgn) 
     1143                    ztab = lbc (ptab[...,      1:-1], 
     1144                                nperio=nperio, cd_type=cd_type, psgn=psgn) 
    10071145                if ay : 
    1008                     return lbc (ptab[..., -1], nperio=nperio, cd_type=cd_type, psgn=psgn) 
     1146                    ztab = lbc (ptab[..., -1], 
     1147                                nperio=nperio, cd_type=cd_type, psgn=psgn) 
    10091148        else : 
    1010             return ptab 
     1149            ztab = ptab 
    10111150    else : 
    1012         return ptab 
     1151        ztab = ptab 
     1152 
     1153    return ztab 
    10131154 
    10141155def lbc_index (jj, ii, jpj, jpi, nperio=None, cd_type='T') : 
    1015     ''' 
    1016     For indexes of a NEMO point, give the corresponding point inside the util domain 
     1156    '''For indexes of a NEMO point, give the corresponding point 
     1157        inside the domain (i.e. not in the halo) 
     1158 
    10171159    jj, ii    : indexes 
    10181160    jpi, jpi  : size of domain 
    10191161    nperio    : type of periodicity 
    10201162    cd_type   : grid specification : T, U, V or F 
    1021      
     1163 
    10221164    See NEMO documentation for further details 
    10231165    ''' 
    10241166 
    1025     if nperio == None : nperio = __guessNperio__ (jpj, jpi, nperio) 
    1026      
    1027     ## For the sake of simplicity, switch to the convention of original lbc Fortran routine from NEMO 
    1028     ## : starts indexes at 1 
    1029     jy = jj + 1 ; ix = ii + 1 
     1167    if nperio is None : 
     1168        nperio = __guess_nperio__ (jpj, jpi, nperio) 
     1169 
     1170    ## For the sake of simplicity, switch to the convention of original 
     1171    ## lbc Fortran routine from NEMO : starts indexes at 1 
     1172    jy = jj + 1 
     1173    ix = ii + 1 
    10301174 
    10311175    mmath = __mmath__ (jj) 
    1032     if mmath == None : mmath=np 
     1176    if mmath is None : 
     1177        mmath=np 
    10331178 
    10341179    # 
     
    10411186 
    10421187    # 
    1043     def modIJ (cond, jy_new, ix_new) : 
     1188    def mod_ij (cond, jy_new, ix_new) : 
    10441189        jy_r = mmath.where (cond, jy_new, jy) 
    10451190        ix_r = mmath.where (cond, ix_new, ix) 
     
    10501195    if nperio in [ 3 , 4 ]  : 
    10511196        if cd_type in  [ 'T' , 'W' ] : 
    1052             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix>=2       ), jpj-2, jpi-ix+2) 
    1053             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix==1       ), jpj-1, 3       )    
    1054             (jy, ix) = modIJ (np.logical_and (jy==jpj-1, ix>=jpi//2+1), jy   , jpi-ix+2)  
     1197            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix>=2       ), jpj-2, jpi-ix+2) 
     1198            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix==1       ), jpj-1, 3       ) 
     1199            jy, ix = mod_ij (np.logical_and (jy==jpj-1, ix>=jpi//2+1), 
     1200                                  jy , jpi-ix+2) 
    10551201 
    10561202        if cd_type in [ 'U' ] : 
    1057             (jy, ix) = modIJ (np.logical_and (jy==jpj  , np.logical_and (ix>=1, ix <= jpi-1)   ), jy   , jpi-ix+1) 
    1058             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix==1  )                               , jpj-2, 2       ) 
    1059             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix==jpi)                               , jpj-2, jpi-1   ) 
    1060             (jy, ix) = modIJ (np.logical_and (jy==jpj-1, np.logical_and (ix>=jpi//2, ix<=jpi-1)), jy   , jpi-ix+1) 
    1061            
     1203            jy, ix = mod_ij (np.logical_and ( 
     1204                      jy==jpj  , 
     1205                      np.logical_and (ix>=1, ix <= jpi-1)   ), 
     1206                                         jy   , jpi-ix+1) 
     1207            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix==1  ) , jpj-2, 2       ) 
     1208            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix==jpi) , jpj-2, jpi-1   ) 
     1209            jy, ix = mod_ij (np.logical_and (jy==jpj-1, 
     1210                            np.logical_and (ix>=jpi//2, ix<=jpi-1)), jy   , jpi-ix+1) 
     1211 
    10621212        if cd_type in [ 'V' ] : 
    1063             (jy, ix) = modIJ (np.logical_and (jy==jpj-1, ix>=2  ), jpj-2, jpi-ix+2) 
    1064             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix>=2  ), jpj-3, jpi-ix+2) 
    1065             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix==1  ), jpj-3,  3      ) 
    1066              
     1213            jy, ix = mod_ij (np.logical_and (jy==jpj-1, ix>=2  ), jpj-2, jpi-ix+2) 
     1214            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix>=2  ), jpj-3, jpi-ix+2) 
     1215            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix==1  ), jpj-3,  3      ) 
     1216 
    10671217        if cd_type in [ 'F' ] : 
    1068             (jy, ix) = modIJ (np.logical_and (jy==jpj-1, ix<=jpi-1), jpj-2, jpi-ix+1) 
    1069             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix<=jpi-1), jpj-3, jpi-ix+1) 
    1070             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix==1    ), jpj-3, 2       ) 
    1071             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix==jpi  ), jpj-3, jpi-1   ) 
     1218            jy, ix = mod_ij (np.logical_and (jy==jpj-1, ix<=jpi-1), jpj-2, jpi-ix+1) 
     1219            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix<=jpi-1), jpj-3, jpi-ix+1) 
     1220            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix==1    ), jpj-3, 2       ) 
     1221            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix==jpi  ), jpj-3, jpi-1   ) 
    10721222 
    10731223    if nperio in [ 5 , 6 ] : 
    10741224        if cd_type in [ 'T' , 'W' ] :                        # T-, W-point 
    1075              (jy, ix) = modIJ (jy==jpj, jpj-1, jpi-ix+1) 
    1076   
     1225            jy, ix = mod_ij (jy==jpj, jpj-1, jpi-ix+1) 
     1226 
    10771227        if cd_type in [ 'U' ] :                              # U-point 
    1078             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix<=jpi-1   ), jpj-1, jpi-ix  ) 
    1079             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix==jpi     ), jpi-1, 1       ) 
    1080              
     1228            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix<=jpi-1   ), jpj-1, jpi-ix  ) 
     1229            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix==jpi     ), jpi-1, 1       ) 
     1230 
    10811231        if cd_type in [ 'V' ] :    # V-point 
    1082             (jy, ix) = modIJ (jy==jpj                                 , jy   , jpi-ix+1) 
    1083             (jy, ix) = modIJ (np.logical_and (jy==jpj-1, ix>=jpi//2+1), jy   , jpi-ix+1) 
    1084              
     1232            jy, ix = mod_ij (jy==jpj                                 , jy   , jpi-ix+1) 
     1233            jy, ix = mod_ij (np.logical_and (jy==jpj-1, ix>=jpi//2+1), jy   , jpi-ix+1) 
     1234 
    10851235        if cd_type in [ 'F' ] :                              # F-point 
    1086             (jy, ix) = modIJ (np.logical_and (jy==jpj  , ix<=jpi-1   ), jpj-2, jpi-ix  ) 
    1087             (jy, ix) = modIJ (np.logical_and (ix==jpj  , ix==jpi     ), jpj-2, 1       ) 
    1088             (jy, ix) = modIJ (np.logical_and (jy==jpj-1, ix>=jpi//2+1), jy   , jpi-ix  ) 
     1236            jy, ix = mod_ij (np.logical_and (jy==jpj  , ix<=jpi-1   ), jpj-2, jpi-ix  ) 
     1237            jy, ix = mod_ij (np.logical_and (ix==jpj  , ix==jpi     ), jpj-2, 1       ) 
     1238            jy, ix = mod_ij (np.logical_and (jy==jpj-1, ix>=jpi//2+1), jy   , jpi-ix  ) 
    10891239 
    10901240    ## Restore convention to Python/C : indexes start at 0 
    1091     jy += -1 ; ix += -1 
    1092  
    1093     if isinstance (jj, int) : jy = jy.item () 
    1094     if isinstance (ii, int) : ix = ix.item () 
     1241    jy += -1 
     1242    ix += -1 
     1243 
     1244    if isinstance (jj, int) : 
     1245        jy = jy.item () 
     1246    if isinstance (ii, int) : 
     1247        ix = ix.item () 
    10951248 
    10961249    return jy, ix 
    1097      
    1098 def findJI (lat_data, lon_data, lat_grid, lon_grid, mask=1.0, verbose=False, out=None) : 
    1099     ''' 
    1100     Description: seeks J,I indices of the grid point which is the closest of a given point  
     1250 
     1251def find_ji (lat_data, lon_data, lat_grid, lon_grid, mask=1.0, verbose=False, out=None) : 
     1252    ''' 
     1253    Description: seeks J,I indices of the grid point which is the closest 
     1254       of a given point 
     1255 
    11011256    Usage: go FindJI  <data latitude> <data longitude> <grid latitudes> <grid longitudes> [mask] 
    1102     <longitude fields> <latitude field> are 2D fields on J/I (Y/X) dimensions 
     1257    <grid latitudes><grid longitudes> are 2D fields on J/I (Y/X) dimensions 
    11031258    mask : if given, seek only non masked grid points (i.e with mask=1) 
    1104      
     1259 
    11051260    Example : findIJ (40, -20, nav_lat, nav_lon, mask=1.0) 
    11061261 
    11071262    Note : all longitudes and latitudes in degrees 
    1108          
     1263 
    11091264    Note : may work with 1D lon/lat (?) 
    11101265    ''' 
    11111266    # Get grid dimensions 
    1112     if len (lon_grid.shape) == 2 : (jpj, jpi) = lon_grid.shape 
    1113     else                         : jpj = len(lat_grid) ; jpi=len(lon_grid) 
    1114  
    1115     mmath = __mmath__ (lat_grid) 
    1116          
    1117     # Compute distance from the point to all grid points (in radian) 
    1118     arg      = np.sin (rad*lat_data) * np.sin (rad*lat_grid) \ 
    1119              + np.cos (rad*lat_data) * np.cos (rad*lat_grid) * np.cos(rad*(lon_data-lon_grid)) 
    1120     distance = np.arccos (arg) + 4.0*rpi*(1.0-mask) # Send masked points to 'infinite'  
     1267    if len (lon_grid.shape) == 2 : 
     1268        jpi = lon_grid.shape[-1] 
     1269    else                         : 
     1270        jpi = len(lon_grid) 
     1271 
     1272    #mmath = __mmath__ (lat_grid) 
     1273 
     1274    # Compute distance from the point to all grid points (in RADian) 
     1275    arg      = ( np.sin (RAD*lat_data) * np.sin (RAD*lat_grid) 
     1276               + np.cos (RAD*lat_data) * np.cos (RAD*lat_grid) * 
     1277                 np.cos(RAD*(lon_data-lon_grid)) ) 
     1278    # Send masked points to 'infinite' 
     1279    distance = np.arccos (arg) + 4.0*RPI*(1.0-mask) 
    11211280 
    11221281    # Truncates to alleviate some precision problem with some grids 
     
    11261285    # Compute minimum of distance, and index of minimum 
    11271286    # 
    1128     distance_min = distance.min    () 
     1287    #distance_min = distance.min    () 
    11291288    jimin        = int (distance.argmin ()) 
    1130      
    1131     # Compute 2D indices  
    1132     jmin = jimin // jpi ; imin = jimin - jmin*jpi 
    1133      
     1289 
     1290    # Compute 2D indices (Python/C flavor : starting at 0) 
     1291    jmin = jimin // jpi 
     1292    imin = jimin - jmin*jpi 
     1293 
    11341294    # Result 
    11351295    if verbose : 
    11361296        # Compute distance achieved 
    1137         mindist = distance [jmin, imin] 
    1138          
     1297        #mindist = distance [jmin, imin] 
     1298 
    11391299        # Compute azimuth 
    11401300        dlon = lon_data-lon_grid[jmin,imin] 
    1141         arg  = np.sin (rad*dlon) /  (np.cos(rad*lat_data)*np.tan(rad*lat_grid[jmin,imin]) - np.sin(rad*lat_data)*np.cos(rad*dlon)) 
    1142         azimuth = dar*np.arctan (arg) 
    1143         print ( f'I={imin:d} J={jmin:d} - Data:{lat_data:5.1f}°N {lon_data:5.1f}°E - Grid:{lat_grid[jmin,imin]:4.1f}°N '   \ 
    1144             +   f'{lon_grid[jmin,imin]:4.1f}°E - Dist: {ra*distance[jmin,imin]:6.1f}km {dar*distance[jmin,imin]:5.2f}° ' \ 
    1145             +   f'- Azimuth: {rad*azimuth:3.2f}rad - {azimuth:5.1f}°' ) 
    1146  
    1147     if   out=='dict'                               : return {'x':imin, 'y':jmin} 
    1148     elif out=='array' or out=='numpy'  or out=='np': return np.array ( [jmin, imin] ) 
    1149     elif out=='xarray' or out=='xr'                : return xr.DataArray ( [jmin, imin] ) 
    1150     elif out=='list'                               : return [jmin, imin] 
    1151     elif out=='tuple'                              : return jmin, imin 
    1152     else                                           : return jmin, imin 
    1153  
    1154 def geo2en (pxx, pyy, pzz, glam, gphi) :  
    1155     ''' 
    1156     Change vector from geocentric to east/north 
     1301        arg  = np.sin (RAD*dlon) / ( 
     1302                  np.cos(RAD*lat_data)*np.tan(RAD*lat_grid[jmin,imin]) 
     1303                - np.sin(RAD*lat_data)*np.cos(RAD*dlon)) 
     1304        azimuth = DAR*np.arctan (arg) 
     1305        print ( f'I={imin:d} J={jmin:d} - Data:{lat_data:5.1f}°N {lon_data:5.1f}°E' \ 
     1306            +   f'- Grid:{lat_grid[jmin,imin]:4.1f}°N '   \ 
     1307            +   f'{lon_grid[jmin,imin]:4.1f}°E - Dist: {RA*distance[jmin,imin]:6.1f}km' \ 
     1308            +   f' {DAR*distance[jmin,imin]:5.2f}° ' \ 
     1309            +   f'- Azimuth: {RAD*azimuth:3.2f}RAD - {azimuth:5.1f}°' ) 
     1310 
     1311    if   out=='dict'                     : 
     1312        return {'x':imin, 'y':jmin} 
     1313    elif out in ['array', 'numpy', 'np'] : 
     1314        return np.array ( [jmin, imin] ) 
     1315    elif out in ['xarray', 'xr']         : 
     1316        return xr.DataArray ( [jmin, imin] ) 
     1317    elif out=='list'                     : 
     1318        return [jmin, imin] 
     1319    elif out=='tuple'                    : 
     1320        return jmin, imin 
     1321    else                                 : 
     1322        return jmin, imin 
     1323 
     1324def curl (tx, ty, e1f, e2f, nperio=None) : 
     1325    '''Returns curl of a vector field 
     1326    ''' 
     1327    ax = __find_axis__ (tx, 'x')[0] 
     1328    ay = __find_axis__ (ty, 'y')[0] 
     1329 
     1330    tx_0  = lbc_add (tx , nperio=nperio, cd_type='U', psgn=-1) 
     1331    ty_0  = lbc_add (ty , nperio=nperio, cd_type='V', psgn=-1) 
     1332    e1f_0 = lbc_add (e1f, nperio=nperio, cd_type='U', psgn=-1) 
     1333    e2f_0 = lbc_add (e2f, nperio=nperio, cd_type='V', psgn=-1) 
     1334 
     1335    tx_1  = tx_0.roll ( {ay:-1} ) 
     1336    ty_1  = ty_0.roll ( {ax:-1} ) 
     1337    tx_1  = lbc (tx_1, nperio=nperio, cd_type='U', psgn=-1) 
     1338    ty_1  = lbc (ty_1, nperio=nperio, cd_type='V', psgn=-1) 
     1339 
     1340    zcurl = (ty_1 - ty_0)/e1f_0 - (tx_1 - tx_0)/e2f_0 
     1341 
     1342    mask = np.logical_or ( 
     1343             np.logical_or ( np.isnan(tx_0), np.isnan(tx_1)), 
     1344             np.logical_or ( np.isnan(ty_0), np.isnan(ty_1)) ) 
     1345 
     1346    zcurl = zcurl.where (np.logical_not (mask), np.nan) 
     1347 
     1348    zcurl = lbc_del (zcurl, nperio=nperio, cd_type='F', psgn=1) 
     1349    zcurl = lbc (zcurl, nperio=nperio, cd_type='F', psgn=1) 
     1350 
     1351    return zcurl 
     1352 
     1353def div (ux, uy, e1t, e2t, nperio=None) : 
     1354    '''Returns divergence of a vector field 
     1355    ''' 
     1356    ax = __find_axis__ (ux, 'x')[0] 
     1357    ay = __find_axis__ (ux, 'y')[0] 
     1358 
     1359    ux_0  = lbc_add (ux , nperio=nperio, cd_type='U', psgn=-1) 
     1360    uy_0  = lbc_add (uy , nperio=nperio, cd_type='V', psgn=-1) 
     1361    e1t_0 = lbc_add (e1t, nperio=nperio, cd_type='U', psgn=-1) 
     1362    e2t_0 = lbc_add (e2t, nperio=nperio, cd_type='V', psgn=-1) 
     1363 
     1364    ux_1 = ux_0.roll ( {ay:1} ) 
     1365    uy_1 = uy_0.roll ( {ax:1} ) 
     1366    ux_1 = lbc (ux_1, nperio=nperio, cd_type='U', psgn=-1) 
     1367    uy_1 = lbc (uy_1, nperio=nperio, cd_type='V', psgn=-1) 
     1368 
     1369    zdiv = (ux_0 - ux_1)/e2t_0 + (uy_0 - uy_1)/e1t_0 
     1370 
     1371    mask = np.logical_or ( 
     1372             np.logical_or ( np.isnan(ux_0), np.isnan(ux_1)), 
     1373             np.logical_or ( np.isnan(uy_0), np.isnan(uy_1)) ) 
     1374 
     1375    zdiv = zdiv.where (np.logical_not (mask), np.nan) 
     1376 
     1377    zdiv = lbc_del (zdiv, nperio=nperio, cd_type='T', psgn=1) 
     1378    zdiv = lbc (zdiv, nperio=nperio, cd_type='T', psgn=1) 
     1379 
     1380    return zdiv 
     1381 
     1382def geo2en (pxx, pyy, pzz, glam, gphi) : 
     1383    '''Change vector from geocentric to east/north 
    11571384 
    11581385    Inputs : 
     
    11611388    ''' 
    11621389 
    1163     gsinlon = np.sin (rad * glam) 
    1164     gcoslon = np.cos (rad * glam) 
    1165     gsinlat = np.sin (rad * gphi) 
    1166     gcoslat = np.cos (rad * gphi) 
    1167            
     1390    gsinlon = np.sin (RAD * glam) 
     1391    gcoslon = np.cos (RAD * glam) 
     1392    gsinlat = np.sin (RAD * gphi) 
     1393    gcoslat = np.cos (RAD * gphi) 
     1394 
    11681395    pte = - pxx * gsinlon            + pyy * gcoslon 
    11691396    ptn = - pxx * gcoslon * gsinlat  - pyy * gsinlon * gsinlat + pzz * gcoslat 
     
    11721399 
    11731400def en2geo (pte, ptn, glam, gphi) : 
    1174     ''' 
    1175     Change vector from east/north to geocentric 
    1176  
    1177     Inputs :  
     1401    '''Change vector from east/north to geocentric 
     1402 
     1403    Inputs : 
    11781404        pte, ptn   : eastward/northward components 
    11791405        glam, gphi : longitude and latitude of the points 
    11801406    ''' 
    1181      
    1182     gsinlon = np.sin (rad * glam) 
    1183     gcoslon = np.cos (rad * glam) 
    1184     gsinlat = np.sin (rad * gphi) 
    1185     gcoslat = np.cos (rad * gphi) 
     1407 
     1408    gsinlon = np.sin (RAD * glam) 
     1409    gcoslon = np.cos (RAD * glam) 
     1410    gsinlat = np.sin (RAD * gphi) 
     1411    gcoslat = np.cos (RAD * gphi) 
    11861412 
    11871413    pxx = - pte * gsinlon - ptn * gcoslon * gsinlat 
    11881414    pyy =   pte * gcoslon - ptn * gsinlon * gsinlat 
    11891415    pzz =   ptn * gcoslat 
    1190      
     1416 
    11911417    return pxx, pyy, pzz 
    11921418 
    11931419 
    11941420def clo_lon (lon, lon0=0., rad=False, deg=True) : 
    1195     '''Choose closest to lon0 longitude, adding or substacting 360° if needed''' 
     1421    '''Choose closest to lon0 longitude, adding/substacting 360° 
     1422    if needed 
     1423    ''' 
    11961424    mmath = __mmath__ (lon, np) 
    1197     if rad : lon_range = 2.*np.pi 
    1198     if deg : lon_range = 360. 
    1199     clo_lon = lon 
    1200     clo_lon = mmath.where (clo_lon > lon0 + lon_range*0.5, clo_lon-lon_range, clo_lon) 
    1201     clo_lon = mmath.where (clo_lon < lon0 - lon_range*0.5, clo_lon+lon_range, clo_lon) 
    1202     clo_lon = mmath.where (clo_lon > lon0 + lon_range*0.5, clo_lon-lon_range, clo_lon) 
    1203     clo_lon = mmath.where (clo_lon < lon0 - lon_range*0.5, clo_lon+lon_range, clo_lon) 
    1204     if clo_lon.shape == () : clo_lon = clo_lon.item () 
     1425    if rad : 
     1426        lon_range = 2.*np.pi 
     1427    if deg : 
     1428        lon_range = 360. 
     1429    c_lon = lon 
     1430    c_lon = mmath.where (c_lon > lon0 + lon_range*0.5, 
     1431                             c_lon-lon_range, clo_lon) 
     1432    c_lon = mmath.where (c_lon < lon0 - lon_range*0.5, 
     1433                             c_lon+lon_range, clo_lon) 
     1434    c_lon = mmath.where (c_lon > lon0 + lon_range*0.5, 
     1435                             c_lon-lon_range, clo_lon) 
     1436    c_lon = mmath.where (c_lon < lon0 - lon_range*0.5, 
     1437                             c_lon+lon_range, clo_lon) 
     1438    if c_lon.shape == () : 
     1439        c_lon = c_lon.item () 
    12051440    if mmath == xr : 
    1206         try :  
    1207             for attr in lon.attrs : clo_lon.attrs[attr] = lon.attrs[attr] 
    1208         except : 
    1209             pass 
    1210     return clo_lon 
    1211  
     1441        if lon.attrs : 
     1442            c_lon.attrs.update ( lon.attrs ) 
     1443    return c_lon 
    12121444 
    12131445def index2depth (pk, gdept_0) : 
    1214     ''' 
    1215     From index (real, continuous), get depth 
     1446    '''From index (real, continuous), get depth 
     1447 
     1448    Needed to use transforms in Matplotlib 
    12161449    ''' 
    12171450    jpk = gdept_0.shape[0] 
     
    12251458 
    12261459def depth2index (pz, gdept_0) : 
    1227     ''' 
    1228     From depth, get index (real, continuous) 
     1460    '''From depth, get index (real, continuous) 
     1461 
     1462    Needed to use transforms in Matplotlib 
    12291463    ''' 
    12301464    jpk  = gdept_0.shape[0] 
    1231     if type (pz) == xr.core.dataarray.DataArray : 
     1465    if   isinstance (pz, xr.core.dataarray.DataArray ) : 
    12321466        zz   = xr.DataArray (pz.values, dims=('zz',)) 
    1233     elif type (pz) == np.ndarray : 
     1467    elif isinstance (pz,  np.ndarray) : 
    12341468        zz   = xr.DataArray (pz.ravel(), dims=('zz',)) 
    12351469    else : 
    12361470        zz   = xr.DataArray (np.array([pz]).ravel(), dims=('zz',)) 
    12371471    zz   = np.minimum (gdept_0[-1], np.maximum (0, zz)) 
    1238      
     1472 
    12391473    idk1 = np.minimum ( (gdept_0-zz), 0.).argmax (axis=0).astype(int) 
    12401474    idk1 = np.maximum (0, np.minimum (jpk-1,  idk1  )) 
    12411475    idk2 = np.maximum (0, np.minimum (jpk-1,  idk1-1)) 
    1242      
    1243     ff = (zz - gdept_0[idk2])/(gdept_0[idk1]-gdept_0[idk2]) 
    1244     idk = ff*idk1 + (1.0-ff)*idk2 
     1476 
     1477    zff = (zz - gdept_0[idk2])/(gdept_0[idk1]-gdept_0[idk2]) 
     1478    idk = zff*idk1 + (1.0-zff)*idk2 
    12451479    idk = xr.where ( np.isnan(idk), idk1, idk) 
    12461480    return idk.values 
    12471481 
    12481482def index2depth_panels (pk, gdept_0, depth0, fact) : 
    1249     ''' 
    1250     From  index (real, continuous), get depth, with bottom part compressed 
     1483    '''From  index (real, continuous), get depth, with bottom part compressed 
     1484 
     1485    Needed to use transforms in Matplotlib 
    12511486    ''' 
    12521487    jpk = gdept_0.shape[0] 
     
    12611496 
    12621497def depth2index_panels (pz, gdept_0, depth0, fact) : 
    1263     ''' 
    1264     From  index (real, continuous), get depth, with bottom part compressed 
     1498    '''From  index (real, continuous), get depth, with bottom part compressed 
     1499 
     1500    Needed to use transforms in Matplotlib 
    12651501    ''' 
    12661502    jpk = gdept_0.shape[0] 
    1267     if type (pz) == xr.core.dataarray.DataArray : 
     1503    if isinstance (pz, xr.core.dataarray.DataArray) : 
    12681504        zz   = xr.DataArray (pz.values , dims=('zz',)) 
    1269     elif type (pz) == np.ndarray : 
     1505    elif isinstance (pz, np.ndarray) : 
    12701506        zz   = xr.DataArray (pz.ravel(), dims=('zz',)) 
    1271     else :  
     1507    else : 
    12721508        zz   = xr.DataArray (np.array([pz]).ravel(), dims=('zz',)) 
    12731509    zz         = np.minimum (gdept_0[-1], np.maximum (0, zz)) 
    1274     gdept_comp = xr.where ( gdept_0>depth0, (gdept_0-depth0)*fact+depth0, gdept_0) 
    1275     zz_comp    = xr.where ( zz     >depth0, (zz     -depth0)*fact+depth0, zz     ) 
     1510    gdept_comp = xr.where ( gdept_0>depth0, 
     1511                                (gdept_0-depth0)*fact+depth0, gdept_0) 
     1512    zz_comp    = xr.where ( zz     >depth0, (zz     -depth0)*fact+depth0, 
     1513                                zz     ) 
    12761514    zz_comp    = np.minimum (gdept_comp[-1], np.maximum (0, zz_comp)) 
    12771515 
     
    12791517    idk1 = np.maximum (0, np.minimum (jpk-1,  idk1  )) 
    12801518    idk2 = np.maximum (0, np.minimum (jpk-1,  idk1-1)) 
    1281       
    1282     ff = (zz_comp - gdept_0[idk2])/(gdept_0[idk1]-gdept_0[idk2]) 
    1283     idk = ff*idk1 + (1.0-ff)*idk2 
     1519 
     1520    zff = (zz_comp - gdept_0[idk2])/(gdept_0[idk1]-gdept_0[idk2]) 
     1521    idk = zff*idk1 + (1.0-zff)*idk2 
    12841522    idk = xr.where ( np.isnan(idk), idk1, idk) 
    12851523    return idk.values 
    12861524 
    12871525def depth2comp (pz, depth0, fact ) : 
    1288     ''' 
    1289     Form depth, get compressed depth, with bottom part compressed 
     1526    '''Form depth, get compressed depth, with bottom part compressed 
     1527 
     1528    Needed to use transforms in Matplotlib 
    12901529    ''' 
    12911530    #print ('start depth2comp') 
    1292     if type (pz) == xr.core.dataarray.DataArray : 
     1531    if isinstance (pz, xr.core.dataarray.DataArray) : 
    12931532        zz   = pz.values 
    1294     elif type(pz) == list : 
     1533    elif isinstance(pz, list) : 
    12951534        zz = np.array (pz) 
    1296     else :  
     1535    else : 
    12971536        zz   = pz 
    12981537    gz = np.where ( zz>depth0, (zz-depth0)*fact+depth0, zz) 
    12991538    #print ( f'depth2comp : {gz=}' ) 
    1300     if type (pz) in [int, float] : return gz.item() 
    1301     else : return gz 
    1302     #print ('end depth2comp') 
     1539    if type (pz) in [int, float] : 
     1540        return gz.item() 
     1541    else : 
     1542        return gz 
    13031543 
    13041544def comp2depth (pz, depth0, fact ) : 
    1305     ''' 
    1306     Form compressed depth, get depth, with bottom part compressed 
    1307     ''' 
    1308     if type (pz) == xr.core.dataarray.DataArray : 
     1545    '''Form compressed depth, get depth, with bottom part compressed 
     1546 
     1547    Needed to use transforms in Matplotlib 
     1548    ''' 
     1549    if isinstance (pz, xr.core.dataarray.DataArray) : 
    13091550        zz   = pz.values 
    1310     elif type(pz) == list : 
     1551    elif isinstance (pz, list) : 
    13111552        zz = np.array (pz) 
    1312     else :  
     1553    else : 
    13131554        zz   = pz 
    13141555    gz = np.where ( zz>depth0, (zz-depth0)/fact+depth0, zz) 
    1315     if type (pz) in [int, float] : return gz.item() 
    1316     else : return gz 
    1317  
    1318 def index2lon (pi, lon1D) : 
    1319     ''' 
    1320     From index (real, continuous), get longitude 
    1321     ''' 
    1322     jpi = lon1D.shape[0] 
     1556    if type (pz) in [int, float] : 
     1557        gz = gz.item() 
     1558 
     1559    return gz 
     1560 
     1561def index2lon (pi, plon_1d) : 
     1562    '''From index (real, continuous), get longitude 
     1563 
     1564    Needed to use transforms in Matplotlib 
     1565    ''' 
     1566    jpi = plon_1d.shape[0] 
    13231567    ii = xr.DataArray (pi) 
    13241568    i =  np.maximum (0, np.minimum (jpi-1, ii    )) 
     
    13261570    i1 = np.maximum (0, np.minimum (jpi-1,  i0+1)) 
    13271571    xx = i - i0 
    1328     gx = (1.0-xx)*lon1D[i0]+ xx*lon1D[i1] 
     1572    gx = (1.0-xx)*plon_1d[i0]+ xx*plon_1d[i1] 
    13291573    return gx.values 
    13301574 
    1331 def lon2index (px, lon1D) : 
    1332     ''' 
    1333     From longitude, get index (real, continuous) 
    1334     ''' 
    1335     jpi  = lon1D.shape[0] 
    1336     if type (px) == xr.core.dataarray.DataArray : 
     1575def lon2index (px, plon_1d) : 
     1576    '''From longitude, get index (real, continuous) 
     1577 
     1578    Needed to use transforms in Matplotlib 
     1579    ''' 
     1580    jpi  = plon_1d.shape[0] 
     1581    if isinstance (px, xr.core.dataarray.DataArray) : 
    13371582        xx   = xr.DataArray (px.values , dims=('xx',)) 
    1338     elif type (px) == np.ndarray : 
     1583    elif isinstance (px, np.ndarray) : 
    13391584        xx   = xr.DataArray (px.ravel(), dims=('xx',)) 
    1340     else :  
     1585    else : 
    13411586        xx   = xr.DataArray (np.array([px]).ravel(), dims=('xx',)) 
    1342     xx   = xr.where ( xx>lon1D.max(), xx-360.0, xx) 
    1343     xx   = xr.where ( xx<lon1D.min(), xx+360.0, xx) 
    1344     xx   = np.minimum (lon1D.max(), np.maximum(xx, lon1D.min() )) 
    1345     idi1 = np.minimum ( (lon1D-xx), 0.).argmax (axis=0).astype(int) 
     1587    xx   = xr.where ( xx>plon_1d.max(), xx-360.0, xx) 
     1588    xx   = xr.where ( xx<plon_1d.min(), xx+360.0, xx) 
     1589    xx   = np.minimum (plon_1d.max(), np.maximum(xx, plon_1d.min() )) 
     1590    idi1 = np.minimum ( (plon_1d-xx), 0.).argmax (axis=0).astype(int) 
    13461591    idi1 = np.maximum (0, np.minimum (jpi-1,  idi1  )) 
    13471592    idi2 = np.maximum (0, np.minimum (jpi-1,  idi1-1)) 
    1348      
    1349     ff = (xx - lon1D[idi2])/(lon1D[idi1]-lon1D[idi2]) 
    1350     idi = ff*idi1 + (1.0-ff)*idi2 
     1593 
     1594    zff = (xx - plon_1d[idi2])/(plon_1d[idi1]-plon_1d[idi2]) 
     1595    idi = zff*idi1 + (1.0-zff)*idi2 
    13511596    idi = xr.where ( np.isnan(idi), idi1, idi) 
    13521597    return idi.values 
    13531598 
    1354 def index2lat (pj, lat1D) : 
    1355     ''' 
    1356     From index (real, continuous), get latitude 
    1357     ''' 
    1358     jpj = lat1D.shape[0] 
     1599def index2lat (pj, plat_1d) : 
     1600    '''From index (real, continuous), get latitude 
     1601 
     1602    Needed to use transforms in Matplotlib 
     1603    ''' 
     1604    jpj = plat_1d.shape[0] 
    13591605    jj  = xr.DataArray (pj) 
    13601606    j   = np.maximum (0, np.minimum (jpj-1, jj    )) 
     
    13621608    j1  = np.maximum (0, np.minimum (jpj-1,  j0+1)) 
    13631609    yy  = j - j0 
    1364     gy  = (1.0-yy)*lat1D[j0]+ yy*lat1D[j1] 
     1610    gy  = (1.0-yy)*plat_1d[j0]+ yy*plat_1d[j1] 
    13651611    return gy.values 
    13661612 
    1367 def lat2index (py, lat1D) : 
    1368     ''' 
    1369     From latitude, get index (real, continuous) 
    1370     ''' 
    1371     jpj = lat1D.shape[0] 
    1372     if type (py) == xr.core.dataarray.DataArray : 
     1613def lat2index (py, plat_1d) : 
     1614    '''From latitude, get index (real, continuous) 
     1615 
     1616    Needed to use transforms in Matplotlib 
     1617    ''' 
     1618    jpj = plat_1d.shape[0] 
     1619    if isinstance (py, xr.core.dataarray.DataArray) : 
    13731620        yy   = xr.DataArray (py.values , dims=('yy',)) 
    1374     elif type (py) == np.ndarray : 
     1621    elif isinstance (py, np.ndarray) : 
    13751622        yy   = xr.DataArray (py.ravel(), dims=('yy',)) 
    1376     else :  
     1623    else : 
    13771624        yy   = xr.DataArray (np.array([py]).ravel(), dims=('yy',)) 
    1378     yy   = np.minimum (lat1D.max(), np.minimum(yy, lat1D.max() )) 
    1379     idj1 = np.minimum ( (lat1D-yy), 0.).argmax (axis=0).astype(int) 
     1625    yy   = np.minimum (plat_1d.max(), np.minimum(yy, plat_1d.max() )) 
     1626    idj1 = np.minimum ( (plat_1d-yy), 0.).argmax (axis=0).astype(int) 
    13801627    idj1 = np.maximum (0, np.minimum (jpj-1,  idj1  )) 
    13811628    idj2 = np.maximum (0, np.minimum (jpj-1,  idj1-1)) 
    1382      
    1383     ff = (yy - lat1D[idj2])/(lat1D[idj1]-lat1D[idj2]) 
    1384     idj = ff*idj1 + (1.0-ff)*idj2 
     1629 
     1630    zff = (yy - plat_1d[idj2])/(plat_1d[idj1]-plat_1d[idj2]) 
     1631    idj = zff*idj1 + (1.0-zff)*idj2 
    13851632    idj = xr.where ( np.isnan(idj), idj1, idj) 
    13861633    return idj.values 
    13871634 
    1388 def angle_full (glamt, gphit, glamu, gphiu, glamv, gphiv, glamf, gphif, nperio=None) : 
    1389     '''Compute sinus and cosinus of model line direction with respect to east''' 
     1635def angle_full (glamt, gphit, glamu, gphiu, glamv, gphiv, 
     1636                glamf, gphif, nperio=None) : 
     1637    '''Computes sinus and cosinus of model line direction with 
     1638    respect to east 
     1639    ''' 
    13901640    mmath = __mmath__ (glamt) 
    13911641 
     
    13981648    zlamf = lbc_add (glamf, nperio, 'F', 1.) 
    13991649    zphif = lbc_add (gphif, nperio, 'F', 1.) 
    1400      
     1650 
    14011651    # north pole direction & modulous (at T-point) 
    1402     zxnpt = 0. - 2.0 * np.cos (rad*zlamt) * np.tan (rpi/4.0 - rad*zphit/2.0) 
    1403     zynpt = 0. - 2.0 * np.sin (rad*zlamt) * np.tan (rpi/4.0 - rad*zphit/2.0) 
     1652    zxnpt = 0. - 2.0 * np.cos (RAD*zlamt) * np.tan (RPI/4.0 - RAD*zphit/2.0) 
     1653    zynpt = 0. - 2.0 * np.sin (RAD*zlamt) * np.tan (RPI/4.0 - RAD*zphit/2.0) 
    14041654    znnpt = zxnpt*zxnpt + zynpt*zynpt 
    1405      
     1655 
    14061656    # north pole direction & modulous (at U-point) 
    1407     zxnpu = 0. - 2.0 * np.cos (rad*zlamu) * np.tan (rpi/4.0 - rad*zphiu/2.0) 
    1408     zynpu = 0. - 2.0 * np.sin (rad*zlamu) * np.tan (rpi/4.0 - rad*zphiu/2.0) 
     1657    zxnpu = 0. - 2.0 * np.cos (RAD*zlamu) * np.tan (RPI/4.0 - RAD*zphiu/2.0) 
     1658    zynpu = 0. - 2.0 * np.sin (RAD*zlamu) * np.tan (RPI/4.0 - RAD*zphiu/2.0) 
    14091659    znnpu = zxnpu*zxnpu + zynpu*zynpu 
    1410      
     1660 
    14111661    # north pole direction & modulous (at V-point) 
    1412     zxnpv = 0. - 2.0 * np.cos (rad*zlamv) * np.tan (rpi/4.0 - rad*zphiv/2.0) 
    1413     zynpv = 0. - 2.0 * np.sin (rad*zlamv) * np.tan (rpi/4.0 - rad*zphiv/2.0) 
     1662    zxnpv = 0. - 2.0 * np.cos (RAD*zlamv) * np.tan (RPI/4.0 - RAD*zphiv/2.0) 
     1663    zynpv = 0. - 2.0 * np.sin (RAD*zlamv) * np.tan (RPI/4.0 - RAD*zphiv/2.0) 
    14141664    znnpv = zxnpv*zxnpv + zynpv*zynpv 
    14151665 
    14161666    # north pole direction & modulous (at F-point) 
    1417     zxnpf = 0. - 2.0 * np.cos( rad*zlamf ) * np.tan ( rpi/4. - rad*zphif/2. ) 
    1418     zynpf = 0. - 2.0 * np.sin( rad*zlamf ) * np.tan ( rpi/4. - rad*zphif/2. ) 
     1667    zxnpf = 0. - 2.0 * np.cos( RAD*zlamf ) * np.tan ( RPI/4. - RAD*zphif/2. ) 
     1668    zynpf = 0. - 2.0 * np.sin( RAD*zlamf ) * np.tan ( RPI/4. - RAD*zphif/2. ) 
    14191669    znnpf = zxnpf*zxnpf + zynpf*zynpf 
    14201670 
    14211671    # j-direction: v-point segment direction (around T-point) 
    1422     zlam = zlamv   
     1672    zlam = zlamv 
    14231673    zphi = zphiv 
    14241674    zlan = np.roll ( zlamv, axis=-2, shift=1)  # glamv (ji,jj-1) 
    14251675    zphh = np.roll ( zphiv, axis=-2, shift=1)  # gphiv (ji,jj-1) 
    1426     zxvvt =  2.0 * np.cos ( rad*zlam ) * np.tan ( rpi/4. - rad*zphi/2. )  \ 
    1427           -  2.0 * np.cos ( rad*zlan ) * np.tan ( rpi/4. - rad*zphh/2. ) 
    1428     zyvvt =  2.0 * np.sin ( rad*zlam ) * np.tan ( rpi/4. - rad*zphi/2. )  \ 
    1429           -  2.0 * np.sin ( rad*zlan ) * np.tan ( rpi/4. - rad*zphh/2. ) 
     1676    zxvvt =  2.0 * np.cos ( RAD*zlam ) * np.tan ( RPI/4. - RAD*zphi/2. ) \ 
     1677          -  2.0 * np.cos ( RAD*zlan ) * np.tan ( RPI/4. - RAD*zphh/2. ) 
     1678    zyvvt =  2.0 * np.sin ( RAD*zlam ) * np.tan ( RPI/4. - RAD*zphi/2. ) \ 
     1679          -  2.0 * np.sin ( RAD*zlan ) * np.tan ( RPI/4. - RAD*zphh/2. ) 
    14301680    znvvt = np.sqrt ( znnpt * ( zxvvt*zxvvt + zyvvt*zyvvt )  ) 
    14311681 
     
    14351685    zlan = np.roll (zlamf, axis=-2, shift=1) # glamf (ji,jj-1) 
    14361686    zphh = np.roll (zphif, axis=-2, shift=1) # gphif (ji,jj-1) 
    1437     zxffu =  2.0 * np.cos ( rad*zlam ) * np.tan ( rpi/4. - rad*zphi/2. )  \ 
    1438           -  2.0 * np.cos ( rad*zlan ) * np.tan ( rpi/4. - rad*zphh/2. ) 
    1439     zyffu =  2.0 * np.sin ( rad*zlam ) * np.tan ( rpi/4. - rad*zphi/2. )  \ 
    1440           -  2.0 * np.sin ( rad*zlan ) * np.tan ( rpi/4. - rad*zphh/2. ) 
     1687    zxffu =  2.0 * np.cos ( RAD*zlam ) * np.tan ( RPI/4. - RAD*zphi/2. ) \ 
     1688          -  2.0 * np.cos ( RAD*zlan ) * np.tan ( RPI/4. - RAD*zphh/2. ) 
     1689    zyffu =  2.0 * np.sin ( RAD*zlam ) * np.tan ( RPI/4. - RAD*zphi/2. ) \ 
     1690          -  2.0 * np.sin ( RAD*zlan ) * np.tan ( RPI/4. - RAD*zphh/2. ) 
    14411691    znffu = np.sqrt ( znnpu * ( zxffu*zxffu + zyffu*zyffu )  ) 
    14421692 
    14431693    # i-direction: f-point segment direction (around v-point) 
    1444     zlam = zlamf   
     1694    zlam = zlamf 
    14451695    zphi = zphif 
    14461696    zlan = np.roll (zlamf, axis=-1, shift=1) # glamf (ji-1,jj) 
    14471697    zphh = np.roll (zphif, axis=-1, shift=1) # gphif (ji-1,jj) 
    1448     zxffv =  2.0 * np.cos ( rad*zlam ) * np.tan ( rpi/4. - rad*zphi/2. )  \ 
    1449           -  2.0 * np.cos ( rad*zlan ) * np.tan ( rpi/4. - rad*zphh/2. ) 
    1450     zyffv =  2.0 * np.sin ( rad*zlam ) * np.tan ( rpi/4. - rad*zphi/2. )  \ 
    1451           -  2.0 * np.sin ( rad*zlan ) * np.tan ( rpi/4. - rad*zphh/2. ) 
     1698    zxffv =  2.0 * np.cos ( RAD*zlam ) * np.tan ( RPI/4. - RAD*zphi/2. ) \ 
     1699          -  2.0 * np.cos ( RAD*zlan ) * np.tan ( RPI/4. - RAD*zphh/2. ) 
     1700    zyffv =  2.0 * np.sin ( RAD*zlam ) * np.tan ( RPI/4. - RAD*zphi/2. ) \ 
     1701          -  2.0 * np.sin ( RAD*zlan ) * np.tan ( RPI/4. - RAD*zphh/2. ) 
    14521702    znffv = np.sqrt ( znnpv * ( zxffv*zxffv + zyffv*zyffv )  ) 
    14531703 
    14541704    # j-direction: u-point segment direction (around f-point) 
    1455     zlam = np.roll (zlamu, axis=-2, shift=-1) # glamu (ji,jj+1)  
     1705    zlam = np.roll (zlamu, axis=-2, shift=-1) # glamu (ji,jj+1) 
    14561706    zphi = np.roll (zphiu, axis=-2, shift=-1) # gphiu (ji,jj+1) 
    14571707    zlan = zlamu 
    14581708    zphh = zphiu 
    1459     zxuuf =  2. * np.cos ( rad*zlam ) * np.tan ( rpi/4. - rad*zphi/2. )  \ 
    1460           -  2. * np.cos ( rad*zlan ) * np.tan ( rpi/4. - rad*zphh/2. ) 
    1461     zyuuf =  2. * np.sin ( rad*zlam ) * np.tan ( rpi/4. - rad*zphi/2. )  \ 
    1462           -  2. * np.sin ( rad*zlan ) * np.tan ( rpi/4. - rad*zphh/2. ) 
     1709    zxuuf =  2. * np.cos ( RAD*zlam ) * np.tan ( RPI/4. - RAD*zphi/2. ) \ 
     1710          -  2. * np.cos ( RAD*zlan ) * np.tan ( RPI/4. - RAD*zphh/2. ) 
     1711    zyuuf =  2. * np.sin ( RAD*zlam ) * np.tan ( RPI/4. - RAD*zphi/2. ) \ 
     1712          -  2. * np.sin ( RAD*zlan ) * np.tan ( RPI/4. - RAD*zphh/2. ) 
    14631713    znuuf = np.sqrt ( znnpf * ( zxuuf*zxuuf + zyuuf*zyuuf )  ) 
    14641714 
    1465      
     1715 
    14661716    # cosinus and sinus using scalar and vectorial products 
    14671717    gsint = ( zxnpt*zyvvt - zynpt*zxvvt ) / znvvt 
    14681718    gcost = ( zxnpt*zxvvt + zynpt*zyvvt ) / znvvt 
    1469      
     1719 
    14701720    gsinu = ( zxnpu*zyffu - zynpu*zxffu ) / znffu 
    14711721    gcosu = ( zxnpu*zxffu + zynpu*zyffu ) / znffu 
    1472      
     1722 
    14731723    gsinf = ( zxnpf*zyuuf - zynpf*zxuuf ) / znuuf 
    14741724    gcosf = ( zxnpf*zxuuf + zynpf*zyuuf ) / znuuf 
    1475      
     1725 
    14761726    gsinv = ( zxnpv*zxffv + zynpv*zyffv ) / znffv 
    1477     gcosv =-( zxnpv*zyffv - zynpv*zxffv ) / znffv  # (caution, rotation of 90 degres) 
    1478      
    1479     #gsint = lbc (gsint, cd_type='T', nperio=nperio, psgn=-1.) 
    1480     #gcost = lbc (gcost, cd_type='T', nperio=nperio, psgn=-1.) 
    1481     #gsinu = lbc (gsinu, cd_type='U', nperio=nperio, psgn=-1.) 
    1482     #gcosu = lbc (gcosu, cd_type='U', nperio=nperio, psgn=-1.) 
    1483     #gsinv = lbc (gsinv, cd_type='V', nperio=nperio, psgn=-1.) 
    1484     #gcosv = lbc (gcosv, cd_type='V', nperio=nperio, psgn=-1.) 
    1485     #gsinf = lbc (gsinf, cd_type='F', nperio=nperio, psgn=-1.) 
    1486     #gcosf = lbc (gcosf, cd_type='F', nperio=nperio, psgn=-1.) 
     1727    # (caution, rotation of 90 degres) 
     1728    gcosv =-( zxnpv*zyffv - zynpv*zxffv ) / znffv 
    14871729 
    14881730    gsint = lbc_del (gsint, cd_type='T', nperio=nperio, psgn=-1.) 
     
    15081750 
    15091751def angle (glam, gphi, nperio, cd_type='T') : 
    1510     '''Compute sinus and cosinus of model line direction with respect to east''' 
     1752    '''Computes sinus and cosinus of model line direction with 
     1753    respect to east 
     1754    ''' 
    15111755    mmath = __mmath__ (glam) 
    15121756 
    15131757    zlam = lbc_add (glam, nperio, cd_type, 1.) 
    15141758    zphi = lbc_add (gphi, nperio, cd_type, 1.) 
    1515      
     1759 
    15161760    # north pole direction & modulous 
    1517     zxnp = 0. - 2.0 * np.cos (rad*zlam) * np.tan (rpi/4.0 - rad*zphi/2.0) 
    1518     zynp = 0. - 2.0 * np.sin (rad*zlam) * np.tan (rpi/4.0 - rad*zphi/2.0) 
     1761    zxnp = 0. - 2.0 * np.cos (RAD*zlam) * np.tan (RPI/4.0 - RAD*zphi/2.0) 
     1762    zynp = 0. - 2.0 * np.sin (RAD*zlam) * np.tan (RPI/4.0 - RAD*zphi/2.0) 
    15191763    znnp = zxnp*zxnp + zynp*zynp 
    15201764 
     
    15241768    zlan_s = np.roll (zlam, axis=-2, shift= 1) # glam [jj-1, ji] 
    15251769    zphh_s = np.roll (zphi, axis=-2, shift= 1) # gphi [jj-1, ji] 
    1526      
    1527     zxff = 2.0 * np.cos (rad*zlan_n) * np.tan (rpi/4.0 - rad*zphh_n/2.0) \ 
    1528         -  2.0 * np.cos (rad*zlan_s) * np.tan (rpi/4.0 - rad*zphh_s/2.0) 
    1529     zyff = 2.0 * np.sin (rad*zlan_n) * np.tan (rpi/4.0 - rad*zphh_n/2.0) \ 
    1530         -  2.0 * np.sin (rad*zlan_s) * np.tan (rpi/4.0 - rad*zphh_s/2.0) 
     1770 
     1771    zxff = 2.0 * np.cos (RAD*zlan_n) * np.tan (RPI/4.0 - RAD*zphh_n/2.0) \ 
     1772        -  2.0 * np.cos (RAD*zlan_s) * np.tan (RPI/4.0 - RAD*zphh_s/2.0) 
     1773    zyff = 2.0 * np.sin (RAD*zlan_n) * np.tan (RPI/4.0 - RAD*zphh_n/2.0) \ 
     1774        -  2.0 * np.sin (RAD*zlan_s) * np.tan (RPI/4.0 - RAD*zphh_s/2.0) 
    15311775    znff = np.sqrt (znnp * (zxff*zxff + zyff*zyff) ) 
    1532   
     1776 
    15331777    gsin = (zxnp*zyff - zynp*zxff) / znff 
    15341778    gcos = (zxnp*zxff + zynp*zyff) / znff 
     
    15401784        gsin = gsin.assign_coords ( glam.coords ) 
    15411785        gcos = gcos.assign_coords ( glam.coords ) 
    1542          
     1786 
    15431787    return gsin, gcos 
    15441788 
    15451789def rot_en2ij ( u_e, v_n, gsin, gcos, nperio, cd_type ) : 
    1546     ''' 
    1547     ** Purpose :   Rotate the Repere: Change vector componantes between 
     1790    '''Rotates the Repere: Change vector componantes between 
    15481791    geographic grid --> stretched coordinates grid. 
    1549     All components are on the same grid (T, U, V or F)  
     1792 
     1793    All components are on the same grid (T, U, V or F) 
    15501794    ''' 
    15511795 
    15521796    u_i = + u_e * gcos + v_n * gsin 
    15531797    v_j = - u_e * gsin + v_n * gcos 
    1554      
     1798 
    15551799    u_i = lbc (u_i, nperio=nperio, cd_type=cd_type, psgn=-1.0) 
    15561800    v_j = lbc (v_j, nperio=nperio, cd_type=cd_type, psgn=-1.0) 
    1557      
     1801 
    15581802    return u_i, v_j 
    15591803 
    15601804def rot_ij2en ( u_i, v_j, gsin, gcos, nperio, cd_type='T' ) : 
    1561     ''' 
    1562     ** Purpose :   Rotate the Repere: Change vector componantes from 
     1805    '''Rotates the Repere: Change vector componantes from 
    15631806    stretched coordinates grid --> geographic grid 
    1564     All components are on the same grid (T, U, V or F)  
     1807 
     1808    All components are on the same grid (T, U, V or F) 
    15651809    ''' 
    15661810    u_e = + u_i * gcos - v_j * gsin 
    15671811    v_n = + u_i * gsin + v_j * gcos 
    1568      
     1812 
    15691813    u_e = lbc (u_e, nperio=nperio, cd_type=cd_type, psgn=1.0) 
    15701814    v_n = lbc (v_n, nperio=nperio, cd_type=cd_type, psgn=1.0) 
     1815 
     1816    return u_e, v_n 
     1817 
     1818def rot_uv2en ( uo, vo, gsint, gcost, nperio, zdim=None ) : 
     1819    '''Rotate the Repere: Change vector componantes from 
     1820    stretched coordinates grid --> geographic grid 
     1821 
     1822    uo : velocity along i at the U grid point 
     1823    vo : valocity along j at the V grid point 
    15711824     
    1572     return u_e, v_n 
    1573  
    1574 def rot_uv2en ( uo, vo, gsint, gcost, nperio, zdim=None ) : 
    1575     ''' 
    1576     ** Purpose :   Rotate the Repere: Change vector componantes from 
    1577     stretched coordinates grid --> geographic grid 
    1578     uo is on the U grid point, vo is on the V grid point 
    1579     east-north components on the T grid point    
    1580     ''' 
    1581     mmath = __mmath__ (uo) 
    1582      
    1583     ut = U2T (uo, nperio=nperio, psgn=-1.0, zdim=zdim) 
    1584     vt = V2T (vo, nperio=nperio, psgn=-1.0, zdim=zdim) 
    1585      
     1825    Returns east-north components on the T grid point 
     1826    ''' 
     1827    ut = u2t (uo, nperio=nperio, psgn=-1.0, zdim=zdim) 
     1828    vt = v2t (vo, nperio=nperio, psgn=-1.0, zdim=zdim) 
     1829 
    15861830    u_e = + ut * gcost - vt * gsint 
    15871831    v_n = + ut * gsint + vt * gcost 
     
    15891833    u_e = lbc (u_e, nperio=nperio, cd_type='T', psgn=1.0) 
    15901834    v_n = lbc (v_n, nperio=nperio, cd_type='T', psgn=1.0) 
     1835 
     1836    return u_e, v_n 
     1837 
     1838def rot_uv2enf ( uo, vo, gsinf, gcosf, nperio, zdim=None ) : 
     1839    '''Rotates the Repere: Change vector componantes from 
     1840    stretched coordinates grid --> geographic grid 
     1841 
     1842    uo : velocity along i at the U grid point 
     1843    vo : valocity along j at the V grid point 
    15911844     
    1592     return u_e, v_n 
    1593  
    1594 def rot_uv2enF ( uo, vo, gsinf, gcosf, nperio, zdim=None ) : 
    1595     ''' 
    1596     ** Purpose : Rotate the Repere: Change vector componantes from 
    1597     stretched coordinates grid --> geographic grid 
    1598     uo is on the U grid point, vo is on the V grid point 
    1599     east-north components on the T grid point    
    1600     ''' 
    1601     mmath = __mmath__ (uo) 
    1602  
    1603     uf = U2F (uo, nperio=nperio, psgn=-1.0, zdim=zdim) 
    1604     vf = V2F (vo, nperio=nperio, psgn=-1.0, zdim=zdim) 
    1605      
     1845    Returns east-north components on the F grid point 
     1846    ''' 
     1847    uf = u2f (uo, nperio=nperio, psgn=-1.0, zdim=zdim) 
     1848    vf = v2f (vo, nperio=nperio, psgn=-1.0, zdim=zdim) 
     1849 
    16061850    u_e = + uf * gcosf - vf * gsinf 
    16071851    v_n = + uf * gsinf + vf * gcosf 
     
    16091853    u_e = lbc (u_e, nperio=nperio, cd_type='F', psgn= 1.0) 
    16101854    v_n = lbc (v_n, nperio=nperio, cd_type='F', psgn= 1.0) 
    1611      
     1855 
    16121856    return u_e, v_n 
    16131857 
    1614 def U2T (utab, nperio=None, psgn=-1.0, zdim=None, action='ave') : 
    1615     '''Interpolate an array from U grid to T grid i-mean)''' 
     1858def u2t (utab, nperio=None, psgn=-1.0, zdim=None, action='ave') : 
     1859    '''Interpolates an array from U grid to T grid (i-mean) 
     1860    ''' 
    16161861    mmath = __mmath__ (utab) 
    16171862    utab_0 = mmath.where ( np.isnan(utab), 0., utab) 
    1618     lperio, aperio = lbc_diag (nperio) 
     1863    #lperio, aperio = lbc_diag (nperio) 
    16191864    utab_0 = lbc_add (utab_0, nperio=nperio, cd_type='U', psgn=psgn) 
    1620     ix, ax = __findAxis__ (utab_0, 'x') 
    1621     kz, az = __findAxis__ (utab_0, 'z') 
    1622  
    1623     if ax :  
    1624         if action == 'ave' : ttab = 0.5 *      (utab_0 + np.roll (utab_0, axis=ix, shift=1)) 
    1625         if action == 'min' : ttab = np.minimum (utab_0 , np.roll (utab_0, axis=ix, shift=1)) 
    1626         if action == 'max' : ttab = np.maximum (utab_0 , np.roll (utab_0, axis=ix, shift=1)) 
    1627         if action == 'mult': ttab =             utab_0 * np.roll (utab_0, axis=ix, shift=1) 
     1865    ax, ix = __find_axis__ (utab_0, 'x') 
     1866    az     = __find_axis__ (utab_0, 'z')[0] 
     1867 
     1868    if ax : 
     1869        if action == 'ave' : 
     1870            ttab = 0.5 *      (utab_0 + np.roll (utab_0, axis=ix, shift=1)) 
     1871        if action == 'min' : 
     1872            ttab = np.minimum (utab_0 , np.roll (utab_0, axis=ix, shift=1)) 
     1873        if action == 'max' : 
     1874            ttab = np.maximum (utab_0 , np.roll (utab_0, axis=ix, shift=1)) 
     1875        if action == 'mult': 
     1876            ttab =             utab_0 * np.roll (utab_0, axis=ix, shift=1) 
    16281877        ttab = lbc_del (ttab  , nperio=nperio, cd_type='T', psgn=psgn) 
    1629     else :  
     1878    else : 
    16301879        ttab = lbc_del (utab_0, nperio=nperio, cd_type='T', psgn=psgn) 
    1631          
     1880 
    16321881    if mmath == xr : 
    16331882        if ax : 
    16341883            ttab = ttab.assign_coords({ax:np.arange (ttab.shape[ix])+1.}) 
    16351884        if zdim and az : 
    1636             if az != zdim : ttab = ttab.rename( {az:zdim})  
     1885            if az != zdim : 
     1886                ttab = ttab.rename( {az:zdim}) 
    16371887    return ttab 
    16381888 
    1639 def V2T (vtab, nperio=None, psgn=-1.0, zdim=None, action='ave') : 
    1640     '''Interpolate an array from V grid to T grid (j-mean)''' 
     1889def v2t (vtab, nperio=None, psgn=-1.0, zdim=None, action='ave') : 
     1890    '''Interpolates an array from V grid to T grid (j-mean) 
     1891    ''' 
    16411892    mmath = __mmath__ (vtab) 
    1642     lperio, aperio = lbc_diag (nperio) 
     1893    #lperio, aperio = lbc_diag (nperio) 
    16431894    vtab_0 = mmath.where ( np.isnan(vtab), 0., vtab) 
    16441895    vtab_0 = lbc_add (vtab_0, nperio=nperio, cd_type='V', psgn=psgn) 
    1645     jy, ay = __findAxis__ (vtab_0, 'y') 
    1646     kz, az = __findAxis__ (vtab_0, 'z') 
    1647     if ay :  
    1648         if action == 'ave'  : ttab = 0.5 *      (vtab_0 + np.roll (vtab_0, axis=jy, shift=1)) 
    1649         if action == 'min'  : ttab = np.minimum (vtab_0 , np.roll (vtab_0, axis=jy, shift=1)) 
    1650         if action == 'max'  : ttab = np.maximum (vtab_0 , np.roll (vtab_0, axis=jy, shift=1)) 
    1651         if action == 'mult' : ttab =             vtab_0 * np.roll (vtab_0, axis=jy, shift=1) 
     1896    ay, jy = __find_axis__ (vtab_0, 'y') 
     1897    az     = __find_axis__ (vtab_0, 'z')[0] 
     1898    if ay : 
     1899        if action == 'ave'  : 
     1900            ttab = 0.5 *      (vtab_0 + np.roll (vtab_0, axis=jy, shift=1)) 
     1901        if action == 'min'  : 
     1902            ttab = np.minimum (vtab_0 , np.roll (vtab_0, axis=jy, shift=1)) 
     1903        if action == 'max'  : 
     1904            ttab = np.maximum (vtab_0 , np.roll (vtab_0, axis=jy, shift=1)) 
     1905        if action == 'mult' : 
     1906            ttab =             vtab_0 * np.roll (vtab_0, axis=jy, shift=1) 
    16521907        ttab = lbc_del (ttab  , nperio=nperio, cd_type='T', psgn=psgn) 
    16531908    else : 
    16541909        ttab = lbc_del (vtab_0, nperio=nperio, cd_type='T', psgn=psgn) 
    1655          
     1910 
    16561911    if mmath == xr : 
    16571912        if ay : 
    16581913            ttab = ttab.assign_coords({ay:np.arange(ttab.shape[jy])+1.}) 
    16591914        if zdim and az : 
    1660             if az != zdim : ttab = ttab.rename( {az:zdim})  
     1915            if az != zdim : 
     1916                ttab = ttab.rename( {az:zdim}) 
    16611917    return ttab 
    16621918 
    1663 def F2T (ftab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
    1664     '''Interpolate an array from F grid to T grid (i- and j- means)''' 
     1919def f2t (ftab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
     1920    '''Interpolates an array from F grid to T grid (i- and j- means) 
     1921    ''' 
    16651922    mmath = __mmath__ (ftab) 
    16661923    ftab_0 = mmath.where ( np.isnan(ftab), 0., ftab) 
    16671924    ftab_0 = lbc_add (ftab_0 , nperio=nperio, cd_type='F', psgn=psgn) 
    1668     ttab = V2T (F2V (ftab_0, nperio=nperio, psgn=psgn, zdim=zdim, action=action), nperio=nperio, psgn=psgn, zdim=zdim, action=action) 
     1925    ttab = v2t (f2v (ftab_0, nperio=nperio, psgn=psgn, zdim=zdim, action=action), 
     1926                     nperio=nperio, psgn=psgn, zdim=zdim, action=action) 
    16691927    return lbc_del (ttab, nperio=nperio, cd_type='T', psgn=psgn) 
    16701928 
    1671 def T2U (ttab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
    1672     '''Interpolate an array from T grid to U grid (i-mean)''' 
     1929def t2u (ttab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
     1930    '''Interpolates an array from T grid to U grid (i-mean) 
     1931    ''' 
    16731932    mmath = __mmath__ (ttab) 
    16741933    ttab_0 = mmath.where ( np.isnan(ttab), 0., ttab) 
    16751934    ttab_0 = lbc_add (ttab_0 , nperio=nperio, cd_type='T', psgn=psgn) 
    1676     ix, ax = __findAxis__ (ttab_0, 'x') 
    1677     kz, az = __findAxis__ (ttab_0, 'z') 
    1678     if ix :  
    1679         if action == 'ave'  : utab = 0.5 *      (ttab_0 + np.roll (ttab_0, axis=ix, shift=-1)) 
    1680         if action == 'min'  : utab = np.minimum (ttab_0 , np.roll (ttab_0, axis=ix, shift=-1)) 
    1681         if action == 'max'  : utab = np.maximum (ttab_0 , np.roll (ttab_0, axis=ix, shift=-1)) 
    1682         if action == 'mult' : utab =             ttab_0 * np.roll (ttab_0, axis=ix, shift=-1) 
     1935    ax, ix = __find_axis__ (ttab_0, 'x')[0] 
     1936    az     = __find_axis__ (ttab_0, 'z') 
     1937    if ix : 
     1938        if action == 'ave'  : 
     1939            utab = 0.5 *      (ttab_0 + np.roll (ttab_0, axis=ix, shift=-1)) 
     1940        if action == 'min'  : 
     1941            utab = np.minimum (ttab_0 , np.roll (ttab_0, axis=ix, shift=-1)) 
     1942        if action == 'max'  : 
     1943            utab = np.maximum (ttab_0 , np.roll (ttab_0, axis=ix, shift=-1)) 
     1944        if action == 'mult' : 
     1945            utab =             ttab_0 * np.roll (ttab_0, axis=ix, shift=-1) 
    16831946        utab = lbc_del (utab  , nperio=nperio, cd_type='U', psgn=psgn) 
    16841947    else : 
    16851948        utab = lbc_del (ttab_0, nperio=nperio, cd_type='U', psgn=psgn) 
    1686          
    1687     if mmath == xr :     
    1688         if ax :  
     1949 
     1950    if mmath == xr : 
     1951        if ax : 
    16891952            utab = ttab.assign_coords({ax:np.arange(utab.shape[ix])+1.}) 
    16901953        if zdim and az : 
    1691             if az != zdim : utab = utab.rename( {az:zdim})  
     1954            if az != zdim : 
     1955                utab = utab.rename( {az:zdim}) 
    16921956    return utab 
    16931957 
    1694 def T2V (ttab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
    1695     '''Interpolate an array from T grid to V grid (j-mean)''' 
     1958def t2v (ttab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
     1959    '''Interpolates an array from T grid to V grid (j-mean) 
     1960    ''' 
    16961961    mmath = __mmath__ (ttab) 
    16971962    ttab_0 = mmath.where ( np.isnan(ttab), 0., ttab) 
    16981963    ttab_0 = lbc_add (ttab_0 , nperio=nperio, cd_type='T', psgn=psgn) 
    1699     jy, ay = __findAxis__ (ttab_0, 'y') 
    1700     kz, az = __findAxis__ (ttab_0, 'z') 
    1701     if jy :  
    1702         if action == 'ave'  : vtab = 0.5 *      (ttab_0 + np.roll (ttab_0, axis=jy, shift=-1)) 
    1703         if action == 'min'  : vtab = np.minimum (ttab_0 , np.roll (ttab_0, axis=jy, shift=-1)) 
    1704         if action == 'max'  : vtab = np.maximum (ttab_0 , np.roll (ttab_0, axis=jy, shift=-1)) 
    1705         if action == 'mult' : vtab =             ttab_0 * np.roll (ttab_0, axis=jy, shift=-1) 
     1964    ay, jy = __find_axis__ (ttab_0, 'y') 
     1965    az     = __find_axis__ (ttab_0, 'z')[0] 
     1966    if jy : 
     1967        if action == 'ave'  : 
     1968            vtab = 0.5 *      (ttab_0 + np.roll (ttab_0, axis=jy, shift=-1)) 
     1969        if action == 'min'  : 
     1970            vtab = np.minimum (ttab_0 , np.roll (ttab_0, axis=jy, shift=-1)) 
     1971        if action == 'max'  : 
     1972            vtab = np.maximum (ttab_0 , np.roll (ttab_0, axis=jy, shift=-1)) 
     1973        if action == 'mult' : 
     1974            vtab =             ttab_0 * np.roll (ttab_0, axis=jy, shift=-1) 
    17061975        vtab = lbc_del (vtab  , nperio=nperio, cd_type='V', psgn=psgn) 
    17071976    else : 
     
    17091978 
    17101979    if mmath == xr : 
    1711         if ay :  
     1980        if ay : 
    17121981            vtab = vtab.assign_coords({ay:np.arange(vtab.shape[jy])+1.}) 
    17131982        if zdim and az : 
    1714             if az != zdim : vtab = vtab.rename( {az:zdim})  
     1983            if az != zdim : 
     1984                vtab = vtab.rename( {az:zdim}) 
    17151985    return vtab 
    17161986 
    1717 def V2F (vtab, nperio=None, psgn=-1.0, zdim=None, action='ave') : 
    1718     '''Interpolate an array from V grid to F grid (i-mean)''' 
     1987def v2f (vtab, nperio=None, psgn=-1.0, zdim=None, action='ave') : 
     1988    '''Interpolates an array from V grid to F grid (i-mean) 
     1989    ''' 
    17191990    mmath = __mmath__ (vtab) 
    17201991    vtab_0 = mmath.where ( np.isnan(vtab), 0., vtab) 
    17211992    vtab_0 = lbc_add (vtab_0 , nperio=nperio, cd_type='V', psgn=psgn) 
    1722     ix, ax = __findAxis__ (vtab_0, 'x') 
    1723     kz, az = __findAxis__ (vtab_0, 'z') 
    1724     if ix :  
    1725         if action == 'ave'  : 0.5 *      (vtab_0 + np.roll (vtab_0, axis=ix, shift=-1)) 
    1726         if action == 'min'  : np.minimum (vtab_0 , np.roll (vtab_0, axis=ix, shift=-1)) 
    1727         if action == 'max'  : np.maximum (vtab_0 , np.roll (vtab_0, axis=ix, shift=-1)) 
    1728         if action == 'mult' :             vtab_0 * np.roll (vtab_0, axis=ix, shift=-1) 
     1993    ax, ix = __find_axis__ (vtab_0, 'x') 
     1994    az     = __find_axis__ (vtab_0, 'z')[0] 
     1995    if ix : 
     1996        if action == 'ave'  : 
     1997            ftab = 0.5 *      (vtab_0 + np.roll (vtab_0, axis=ix, shift=-1)) 
     1998        if action == 'min'  : 
     1999            ftab = np.minimum (vtab_0 , np.roll (vtab_0, axis=ix, shift=-1)) 
     2000        if action == 'max'  : 
     2001            ftab = np.maximum (vtab_0 , np.roll (vtab_0, axis=ix, shift=-1)) 
     2002        if action == 'mult' : 
     2003            ftab =             vtab_0 * np.roll (vtab_0, axis=ix, shift=-1) 
    17292004        ftab = lbc_del (ftab  , nperio=nperio, cd_type='F', psgn=psgn) 
    17302005    else : 
    1731          ftab = lbc_del (vtab_0, nperio=nperio, cd_type='F', psgn=psgn) 
    1732     
     2006        ftab = lbc_del (vtab_0, nperio=nperio, cd_type='F', psgn=psgn) 
     2007 
    17332008    if mmath == xr : 
    1734         if ax :  
     2009        if ax : 
    17352010            ftab = ftab.assign_coords({ax:np.arange(ftab.shape[ix])+1.}) 
    17362011        if zdim and az : 
    1737             if az != zdim : ftab = ftab.rename( {az:zdim})  
     2012            if az != zdim : 
     2013                ftab = ftab.rename( {az:zdim}) 
    17382014    return lbc_del (ftab, nperio=nperio, cd_type='F', psgn=psgn) 
    17392015 
    1740 def U2F (utab, nperio=None, psgn=-1.0, zdim=None, action='ave') : 
    1741     '''Interpolate an array from U grid to F grid i-mean)''' 
     2016def u2f (utab, nperio=None, psgn=-1.0, zdim=None, action='ave') : 
     2017    '''Interpolates an array from U grid to F grid i-mean) 
     2018    ''' 
    17422019    mmath = __mmath__ (utab) 
    17432020    utab_0 = mmath.where ( np.isnan(utab), 0., utab) 
    17442021    utab_0 = lbc_add (utab_0 , nperio=nperio, cd_type='U', psgn=psgn) 
    1745     jy, ay = __findAxis__ (utab_0, 'y') 
    1746     kz, az = __findAxis__ (utab_0, 'z') 
    1747     if jy :  
    1748         if action == 'ave'  :    ftab = 0.5 *      (utab_0 + np.roll (utab_0, axis=jy, shift=-1)) 
    1749         if action == 'min'  :    ftab = np.minimum (utab_0 , np.roll (utab_0, axis=jy, shift=-1)) 
    1750         if action == 'max'  :    ftab = np.maximum (utab_0 , np.roll (utab_0, axis=jy, shift=-1)) 
    1751         if action == 'mult' :    ftab =             utab_0 * np.roll (utab_0, axis=jy, shift=-1) 
    1752         ftab = lbc_del (ftab  , nperio=nperio, cd_type='F', psgn=psgn) 
     2022    ay, jy = __find_axis__ (utab_0, 'y') 
     2023    az     = __find_axis__ (utab_0, 'z')[0] 
     2024    if jy : 
     2025        if action == 'ave'  : 
     2026            ftab = 0.5 *      (utab_0 + np.roll (utab_0, axis=jy, shift=-1)) 
     2027        if action == 'min'  : 
     2028            ftab = np.minimum (utab_0 , np.roll (utab_0, axis=jy, shift=-1)) 
     2029        if action == 'max'  : 
     2030            ftab = np.maximum (utab_0 , np.roll (utab_0, axis=jy, shift=-1)) 
     2031        if action == 'mult' : 
     2032            ftab =             utab_0 * np.roll (utab_0, axis=jy, shift=-1) 
     2033        ftab = lbc_del (ftab, nperio=nperio, cd_type='F', psgn=psgn) 
    17532034    else : 
    17542035        ftab = lbc_del (utab_0, nperio=nperio, cd_type='F', psgn=psgn) 
    1755    
     2036 
    17562037    if mmath == xr : 
    1757         if ay :  
     2038        if ay : 
    17582039            ftab = ftab.assign_coords({'y':np.arange(ftab.shape[jy])+1.}) 
    17592040        if zdim and az : 
    1760             if az != zdim : ftab = ftab.rename( {az:zdim})  
     2041            if az != zdim : 
     2042                ftab = ftab.rename( {az:zdim}) 
    17612043    return ftab 
    17622044 
    1763 def F2T (ftab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
    1764     '''Interpolate an array on F grid to T grid (i- and j- means)''' 
    1765     mmath = __mmath__ (ftab) 
    1766     ftab_0 = mmath.where ( np.isnan(ttab), 0., ttab) 
    1767     ftab_0 = lbc_add (ftab_0 , nperio=nperio, cd_type='F', psgn=psgn) 
    1768     ttab = U2T(F2U(ftab_0, nperio=nperio, psgn=psgn, zdim=zdim, action=action), nperio=nperio, psgn=psgn, zdim=zdim, action=action) 
    1769     return lbc_del (ttab, nperio=nperio, cd_type='T', psgn=psgn) 
    1770  
    1771 def T2F (ttab, nperio=None, psgn=1.0, zdim=None, action='mean') : 
    1772     '''Interpolate an array on T grid to F grid (i- and j- means)''' 
     2045def t2f (ttab, nperio=None, psgn=1.0, zdim=None, action='mean') : 
     2046    '''Interpolates an array on T grid to F grid (i- and j- means) 
     2047    ''' 
    17732048    mmath = __mmath__ (ttab) 
    17742049    ttab_0 = mmath.where ( np.isnan(ttab), 0., ttab) 
    17752050    ttab_0 = lbc_add (ttab_0 , nperio=nperio, cd_type='T', psgn=psgn) 
    1776     ftab = T2U (U2F (ttab, nperio=nperio, psgn=psgn, zdim=zdim, action=action), nperio=nperio, psgn=psgn, zdim=zdim, action=action) 
    1777      
     2051    ftab = t2u (u2f (ttab, nperio=nperio, psgn=psgn, zdim=zdim, action=action), 
     2052                     nperio=nperio, psgn=psgn, zdim=zdim, action=action) 
     2053 
    17782054    return lbc_del (ftab, nperio=nperio, cd_type='F', psgn=psgn) 
    17792055 
    1780 def F2U (ftab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
    1781     '''Interpolate an array on F grid to FUgrid (i-mean)''' 
     2056def f2u (ftab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
     2057    '''Interpolates an array on F grid to U grid (j-mean) 
     2058    ''' 
    17822059    mmath = __mmath__ (ftab) 
    17832060    ftab_0 = mmath.where ( np.isnan(ftab), 0., ftab) 
    17842061    ftab_0 = lbc_add (ftab_0 , nperio=nperio, cd_type='F', psgn=psgn) 
    1785     jy, ay = __findAxis__ (ftab_0, 'y') 
    1786     kz, az = __findAxis__ (ftab_0, 'z') 
    1787     if jy :  
    1788         if action == 'ave'  : utab = 0.5 *      (ftab_0 + np.roll (ftab_0, axis=jy, shift=-1)) 
    1789         if action == 'min'  : utab = np.minimum (ftab_0 , np.roll (ftab_0, axis=jy, shift=-1)) 
    1790         if action == 'max'  : utab = np.maximum (ftab_0 , np.roll (ftab_0, axis=jy, shift=-1)) 
    1791         if action == 'mult' : utab =             ftab_0 * np.roll (ftab_0, axis=jy, shift=-1) 
     2062    ay, jy = __find_axis__ (ftab_0, 'y') 
     2063    az     = __find_axis__ (ftab_0, 'z')[0] 
     2064    if jy : 
     2065        if action == 'ave'  : 
     2066            utab = 0.5 *      (ftab_0 + np.roll (ftab_0, axis=jy, shift=-1)) 
     2067        if action == 'min'  : 
     2068            utab = np.minimum (ftab_0 , np.roll (ftab_0, axis=jy, shift=-1)) 
     2069        if action == 'max'  : 
     2070            utab = np.maximum (ftab_0 , np.roll (ftab_0, axis=jy, shift=-1)) 
     2071        if action == 'mult' : 
     2072            utab =             ftab_0 * np.roll (ftab_0, axis=jy, shift=-1) 
    17922073        utab = lbc_del (utab  , nperio=nperio, cd_type='U', psgn=psgn) 
    17932074    else : 
     
    17962077    if mmath == xr : 
    17972078        utab = utab.assign_coords({ay:np.arange(ftab.shape[jy])+1.}) 
    1798         if zdim and zz : 
    1799             if az != zdim : utab = utab.rename( {az:zdim})  
     2079        if zdim and az and az != zdim : 
     2080            utab = utab.rename( {az:zdim}) 
    18002081    return utab 
    18012082 
    1802 def F2V (ftab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
    1803     '''Interpolate an array from F grid to V grid (i-mean)''' 
     2083def f2v (ftab, nperio=None, psgn=1.0, zdim=None, action='ave') : 
     2084    '''Interpolates an array from F grid to V grid (i-mean) 
     2085    ''' 
    18042086    mmath = __mmath__ (ftab) 
    18052087    ftab_0 = mmath.where ( np.isnan(ftab), 0., ftab) 
    18062088    ftab_0 = lbc_add (ftab_0 , nperio=nperio, cd_type='F', psgn=psgn) 
    1807     ix, ax = __findAxis__ (ftab_0, 'x') 
    1808     kz, az = __findAxis__ (ftab_0, 'z') 
    1809     if ix :  
    1810         if action == 'ave'  : vtab = 0.5 *      (ftab_0 + np.roll (ftab_0, axis=ix, shift=-1)) 
    1811         if action == 'min'  : vtab = np.minimum (ftab_0 , np.roll (ftab_0, axis=ix, shift=-1)) 
    1812         if action == 'max'  : vtab = np.maximum (ftab_0 , np.roll (ftab_0, axis=ix, shift=-1)) 
    1813         if action == 'mult' : vtab =             ftab_0 * np.roll (ftab_0, axis=ix, shift=-1) 
     2089    ax, ix = __find_axis__ (ftab_0, 'x') 
     2090    az     = __find_axis__ (ftab_0, 'z')[0] 
     2091    if ix : 
     2092        if action == 'ave'  : 
     2093            vtab = 0.5 *      (ftab_0 + np.roll (ftab_0, axis=ix, shift=-1)) 
     2094        if action == 'min'  : 
     2095            vtab = np.minimum (ftab_0 , np.roll (ftab_0, axis=ix, shift=-1)) 
     2096        if action == 'max'  : 
     2097            vtab = np.maximum (ftab_0 , np.roll (ftab_0, axis=ix, shift=-1)) 
     2098        if action == 'mult' : 
     2099            vtab =             ftab_0 * np.roll (ftab_0, axis=ix, shift=-1) 
    18142100        vtab = lbc_del (vtab  , nperio=nperio, cd_type='V', psgn=psgn) 
    1815     else :  
     2101    else : 
    18162102        vtab = lbc_del (ftab_0, nperio=nperio, cd_type='V', psgn=psgn) 
    18172103 
     
    18192105        vtab = vtab.assign_coords({ax:np.arange(ftab.shape[ix])+1.}) 
    18202106        if zdim and az : 
    1821             if az != zdim : vtab = vtab.rename( {az:zdim})  
     2107            if az != zdim : 
     2108                vtab = vtab.rename( {az:zdim}) 
    18222109    return vtab 
    18232110 
    1824 def W2T (wtab, zcoord=None, zdim=None, sval=np.nan) : 
    1825     ''' 
    1826     Interpolate an array on W grid to T grid (k-mean) 
     2111def w2t (wtab, zcoord=None, zdim=None, sval=np.nan) : 
     2112    '''Interpolates an array on W grid to T grid (k-mean) 
     2113 
    18272114    sval is the bottom value 
    18282115    ''' 
     
    18302117    wtab_0 = mmath.where ( np.isnan(wtab), 0., wtab) 
    18312118 
    1832     kz, az = __findAxis__ (wtab_0, 'z') 
    1833  
    1834     if kz :  
     2119    az, kz = __find_axis__ (wtab_0, 'z') 
     2120 
     2121    if kz : 
    18352122        ttab = 0.5 * ( wtab_0 + np.roll (wtab_0, axis=kz, shift=-1) ) 
    18362123    else : 
     
    18402127        ttab[{az:kz}] = sval 
    18412128        if zdim and az : 
    1842             if az != zdim : ttab = ttab.rename ( {az:zdim} ) 
     2129            if az != zdim : 
     2130                ttab = ttab.rename ( {az:zdim} ) 
    18432131        if zcoord is not None : 
    18442132            ttab = ttab.assign_coords ( {zdim:zcoord} ) 
     
    18482136    return ttab 
    18492137 
    1850 def T2W (ttab, zcoord=None, zdim=None, sval=np.nan, extrap_surf=False) : 
    1851     '''Interpolate an array from T grid to W grid (k-mean) 
     2138def t2w (ttab, zcoord=None, zdim=None, sval=np.nan, extrap_surf=False) : 
     2139    '''Interpolates an array from T grid to W grid (k-mean) 
     2140 
    18522141    sval is the surface value 
    18532142    if extrap_surf==True, surface value is taken from 1st level value. 
     
    18552144    mmath = __mmath__ (ttab) 
    18562145    ttab_0 = mmath.where ( np.isnan(ttab), 0., ttab) 
    1857     kz, az = __findAxis__ (ttab_0, 'z') 
     2146    az, kz = __find_axis__ (ttab_0, 'z') 
    18582147    wtab = 0.5 * ( ttab_0 + np.roll (ttab_0, axis=kz, shift=1) ) 
    18592148 
    18602149    if mmath == xr : 
    1861         if extrap_surf : wtab[{az:0}] = ttabb[{az:0}] 
    1862         else           : wtab[{az:0}] = sval 
    1863     else :  
    1864         if extrap_surf : wtab[..., 0, :, :] = ttab[..., 0, :, :] 
    1865         else           : wtab[..., 0, :, :] = sval 
     2150        if extrap_surf : 
     2151            wtab[{az:0}] = ttab[{az:0}] 
     2152        else           : 
     2153            wtab[{az:0}] = sval 
     2154    else : 
     2155        if extrap_surf : 
     2156            wtab[..., 0, :, :] = ttab[..., 0, :, :] 
     2157        else           : 
     2158            wtab[..., 0, :, :] = sval 
    18662159 
    18672160    if mmath == xr : 
    1868         if zdim and az : 
    1869             if az != zdim : wtab = wtab.rename ( {az:zdim}) 
     2161        if zdim and az and az != zdim : 
     2162            wtab = wtab.rename ( {az:zdim}) 
    18702163        if zcoord is not None : 
    18712164            wtab = wtab.assign_coords ( {zdim:zcoord}) 
    18722165        else : 
    1873             ztab = wtab.assign_coords ( {zdim:np.arange(ttab.shape[kz])+1.} ) 
     2166            wtab = wtab.assign_coords ( {zdim:np.arange(ttab.shape[kz])+1.} ) 
    18742167    return wtab 
    18752168 
    1876 def fill (ptab, nperio, cd_type='T', npass=1, sval=0.) : 
    1877     ''' 
    1878     Fill sval values with mean of neighbours 
    1879     
     2169def fill (ptab, nperio, cd_type='T', npass=1, sval=np.nan) : 
     2170    '''Fills np.nan values with mean of neighbours 
     2171 
    18802172    Inputs : 
    18812173       ptab : input field to fill 
    18822174       nperio, cd_type : periodicity characteristics 
    1883     '''        
     2175    ''' 
    18842176 
    18852177    mmath = __mmath__ (ptab) 
    18862178 
    1887     DoPerio = False ; lperio = nperio 
     2179    do_perio  = False 
     2180    lperio    = nperio 
    18882181    if nperio == 4.2 : 
    1889         DoPerio = True ; lperio = 4 
     2182        do_perio, lperio = True, 4 
    18902183    if nperio == 6.2 : 
    1891         DoPerio = True ; lperio = 6 
    1892          
    1893     if DoPerio : 
    1894         ztab = lbc_add (ptab, nperio=nperio, sval=sval) 
    1895     else :  
     2184        do_perio, lperio = True, 6 
     2185 
     2186    if do_perio : 
     2187        ztab = lbc_add (ptab, nperio=nperio) 
     2188    else : 
    18962189        ztab = ptab 
    1897          
    1898     if np.isnan (sval) :  
     2190 
     2191    if np.isnan (sval) : 
    18992192        ztab   = mmath.where (np.isnan(ztab), np.nan, ztab) 
    19002193    else : 
    19012194        ztab   = mmath.where (ztab==sval    , np.nan, ztab) 
    1902     
    1903     for nn in np.arange (npass) :  
     2195 
     2196    for _ in np.arange (npass) : 
    19042197        zmask = mmath.where ( np.isnan(ztab), 0., 1.   ) 
    19052198        ztab0 = mmath.where ( np.isnan(ztab), 0., ztab ) 
     
    19252218        zcount = lbc (zcount, nperio=lperio, cd_type=cd_type) 
    19262219        znew   = lbc (znew  , nperio=lperio, cd_type=cd_type) 
    1927          
     2220 
    19282221        ztab = mmath.where (np.logical_and (zmask==0., zcount>0), znew/zcount, ztab) 
    19292222 
    19302223    ztab = mmath.where (zcount==0, sval, ztab) 
    1931     if DoPerio : ztab = lbc_del (ztab, nperio=lperio) 
     2224    if do_perio : 
     2225        ztab = lbc_del (ztab, nperio=lperio) 
    19322226 
    19332227    return ztab 
     
    19352229def correct_uv (u, v, lat) : 
    19362230    ''' 
    1937     Correct a Cartopy bug in orthographic projection 
     2231    Corrects a Cartopy bug in orthographic projection 
    19382232 
    19392233    See https://github.com/SciTools/cartopy/issues/1179 
     
    19472241       lat  : latitude of the point (degrees north) 
    19482242 
    1949     Outputs :  
     2243    Outputs : 
    19502244       modified eastward/nothward components to have correct polar projections in cartopy 
    19512245    ''' 
    19522246    uv = np.sqrt (u*u + v*v)           # Original modulus 
    19532247    zu = u 
    1954     zv = v * np.cos (rad*lat) 
     2248    zv = v * np.cos (RAD*lat) 
    19552249    zz = np.sqrt ( zu*zu + zv*zv )     # Corrected modulus 
    1956     uc = zu*uv/zz ; vc = zv*uv/zz      # Final corrected values 
     2250    uc = zu*uv/zz 
     2251    vc = zv*uv/zz      # Final corrected values 
    19572252    return uc, vc 
    19582253 
    19592254def norm_uv (u, v) : 
    1960     ''' 
    1961     Return norm of a 2 components vector 
     2255    '''Returns norm of a 2 components vector 
    19622256    ''' 
    19632257    return np.sqrt (u*u + v*v) 
    19642258 
    19652259def normalize_uv (u, v) : 
    1966     ''' 
    1967     Normalize 2 components vector 
     2260    '''Normalizes 2 components vector 
    19682261    ''' 
    19692262    uv = norm_uv (u, v) 
    19702263    return u/uv, v/uv 
    19712264 
    1972 def msf (vv, e1v_e3v, lat1d, depthw) : 
    1973     ''' 
    1974     Computes the meridonal stream function 
    1975     First input is meridional_velocity*e1v*e3v 
    1976     ''' 
    1977   
     2265def msf (vv, e1v_e3v, plat1d, depthw) : 
     2266    '''Computes the meridonal stream function 
     2267 
     2268    vv : meridional_velocity 
     2269    e1v_e3v : prodcut of scale factors e1v*e3v 
     2270    ''' 
     2271 
    19782272    v_e1v_e3v = vv * e1v_e3v 
    19792273    v_e1v_e3v.attrs = vv.attrs 
    1980      
    1981     ix, ax = __findAxis__ (v_e1v_e3v, 'x') 
    1982     kz, az = __findAxis__ (v_e1v_e3v, 'z') 
    1983     if az == 'olevel' : new_az = 'olevel' 
    1984     else              : new_az = 'depthw' 
     2274 
     2275    ax = __find_axis__ (v_e1v_e3v, 'x')[0] 
     2276    az = __find_axis__ (v_e1v_e3v, 'z')[0] 
     2277    if az == 'olevel' : 
     2278        new_az = 'olevel' 
     2279    else              : 
     2280        new_az = 'depthw' 
    19852281 
    19862282    zomsf = -v_e1v_e3v.cumsum ( dim=az, keep_attrs=True).sum (dim=ax, keep_attrs=True)*1.E-6 
    19872283    zomsf = zomsf - zomsf.isel ( { az:-1} ) 
    1988      
    1989     jy, ay = __findAxis__ (zomsf, 'y' ) 
    1990     zomsf = zomsf.assign_coords ( {az:depthw.values, ay:lat1d.values}) 
    1991      
     2284 
     2285    ay = __find_axis__ (zomsf, 'y' )[0] 
     2286    zomsf = zomsf.assign_coords ( {az:depthw.values, ay:plat1d.values}) 
     2287 
    19922288    zomsf = zomsf.rename ( {ay:'lat'}) 
    1993     if az != new_az : zomsf = zomsf.rename ( {az:new_az} ) 
     2289    if az != new_az : 
     2290        zomsf = zomsf.rename ( {az:new_az} ) 
    19942291    zomsf.attrs['standard_name'] = 'Meridional stream function' 
    19952292    zomsf.attrs['long_name'] = 'Meridional stream function' 
    19962293    zomsf.attrs['units'] = 'Sv' 
    19972294    zomsf[new_az].attrs  = depthw.attrs 
    1998     zomsf.lat.attrs=lat1d.attrs 
    1999          
     2295    zomsf.lat.attrs=plat1d.attrs 
     2296 
    20002297    return zomsf 
    20012298 
    20022299def bsf (uu, e2u_e3u, mask, nperio=None, bsf0=None ) : 
    2003     ''' 
    2004     Computes the barotropic stream function 
    2005     First input is zonal_velocity*e2u*e3u 
    2006     bsf0 is the point with bsf=0  
    2007     (ex: bsf0={'x':3, 'y':120} for orca2,  
    2008          bsf0={'x':5, 'y':300} for eeORCA1 
     2300    '''Computes the barotropic stream function 
     2301 
     2302    uu      : zonal_velocity 
     2303    e2u_e3u : product of scales factor e2u*e3u 
     2304    bsf0    : the point with bsf=0 
     2305    (ex: bsf0={'x':3, 'y':120} for orca2, 
     2306         bsf0={'x':5, 'y':300} for eORCA1 
    20092307    ''' 
    20102308    u_e2u_e3u       = uu * e2u_e3u 
    20112309    u_e2u_e3u.attrs = uu.attrs 
    20122310 
    2013     iy, ay = __findAxis__ (u_e2u_e3u, 'y') 
    2014     kz, az = __findAxis__ (u_e2u_e3u, 'z') 
    2015      
    2016     bsf = -u_e2u_e3u.cumsum ( dim=ay, keep_attrs=True ) 
    2017     bsf = bsf.sum (dim=az, keep_attrs=True)*1.E-6 
    2018          
     2311    ay = __find_axis__ (u_e2u_e3u, 'y')[0] 
     2312    az = __find_axis__ (u_e2u_e3u, 'z')[0] 
     2313 
     2314    zbsf = -u_e2u_e3u.cumsum ( dim=ay, keep_attrs=True ) 
     2315    zbsf = zbsf.sum (dim=az, keep_attrs=True)*1.E-6 
     2316 
    20192317    if bsf0 : 
    2020         bsf = bsf - bsf.isel (bsf0) 
    2021         
    2022     bsf = bsf.where (mask !=0, np.nan) 
    2023     for attr in uu.attrs : 
    2024         bsf.attrs[attr] = uu.attrs[attr] 
    2025     bsf.attrs['standard_name'] = 'barotropic_stream_function' 
    2026     bsf.attrs['long_name']     = 'Barotropic stream function' 
    2027     bsf.attrs['units']         = 'Sv' 
    2028     bsf = lbc (bsf, nperio=nperio, cd_type='F') 
    2029         
    2030     return bsf 
    2031  
    2032 def namelist_read (ref=None, cfg=None, out='dict', flat=False, verbose=False) : 
    2033     ''' 
    2034     Read NEMO namelist(s) and return either a dictionnary or an xarray dataset 
    2035  
    2036     ref : file with reference namelist, or a f90nml.namelist.Namelist object 
    2037     cfg : file with config namelist, or a f90nml.namelist.Namelist object 
    2038     At least one namelist neaded 
    2039  
    2040     out:  
     2318        zbsf = zbsf - zbsf.isel (bsf0) 
     2319 
     2320    zbsf = zbsf.where (mask !=0, np.nan) 
     2321    zbsf.attrs.update (uu.attrs) 
     2322    zbsf.attrs['standard_name'] = 'barotropic_stream_function' 
     2323    zbsf.attrs['long_name']     = 'Barotropic stream function' 
     2324    zbsf.attrs['units']         = 'Sv' 
     2325    zbsf = lbc (zbsf, nperio=nperio, cd_type='F') 
     2326 
     2327    return zbsf 
     2328 
     2329if f90nml : 
     2330    def namelist_read (ref=None, cfg=None, out='dict', flat=False, verbose=False) : 
     2331        '''Read NEMO namelist(s) and return either a dictionnary or an xarray dataset 
     2332 
     2333        ref : file with reference namelist, or a f90nml.namelist.Namelist object 
     2334        cfg : file with config namelist, or a f90nml.namelist.Namelist object 
     2335        At least one namelist neaded 
     2336 
     2337        out: 
    20412338        'dict' to return a dictonnary 
    20422339        'xr'   to return an xarray dataset 
    2043     flat : only for dict output. Output a flat dictionnary with all values. 
    2044      
    2045     ''' 
    2046      
    2047     import f90nml 
    2048     if ref : 
    2049         if isinstance (ref, str) : nml_ref = f90nml.read (ref) 
    2050         if isinstance (ref, f90nml.namelist.Namelist) : nml_ref = ref 
    2051          
    2052     if cfg : 
    2053         if isinstance (cfg, str) : nml_cfg = f90nml.read (cfg) 
    2054         if isinstance (cfg, f90nml.namelist.Namelist) : nml_cfg = cfg 
    2055      
    2056     if out == 'dict' : dict_namelist = {} 
    2057     if out == 'xr'   : xr_namelist = xr.Dataset () 
    2058  
    2059     list_nml = [] ; list_comment = [] 
    2060  
    2061     if ref : list_nml.append (nml_ref) ; list_comment.append ('ref') 
    2062     if cfg : list_nml.append (nml_cfg) ; list_comment.append ('cfg') 
    2063  
    2064     for nml, comment in zip (list_nml, list_comment) : 
    2065         if verbose : print (comment) 
    2066         if flat and out =='dict' : 
    2067             for nam in nml.keys () : 
    2068                 if verbose : print (nam) 
    2069                 for value in nml[nam] : 
    2070                      if out == 'dict' : dict_namelist[value] = nml[nam][value] 
    2071                      if verbose : print (nam, ':', value, ':', nml[nam][value]) 
    2072         else : 
    2073             for nam in nml.keys () : 
    2074                 if verbose : print (nam) 
    2075                 if out == 'dict' : 
    2076                     if nam not in dict_namelist.keys () : dict_namelist[nam] = {} 
    2077                 for value in nml[nam] : 
    2078                     if out == 'dict' : dict_namelist[nam][value] = nml[nam][value] 
    2079                     if out == 'xr'   : xr_namelist[value] = nml[nam][value] 
    2080                     if verbose : print (nam, ':', value, ':', nml[nam][value]) 
    2081  
    2082     if out == 'dict' : return dict_namelist 
    2083     if out == 'xr'   : return xr_namelist 
     2340        flat : only for dict output. Output a flat dictionary with all values. 
     2341 
     2342        ''' 
     2343        if ref : 
     2344            if isinstance (ref, str) : 
     2345                nml_ref = f90nml.read (ref) 
     2346            if isinstance (ref, f90nml.namelist.Namelist) : 
     2347                nml_ref = ref 
     2348 
     2349        if cfg : 
     2350            if isinstance (cfg, str) : 
     2351                nml_cfg = f90nml.read (cfg) 
     2352            if isinstance (cfg, f90nml.namelist.Namelist) : 
     2353                nml_cfg = cfg 
     2354 
     2355        if out == 'dict' : 
     2356            dict_namelist = {} 
     2357        if out == 'xr'   : 
     2358            xr_namelist = xr.Dataset () 
     2359 
     2360        list_nml     = [] 
     2361        list_comment = [] 
     2362 
     2363        if ref : 
     2364            list_nml.append (nml_ref) 
     2365            list_comment.append ('ref') 
     2366        if cfg : 
     2367            list_nml.append (nml_cfg) 
     2368            list_comment.append ('cfg') 
     2369 
     2370        for nml, comment in zip (list_nml, list_comment) : 
     2371            if verbose : 
     2372                print (comment) 
     2373            if flat and out =='dict' : 
     2374                for nam in nml.keys () : 
     2375                    if verbose : 
     2376                        print (nam) 
     2377                    for value in nml[nam] : 
     2378                        if out == 'dict' : 
     2379                            dict_namelist[value] = nml[nam][value] 
     2380                        if verbose : 
     2381                            print (nam, ':', value, ':', nml[nam][value]) 
     2382            else : 
     2383                for nam in nml.keys () : 
     2384                    if verbose : 
     2385                        print (nam) 
     2386                    if out == 'dict' : 
     2387                        if nam not in dict_namelist.keys () : 
     2388                            dict_namelist[nam] = {} 
     2389                    for value in nml[nam] : 
     2390                        if out == 'dict' : 
     2391                            dict_namelist[nam][value] = nml[nam][value] 
     2392                        if out == 'xr'   : 
     2393                            xr_namelist[value] = nml[nam][value] 
     2394                        if verbose : 
     2395                            print (nam, ':', value, ':', nml[nam][value]) 
     2396 
     2397        if out == 'dict' : 
     2398            return dict_namelist 
     2399        if out == 'xr'   : 
     2400            return xr_namelist 
     2401else : 
     2402     def namelist_read (ref=None, cfg=None, out='dict', flat=False, verbose=False) : 
     2403        '''Shadow version of namelist read, when f90nm module was not found 
     2404 
     2405        namelist_read :  
     2406        Read NEMO namelist(s) and return either a dictionnary or an xarray dataset 
     2407        ''' 
     2408        print ( 'Error : module f90nml not found' ) 
     2409        print ( 'Cannot call namelist_read' ) 
     2410        print ( 'Call parameters where : ') 
     2411        print ( f'{err=} {ref=} {cfg=} {out=} {flat=} {verbose=}' ) 
    20842412 
    20852413def fill_closed_seas (imask, nperio=None,  cd_type='T') : 
    20862414    '''Fill closed seas with image processing library 
     2415 
    20872416    imask : mask, 1 on ocean, 0 on land 
    20882417    ''' 
     
    20942423    return imask_filled 
    20952424 
    2096 ''' 
    2097 Sea water state function parameters from NEMO code 
    2098 ''' 
    2099 rdeltaS = 32. ; r1_S0  = 0.875/35.16504 ; r1_T0  = 1./40. ; r1_Z0  = 1.e-4 
    2100  
    2101 EOS000 =  8.0189615746e+02 ; EOS100 =  8.6672408165e+02 ; EOS200 = -1.7864682637e+03 ; EOS300 =  2.0375295546e+03 ; EOS400 = -1.2849161071e+03 ; EOS500 =  4.3227585684e+02 ; EOS600 = -6.0579916612e+01 
    2102 EOS010 =  2.6010145068e+01 ; EOS110 = -6.5281885265e+01 ; EOS210 =  8.1770425108e+01 ; EOS310 = -5.6888046321e+01 ; EOS410 =  1.7681814114e+01 ; EOS510 = -1.9193502195 
    2103 EOS020 = -3.7074170417e+01 ; EOS120 =  6.1548258127e+01 ; EOS220 = -6.0362551501e+01 ; EOS320 =  2.9130021253e+01 ; EOS420 = -5.4723692739     ; EOS030 =  2.1661789529e+01  
    2104 EOS130 = -3.3449108469e+01 ; EOS230 =  1.9717078466e+01 ; EOS330 = -3.1742946532 
    2105 EOS040 = -8.3627885467     ; EOS140 =  1.1311538584e+01 ; EOS240 = -5.3563304045 
    2106 EOS050 =  5.4048723791e-01 ; EOS150 =  4.8169980163e-01 
     2425# ====================================================== 
     2426# Sea water state function parameters from NEMO code 
     2427 
     2428RDELTAS = 32. 
     2429R1_S0   = 0.875/35.16504 
     2430R1_T0   = 1./40. 
     2431R1_Z0   = 1.e-4 
     2432 
     2433EOS000 =  8.0189615746e+02 
     2434EOS100 =  8.6672408165e+02 
     2435EOS200 = -1.7864682637e+03 
     2436EOS300 =  2.0375295546e+03 
     2437EOS400 = -1.2849161071e+03 
     2438EOS500 =  4.3227585684e+02 
     2439EOS600 = -6.0579916612e+01 
     2440EOS010 =  2.6010145068e+01 
     2441EOS110 = -6.5281885265e+01 
     2442EOS210 =  8.1770425108e+01 
     2443EOS310 = -5.6888046321e+01 
     2444EOS410 =  1.7681814114e+01 
     2445EOS510 = -1.9193502195 
     2446EOS020 = -3.7074170417e+01 
     2447EOS120 =  6.1548258127e+01 
     2448EOS220 = -6.0362551501e+01 
     2449EOS320 =  2.9130021253e+01 
     2450EOS420 = -5.4723692739 
     2451EOS030 =  2.1661789529e+01 
     2452EOS130 = -3.3449108469e+01 
     2453EOS230 =  1.9717078466e+01 
     2454EOS330 = -3.1742946532 
     2455EOS040 = -8.3627885467 
     2456EOS140 =  1.1311538584e+01 
     2457EOS240 = -5.3563304045 
     2458EOS050 =  5.4048723791e-01 
     2459EOS150 =  4.8169980163e-01 
    21072460EOS060 = -1.9083568888e-01 
    2108 EOS001 =  1.9681925209e+01 ; EOS101 = -4.2549998214e+01 ; EOS201 =  5.0774768218e+01 ; EOS301 = -3.0938076334e+01 ; EOS401 =   6.6051753097    ; EOS011 = -1.3336301113e+01 
    2109 EOS111 = -4.4870114575     ; EOS211 =  5.0042598061     ; EOS311 = -6.5399043664e-01 ; EOS021 =  6.7080479603     ; EOS121 =   3.5063081279 
    2110 EOS221 = -1.8795372996     ; EOS031 = -2.4649669534     ; EOS131 = -5.5077101279e-01 ; EOS041 =  5.5927935970e-01 
    2111 EOS002 =  2.0660924175     ; EOS102 = -4.9527603989     ; EOS202 =  2.5019633244     ; EOS012 =  2.0564311499     ; EOS112 = -2.1311365518e-01 ; EOS022 = -1.2419983026 
    2112 EOS003 = -2.3342758797e-02 ; EOS103 = -1.8507636718e-02 ; EOS013 =  3.7969820455e-01  
     2461EOS001 =  1.9681925209e+01 
     2462EOS101 = -4.2549998214e+01 
     2463EOS201 =  5.0774768218e+01 
     2464EOS301 = -3.0938076334e+01 
     2465EOS401 =  6.6051753097 
     2466EOS011 = -1.3336301113e+01 
     2467EOS111 = -4.4870114575 
     2468EOS211 =  5.0042598061 
     2469EOS311 = -6.5399043664e-01 
     2470EOS021 =  6.7080479603 
     2471EOS121 =  3.5063081279 
     2472EOS221 = -1.8795372996 
     2473EOS031 = -2.4649669534 
     2474EOS131 = -5.5077101279e-01 
     2475EOS041 =  5.5927935970e-01 
     2476EOS002 =  2.0660924175 
     2477EOS102 = -4.9527603989 
     2478EOS202 =  2.5019633244 
     2479EOS012 =  2.0564311499 
     2480EOS112 = -2.1311365518e-01 
     2481EOS022 = -1.2419983026 
     2482EOS003 = -2.3342758797e-02 
     2483EOS103 = -1.8507636718e-02 
     2484EOS013 =  3.7969820455e-01 
    21132485 
    21142486def rhop ( ptemp, psal ) : 
    2115     ''' 
    2116     Potential density referenced to surface 
     2487    '''Returns potential density referenced to surface 
     2488 
    21172489    Computation from NEMO code 
    21182490    ''' 
    2119     zt  = ptemp * r1_T0                                  # Temperature (°C) 
    2120     zs  = np.sqrt ( np.abs( psal + rdeltaS ) * r1_S0 )   # Square root of salinity (PSS) 
     2491    zt      = ptemp * R1_T0                                  # Temperature (°C) 
     2492    zs      = np.sqrt ( np.abs( psal + RDELTAS ) * R1_S0 )   # Square root of salinity (PSS) 
    21212493    # 
    2122     prhop = (((((EOS060*zt   \ 
    2123              + EOS150*zs     + EOS050)*zt   \ 
    2124              + (EOS240*zs    + EOS140)*zs + EOS040)*zt   \ 
    2125              + ((EOS330*zs   + EOS230)*zs + EOS130)*zs + EOS030)*zt   \ 
    2126              + (((EOS420*zs  + EOS320)*zs + EOS220)*zs + EOS120)*zs + EOS020)*zt   \ 
    2127              + ((((EOS510*zs + EOS410)*zs + EOS310)*zs + EOS210)*zs + EOS110)*zs + EOS010)*zt   \ 
    2128              + (((((EOS600*zs+ EOS500)*zs + EOS400)*zs + EOS300)*zs + EOS200)*zs + EOS100)*zs + EOS000 
     2494    prhop = ( 
     2495      (((((EOS060*zt 
     2496         + EOS150*zs     + EOS050)*zt 
     2497         + (EOS240*zs    + EOS140)*zs + EOS040)*zt 
     2498         + ((EOS330*zs   + EOS230)*zs + EOS130)*zs + EOS030)*zt 
     2499         + (((EOS420*zs  + EOS320)*zs + EOS220)*zs + EOS120)*zs + EOS020)*zt 
     2500         + ((((EOS510*zs + EOS410)*zs + EOS310)*zs + EOS210)*zs + EOS110)*zs + EOS010)*zt 
     2501         + (((((EOS600*zs+ EOS500)*zs + EOS400)*zs + EOS300)*zs + EOS200)*zs + EOS100)*zs + EOS000 ) 
    21292502    # 
    21302503    return prhop 
    21312504 
    21322505def rho ( pdep, ptemp, psal ) : 
    2133     ''' 
    2134     In situ density 
     2506    '''Returns in situ density 
     2507 
    21352508    Computation from NEMO code 
    21362509    ''' 
    2137     zh  = pdep  * r1_Z0                                  # Depth (m) 
    2138     zt  = ptemp * r1_T0                                  # Temperature (°C) 
    2139     zs  = np.sqrt ( np.abs( psal + rdeltaS ) * r1_S0 )   # Square root salinity (PSS) 
     2510    zh      = pdep  * R1_Z0                                  # Depth (m) 
     2511    zt      = ptemp * R1_T0                                  # Temperature (°C) 
     2512    zs      = np.sqrt ( np.abs( psal + RDELTAS ) * R1_S0 )   # Square root salinity (PSS) 
    21402513    # 
    21412514    zn3 = EOS013*zt + EOS103*zs+EOS003 
     
    21432516    zn2 = (EOS022*zt + EOS112*zs+EOS012)*zt + (EOS202*zs+EOS102)*zs+EOS002 
    21442517    # 
    2145     zn1 = (((EOS041*zt   \ 
    2146          + EOS131*zs   + EOS031)*zt   \ 
    2147          + (EOS221*zs  + EOS121)*zs + EOS021)*zt   \ 
    2148         + ((EOS311*zs  + EOS211)*zs + EOS111)*zs + EOS011)*zt   \ 
    2149         + (((EOS401*zs + EOS301)*zs + EOS201)*zs + EOS101)*zs + EOS001 
     2518    zn1 = ( 
     2519      (((EOS041*zt 
     2520       + EOS131*zs   + EOS031)*zt 
     2521       + (EOS221*zs  + EOS121)*zs + EOS021)*zt 
     2522       + ((EOS311*zs  + EOS211)*zs + EOS111)*zs + EOS011)*zt 
     2523       + (((EOS401*zs + EOS301)*zs + EOS201)*zs + EOS101)*zs + EOS001 ) 
    21502524    # 
    2151     zn0 = (((((EOS060*zt   \ 
    2152              + EOS150*zs      + EOS050)*zt   \ 
    2153              + (EOS240*zs     + EOS140)*zs + EOS040)*zt   \ 
    2154              + ((EOS330*zs    + EOS230)*zs + EOS130)*zs + EOS030)*zt   \ 
    2155              + (((EOS420*zs   + EOS320)*zs + EOS220)*zs + EOS120)*zs + EOS020)*zt   \ 
    2156              + ((((EOS510*zs  + EOS410)*zs + EOS310)*zs + EOS210)*zs + EOS110)*zs + EOS010)*zt   \ 
    2157              + (((((EOS600*zs + EOS500)*zs + EOS400)*zs + EOS300)*zs + EOS200)*zs + EOS100)*zs + EOS000 
     2525    zn0 = ( 
     2526      (((((EOS060*zt 
     2527         + EOS150*zs      + EOS050)*zt 
     2528         + (EOS240*zs     + EOS140)*zs + EOS040)*zt 
     2529         + ((EOS330*zs    + EOS230)*zs + EOS130)*zs + EOS030)*zt 
     2530         + (((EOS420*zs   + EOS320)*zs + EOS220)*zs + EOS120)*zs + EOS020)*zt 
     2531         + ((((EOS510*zs  + EOS410)*zs + EOS310)*zs + EOS210)*zs + EOS110)*zs + EOS010)*zt 
     2532         + (((((EOS600*zs + EOS500)*zs + EOS400)*zs + EOS300)*zs + 
     2533                                       EOS200)*zs + EOS100)*zs + EOS000 ) 
    21582534    # 
    21592535    prho  = ( ( zn3 * zh + zn2 ) * zh + zn1 ) * zh + zn0 
     
    21672543## =========================================================================== 
    21682544 
    2169 def __is_orca_north_fold__ ( Xtest, cname_long='T' ) : 
    2170     ''' 
    2171     Ported (pirated !!?) from Sosie 
    2172  
    2173     Tell if there is a 2/point band overlaping folding at the north pole typical of the ORCA grid 
    2174  
    2175     0 => not an orca grid (or unknown one) 
    2176     4 => North fold T-point pivot (ex: ORCA2) 
    2177     6 => North fold F-point pivot (ex: ORCA1) 
    2178  
    2179     We need all this 'cname_long' stuff because with our method, there is a 
    2180     confusion between "Grid_U with T-fold" and "Grid_V with F-fold" 
    2181     => so knowing the name of the longitude array (as in namelist, and hence as 
    2182     in netcdf file) might help taking the righ decision !!! UGLY!!! 
    2183     => not implemented yet 
    2184     ''' 
    2185      
    2186     ifld_nord =  0 ; cgrd_type = 'X' 
    2187     ny, nx = Xtest.shape[-2:] 
    2188  
    2189     if ny > 3 : # (case if called with a 1D array, ignoring...) 
    2190         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-3, nx-1:nx-nx//2+1:-1] ).sum() == 0. : 
    2191           ifld_nord = 4 ; cgrd_type = 'T' # T-pivot, grid_T       
    2192  
    2193         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-3, nx-2:nx-nx//2  :-1] ).sum() == 0. : 
    2194             if cnlon == 'U' : ifld_nord = 4 ;  cgrd_type = 'U' # T-pivot, grid_T 
    2195                 ## LOLO: PROBLEM == 6, V !!! 
    2196  
    2197         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-3, nx-1:nx-nx//2+1:-1] ).sum() == 0. : 
    2198             ifld_nord = 4 ; cgrd_type = 'V' # T-pivot, grid_V 
    2199  
    2200         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-2, nx-1-1:nx-nx//2:-1] ).sum() == 0. : 
    2201             ifld_nord = 6 ; cgrd_type = 'T'# F-pivot, grid_T 
    2202  
    2203         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-1, nx-1:nx-nx//2-1:-1] ).sum() == 0. : 
    2204             ifld_nord = 6 ;  cgrd_type = 'U' # F-pivot, grid_U 
    2205  
    2206         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-3, nx-2:nx-nx//2  :-1] ).sum() == 0. : 
    2207             if cnlon == 'V' : ifld_nord = 6 ; cgrd_type = 'V' # F-pivot, grid_V 
    2208                 ## LOLO: PROBLEM == 4, U !!! 
    2209  
    2210     return ifld_nord, cgrd_type 
     2545# def __is_orca_north_fold__ ( Xtest, cname_long='T' ) : 
     2546#     ''' 
     2547#     Ported (pirated !!?) from Sosie 
     2548 
     2549#     Tell if there is a 2/point band overlaping folding at the north pole typical of the ORCA grid 
     2550 
     2551#     0 => not an orca grid (or unknown one) 
     2552#     4 => North fold T-point pivot (ex: ORCA2) 
     2553#     6 => North fold F-point pivot (ex: ORCA1) 
     2554 
     2555#     We need all this 'cname_long' stuff because with our method, there is a 
     2556#     confusion between "Grid_U with T-fold" and "Grid_V with F-fold" 
     2557#     => so knowing the name of the longitude array (as in namelist, and hence as 
     2558#     in netcdf file) might help taking the righ decision !!! UGLY!!! 
     2559#     => not implemented yet 
     2560#     ''' 
     2561 
     2562#     ifld_nord =  0 ; cgrd_type = 'X' 
     2563#     ny, nx = Xtest.shape[-2:] 
     2564 
     2565#     if ny > 3 : # (case if called with a 1D array, ignoring...) 
     2566#         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-3, nx-1:nx-nx//2+1:-1] ).sum() == 0. : 
     2567#           ifld_nord = 4 ; cgrd_type = 'T' # T-pivot, grid_T 
     2568 
     2569#         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-3, nx-2:nx-nx//2  :-1] ).sum() == 0. : 
     2570#             if cnlon == 'U' : ifld_nord = 4 ;  cgrd_type = 'U' # T-pivot, grid_T 
     2571#                 ## LOLO: PROBLEM == 6, V !!! 
     2572 
     2573#         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-3, nx-1:nx-nx//2+1:-1] ).sum() == 0. : 
     2574#             ifld_nord = 4 ; cgrd_type = 'V' # T-pivot, grid_V 
     2575 
     2576#         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-2, nx-1-1:nx-nx//2:-1] ).sum() == 0. : 
     2577#             ifld_nord = 6 ; cgrd_type = 'T'# F-pivot, grid_T 
     2578 
     2579#         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-1, nx-1:nx-nx//2-1:-1] ).sum() == 0. : 
     2580#             ifld_nord = 6 ;  cgrd_type = 'U' # F-pivot, grid_U 
     2581 
     2582#         if ( Xtest [ny-1, 1:nx//2-1] - Xtest [ny-3, nx-2:nx-nx//2  :-1] ).sum() == 0. : 
     2583#             if cnlon == 'V' : ifld_nord = 6 ; cgrd_type = 'V' # F-pivot, grid_V 
     2584#                 ## LOLO: PROBLEM == 4, U !!! 
     2585 
     2586#     return ifld_nord, cgrd_type 
Note: See TracChangeset for help on using the changeset viewer.