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.
chap_OBS.tex in NEMO/branches/2018/dev_r10164_HPC09_ESIWACE_PREP_MERGE/doc/latex/NEMO/subfiles – NEMO

source: NEMO/branches/2018/dev_r10164_HPC09_ESIWACE_PREP_MERGE/doc/latex/NEMO/subfiles/chap_OBS.tex @ 10368

Last change on this file since 10368 was 10368, checked in by smasson, 5 years ago

dev_r10164_HPC09_ESIWACE_PREP_MERGE: merge with trunk@10365, see #2133

File size: 62.1 KB
Line 
1\documentclass[../tex_main/NEMO_manual]{subfiles}
2\begin{document}
3% ================================================================
4% Chapter observation operator (OBS)
5% ================================================================
6\chapter{Observation and Model Comparison (OBS)}
7\label{chap:OBS}
8
9Authors: D. Lea, M. Martin, K. Mogensen, A. Vidard, A. Weaver, A. Ryan, ...   % do we keep that ?
10
11\minitoc
12
13
14\newpage
15$\ $\newline    % force a new line
16
17The observation and model comparison code (OBS) reads in observation files
18(profile temperature and salinity, sea surface temperature, sea level anomaly, sea ice concentration, and velocity) and calculates an interpolated model equivalent value at the observation location and nearest model timestep.
19The resulting data are saved in a ``feedback'' file (or files).
20The code was originally developed for use with the NEMOVAR data assimilation code,
21but can be used for validation or verification of the model or with any other data assimilation system.
22
23The OBS code is called from \mdl{nemogcm} for model initialisation and to calculate the model equivalent values for observations on the 0th timestep.
24The code is then called again after each timestep from \mdl{step}.
25The code is only activated if the namelist logical \np{ln\_diaobs} is set to true.
26
27For all data types a 2D horizontal interpolator or averager is needed to
28interpolate/average the model fields to the observation location.
29For {\em in situ} profiles, a 1D vertical interpolator is needed in addition to
30provide model fields at the observation depths.
31This now works in a generalised vertical coordinate system.
32
33Some profile observation types (e.g. tropical moored buoys) are made available as daily averaged quantities.
34The observation operator code can be set-up to calculate the equivalent daily average model temperature fields using
35the \np{nn\_profdavtypes} namelist array.
36Some SST observations are equivalent to a night-time average value and
37the observation operator code can calculate equivalent night-time average model SST fields by
38setting the namelist value \np{ln\_sstnight} to true.
39Otherwise the model value from the nearest timestep to the observation time is used.
40
41The code is controlled by the namelist \textit{namobs}.
42See the following sections for more details on setting up the namelist.
43
44\autoref{sec:OBS_example} introduces a test example of the observation operator code including
45where to obtain data and how to setup the namelist.
46\autoref{sec:OBS_details} introduces some more technical details of the different observation types used and
47also shows a more complete namelist.
48\autoref{sec:OBS_theory} introduces some of the theoretical aspects of the observation operator including
49interpolation methods and running on multiple processors.
50\autoref{sec:OBS_ooo} describes the offline observation operator code.
51\autoref{sec:OBS_obsutils} introduces some utilities to help working with the files produced by the OBS code.
52
53% ================================================================
54% Example
55% ================================================================
56\section{Running the observation operator code example}
57\label{sec:OBS_example}
58
59This section describes an example of running the observation operator code using
60profile data which can be freely downloaded.
61It shows how to adapt an existing run and build of NEMO to run the observation operator.
62
63\begin{enumerate}
64\item Compile NEMO.
65
66\item Download some EN4 data from \href{http://www.metoffice.gov.uk/hadobs}{www.metoffice.gov.uk/hadobs}.
67  Choose observations which are valid for the period of your test run because
68  the observation operator compares the model and observations for a matching date and time.
69
70\item Compile the OBSTOOLS code using:
71\begin{cmds}
72./maketools -n OBSTOOLS -m [ARCH].
73\end{cmds}
74
75\item Convert the EN4 data into feedback format:
76\begin{cmds}
77enact2fb.exe profiles_01.nc EN.4.1.1.f.profiles.g10.YYYYMM.nc
78\end{cmds}
79
80\item Include the following in the NEMO namelist to run the observation operator on this data:
81\end{enumerate}
82
83Options are defined through the \ngn{namobs} namelist variables.
84The options \np{ln\_t3d} and \np{ln\_s3d} switch on the temperature and salinity profile observation operator code.
85The filename or array of filenames are specified using the \np{cn\_profbfiles} variable.
86The model grid points for a particular observation latitude and longitude are found using
87the grid searching part of the code.
88This can be expensive, particularly for large numbers of observations,
89setting \np{ln\_grid\_search\_lookup} allows the use of a lookup table which
90is saved into an ``xypos`` file (or files).
91This will need to be generated the first time if it does not exist in the run directory.
92However, once produced it will significantly speed up future grid searches.
93Setting \np{ln\_grid\_global} means that the code distributes the observations evenly between processors.
94Alternatively each processor will work with observations located within the model subdomain
95(see section~\autoref{subsec:OBS_parallel}).
96
97A number of utilities are now provided to plot the feedback files, convert and recombine the files.
98These are explained in more detail in section~\autoref{sec:OBS_obsutils}.
99Utilites to convert other input data formats into the feedback format are also described in
100section~\autoref{sec:OBS_obsutils}.
101
102\section{Technical details (feedback type observation file headers)}
103\label{sec:OBS_details}
104
105Here we show a more complete example namelist \ngn{namobs} and also show the NetCDF headers of
106the observation files that may be used with the observation operator.
107
108%------------------------------------------namobs--------------------------------------------------------
109
110\nlst{namobs}
111%-------------------------------------------------------------------------------------------------------------
112
113The observation operator code uses the "feedback" observation file format for all data types.
114All the observation files must be in NetCDF format.
115Some example headers (produced using \mbox{\textit{ncdump~-h}}) for profile data, sea level anomaly and
116sea surface temperature are in the following subsections.
117
118\subsection{Profile feedback}
119
120\begin{clines}
121netcdf profiles_01 {
122dimensions:
123     N_OBS = 603 ;
124     N_LEVELS = 150 ;
125     N_VARS = 2 ;
126     N_QCF = 2 ;
127     N_ENTRIES = 1 ;
128     N_EXTRA = 1 ;
129     STRINGNAM = 8 ;
130     STRINGGRID = 1 ;
131     STRINGWMO = 8 ;
132     STRINGTYP = 4 ;
133     STRINGJULD = 14 ;
134variables:
135     char VARIABLES(N_VARS, STRINGNAM) ;
136          VARIABLES:long_name = "List of variables in feedback files" ;
137     char ENTRIES(N_ENTRIES, STRINGNAM) ;
138          ENTRIES:long_name = "List of additional entries for each variable in feedback files" ;
139     char EXTRA(N_EXTRA, STRINGNAM) ;
140          EXTRA:long_name = "List of extra variables" ;
141     char STATION_IDENTIFIER(N_OBS, STRINGWMO) ;
142          STATION_IDENTIFIER:long_name = "Station identifier" ;
143     char STATION_TYPE(N_OBS, STRINGTYP) ;
144          STATION_TYPE:long_name = "Code instrument type" ;
145     double LONGITUDE(N_OBS) ;
146          LONGITUDE:long_name = "Longitude" ;
147          LONGITUDE:units = "degrees_east" ;
148          LONGITUDE:_Fillvalue = 99999.f ;
149     double LATITUDE(N_OBS) ;
150          LATITUDE:long_name = "Latitude" ;
151          LATITUDE:units = "degrees_north" ;
152          LATITUDE:_Fillvalue = 99999.f ;
153     double DEPTH(N_OBS, N_LEVELS) ;
154          DEPTH:long_name = "Depth" ;
155          DEPTH:units = "metre" ;
156          DEPTH:_Fillvalue = 99999.f ;
157     int DEPTH_QC(N_OBS, N_LEVELS) ;
158          DEPTH_QC:long_name = "Quality on depth" ;
159          DEPTH_QC:Conventions = "q where q =[0,9]" ;
160          DEPTH_QC:_Fillvalue = 0 ;
161     int DEPTH_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
162          DEPTH_QC_FLAGS:long_name = "Quality flags on depth" ;
163          DEPTH_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
164     double JULD(N_OBS) ;
165          JULD:long_name = "Julian day" ;
166          JULD:units = "days since JULD_REFERENCE" ;
167          JULD:Conventions = "relative julian days with decimal part (as parts of day)" ;
168          JULD:_Fillvalue = 99999.f ;
169     char JULD_REFERENCE(STRINGJULD) ;
170          JULD_REFERENCE:long_name = "Date of reference for julian days" ;
171          JULD_REFERENCE:Conventions = "YYYYMMDDHHMMSS" ;
172     int OBSERVATION_QC(N_OBS) ;
173          OBSERVATION_QC:long_name = "Quality on observation" ;
174          OBSERVATION_QC:Conventions = "q where q =[0,9]" ;
175          OBSERVATION_QC:_Fillvalue = 0 ;
176     int OBSERVATION_QC_FLAGS(N_OBS, N_QCF) ;
177          OBSERVATION_QC_FLAGS:long_name = "Quality flags on observation" ;
178          OBSERVATION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
179          OBSERVATION_QC_FLAGS:_Fillvalue = 0 ;
180     int POSITION_QC(N_OBS) ;
181          POSITION_QC:long_name = "Quality on position (latitude and longitude)" ;
182          POSITION_QC:Conventions = "q where q =[0,9]" ;
183          POSITION_QC:_Fillvalue = 0 ;
184     int POSITION_QC_FLAGS(N_OBS, N_QCF) ;
185          POSITION_QC_FLAGS:long_name = "Quality flags on position" ;
186          POSITION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
187          POSITION_QC_FLAGS:_Fillvalue = 0 ;
188     int JULD_QC(N_OBS) ;
189          JULD_QC:long_name = "Quality on date and time" ;
190          JULD_QC:Conventions = "q where q =[0,9]" ;
191          JULD_QC:_Fillvalue = 0 ;
192     int JULD_QC_FLAGS(N_OBS, N_QCF) ;
193          JULD_QC_FLAGS:long_name = "Quality flags on date and time" ;
194          JULD_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
195          JULD_QC_FLAGS:_Fillvalue = 0 ;
196     int ORIGINAL_FILE_INDEX(N_OBS) ;
197          ORIGINAL_FILE_INDEX:long_name = "Index in original data file" ;
198          ORIGINAL_FILE_INDEX:_Fillvalue = -99999 ;
199     float POTM_OBS(N_OBS, N_LEVELS) ;
200          POTM_OBS:long_name = "Potential temperature" ;
201          POTM_OBS:units = "Degrees Celsius" ;
202          POTM_OBS:_Fillvalue = 99999.f ;
203     float POTM_Hx(N_OBS, N_LEVELS) ;
204          POTM_Hx:long_name = "Model interpolated potential temperature" ;
205          POTM_Hx:units = "Degrees Celsius" ;
206          POTM_Hx:_Fillvalue = 99999.f ;
207     int POTM_QC(N_OBS) ;
208          POTM_QC:long_name = "Quality on potential temperature" ;
209          POTM_QC:Conventions = "q where q =[0,9]" ;
210          POTM_QC:_Fillvalue = 0 ;
211     int POTM_QC_FLAGS(N_OBS, N_QCF) ;
212          POTM_QC_FLAGS:long_name = "Quality flags on potential temperature" ;
213          POTM_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
214          POTM_QC_FLAGS:_Fillvalue = 0 ;
215     int POTM_LEVEL_QC(N_OBS, N_LEVELS) ;
216          POTM_LEVEL_QC:long_name = "Quality for each level on potential temperature" ;
217          POTM_LEVEL_QC:Conventions = "q where q =[0,9]" ;
218          POTM_LEVEL_QC:_Fillvalue = 0 ;
219     int POTM_LEVEL_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
220          POTM_LEVEL_QC_FLAGS:long_name = "Quality flags for each level on potential temperature" ;
221          POTM_LEVEL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
222          POTM_LEVEL_QC_FLAGS:_Fillvalue = 0 ;
223     int POTM_IOBSI(N_OBS) ;
224          POTM_IOBSI:long_name = "ORCA grid search I coordinate" ;
225     int POTM_IOBSJ(N_OBS) ;
226          POTM_IOBSJ:long_name = "ORCA grid search J coordinate" ;
227     int POTM_IOBSK(N_OBS, N_LEVELS) ;
228          POTM_IOBSK:long_name = "ORCA grid search K coordinate" ;
229     char POTM_GRID(STRINGGRID) ;
230          POTM_GRID:long_name = "ORCA grid search grid (T,U,V)" ;
231     float PSAL_OBS(N_OBS, N_LEVELS) ;
232          PSAL_OBS:long_name = "Practical salinity" ;
233          PSAL_OBS:units = "PSU" ;
234          PSAL_OBS:_Fillvalue = 99999.f ;
235     float PSAL_Hx(N_OBS, N_LEVELS) ;
236          PSAL_Hx:long_name = "Model interpolated practical salinity" ;
237          PSAL_Hx:units = "PSU" ;
238          PSAL_Hx:_Fillvalue = 99999.f ;
239     int PSAL_QC(N_OBS) ;
240          PSAL_QC:long_name = "Quality on practical salinity" ;
241          PSAL_QC:Conventions = "q where q =[0,9]" ;
242          PSAL_QC:_Fillvalue = 0 ;
243     int PSAL_QC_FLAGS(N_OBS, N_QCF) ;
244          PSAL_QC_FLAGS:long_name = "Quality flags on practical salinity" ;
245          PSAL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
246          PSAL_QC_FLAGS:_Fillvalue = 0 ;
247     int PSAL_LEVEL_QC(N_OBS, N_LEVELS) ;
248          PSAL_LEVEL_QC:long_name = "Quality for each level on practical salinity" ;
249          PSAL_LEVEL_QC:Conventions = "q where q =[0,9]" ;
250          PSAL_LEVEL_QC:_Fillvalue = 0 ;
251     int PSAL_LEVEL_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
252          PSAL_LEVEL_QC_FLAGS:long_name = "Quality flags for each level on practical salinity" ;
253          PSAL_LEVEL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
254          PSAL_LEVEL_QC_FLAGS:_Fillvalue = 0 ;
255     int PSAL_IOBSI(N_OBS) ;
256          PSAL_IOBSI:long_name = "ORCA grid search I coordinate" ;
257     int PSAL_IOBSJ(N_OBS) ;
258          PSAL_IOBSJ:long_name = "ORCA grid search J coordinate" ;
259     int PSAL_IOBSK(N_OBS, N_LEVELS) ;
260          PSAL_IOBSK:long_name = "ORCA grid search K coordinate" ;
261     char PSAL_GRID(STRINGGRID) ;
262          PSAL_GRID:long_name = "ORCA grid search grid (T,U,V)" ;
263     float TEMP(N_OBS, N_LEVELS) ;
264          TEMP:long_name = "Insitu temperature" ;
265          TEMP:units = "Degrees Celsius" ;
266          TEMP:_Fillvalue = 99999.f ;
267
268// global attributes:
269          :title = "NEMO observation operator output" ;
270          :Convention = "NEMO unified observation operator output" ;
271}
272\end{clines}
273
274\subsection{Sea level anomaly feedback}
275
276\begin{clines}
277netcdf sla_01 {
278dimensions:
279     N_OBS = 41301 ;
280     N_LEVELS = 1 ;
281     N_VARS = 1 ;
282     N_QCF = 2 ;
283     N_ENTRIES = 1 ;
284     N_EXTRA = 1 ;
285     STRINGNAM = 8 ;
286     STRINGGRID = 1 ;
287     STRINGWMO = 8 ;
288     STRINGTYP = 4 ;
289     STRINGJULD = 14 ;
290variables:
291     char VARIABLES(N_VARS, STRINGNAM) ;
292          VARIABLES:long_name = "List of variables in feedback files" ;
293     char ENTRIES(N_ENTRIES, STRINGNAM) ;
294          ENTRIES:long_name = "List of additional entries for each variable in feedback files" ;
295     char EXTRA(N_EXTRA, STRINGNAM) ;
296          EXTRA:long_name = "List of extra variables" ;
297     char STATION_IDENTIFIER(N_OBS, STRINGWMO) ;
298          STATION_IDENTIFIER:long_name = "Station identifier" ;
299     char STATION_TYPE(N_OBS, STRINGTYP) ;
300          STATION_TYPE:long_name = "Code instrument type" ;
301     double LONGITUDE(N_OBS) ;
302          LONGITUDE:long_name = "Longitude" ;
303          LONGITUDE:units = "degrees_east" ;
304          LONGITUDE:_Fillvalue = 99999.f ;
305     double LATITUDE(N_OBS) ;
306          LATITUDE:long_name = "Latitude" ;
307          LATITUDE:units = "degrees_north" ;
308          LATITUDE:_Fillvalue = 99999.f ;
309     double DEPTH(N_OBS, N_LEVELS) ;
310          DEPTH:long_name = "Depth" ;
311          DEPTH:units = "metre" ;
312          DEPTH:_Fillvalue = 99999.f ;
313     int DEPTH_QC(N_OBS, N_LEVELS) ;
314          DEPTH_QC:long_name = "Quality on depth" ;
315          DEPTH_QC:Conventions = "q where q =[0,9]" ;
316          DEPTH_QC:_Fillvalue = 0 ;
317     int DEPTH_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
318          DEPTH_QC_FLAGS:long_name = "Quality flags on depth" ;
319          DEPTH_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
320     double JULD(N_OBS) ;
321          JULD:long_name = "Julian day" ;
322          JULD:units = "days since JULD_REFERENCE" ;
323          JULD:Conventions = "relative julian days with decimal part (as parts of day)" ;
324          JULD:_Fillvalue = 99999.f ;
325     char JULD_REFERENCE(STRINGJULD) ;
326          JULD_REFERENCE:long_name = "Date of reference for julian days" ;
327          JULD_REFERENCE:Conventions = "YYYYMMDDHHMMSS" ;
328     int OBSERVATION_QC(N_OBS) ;
329          OBSERVATION_QC:long_name = "Quality on observation" ;
330          OBSERVATION_QC:Conventions = "q where q =[0,9]" ;
331          OBSERVATION_QC:_Fillvalue = 0 ;
332     int OBSERVATION_QC_FLAGS(N_OBS, N_QCF) ;
333          OBSERVATION_QC_FLAGS:long_name = "Quality flags on observation" ;
334          OBSERVATION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
335          OBSERVATION_QC_FLAGS:_Fillvalue = 0 ;
336     int POSITION_QC(N_OBS) ;
337          POSITION_QC:long_name = "Quality on position (latitude and longitude)" ;
338          POSITION_QC:Conventions = "q where q =[0,9]" ;
339          POSITION_QC:_Fillvalue = 0 ;
340     int POSITION_QC_FLAGS(N_OBS, N_QCF) ;
341          POSITION_QC_FLAGS:long_name = "Quality flags on position" ;
342          POSITION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
343          POSITION_QC_FLAGS:_Fillvalue = 0 ;
344     int JULD_QC(N_OBS) ;
345          JULD_QC:long_name = "Quality on date and time" ;
346          JULD_QC:Conventions = "q where q =[0,9]" ;
347          JULD_QC:_Fillvalue = 0 ;
348     int JULD_QC_FLAGS(N_OBS, N_QCF) ;
349          JULD_QC_FLAGS:long_name = "Quality flags on date and time" ;
350          JULD_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
351          JULD_QC_FLAGS:_Fillvalue = 0 ;
352     int ORIGINAL_FILE_INDEX(N_OBS) ;
353          ORIGINAL_FILE_INDEX:long_name = "Index in original data file" ;
354          ORIGINAL_FILE_INDEX:_Fillvalue = -99999 ;
355     float SLA_OBS(N_OBS, N_LEVELS) ;
356          SLA_OBS:long_name = "Sea level anomaly" ;
357          SLA_OBS:units = "metre" ;
358          SLA_OBS:_Fillvalue = 99999.f ;
359     float SLA_Hx(N_OBS, N_LEVELS) ;
360          SLA_Hx:long_name = "Model interpolated sea level anomaly" ;
361          SLA_Hx:units = "metre" ;
362          SLA_Hx:_Fillvalue = 99999.f ;
363     int SLA_QC(N_OBS) ;
364          SLA_QC:long_name = "Quality on sea level anomaly" ;
365          SLA_QC:Conventions = "q where q =[0,9]" ;
366          SLA_QC:_Fillvalue = 0 ;
367     int SLA_QC_FLAGS(N_OBS, N_QCF) ;
368          SLA_QC_FLAGS:long_name = "Quality flags on sea level anomaly" ;
369          SLA_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
370          SLA_QC_FLAGS:_Fillvalue = 0 ;
371     int SLA_LEVEL_QC(N_OBS, N_LEVELS) ;
372          SLA_LEVEL_QC:long_name = "Quality for each level on sea level anomaly" ;
373          SLA_LEVEL_QC:Conventions = "q where q =[0,9]" ;
374          SLA_LEVEL_QC:_Fillvalue = 0 ;
375     int SLA_LEVEL_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
376          SLA_LEVEL_QC_FLAGS:long_name = "Quality flags for each level on sea level anomaly" ;
377          SLA_LEVEL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
378          SLA_LEVEL_QC_FLAGS:_Fillvalue = 0 ;
379     int SLA_IOBSI(N_OBS) ;
380          SLA_IOBSI:long_name = "ORCA grid search I coordinate" ;
381     int SLA_IOBSJ(N_OBS) ;
382          SLA_IOBSJ:long_name = "ORCA grid search J coordinate" ;
383     int SLA_IOBSK(N_OBS, N_LEVELS) ;
384          SLA_IOBSK:long_name = "ORCA grid search K coordinate" ;
385     char SLA_GRID(STRINGGRID) ;
386          SLA_GRID:long_name = "ORCA grid search grid (T,U,V)" ;
387     float MDT(N_OBS, N_LEVELS) ;
388          MDT:long_name = "Mean Dynamic Topography" ;
389          MDT:units = "metre" ;
390          MDT:_Fillvalue = 99999.f ;
391
392// global attributes:
393          :title = "NEMO observation operator output" ;
394          :Convention = "NEMO unified observation operator output" ;
395}
396\end{clines}
397
398The mean dynamic topography (MDT) must be provided in a separate file defined on
399the model grid called \ifile{slaReferenceLevel}.
400The MDT is required in order to produce the model equivalent sea level anomaly from the model sea surface height.
401Below is an example header for this file (on the ORCA025 grid).
402
403\begin{clines}
404dimensions:
405        x = 1442 ;
406        y = 1021 ;
407variables:
408        float nav_lon(y, x) ;
409                nav_lon:units = "degrees_east" ;
410        float nav_lat(y, x) ;
411                nav_lat:units = "degrees_north" ;
412        float sossheig(y, x) ;
413                sossheig:_FillValue = -1.e+30f ;
414                sossheig:coordinates = "nav_lon nav_lat" ;
415                sossheig:long_name = "Mean Dynamic Topography" ;
416                sossheig:units = "metres" ;
417                sossheig:grid = "orca025T" ;
418\end{clines}
419
420\subsection{Sea surface temperature feedback}
421
422\begin{clines}
423netcdf sst_01 {
424dimensions:
425     N_OBS = 33099 ;
426     N_LEVELS = 1 ;
427     N_VARS = 1 ;
428     N_QCF = 2 ;
429     N_ENTRIES = 1 ;
430     STRINGNAM = 8 ;
431     STRINGGRID = 1 ;
432     STRINGWMO = 8 ;
433     STRINGTYP = 4 ;
434     STRINGJULD = 14 ;
435variables:
436     char VARIABLES(N_VARS, STRINGNAM) ;
437          VARIABLES:long_name = "List of variables in feedback files" ;
438     char ENTRIES(N_ENTRIES, STRINGNAM) ;
439          ENTRIES:long_name = "List of additional entries for each variable in feedback files" ;
440     char STATION_IDENTIFIER(N_OBS, STRINGWMO) ;
441          STATION_IDENTIFIER:long_name = "Station identifier" ;
442     char STATION_TYPE(N_OBS, STRINGTYP) ;
443          STATION_TYPE:long_name = "Code instrument type" ;
444     double LONGITUDE(N_OBS) ;
445          LONGITUDE:long_name = "Longitude" ;
446          LONGITUDE:units = "degrees_east" ;
447          LONGITUDE:_Fillvalue = 99999.f ;
448     double LATITUDE(N_OBS) ;
449          LATITUDE:long_name = "Latitude" ;
450          LATITUDE:units = "degrees_north" ;
451          LATITUDE:_Fillvalue = 99999.f ;
452     double DEPTH(N_OBS, N_LEVELS) ;
453          DEPTH:long_name = "Depth" ;
454          DEPTH:units = "metre" ;
455          DEPTH:_Fillvalue = 99999.f ;
456     int DEPTH_QC(N_OBS, N_LEVELS) ;
457          DEPTH_QC:long_name = "Quality on depth" ;
458          DEPTH_QC:Conventions = "q where q =[0,9]" ;
459          DEPTH_QC:_Fillvalue = 0 ;
460     int DEPTH_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
461          DEPTH_QC_FLAGS:long_name = "Quality flags on depth" ;
462          DEPTH_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
463     double JULD(N_OBS) ;
464          JULD:long_name = "Julian day" ;
465          JULD:units = "days since JULD_REFERENCE" ;
466          JULD:Conventions = "relative julian days with decimal part (as parts of day)" ;
467          JULD:_Fillvalue = 99999.f ;
468     char JULD_REFERENCE(STRINGJULD) ;
469          JULD_REFERENCE:long_name = "Date of reference for julian days" ;
470          JULD_REFERENCE:Conventions = "YYYYMMDDHHMMSS" ;
471     int OBSERVATION_QC(N_OBS) ;
472          OBSERVATION_QC:long_name = "Quality on observation" ;
473          OBSERVATION_QC:Conventions = "q where q =[0,9]" ;
474          OBSERVATION_QC:_Fillvalue = 0 ;
475     int OBSERVATION_QC_FLAGS(N_OBS, N_QCF) ;
476          OBSERVATION_QC_FLAGS:long_name = "Quality flags on observation" ;
477          OBSERVATION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
478          OBSERVATION_QC_FLAGS:_Fillvalue = 0 ;
479     int POSITION_QC(N_OBS) ;
480          POSITION_QC:long_name = "Quality on position (latitude and longitude)" ;
481          POSITION_QC:Conventions = "q where q =[0,9]" ;
482          POSITION_QC:_Fillvalue = 0 ;
483     int POSITION_QC_FLAGS(N_OBS, N_QCF) ;
484          POSITION_QC_FLAGS:long_name = "Quality flags on position" ;
485          POSITION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
486          POSITION_QC_FLAGS:_Fillvalue = 0 ;
487     int JULD_QC(N_OBS) ;
488          JULD_QC:long_name = "Quality on date and time" ;
489          JULD_QC:Conventions = "q where q =[0,9]" ;
490          JULD_QC:_Fillvalue = 0 ;
491     int JULD_QC_FLAGS(N_OBS, N_QCF) ;
492          JULD_QC_FLAGS:long_name = "Quality flags on date and time" ;
493          JULD_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
494          JULD_QC_FLAGS:_Fillvalue = 0 ;
495     int ORIGINAL_FILE_INDEX(N_OBS) ;
496          ORIGINAL_FILE_INDEX:long_name = "Index in original data file" ;
497          ORIGINAL_FILE_INDEX:_Fillvalue = -99999 ;
498     float SST_OBS(N_OBS, N_LEVELS) ;
499          SST_OBS:long_name = "Sea surface temperature" ;
500          SST_OBS:units = "Degree centigrade" ;
501          SST_OBS:_Fillvalue = 99999.f ;
502     float SST_Hx(N_OBS, N_LEVELS) ;
503          SST_Hx:long_name = "Model interpolated sea surface temperature" ;
504          SST_Hx:units = "Degree centigrade" ;
505          SST_Hx:_Fillvalue = 99999.f ;
506     int SST_QC(N_OBS) ;
507          SST_QC:long_name = "Quality on sea surface temperature" ;
508          SST_QC:Conventions = "q where q =[0,9]" ;
509          SST_QC:_Fillvalue = 0 ;
510     int SST_QC_FLAGS(N_OBS, N_QCF) ;
511          SST_QC_FLAGS:long_name = "Quality flags on sea surface temperature" ;
512          SST_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
513          SST_QC_FLAGS:_Fillvalue = 0 ;
514     int SST_LEVEL_QC(N_OBS, N_LEVELS) ;
515          SST_LEVEL_QC:long_name = "Quality for each level on sea surface temperature" ;
516          SST_LEVEL_QC:Conventions = "q where q =[0,9]" ;
517          SST_LEVEL_QC:_Fillvalue = 0 ;
518     int SST_LEVEL_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
519          SST_LEVEL_QC_FLAGS:long_name = "Quality flags for each level on sea surface temperature" ;
520          SST_LEVEL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
521          SST_LEVEL_QC_FLAGS:_Fillvalue = 0 ;
522     int SST_IOBSI(N_OBS) ;
523          SST_IOBSI:long_name = "ORCA grid search I coordinate" ;
524     int SST_IOBSJ(N_OBS) ;
525          SST_IOBSJ:long_name = "ORCA grid search J coordinate" ;
526     int SST_IOBSK(N_OBS, N_LEVELS) ;
527          SST_IOBSK:long_name = "ORCA grid search K coordinate" ;
528     char SST_GRID(STRINGGRID) ;
529          SST_GRID:long_name = "ORCA grid search grid (T,U,V)" ;
530
531// global attributes:
532          :title = "NEMO observation operator output" ;
533          :Convention = "NEMO unified observation operator output" ;
534}
535\end{clines}
536
537\section{Theoretical details}
538\label{sec:OBS_theory}
539
540\subsection{Horizontal interpolation and averaging methods}
541
542For most observation types, the horizontal extent of the observation is small compared to the model grid size and so
543the model equivalent of the observation is calculated by interpolating from
544the four surrounding grid points to the observation location.
545Some satellite observations (e.g. microwave satellite SST data, or satellite SSS data) have a footprint which
546is similar in size or larger than the model grid size (particularly when the grid size is small).
547In those cases the model counterpart should be calculated by averaging the model grid points over
548the same size as the footprint.
549NEMO therefore has the capability to specify either an interpolation or an averaging
550(for surface observation types only).
551
552The main namelist option associated with the interpolation/averaging is \np{nn\_2dint}.
553This default option can be set to values from 0 to 6.
554Values between 0 to 4 are associated with interpolation while values 5 or 6 are associated with averaging.
555\begin{itemize}
556\item \np{nn\_2dint}\forcode{ = 0}: Distance-weighted interpolation
557\item \np{nn\_2dint}\forcode{ = 1}: Distance-weighted interpolation (small angle)
558\item \np{nn\_2dint}\forcode{ = 2}: Bilinear interpolation (geographical grid)
559\item \np{nn\_2dint}\forcode{ = 3}: Bilinear remapping interpolation (general grid)
560\item \np{nn\_2dint}\forcode{ = 4}: Polynomial interpolation
561\item \np{nn\_2dint}\forcode{ = 5}: Radial footprint averaging with diameter specified in the namelist as
562  \np{rn\_???\_avglamscl} in degrees or metres (set using \np{ln\_???\_fp\_indegs})
563\item \np{nn\_2dint}\forcode{ = 6}: Rectangular footprint averaging with E/W and N/S size specified in
564  the namelist as \np{rn\_???\_avglamscl} and \np{rn\_???\_avgphiscl} in degrees or metres
565  (set using \np{ln\_???\_fp\_indegs})
566\end{itemize}
567The ??? in the last two options indicate these options should be specified for each observation type for
568which the averaging is to be performed (see namelist example above).
569The \np{nn\_2dint} default option can be overridden for surface observation types using
570namelist values \np{nn\_2dint\_???} where ??? is one of sla,sst,sss,sic.
571
572Below is some more detail on the various options for interpolation and averaging available in NEMO.
573
574\subsubsection{Horizontal interpolation}
575Consider an observation point ${\rm P}$ with with longitude and latitude $({\lambda_{}}_{\rm P}, \phi_{\rm P})$ and
576the four nearest neighbouring model grid points ${\rm A}$, ${\rm B}$, ${\rm C}$ and ${\rm D}$ with
577longitude and latitude ($\lambda_{\rm A}$, $\phi_{\rm A}$),($\lambda_{\rm B}$, $\phi_{\rm B}$) etc.
578All horizontal interpolation methods implemented in NEMO estimate the value of a model variable $x$ at point $P$ as
579a weighted linear combination of the values of the model variables at the grid points ${\rm A}$, ${\rm B}$ etc.:
580\begin{eqnarray}
581{x_{}}_{\rm P} & \hspace{-2mm} = \hspace{-2mm} & 
582\frac{1}{w} \left( {w_{}}_{\rm A} {x_{}}_{\rm A} +
583                   {w_{}}_{\rm B} {x_{}}_{\rm B} +
584                   {w_{}}_{\rm C} {x_{}}_{\rm C} +
585                   {w_{}}_{\rm D} {x_{}}_{\rm D} \right)
586\end{eqnarray}
587where ${w_{}}_{\rm A}$, ${w_{}}_{\rm B}$ etc. are the respective weights for the model field at
588points ${\rm A}$, ${\rm B}$ etc., and $w = {w_{}}_{\rm A} + {w_{}}_{\rm B} + {w_{}}_{\rm C} + {w_{}}_{\rm D}$.
589
590Four different possibilities are available for computing the weights.
591
592\begin{enumerate}
593
594\item[1.] {\bf Great-Circle distance-weighted interpolation.}
595  The weights are computed as a function of the great-circle distance $s(P, \cdot)$ between $P$ and
596  the model grid points $A$, $B$ etc.
597  For example, the weight given to the field ${x_{}}_{\rm A}$ is specified as the product of the distances
598  from ${\rm P}$ to the other points:
599  \begin{eqnarray}
600  {w_{}}_{\rm A} = s({\rm P}, {\rm B}) \, s({\rm P}, {\rm C}) \, s({\rm P}, {\rm D})
601  \nonumber
602  \end{eqnarray}
603  where
604  \begin{eqnarray}
605   s\left ({\rm P}, {\rm M} \right )
606     & \hspace{-2mm} = \hspace{-2mm} & 
607      \cos^{-1} \! \left\{ 
608               \sin {\phi_{}}_{\rm P} \sin {\phi_{}}_{\rm M}
609             + \cos {\phi_{}}_{\rm P} \cos {\phi_{}}_{\rm M} 
610               \cos ({\lambda_{}}_{\rm M} - {\lambda_{}}_{\rm P})
611                   \right\}
612   \end{eqnarray}
613   and $M$ corresponds to $B$, $C$ or $D$.
614   A more stable form of the great-circle distance formula for small distances ($x$ near 1)
615   involves the arcsine function ($e.g.$ see p.~101 of \citet{Daley_Barker_Bk01}:
616   \begin{eqnarray}
617   s\left( {\rm P}, {\rm M} \right)
618     & \hspace{-2mm} = \hspace{-2mm} & 
619      \sin^{-1} \! \left\{ \sqrt{ 1 - x^2 } \right\}
620   \nonumber
621   \end{eqnarray}
622   where
623   \begin{eqnarray}
624    x & \hspace{-2mm} = \hspace{-2mm} & 
625      {a_{}}_{\rm M} {a_{}}_{\rm P} + {b_{}}_{\rm M} {b_{}}_{\rm P} + {c_{}}_{\rm M} {c_{}}_{\rm P}
626   \nonumber
627   \end{eqnarray}
628   and
629   \begin{eqnarray}
630      {a_{}}_{\rm M} & \hspace{-2mm} = \hspace{-2mm} & \sin {\phi_{}}_{\rm M},
631      \nonumber \\
632      {a_{}}_{\rm P} & \hspace{-2mm} = \hspace{-2mm} & \sin {\phi_{}}_{\rm P},
633      \nonumber \\
634      {b_{}}_{\rm M} & \hspace{-2mm} = \hspace{-2mm} & \cos {\phi_{}}_{\rm M} \cos {\phi_{}}_{\rm M},
635      \nonumber \\
636      {b_{}}_{\rm P} & \hspace{-2mm} = \hspace{-2mm} & \cos {\phi_{}}_{\rm P} \cos {\phi_{}}_{\rm P},
637      \nonumber \\
638      {c_{}}_{\rm M} & \hspace{-2mm} = \hspace{-2mm} & \cos {\phi_{}}_{\rm M} \sin {\phi_{}}_{\rm M},
639      \nonumber \\
640      {c_{}}_{\rm P} & \hspace{-2mm} = \hspace{-2mm} & \cos {\phi_{}}_{\rm P} \sin {\phi_{}}_{\rm P}.
641      \nonumber
642   \nonumber
643  \end{eqnarray}
644
645\item[2.] {\bf Great-Circle distance-weighted interpolation with small angle approximation.}
646  Similar to the previous interpolation but with the distance $s$ computed as
647  \begin{eqnarray}
648    s\left( {\rm P}, {\rm M} \right)
649     & \hspace{-2mm} = \hspace{-2mm} & 
650      \sqrt{ \left( {\phi_{}}_{\rm M} - {\phi_{}}_{\rm P} \right)^{2} 
651      + \left( {\lambda_{}}_{\rm M} - {\lambda_{}}_{\rm P} \right)^{2}
652        \cos^{2} {\phi_{}}_{\rm M} }
653  \end{eqnarray}
654  where $M$ corresponds to $A$, $B$, $C$ or $D$.
655
656\item[3.] {\bf Bilinear interpolation for a regular spaced grid.}
657  The interpolation is split into two 1D interpolations in the longitude and latitude directions, respectively.
658
659\item[4.] {\bf Bilinear remapping interpolation for a general grid.}
660  An iterative scheme that involves first mapping a quadrilateral cell into
661  a cell with coordinates (0,0), (1,0), (0,1) and (1,1).
662  This method is based on the SCRIP interpolation package \citep{Jones_1998}.
663 
664\end{enumerate}
665
666\subsubsection{Horizontal averaging}
667
668For each surface observation type:
669\begin{itemize}
670\item The standard grid-searching code is used to find the nearest model grid point to the observation location
671  (see next subsection).
672\item The maximum number of grid points is calculated in the local grid domain for which
673  the averaging is likely need to cover.
674\item The lats/longs of the grid points surrounding the nearest model grid box are extracted using
675  existing mpi routines.
676\item The weights for each grid point associated with each observation are calculated,
677  either for radial or rectangular footprints.
678  For grid points completely within the footprint, the weight is one;
679  for grid points completely outside the footprint, the weight is zero.
680  For grid points which are partly within the footprint the ratio between the area of the footprint within
681  the grid box and the total area of the grid box is used as the weight.
682\item The weighted average of the model grid points associated with each observation is calculated,
683  and this is then given as the model counterpart of the observation.
684\end{itemize}
685
686Examples of the weights calculated for an observation with rectangular and radial footprints are shown in
687Figs.~\autoref{fig:obsavgrec} and~\autoref{fig:obsavgrad}.
688
689%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
690\begin{figure}      \begin{center}
691\includegraphics[width=0.90\textwidth]{Fig_OBS_avg_rec}
692\caption{      \protect\label{fig:obsavgrec}
693  Weights associated with each model grid box (blue lines and numbers)
694  for an observation at -170.5E, 56.0N with a rectangular footprint of 1\deg x 1\deg.}
695\end{center}      \end{figure}
696%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
697
698%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
699\begin{figure}      \begin{center}
700\includegraphics[width=0.90\textwidth]{Fig_OBS_avg_rad}
701\caption{      \protect\label{fig:obsavgrad}
702  Weights associated with each model grid box (blue lines and numbers)
703  for an observation at -170.5E, 56.0N with a radial footprint with diameter 1\deg.} 
704\end{center}      \end{figure}
705%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
706
707
708\subsection{Grid search}
709
710For many grids used by the NEMO model, such as the ORCA family, the horizontal grid coordinates $i$ and $j$ are not simple functions of latitude and longitude.
711Therefore, it is not always straightforward to determine the grid points surrounding any given observational position.
712Before the interpolation can be performed, a search algorithm is then required to determine the corner points of
713the quadrilateral cell in which the observation is located.
714This is the most difficult and time consuming part of the 2D interpolation procedure.
715A robust test for determining if an observation falls within a given quadrilateral cell is as follows.
716Let ${\rm P}({\lambda_{}}_{\rm P} ,{\phi_{}}_{\rm P} )$ denote the observation point,
717and let ${\rm A}({\lambda_{}}_{\rm A} ,{\phi_{}}_{\rm A} )$, ${\rm B}({\lambda_{}}_{\rm B} ,{\phi_{}}_{\rm B} )$,
718${\rm C}({\lambda_{}}_{\rm C} ,{\phi_{}}_{\rm C} )$ and ${\rm D}({\lambda_{}}_{\rm D} ,{\phi_{}}_{\rm D} )$
719denote the bottom left, bottom right, top left and top right corner points of the cell, respectively.
720To determine if P is inside the cell, we verify that the cross-products
721\begin{eqnarray}
722\begin{array}{lllll}
723{{\bf r}_{}}_{\rm PA} \times {{\bf r}_{}}_{\rm PC}
724& = & [({\lambda_{}}_{\rm A}\; -\; {\lambda_{}}_{\rm P} )
725      ({\phi_{}}_{\rm C}   \; -\; {\phi_{}}_{\rm P} )
726    - ({\lambda_{}}_{\rm C}\; -\; {\lambda_{}}_{\rm P} )
727      ({\phi_{}}_{\rm A}   \; -\; {\phi_{}}_{\rm P} )] \; \widehat{\bf k} \\
728{{\bf r}_{}}_{\rm PB} \times {{\bf r}_{}}_{\rm PA}
729& = & [({\lambda_{}}_{\rm B}\; -\; {\lambda_{}}_{\rm P} )
730      ({\phi_{}}_{\rm A}   \; -\; {\phi_{}}_{\rm P} )
731    - ({\lambda_{}}_{\rm A}\; -\; {\lambda_{}}_{\rm P} )
732      ({\phi_{}}_{\rm B}   \; -\; {\phi_{}}_{\rm P} )] \; \widehat{\bf k} \\
733{{\bf r}_{}}_{\rm PC} \times {{\bf r}_{}}_{\rm PD}
734& = & [({\lambda_{}}_{\rm C}\; -\; {\lambda_{}}_{\rm P} )
735      ({\phi_{}}_{\rm D}   \; -\; {\phi_{}}_{\rm P} )
736    - ({\lambda_{}}_{\rm D}\; -\; {\lambda_{}}_{\rm P} )
737      ({\phi_{}}_{\rm C}   \; -\; {\phi_{}}_{\rm P} )] \; \widehat{\bf k} \\
738{{\bf r}_{}}_{\rm PD} \times {{\bf r}_{}}_{\rm PB}
739& = & [({\lambda_{}}_{\rm D}\; -\; {\lambda_{}}_{\rm P} )
740      ({\phi_{}}_{\rm B}   \; -\; {\phi_{}}_{\rm P} )
741    - ({\lambda_{}}_{\rm B}\; -\; {\lambda_{}}_{\rm P} )
742      ({\phi_{}}_{\rm D}  \;  - \; {\phi_{}}_{\rm P} )] \; \widehat{\bf k} \\
743\end{array}
744\label{eq:cross}
745\end{eqnarray}
746point in the opposite direction to the unit normal $\widehat{\bf k}$
747(i.e., that the coefficients of $\widehat{\bf k}$ are negative),
748where ${{\bf r}_{}}_{\rm PA}$, ${{\bf r}_{}}_{\rm PB}$, etc. correspond to
749the vectors between points P and A, P and B, etc..
750The method used is similar to the method used in the SCRIP interpolation package \citep{Jones_1998}.
751
752In order to speed up the grid search, there is the possibility to construct a lookup table for a user specified resolution.
753This lookup table contains the lower and upper bounds on the $i$ and $j$ indices to
754be searched for on a regular grid.
755For each observation position, the closest point on the regular grid of this position is computed and
756the $i$ and $j$ ranges of this point searched to determine the precise four points surrounding the observation.
757
758\subsection{Parallel aspects of horizontal interpolation}
759\label{subsec:OBS_parallel}
760
761For horizontal interpolation, there is the basic problem that
762the observations are unevenly distributed on the globe.
763In numerical models, it is common to divide the model grid into subgrids (or domains) where
764each subgrid is executed on a single processing element with explicit message passing for
765exchange of information along the domain boundaries when running on a massively parallel processor (MPP) system.
766This approach is used by \NEMO.
767
768For observations there is no natural distribution since the observations are not equally distributed on the globe.
769Two options have been made available:
7701) geographical distribution;
771and 2) round-robin.
772
773\subsubsection{Geographical distribution of observations among processors}
774
775%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
776\begin{figure}      \begin{center}
777\includegraphics[width=10cm,height=12cm,angle=-90.]{Fig_ASM_obsdist_local}
778\caption{      \protect\label{fig:obslocal}
779  Example of the distribution of observations with the geographical distribution of observational data.} 
780\end{center}      \end{figure}
781%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
782
783This is the simplest option in which the observations are distributed according to
784the domain of the grid-point parallelization.
785\autoref{fig:obslocal} shows an example of the distribution of the {\em in situ} data on processors with
786a different colour for each observation on a given processor for a 4 $\times$ 2 decomposition with ORCA2.
787The grid-point domain decomposition is clearly visible on the plot.
788
789The advantage of this approach is that all information needed for horizontal interpolation is available without
790any MPP communication.
791Of course, this is under the assumption that we are only using a $2 \times 2$ grid-point stencil for
792the interpolation (e.g., bilinear interpolation).
793For higher order interpolation schemes this is no longer valid.
794A disadvantage with the above scheme is that the number of observations on each processor can be very different.
795If the cost of the actual interpolation is expensive relative to the communication of data needed for interpolation,
796this could lead to load imbalance.
797
798\subsubsection{Round-robin distribution of observations among processors}
799
800%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
801\begin{figure}     \begin{center}
802\includegraphics[width=10cm,height=12cm,angle=-90.]{Fig_ASM_obsdist_global}
803\caption{      \protect\label{fig:obsglobal}
804  Example of the distribution of observations with the round-robin distribution of observational data.}
805\end{center}     \end{figure}
806%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
807
808An alternative approach is to distribute the observations equally among processors and
809use message passing in order to retrieve the stencil for interpolation.
810The simplest distribution of the observations is to distribute them using a round-robin scheme.
811\autoref{fig:obsglobal} shows the distribution of the {\em in situ} data on processors for
812the round-robin distribution of observations with a different colour for each observation on a given processor for
813a 4 $\times$ 2 decomposition with ORCA2 for the same input data as in \autoref{fig:obslocal}.
814The observations are now clearly randomly distributed on the globe.
815In order to be able to perform horizontal interpolation in this case,
816a subroutine has been developed that retrieves any grid points in the global space.
817
818\subsection{Vertical interpolation operator}
819
820Vertical interpolation is achieved using either a cubic spline or linear interpolation.
821For the cubic spline, the top and bottom boundary conditions for the second derivative of
822the interpolating polynomial in the spline are set to zero.
823At the bottom boundary, this is done using the land-ocean mask.
824
825\newpage
826
827% ================================================================
828% Offline observation operator documentation
829% ================================================================
830
831%\usepackage{framed}
832
833\section{Offline observation operator}
834\label{sec:OBS_ooo}
835
836\subsection{Concept}
837
838The obs oper maps model variables to observation space.
839It is possible to apply this mapping without running the model.
840The software which performs this functionality is known as the \textbf{offline obs oper}.
841The obs oper is divided into three stages.
842An initialisation phase, an interpolation phase and an output phase.
843The implementation of which is outlined in the previous sections.
844During the interpolation phase the offline obs oper populates the model arrays by
845reading saved model fields from disk.
846
847There are two ways of exploiting this offline capacity.
848The first is to mimic the behaviour of the online system by supplying model fields at
849regular intervals between the start and the end of the run.
850This approach results in a single model counterpart per observation.
851This kind of usage produces feedback files the same file format as the online obs oper.
852The second is to take advantage of the offline setting in which
853multiple model counterparts can be calculated per observation.
854In this case it is possible to consider all forecasts verifying at the same time.
855By forecast, I mean any method which produces an estimate of physical reality which is not an observed value.
856In the case of class 4 files this means forecasts, analyses, persisted analyses and
857climatological values verifying at the same time.
858Although the class 4 file format doesn't account for multiple ensemble members or
859multiple experiments per observation, it is possible to include these components in the same or multiple files.
860
861%--------------------------------------------------------------------------------------------------------
862% offline_oper.exe
863%--------------------------------------------------------------------------------------------------------
864
865\subsection{Using the offline observation operator}
866
867\subsubsection{Building}
868
869In addition to \emph{OPA\_SRC} the offline obs oper requires the inclusion of the \emph{OOO\_SRC} directory.
870\emph{OOO\_SRC} contains a replacement \mdl{nemo} and \mdl{nemogcm} which
871overwrites the resultant \textbf{nemo.exe}.
872This is the approach taken by \emph{SAS\_SRC} and \emph{OFF\_SRC}.
873
874%--------------------------------------------------------------------------------------------------------
875% Running
876%--------------------------------------------------------------------------------------------------------
877\subsubsection{Running}
878
879The simplest way to use the executable is to edit and append the \textbf{ooo.nml} namelist to
880a full NEMO namelist and then to run the executable as if it were nemo.exe.
881
882\subsubsection{Quick script}
883
884A useful Python utility to control the namelist options can be found in \textbf{OBSTOOLS/OOO}.
885The functions which locate model fields and observation files can be manually specified.
886The package can be installed by appropriate use of the included setup.py script.
887
888Documentation can be auto-generated by Sphinx by running \emph{make html} in the \textbf{doc} directory.
889
890%--------------------------------------------------------------------------------------------------------
891% Configuration section
892%--------------------------------------------------------------------------------------------------------
893\subsection{Configuring the offline observation operator}
894The observation files and settings understood by \textbf{namobs} have been outlined in the online obs oper section.
895In addition there are two further namelists wich control the operation of the offline obs oper.
896\textbf{namooo} which controls the input model fields and \textbf{namcl4} which
897controls the production of class 4 files.
898
899\subsubsection{Single field}
900
901In offline mode model arrays are populated at appropriate time steps via input files.
902At present, \textbf{tsn} and \textbf{sshn} are populated by the default read routines.
903These routines will be expanded upon in future versions to allow the specification of any model variable.
904As such, input files must be global versions of the model domain with
905\textbf{votemper}, \textbf{vosaline} and optionally \textbf{sshn} present.
906
907For each field read there must be an entry in the \textbf{namooo} namelist specifying
908the name of the file to read and the index along the \emph{time\_counter}.
909For example, to read the second time counter from a single file the namelist would be.
910
911\begin{forlines}
912!----------------------------------------------------------------------
913!       namooo Offline obs_oper namelist
914!----------------------------------------------------------------------
915!   ooo_files    specifies the files containing the model counterpart
916!   nn_ooo_idx   specifies the time_counter index within the model file
917&namooo
918   ooo_files = "foo.nc"
919   nn_ooo_idx = 2
920/
921\end{forlines}
922
923\subsubsection{Multiple fields per run}
924
925Model field iteration is controlled via \textbf{nn\_ooo\_freq} which
926specifies the number of model steps at which the next field gets read.
927For example, if 12 hourly fields are to be interpolated in a setup where 288 steps equals 24 hours.
928
929\begin{forlines}
930!----------------------------------------------------------------------
931!       namooo Offline obs_oper namelist
932!----------------------------------------------------------------------
933!   ooo_files    specifies the files containing the model counterpart
934!   nn_ooo_idx   specifies the time_counter index within the model file
935!   nn_ooo_freq  specifies number of time steps between read operations
936&namooo
937   ooo_files = "foo.nc" "foo.nc"
938   nn_ooo_idx = 1 2
939   nn_ooo_freq = 144
940/
941\end{forlines}
942
943The above namelist will result in feedback files whose first 12 hours contain the first field of foo.nc and
944the second 12 hours contain the second field.
945
946%\begin{framed}
947\textbf{Note} Missing files can be denoted as "nofile".
948%\end{framed}
949
950It is easy to see how a collection of fields taken fron a number of files at different indices can be combined at
951a particular frequency in time to generate a pseudo model evolution.
952As long as all that is needed is a single model counterpart at a regular interval then
953namooo is all that needs to be edited.
954However, a far more interesting approach can be taken in which multiple forecasts, analyses, persisted analyses and
955climatologies are considered against the same set of observations.
956For this a slightly more complicated approach is needed.
957It is referred to as \emph{Class 4} since it is the fourth metric defined by the GODAE intercomparison project.
958
959%--------------------------------------------------------------------------------------------------------
960% Class 4 file section
961%--------------------------------------------------------------------------------------------------------
962\subsubsection{Multiple model counterparts per observation a.k.a Class 4}
963
964A generalisation of feedback files to allow multiple model components per observation.
965For a single observation, as well as previous forecasts verifying at the same time
966there are also analyses, persisted analyses and climatologies.
967
968
969The above namelist performs two basic functions.
970It organises the fields given in \textbf{namooo} into groups so that observations can be matched up multiple times.
971It also controls the metadata and the output variable of the class 4 file when a write routine is called.
972
973%\begin{framed}
974\textbf{Note: ln\_cl4} must be set to \forcode{.true.} in \textbf{namobs} to use class 4 outputs.
975%\end{framed}
976
977\subsubsection{Class 4 naming convention}
978
979The standard class 4 file naming convention is as follows.
980
981\noindent
982\linebreak
983\textbf{\$\{prefix\}\_\$\{yyyymmdd\}\_\$\{sys\}\_\$\{cfg\}\_\$\{vn\}\_\$\{kind\}\_\$\{nproc\}}.nc
984
985\noindent
986\linebreak
987Much of the namelist is devoted to specifying this convention.
988The following namelist settings control the elements of the output file names.
989Each should be specified as a single string of character data.
990
991\begin{description}
992\item[cl4\_prefix]
993  Prefix for class 4 files e.g. class4
994\item[cl4\_date]
995  YYYYMMDD validity date
996\item[cl4\_sys]
997  The name of the class 4 model system e.g. FOAM
998\item[cl4\_cfg]
999  The name of the class 4 model configuration e.g. orca025
1000\item[cl4\_vn]
1001  The name of the class 4 model version e.g. 12.0
1002\end{description}
1003
1004\noindent
1005The kind is specified by the observation type internally to the obs oper.
1006The processor number is specified internally in NEMO.
1007
1008\subsubsection{Class 4 file global attributes}
1009
1010Global attributes necessary to fulfill the class 4 file definition.
1011These are also useful pieces of information when collaborating with external partners.
1012
1013\begin{description}
1014\item[cl4\_contact]
1015  Contact email for class 4 files.
1016\item[cl4\_inst]
1017  The name of the producers institution.
1018\item[cl4\_cfg]
1019  The name of the class 4 model configuration e.g. orca025
1020\item[cl4\_vn]
1021  The name of the class 4 model version e.g. 12.0
1022\end{description}
1023
1024\noindent
1025The obs\_type, creation date and validity time are specified internally to the obs oper.
1026
1027\subsubsection{Class 4 model counterpart configuration}
1028
1029As seen previously it is possible to perform a single sweep of the obs oper and
1030specify a collection of model fields equally spaced along that sweep.
1031In the class 4 case the single sweep is replaced with multiple sweeps and
1032a certain ammount of book keeping is needed to ensure each model counterpart makes its way to
1033the correct piece of memory in the output files.
1034
1035\noindent
1036\linebreak
1037In terms of book keeping, the offline obs oper needs to know how many full sweeps need to be performed.
1038This is specified via the \textbf{cl4\_match\_len} variable and
1039is the total number of model counterparts per observation.
1040For example, a 3 forecasts plus 3 persistence fields plus an analysis field would be 7 counterparts per observation.
1041
1042\begin{forlines}
1043   cl4_match_len = 7
1044\end{forlines}
1045
1046Then to correctly allocate a class 4 file the forecast axis must be defined.
1047This is controlled via \textbf{cl4\_fcst\_len}, which in out above example would be 3.
1048
1049\begin{forlines}
1050   cl4_fcst_len = 3
1051\end{forlines}
1052
1053Then for each model field it is necessary to designate what class 4 variable and index along
1054the forecast dimension the model counterpart should be stored in the output file.
1055As well as a value for that lead time in hours, this will be useful when interpreting the data afterwards.
1056
1057\begin{forlines}
1058   cl4_vars = "forecast" "forecast" "forecast" "persistence" "persistence"
1059              "persistence" "best_estimate"
1060   cl4_fcst_idx = 1 2 3 1 2 3 1
1061   cl4_leadtime = 12 36 60
1062\end{forlines}
1063
1064In terms of files and indices of fields inside each file the class 4 approach makes use of
1065the \textbf{namooo} namelist.
1066If our fields are in separate files with a single field per file our example inputs will be specified.
1067
1068\begin{forlines}
1069   ooo_files = "F.1.nc" "F.2.nc" "F.3.nc" "P.1.nc" "P.2.nc" "P.3.nc" "A.1.nc"
1070   nn_ooo_idx = 1 1 1 1 1 1 1
1071\end{forlines}
1072
1073When we combine all of the naming conventions, global attributes and i/o instructions the class 4 namelist becomes.
1074
1075\begin{forlines}
1076!----------------------------------------------------------------------
1077!       namooo Offline obs_oper namelist
1078!----------------------------------------------------------------------
1079!   ooo_files    specifies the files containing the model counterpart
1080!   nn_ooo_idx   specifies the time_counter index within the model file
1081!   nn_ooo_freq  specifies number of time steps between read operations
1082&namooo
1083   ooo_files = "F.1.nc" "F.2.nc" "F.3.nc" "P.1.nc" "P.2.nc" "P.3.nc" "A.1.nc"
1084   nn_ooo_idx = 1 1 1 1 1 1 1
1085/
1086!----------------------------------------------------------------------
1087!       namcl4 Offline obs_oper class 4 namelist
1088!----------------------------------------------------------------------
1089!
1090!  Naming convention
1091!  -----------------
1092!  cl4_prefix    specifies the output file prefix
1093!  cl4_date      specifies the output file validity date
1094!  cl4_sys       specifies the model counterpart system
1095!  cl4_cfg       specifies the model counterpart configuration
1096!  cl4_vn        specifies the model counterpart version
1097!  cl4_inst      specifies the model counterpart institute
1098!  cl4_contact   specifies the file producers contact details
1099!
1100!  I/O specification
1101!  -----------------
1102!  cl4_vars      specifies the names of the output file netcdf variable
1103!  cl4_fcst_idx  specifies output file forecast index
1104!  cl4_fcst_len  specifies forecast axis length
1105!  cl4_match_len specifies number of unique matches per observation
1106!  cl4_leadtime  specifies the forecast axis lead time
1107!
1108&namcl4
1109   cl4_match_len = 7
1110   cl4_fcst_len = 3
1111   cl4_fcst_idx = 1 2 3 1 2 3 1
1112   cl4_vars = "forecast" "forecast" "forecast" "persistence" "persistence"
1113              "persistence" "best_estimate"
1114   cl4_leadtime = 12 36 60
1115   cl4_prefix = "class4"
1116   cl4_date = "20130101"
1117   cl4_vn = "12.0"
1118   cl4_sys = "FOAM"
1119   cl4_cfg = "AMM7"
1120   cl4_contact = "example@example.com"
1121   cl4_inst = "UK Met Office"
1122/
1123\end{forlines}
1124
1125\subsubsection{Climatology interpolation}
1126
1127The climatological counterpart is generated at the start of the run by
1128restarting the model from climatology through appropriate use of \textbf{namtsd}.
1129To override the offline observation operator read routine and to take advantage of the restart settings,
1130specify the first entry in \textbf{cl4\_vars} as "climatology".
1131This will then pipe the restart from climatology into the output class 4 file.
1132As in every other class 4 matchup the input file, input index and output index must be specified.
1133These can be replaced with dummy data since they are not used but
1134they must be present to cycle through the matchups correctly.
1135
1136\subsection{Advanced usage}
1137
1138In certain cases it may be desirable to include both multiple model fields per observation window with
1139multiple match ups per observation.
1140This can be achieved by specifying \textbf{nn\_ooo\_freq} as well as the class 4 settings.
1141Care must be taken in generating the ooo\_files list such that the files are arranged into
1142consecutive blocks of single match ups.
1143For example, 2 forecast fields of 12 hourly data would result in 4 separate read operations but
1144only 2 write operations, 1 per forecast.
1145
1146\begin{forlines}
1147   ooo_files = "F1.nc" "F1.nc" "F2.nc" "F2.nc"
1148...
1149   cl4_fcst_idx = 1 2
1150\end{forlines}
1151
1152The above notation reveals the internal split between match up iterators and file iterators.
1153This technique has not been used before so experimentation is needed before results can be trusted.
1154
1155
1156
1157
1158\newpage
1159
1160\section{Observation utilities}
1161\label{sec:OBS_obsutils}
1162
1163Some tools for viewing and processing of observation and feedback files are provided in
1164the NEMO repository for convenience.
1165These include OBSTOOLS which are a collection of Fortran programs which are helpful to deal with feedback files.
1166They do such tasks as observation file conversion, printing of file contents,
1167some basic statistical analysis of feedback files.
1168The other tool is an IDL program called dataplot which uses a graphical interface to
1169visualise observations and feedback files.
1170OBSTOOLS and dataplot are described in more detail below.
1171
1172\subsection{Obstools}
1173
1174A series of Fortran utilities is provided with NEMO called OBSTOOLS.
1175This are helpful in handling observation files and the feedback file output from the NEMO observation operator.
1176The utilities are as follows
1177
1178\subsubsection{c4comb}
1179
1180The program c4comb combines multiple class 4 files produced by individual processors in
1181an MPI run of NEMO offline obs\_oper into a single class 4 file.
1182The program is called in the following way:
1183
1184
1185\footnotesize
1186\begin{cmds}
1187c4comb.exe outputfile inputfile1 inputfile2 ...
1188\end{cmds}
1189
1190\subsubsection{corio2fb}
1191
1192The program corio2fb converts profile observation files from the Coriolis format to the standard feedback format.
1193The program is called in the following way:
1194
1195\footnotesize
1196\begin{cmds}
1197corio2fb.exe outputfile inputfile1 inputfile2 ...
1198\end{cmds}
1199
1200\subsubsection{enact2fb}
1201
1202The program enact2fb converts profile observation files from the ENACT format to the standard feedback format.
1203The program is called in the following way:
1204
1205\footnotesize
1206\begin{cmds}
1207enact2fb.exe outputfile inputfile1 inputfile2 ...
1208\end{cmds}
1209
1210\subsubsection{fbcomb}
1211
1212The program fbcomb combines multiple feedback files produced by individual processors in
1213an MPI run of NEMO into a single feedback file.
1214The program is called in the following way:
1215
1216\footnotesize
1217\begin{cmds}
1218fbcomb.exe outputfile inputfile1 inputfile2 ...
1219\end{cmds}
1220
1221\subsubsection{fbmatchup}
1222
1223The program fbmatchup will match observations from two feedback files.
1224The program is called in the following way:
1225
1226\footnotesize
1227\begin{cmds}
1228fbmatchup.exe outputfile inputfile1 varname1 inputfile2 varname2 ...
1229\end{cmds}
1230
1231\subsubsection{fbprint}
1232
1233The program fbprint will print the contents of a feedback file or files to standard output.
1234Selected information can be output using optional arguments.
1235The program is called in the following way:
1236
1237\footnotesize
1238\begin{cmds}
1239fbprint.exe [options] inputfile
1240
1241options:
1242     -b            shorter output
1243     -q            Select observations based on QC flags
1244     -Q            Select observations based on QC flags
1245     -B            Select observations based on QC flags
1246     -u            unsorted
1247     -s ID         select station ID 
1248     -t TYPE       select observation type
1249     -v NUM1-NUM2  select variable range to print by number
1250                      (default all)
1251     -a NUM1-NUM2  select additional variable range to print by number
1252                      (default all)
1253     -e NUM1-NUM2  select extra variable range to print by number
1254                      (default all)
1255     -d            output date range
1256     -D            print depths
1257     -z            use zipped files
1258\end{cmds}
1259
1260\subsubsection{fbsel}
1261
1262The program fbsel will select or subsample observations.
1263The program is called in the following way:
1264
1265\footnotesize
1266\begin{cmds}
1267fbsel.exe <input filename> <output filename>
1268\end{cmds}
1269
1270\subsubsection{fbstat}
1271
1272The program fbstat will output summary statistics in different global areas into a number of files.
1273The program is called in the following way:
1274
1275\footnotesize
1276\begin{cmds}
1277fbstat.exe [-nmlev] <filenames>
1278\end{cmds}
1279
1280\subsubsection{fbthin}
1281
1282The program fbthin will thin the data to 1 degree resolution.
1283The code could easily be modified to thin to a different resolution.
1284The program is called in the following way:
1285
1286\footnotesize
1287\begin{cmds}
1288fbthin.exe inputfile outputfile
1289\end{cmds}
1290
1291\subsubsection{sla2fb}
1292
1293The program sla2fb will convert an AVISO SLA format file to feedback format.
1294The program is called in the following way:
1295
1296\footnotesize
1297\begin{cmds}
1298sla2fb.exe [-s type] outputfile inputfile1 inputfile2 ...
1299
1300Option:
1301     -s            Select altimeter data_source
1302\end{cmds}
1303
1304\subsubsection{vel2fb}
1305
1306The program vel2fb will convert TAO/PIRATA/RAMA currents files to feedback format.
1307The program is called in the following way:
1308
1309\footnotesize
1310\begin{cmds}
1311vel2fb.exe outputfile inputfile1 inputfile2 ...
1312\end{cmds}
1313
1314\subsection{Building the obstools}
1315
1316To build the obstools use in the tools directory use ./maketools -n OBSTOOLS -m [ARCH].
1317
1318\subsection{Dataplot}
1319
1320An IDL program called dataplot is included which uses a graphical interface to
1321visualise observations and feedback files.
1322It is possible to zoom in, plot individual profiles and calculate some basic statistics.
1323To plot some data run IDL and then:
1324\footnotesize
1325\begin{minted}{idl}
1326IDL> dataplot, "filename"
1327\end{minted}
1328
1329To read multiple files into dataplot,
1330for example multiple feedback files from different processors or from different days,
1331the easiest method is to use the spawn command to generate a list of files which can then be passed to dataplot.
1332\footnotesize
1333\begin{minted}{idl}
1334IDL> spawn, 'ls profb*.nc', files
1335IDL> dataplot, files
1336\end{minted}
1337
1338\autoref{fig:obsdataplotmain} shows the main window which is launched when dataplot starts.
1339This is split into three parts.
1340At the top there is a menu bar which contains a variety of drop down menus.
1341Areas - zooms into prespecified regions;
1342plot - plots the data as a timeseries or a T-S diagram if appropriate;
1343Find - allows data to be searched;
1344Config - sets various configuration options.
1345
1346The middle part is a plot of the geographical location of the observations.
1347This will plot the observation value, the model background value or observation minus background value depending on
1348the option selected in the radio button at the bottom of the window.
1349The plotting colour range can be changed by clicking on the colour bar.
1350The title of the plot gives some basic information about the date range and depth range shown,
1351the extreme values, and the mean and rms values.
1352It is possible to zoom in using a drag-box.
1353You may also zoom in or out using the mouse wheel.
1354
1355The bottom part of the window controls what is visible in the plot above.
1356There are two bars which select the level range plotted (for profile data).
1357The other bars below select the date range shown.
1358The bottom of the figure allows the option to plot the mean, root mean square, standard deviation or
1359mean square values.
1360As mentioned above you can choose to plot the observation value, the model background value or
1361observation minus background value.
1362The next group of radio buttons selects the map projection.
1363This can either be regular latitude longitude grid, or north or south polar stereographic.
1364The next group of radio buttons will plot bad observations, switch to salinity and
1365plot density for profile observations.
1366The rightmost group of buttons will print the plot window as a postscript, save it as png, or exit from dataplot.
1367
1368%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1369\begin{figure}     \begin{center}
1370%\includegraphics[width=10cm,height=12cm,angle=-90.]{Fig_OBS_dataplot_main}
1371\includegraphics[width=9cm,angle=-90.]{Fig_OBS_dataplot_main}
1372\caption{      \protect\label{fig:obsdataplotmain}
1373  Main window of dataplot.}
1374\end{center}     \end{figure}
1375%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1376
1377If a profile point is clicked with the mouse button a plot of the observation and background values as
1378a function of depth (\autoref{fig:obsdataplotprofile}).
1379
1380%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1381\begin{figure}     \begin{center}
1382%\includegraphics[width=10cm,height=12cm,angle=-90.]{Fig_OBS_dataplot_prof}
1383\includegraphics[width=7cm,angle=-90.]{Fig_OBS_dataplot_prof}
1384\caption{      \protect\label{fig:obsdataplotprofile}
1385  Profile plot from dataplot produced by right clicking on a point in the main window.}
1386\end{center}     \end{figure}
1387%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1388
1389
1390
1391
1392\end{document}
Note: See TracBrowser for help on using the repository browser.