New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
analyze_output.py in NEMO/branches/2020/dev_r13648_ASINTER-04_laurent_bulk_ice/tests/STATION_ASF/SANITY_CHECK – NEMO

source: NEMO/branches/2020/dev_r13648_ASINTER-04_laurent_bulk_ice/tests/STATION_ASF/SANITY_CHECK/analyze_output.py @ 13868

Last change on this file since 13868 was 13868, checked in by laurent, 3 years ago

Updating README for test STATION_ASF...

  • Property svn:executable set to *
File size: 8.6 KB
Line 
1#!/usr/bin/env python3
2# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
3#
4#######################################################################################
5# This script analyzes the output of STATION_ASF test-case with IDEALIZED forcing
6# in order to test the validity of computed fluxes and bulk transfer coefficient.
7# Beside an explicit standard output message, a result file is spawned:
8#    * SBCBLK.success => the test passed !
9#    * SBCBLK.fail    => the test failed !
10#
11#   Brodeau, 2020
12#
13########################################################################################
14
15import sys
16from os import path as path
17import math
18import numpy as nmp
19from netCDF4 import Dataset
20
21l_t_shift = False  ; # because time interp. is set to FALSE into "&namsbc_blk" of NEMO...
22#                    #  ==> so time array is shifted by 30 minutes but fluxes are the same (persitence of input fields ???)
23
24l_alg = [ 'ECMWF' , 'NCAR' , 'COARE3p0', 'COARE3p6', 'ANDREAS' ]
25nb_alg     =    len(l_alg)
26
27
28# Variables to check:
29l_var_rf = [  'Qsen'   ,   'Qlat'   ,  'Qlw'   ,   'Tau',   'Cd'  ,   'Ce'   ] ; # In forcing file "IDEALIZED/input_output_VALIDATION_IDEALIZED.nc"
30l_var_ot = [ 'qsb_oce' , 'qla_oce'  , 'qlw_oce',  'taum', 'Cd_oce', 'Ce_oce' ] ; # names in the NEMO/STATION_ASF output file (check file_def_oce.xml)
31nb_var  = len(l_var_rf)
32
33dir_figs='.'
34size_fig=(13,8)
35#fig_ext='png'
36fig_ext='svg'
37
38
39rDPI=100.
40
41
42class fclrs:
43    OKGR = '\033[92m'
44    FAIL = '\033[91m'
45    ENDC = '\033[0m'
46
47
48
49# Getting arguments:
50narg = len(sys.argv)
51if not narg in [3,4]:
52    print('Usage: '+sys.argv[0]+' <forcing_+_validation_file> <NEMO-STATION_ASF_output_directory> (<m> for more/debug)'); sys.exit(0)
53cf_rf = sys.argv[1]
54cdir_out = sys.argv[2]
55l_more = False
56if narg==4:
57    l_more = ( sys.argv[3] in ['m','M'] )
58    import matplotlib as mpl
59    mpl.use('Agg')
60    import matplotlib.pyplot as plt
61
62
63
64   
65# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
66# Populating and checking existence of files to be read
67# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
68def chck4f(cf):
69    cmesg = 'ERROR: File '+cf+' does not exist !!!'
70    if not path.exists(cf): print(cmesg) ; sys.exit(0)
71
72print('\n')
73
74# Input forcing/valid file:
75chck4f(cf_rf)
76id_rf = Dataset(cf_rf)
77vt = id_rf.variables['time'][:]
78cunit_t = id_rf.variables['time'].units
79id_rf.close()
80Nt_rf = len(vt)
81vtime_rf = nmp.zeros(Nt_rf); vtime_rf[:]  = vt[:]
82del vt
83print(' *** in forcing/valid file, "time" is in "'+cunit_t+'", Nt = '+str(Nt_rf)+'\n')
84
85
86# STATION_ASF output files (1 file per algorithm):
87cf_nemo = []
88for ja in range(nb_alg):
89    cfi = cdir_out+'/STATION_ASF-'+l_alg[ja]+'_IDEALIZED_1h_20200101_20200105_gridT.nc'
90    chck4f(cfi)
91    cf_nemo.append(cfi)
92print('\n *** NEMO/STATION_ASF output files we are goin to check:')
93for ja in range(nb_alg): print(cf_nemo[ja])
94print('\n')
95#-----------------------------------------------------------------
96
97# Getting time array from the first file:
98id_nm = Dataset(cf_nemo[0])
99vt = id_nm.variables['time_counter'][:]
100cunit_t = id_nm.variables['time_counter'].units ; print(' "time_counter" is in "'+cunit_t+'"')
101id_nm.close()
102Nt = len(vt)
103vtime_nm = nmp.zeros(Nt); vtime_nm[:]  = vt[:]
104del vt
105
106if Nt != Nt_rf-1: print('ERROR: the two files do not agree in terms of record lengrth: '+Nt_rf-1+' vs '+Nt)
107
108print('\n *** Excellent! We are going to look at surface fluxes under '+str(Nt)+' different scenarios of air-sea stability/wind-speed conditions...\n')
109
110# 30 minute shift, just like NEMO
111vtime = nmp.zeros(Nt)
112if l_t_shift:
113    vtime[:] = 0.5*(vtime_rf[:-1] + vtime_rf[1:])
114else:
115     vtime[:] =     vtime_rf[:-1]
116# Debug:
117#for jt in range(3):
118#    print(' Ref.  , Nemo "', vtime_rf[jt], vtime_nm[jt], vtime[jt])
119#sys.exit(0)
120
121
122
123
124##
125IREPORT = nmp.zeros((nb_alg,nb_var), dtype=int)
126
127
128
129
130# Loop on the fields to control...
131###################################
132
133jv=0
134for cv in l_var_rf:
135    cv_rf_m = cv+'_mean'
136    cv_rf_t = cv+'_tol'
137    cv_nemo = l_var_ot[jv]
138    print('\n\n ==== Checking variable '+cv_nemo+' against '+cv_rf_m+' !')
139
140    F_rf_m = nmp.zeros( Nt )
141    F_rf_t = nmp.zeros( Nt )
142    F_nemo = nmp.zeros((Nt,nb_alg))
143
144    wnd_rf = nmp.zeros( Nt ) ; #DEBUG
145    tzt_rf = nmp.zeros( Nt ) ; #DEBUG
146    qzt_rf = nmp.zeros( Nt ) ; #DEBUG
147    sst_rf = nmp.zeros( Nt ) ; #DEBUG
148   
149    id_rf = Dataset(cf_rf)
150    trf_m   = id_rf.variables[cv_rf_m][:] ; # Nt+1
151    trf_t   = id_rf.variables[cv_rf_t][:] ; # Nt+1
152    trf_wnd = id_rf.variables['wndspd'][:,1,1] ; # DEBUG
153    trf_tzt = id_rf.variables['t_air'][:,1,1] ; # DEBUG
154    trf_qzt = id_rf.variables['rh_air'][:,1,1] ; # DEBUG
155    trf_sst = id_rf.variables['sst'][:,1,1] ; # DEBUG
156    id_rf.close()
157   
158    if l_t_shift:
159        # 30 minute shift, just like NEMO
160        F_rf_m[:] = 0.5 * (trf_m[:-1] + trf_m[1:])
161        F_rf_t[:] = 0.5 * (trf_t[:-1] + trf_t[1:])
162    else:
163        F_rf_m[:] =        trf_m[:-1]
164        F_rf_t[:] =        trf_t[:-1]
165
166        wnd_rf[:] =        trf_wnd[:-1]       
167        tzt_rf[:] =        trf_tzt[:-1]
168        qzt_rf[:] =        trf_qzt[:-1]
169        sst_rf[:] =        trf_sst[:-1]       
170   
171   
172    for ja in range(nb_alg):
173       
174        calgo = l_alg[ja]
175
176        print(' *** '+calgo+' => '+cf_nemo[ja])
177
178        id_nemo = Dataset(cf_nemo[ja])
179        F_nemo[:,ja] = id_nemo.variables[cv_nemo][:,1,1] ; # it's 3x3 spatial domain, taking middle point !
180        id_nemo.close()
181
182
183        if l_more:
184            #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
185            # How does all this look on on a figure?
186            cfig = l_var_rf[jv]+'_'+calgo+'.'+fig_ext
187            print(' *** will plot '+cfig)
188            fig = plt.figure(num=1, figsize=size_fig, facecolor='w', edgecolor='k')
189            ax1 = plt.axes([0.08, 0.25, 0.9, 0.7])
190            #
191            plt.plot(vtime, F_nemo[:,ja], label='NEMO['+calgo+']', zorder=1)
192            plt.plot(vtime, F_rf_m[:], color='k', label='MEAN REF!', zorder=10)
193            # +- rtol enveloppe:
194            plt.fill_between(vtime, F_rf_m[:]-F_rf_t[:], F_rf_m[:]+F_rf_t[:], alpha=0.2)
195            #
196            ax1.grid(color='k', linestyle='-', linewidth=0.3)
197            plt.legend(loc='best', ncol=1, shadow=True, fancybox=True)
198            plt.savefig(cfig, dpi=int(rDPI), transparent=False)
199            plt.close(1)
200            print('')
201            #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
202
203
204        # Does the field look okay with respect to reference +- tolerance ?
205
206        l_overshoot_a = nmp.any( F_nemo[:,ja] > F_rf_m[:]+F_rf_t[:] )
207        l_overshoot_b = nmp.any( F_nemo[:,ja] < F_rf_m[:]-F_rf_t[:] )
208
209        if l_overshoot_a: print(fclrs.FAIL+'\n ***** BAD overshoot + for '+calgo+' for variable '+cv+' !!!\n'+fclrs.ENDC )
210           
211        if l_overshoot_b: print(fclrs.FAIL+'\n ***** BAD overshoot - for '+calgo+' for variable '+cv+' !!!'+fclrs.ENDC )
212
213        if l_overshoot_a or l_overshoot_b:
214            print(fclrs.FAIL+'\n ***** TEST NOT PASSED FOR '+calgo+' for variable '+cv+' !!!\n'+fclrs.ENDC )
215        else:
216            # We're all good !
217            IREPORT[ja,jv] = 1
218            if l_more: print(fclrs.OKGR+'\n ***** TEST PASSED FOR '+calgo+' for variable '+cv+' :D !!!\n'+fclrs.ENDC )
219                   
220    jv=jv+1
221
222
223
224l_ok =  nmp.sum(IREPORT[:,:]) == nb_var*nb_alg
225
226
227
228if l_ok:
229    ctxt      = 'PASSED'
230    ccol      = fclrs.OKGR
231    cf_report = 'SBCBLK.success'
232else:
233    ctxt      = 'FAILED'
234    ccol      = fclrs.FAIL
235    cf_report = 'SBCBLK.fail'
236   
237
238print(ccol+'\n\n ############ FINAL REPORT ############\n'+fclrs.ENDC)
239
240f = open(cf_report, 'w')
241
242f.write("### Sanity-check report for SBCBLK generated via 'STATION_ASF/EXP00/sbcblk_sanity_check.sh'\n\n")
243
244for ja in range(nb_alg):
245    calgo = l_alg[ja]
246   
247    if nmp.sum(IREPORT[ja,:]) == nb_var:
248        # Success for this algo
249        cbla = ' ***** Algorithm "'+calgo+'" PASSED sanity check !!!\n\n'
250        print(fclrs.OKGR+cbla+fclrs.ENDC ) ; f.write(cbla)
251    else:
252        # Algo FAILS!
253        cbla = ' ***** Algorithm "'+calgo+'" FAILED sanity check !!!\n'
254        print(fclrs.FAIL+cbla+fclrs.ENDC ) ; f.write(cbla)
255        (idx_fail,) = nmp.where(IREPORT[ja,:]==0)
256        for jv in idx_fail:
257            cbla = '   ==> on variable '+l_var_rf[jv]+' !\n\n'
258            print(fclrs.FAIL+cbla+fclrs.ENDC ) ; f.write(cbla)
259
260# Conclusion:
261clist=''
262for cc in l_var_ot: clist=clist+cc+', '
263cbla = ' Test performed on the following NEMO prognostic variables:\n   ==> '+clist[:-2]+'\n'
264print(ccol+cbla+fclrs.ENDC ) ; f.write(cbla+'\n')
265
266cbla = '    ####################################\n'  +\
267       '    ###   TEST '+ctxt+' FOR SBCBLK !   ###\n'+\
268       '    ####################################\n\n'
269
270print(ccol+cbla+fclrs.ENDC ) ; f.write(cbla)
271
272f.close()
Note: See TracBrowser for help on using the repository browser.