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/trunk/doc/latex/NEMO/subfiles – NEMO

source: NEMO/trunk/doc/latex/NEMO/subfiles/chap_OBS.tex @ 11596

Last change on this file since 11596 was 11596, checked in by nicolasmartin, 5 years ago

Application of some coding rules

  • Replace comments before sectioning cmds by a single line of 100 characters long to display when every line should break
  • Replace multi blank lines by one single blank line
  • For list environment, put \item, label and content on the same line
  • Remove \newpage and comments line around figure envs
File size: 54.5 KB
Line 
1\documentclass[../main/NEMO_manual]{subfiles}
2
3\begin{document}
4\chapter{Observation and Model Comparison (OBS)}
5\label{chap:OBS}
6
7\chaptertoc
8
9\vfill
10\begin{figure}[b]
11\subsubsection*{Changes record}
12\begin{tabular}{l||l|m{0.65\linewidth}}
13    Release   & Author        & Modifications \\
14    {\em 4.0} & {\em D. J. Lea} & {\em \NEMO\ 4.0 updates}  \\
15    {\em 3.6} & {\em M. Martin, A. Ryan} & {\em Add averaging operator, standalone obs oper} \\
16    {\em 3.4} & {\em D. J. Lea, M. Martin, ...} & {\em Initial version}  \\
17    {\em --\texttt{"}--} & {\em ... K. Mogensen, A. Vidard, A. Weaver} & {\em ---\texttt{"}---}  \\
18\end{tabular}
19\end{figure}
20
21The observation and model comparison code, the observation operator (OBS), reads in observation files
22(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 time step.
23The resulting data are saved in a ``feedback'' file (or files).
24The code was originally developed for use with the NEMOVAR data assimilation code,
25but can be used for validation or verification of the model or with any other data assimilation system.
26
27The OBS code is called from \mdl{nemogcm} for model initialisation and to calculate the model equivalent values for observations on the 0th time step.
28The code is then called again after each time step from \mdl{step}.
29The code is only activated if the \nam{obs}{obs} namelist logical \np{ln_diaobs}{ln\_diaobs} is set to true.
30
31For all data types a 2D horizontal interpolator or averager is needed to
32interpolate/average the model fields to the observation location.
33For {\em in situ} profiles, a 1D vertical interpolator is needed in addition to
34provide model fields at the observation depths.
35This now works in a generalised vertical coordinate system.
36
37Some profile observation types (\eg\ tropical moored buoys) are made available as daily averaged quantities.
38The observation operator code can be set-up to calculate the equivalent daily average model temperature fields using
39the \np{nn_profdavtypes}{nn\_profdavtypes} namelist array.
40Some SST observations are equivalent to a night-time average value and
41the observation operator code can calculate equivalent night-time average model SST fields by
42setting the namelist value \np{ln_sstnight}{ln\_sstnight} to true.
43Otherwise (by default) the model value from the nearest time step to the observation time is used.
44
45The code is controlled by the namelist \nam{obs}{obs}.
46See the following sections for more details on setting up the namelist.
47
48In \autoref{sec:OBS_example} a test example of the observation operator code is introduced, including
49where to obtain data and how to setup the namelist.
50In \autoref{sec:OBS_details} some more technical details of the different observation types used are introduced, and we
51also show a more complete namelist.
52In \autoref{sec:OBS_theory} some of the theoretical aspects of the observation operator are described including
53interpolation methods and running on multiple processors.
54In \autoref{sec:OBS_sao} the standalone observation operator code is described.
55In \autoref{sec:OBS_obsutils} we describe some utilities to help work with the files produced by the OBS code.
56
57\section{Running the observation operator code example}
58\label{sec:OBS_example}
59
60In this section an example of running the observation operator code is described using
61profile observation data which can be freely downloaded.
62It shows how to adapt an existing run and build of \NEMO\ to run the observation operator. Note also the observation operator and the assimilation increments code are run in the ORCA2\_ICE\_OBS SETTE test.
63
64\begin{enumerate}
65\item Compile \NEMO.
66
67\item Download some EN4 data from \href{http://www.metoffice.gov.uk/hadobs}{www.metoffice.gov.uk/hadobs}.
68  Choose observations which are valid for the period of your test run because
69  the observation operator compares the model and observations for a matching date and time.
70
71\item Compile the OBSTOOLS code in the \path{tools} directory using:
72\begin{cmds}
73./maketools -n OBSTOOLS -m [ARCH]
74\end{cmds}
75
76replacing \texttt{[ARCH]} with the build architecture file for your machine. Note the tools are checked out from a separate location of the repository (under \path{/utils/tools}).
77
78\item Convert the EN4 data into feedback format:
79\begin{cmds}
80enact2fb.exe profiles_01.nc EN.4.1.1.f.profiles.g10.YYYYMM.nc
81\end{cmds}
82
83\item Include the following in the \NEMO\ namelist to run the observation operator on this data:
84\end{enumerate}
85
86Options are defined through the \nam{obs}{obs} namelist variables.
87The options \np{ln_t3d}{ln\_t3d} and \np{ln_s3d}{ln\_s3d} switch on the temperature and salinity profile observation operator code.
88The filename or array of filenames are specified using the \np{cn_profbfiles}{cn\_profbfiles} variable.
89The model grid points for a particular observation latitude and longitude are found using
90the grid searching part of the code.
91This can be expensive, particularly for large numbers of observations,
92setting \np{ln_grid_search_lookup}{ln\_grid\_search\_lookup} allows the use of a lookup table which
93is saved into an \np{cn_gridsearch}{cn\_gridsearch} file (or files).
94This will need to be generated the first time if it does not exist in the run directory.
95However, once produced it will significantly speed up future grid searches.
96Setting \np{ln_grid_global}{ln\_grid\_global} means that the code distributes the observations evenly between processors.
97Alternatively each processor will work with observations located within the model subdomain
98(see \autoref{subsec:OBS_parallel}).
99
100A number of utilities are now provided to plot the feedback files, convert and recombine the files.
101These are explained in more detail in \autoref{sec:OBS_obsutils}.
102Utilities to convert other input data formats into the feedback format are also described in
103\autoref{sec:OBS_obsutils}.
104
105\section{Technical details (feedback type observation file headers)}
106\label{sec:OBS_details}
107
108Here we show a more complete example namelist \nam{obs}{obs} and also show the NetCDF headers of
109the observation files that may be used with the observation operator.
110
111%------------------------------------------namobs--------------------------------------------------------
112
113\begin{listing}
114  \nlst{namobs}
115  \caption{\forcode{&namobs}}
116  \label{lst:namobs}
117\end{listing}
118%-------------------------------------------------------------------------------------------------------------
119
120The observation operator code uses the feedback observation file format for all data types.
121All the observation files must be in NetCDF format.
122Some example headers (produced using \mbox{\textit{ncdump~-h}}) for profile data, sea level anomaly and
123sea surface temperature are in the following subsections.
124
125\subsection{Profile feedback file}
126
127\begin{clines}
128netcdf profiles_01 {
129dimensions:
130     N_OBS = 603 ;
131     N_LEVELS = 150 ;
132     N_VARS = 2 ;
133     N_QCF = 2 ;
134     N_ENTRIES = 1 ;
135     N_EXTRA = 1 ;
136     STRINGNAM = 8 ;
137     STRINGGRID = 1 ;
138     STRINGWMO = 8 ;
139     STRINGTYP = 4 ;
140     STRINGJULD = 14 ;
141variables:
142     char VARIABLES(N_VARS, STRINGNAM) ;
143          VARIABLES:long_name = "List of variables in feedback files" ;
144     char ENTRIES(N_ENTRIES, STRINGNAM) ;
145          ENTRIES:long_name = "List of additional entries for each variable in feedback files" ;
146     char EXTRA(N_EXTRA, STRINGNAM) ;
147          EXTRA:long_name = "List of extra variables" ;
148     char STATION_IDENTIFIER(N_OBS, STRINGWMO) ;
149          STATION_IDENTIFIER:long_name = "Station identifier" ;
150     char STATION_TYPE(N_OBS, STRINGTYP) ;
151          STATION_TYPE:long_name = "Code instrument type" ;
152     double LONGITUDE(N_OBS) ;
153          LONGITUDE:long_name = "Longitude" ;
154          LONGITUDE:units = "degrees_east" ;
155          LONGITUDE:_Fillvalue = 99999.f ;
156     double LATITUDE(N_OBS) ;
157          LATITUDE:long_name = "Latitude" ;
158          LATITUDE:units = "degrees_north" ;
159          LATITUDE:_Fillvalue = 99999.f ;
160     double DEPTH(N_OBS, N_LEVELS) ;
161          DEPTH:long_name = "Depth" ;
162          DEPTH:units = "metre" ;
163          DEPTH:_Fillvalue = 99999.f ;
164     int DEPTH_QC(N_OBS, N_LEVELS) ;
165          DEPTH_QC:long_name = "Quality on depth" ;
166          DEPTH_QC:Conventions = "q where q =[0,9]" ;
167          DEPTH_QC:_Fillvalue = 0 ;
168     int DEPTH_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
169          DEPTH_QC_FLAGS:long_name = "Quality flags on depth" ;
170          DEPTH_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
171     double JULD(N_OBS) ;
172          JULD:long_name = "Julian day" ;
173          JULD:units = "days since JULD_REFERENCE" ;
174          JULD:Conventions = "relative julian days with decimal part (as parts of day)" ;
175          JULD:_Fillvalue = 99999.f ;
176     char JULD_REFERENCE(STRINGJULD) ;
177          JULD_REFERENCE:long_name = "Date of reference for julian days" ;
178          JULD_REFERENCE:Conventions = "YYYYMMDDHHMMSS" ;
179     int OBSERVATION_QC(N_OBS) ;
180          OBSERVATION_QC:long_name = "Quality on observation" ;
181          OBSERVATION_QC:Conventions = "q where q =[0,9]" ;
182          OBSERVATION_QC:_Fillvalue = 0 ;
183     int OBSERVATION_QC_FLAGS(N_OBS, N_QCF) ;
184          OBSERVATION_QC_FLAGS:long_name = "Quality flags on observation" ;
185          OBSERVATION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
186          OBSERVATION_QC_FLAGS:_Fillvalue = 0 ;
187     int POSITION_QC(N_OBS) ;
188          POSITION_QC:long_name = "Quality on position (latitude and longitude)" ;
189          POSITION_QC:Conventions = "q where q =[0,9]" ;
190          POSITION_QC:_Fillvalue = 0 ;
191     int POSITION_QC_FLAGS(N_OBS, N_QCF) ;
192          POSITION_QC_FLAGS:long_name = "Quality flags on position" ;
193          POSITION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
194          POSITION_QC_FLAGS:_Fillvalue = 0 ;
195     int JULD_QC(N_OBS) ;
196          JULD_QC:long_name = "Quality on date and time" ;
197          JULD_QC:Conventions = "q where q =[0,9]" ;
198          JULD_QC:_Fillvalue = 0 ;
199     int JULD_QC_FLAGS(N_OBS, N_QCF) ;
200          JULD_QC_FLAGS:long_name = "Quality flags on date and time" ;
201          JULD_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
202          JULD_QC_FLAGS:_Fillvalue = 0 ;
203     int ORIGINAL_FILE_INDEX(N_OBS) ;
204          ORIGINAL_FILE_INDEX:long_name = "Index in original data file" ;
205          ORIGINAL_FILE_INDEX:_Fillvalue = -99999 ;
206     float POTM_OBS(N_OBS, N_LEVELS) ;
207          POTM_OBS:long_name = "Potential temperature" ;
208          POTM_OBS:units = "Degrees Celsius" ;
209          POTM_OBS:_Fillvalue = 99999.f ;
210     float POTM_Hx(N_OBS, N_LEVELS) ;
211          POTM_Hx:long_name = "Model interpolated potential temperature" ;
212          POTM_Hx:units = "Degrees Celsius" ;
213          POTM_Hx:_Fillvalue = 99999.f ;
214     int POTM_QC(N_OBS) ;
215          POTM_QC:long_name = "Quality on potential temperature" ;
216          POTM_QC:Conventions = "q where q =[0,9]" ;
217          POTM_QC:_Fillvalue = 0 ;
218     int POTM_QC_FLAGS(N_OBS, N_QCF) ;
219          POTM_QC_FLAGS:long_name = "Quality flags on potential temperature" ;
220          POTM_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
221          POTM_QC_FLAGS:_Fillvalue = 0 ;
222     int POTM_LEVEL_QC(N_OBS, N_LEVELS) ;
223          POTM_LEVEL_QC:long_name = "Quality for each level on potential temperature" ;
224          POTM_LEVEL_QC:Conventions = "q where q =[0,9]" ;
225          POTM_LEVEL_QC:_Fillvalue = 0 ;
226     int POTM_LEVEL_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
227          POTM_LEVEL_QC_FLAGS:long_name = "Quality flags for each level on potential temperature" ;
228          POTM_LEVEL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
229          POTM_LEVEL_QC_FLAGS:_Fillvalue = 0 ;
230     int POTM_IOBSI(N_OBS) ;
231          POTM_IOBSI:long_name = "ORCA grid search I coordinate" ;
232     int POTM_IOBSJ(N_OBS) ;
233          POTM_IOBSJ:long_name = "ORCA grid search J coordinate" ;
234     int POTM_IOBSK(N_OBS, N_LEVELS) ;
235          POTM_IOBSK:long_name = "ORCA grid search K coordinate" ;
236     char POTM_GRID(STRINGGRID) ;
237          POTM_GRID:long_name = "ORCA grid search grid (T,U,V)" ;
238     float PSAL_OBS(N_OBS, N_LEVELS) ;
239          PSAL_OBS:long_name = "Practical salinity" ;
240          PSAL_OBS:units = "PSU" ;
241          PSAL_OBS:_Fillvalue = 99999.f ;
242     float PSAL_Hx(N_OBS, N_LEVELS) ;
243          PSAL_Hx:long_name = "Model interpolated practical salinity" ;
244          PSAL_Hx:units = "PSU" ;
245          PSAL_Hx:_Fillvalue = 99999.f ;
246     int PSAL_QC(N_OBS) ;
247          PSAL_QC:long_name = "Quality on practical salinity" ;
248          PSAL_QC:Conventions = "q where q =[0,9]" ;
249          PSAL_QC:_Fillvalue = 0 ;
250     int PSAL_QC_FLAGS(N_OBS, N_QCF) ;
251          PSAL_QC_FLAGS:long_name = "Quality flags on practical salinity" ;
252          PSAL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
253          PSAL_QC_FLAGS:_Fillvalue = 0 ;
254     int PSAL_LEVEL_QC(N_OBS, N_LEVELS) ;
255          PSAL_LEVEL_QC:long_name = "Quality for each level on practical salinity" ;
256          PSAL_LEVEL_QC:Conventions = "q where q =[0,9]" ;
257          PSAL_LEVEL_QC:_Fillvalue = 0 ;
258     int PSAL_LEVEL_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
259          PSAL_LEVEL_QC_FLAGS:long_name = "Quality flags for each level on practical salinity" ;
260          PSAL_LEVEL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
261          PSAL_LEVEL_QC_FLAGS:_Fillvalue = 0 ;
262     int PSAL_IOBSI(N_OBS) ;
263          PSAL_IOBSI:long_name = "ORCA grid search I coordinate" ;
264     int PSAL_IOBSJ(N_OBS) ;
265          PSAL_IOBSJ:long_name = "ORCA grid search J coordinate" ;
266     int PSAL_IOBSK(N_OBS, N_LEVELS) ;
267          PSAL_IOBSK:long_name = "ORCA grid search K coordinate" ;
268     char PSAL_GRID(STRINGGRID) ;
269          PSAL_GRID:long_name = "ORCA grid search grid (T,U,V)" ;
270     float TEMP(N_OBS, N_LEVELS) ;
271          TEMP:long_name = "Insitu temperature" ;
272          TEMP:units = "Degrees Celsius" ;
273          TEMP:_Fillvalue = 99999.f ;
274
275// global attributes:
276          :title = "NEMO observation operator output" ;
277          :Convention = "NEMO unified observation operator output" ;
278}
279\end{clines}
280
281\subsection{Sea level anomaly feedback file}
282
283\begin{clines}
284netcdf sla_01 {
285dimensions:
286     N_OBS = 41301 ;
287     N_LEVELS = 1 ;
288     N_VARS = 1 ;
289     N_QCF = 2 ;
290     N_ENTRIES = 1 ;
291     N_EXTRA = 1 ;
292     STRINGNAM = 8 ;
293     STRINGGRID = 1 ;
294     STRINGWMO = 8 ;
295     STRINGTYP = 4 ;
296     STRINGJULD = 14 ;
297variables:
298     char VARIABLES(N_VARS, STRINGNAM) ;
299          VARIABLES:long_name = "List of variables in feedback files" ;
300     char ENTRIES(N_ENTRIES, STRINGNAM) ;
301          ENTRIES:long_name = "List of additional entries for each variable in feedback files" ;
302     char EXTRA(N_EXTRA, STRINGNAM) ;
303          EXTRA:long_name = "List of extra variables" ;
304     char STATION_IDENTIFIER(N_OBS, STRINGWMO) ;
305          STATION_IDENTIFIER:long_name = "Station identifier" ;
306     char STATION_TYPE(N_OBS, STRINGTYP) ;
307          STATION_TYPE:long_name = "Code instrument type" ;
308     double LONGITUDE(N_OBS) ;
309          LONGITUDE:long_name = "Longitude" ;
310          LONGITUDE:units = "degrees_east" ;
311          LONGITUDE:_Fillvalue = 99999.f ;
312     double LATITUDE(N_OBS) ;
313          LATITUDE:long_name = "Latitude" ;
314          LATITUDE:units = "degrees_north" ;
315          LATITUDE:_Fillvalue = 99999.f ;
316     double DEPTH(N_OBS, N_LEVELS) ;
317          DEPTH:long_name = "Depth" ;
318          DEPTH:units = "metre" ;
319          DEPTH:_Fillvalue = 99999.f ;
320     int DEPTH_QC(N_OBS, N_LEVELS) ;
321          DEPTH_QC:long_name = "Quality on depth" ;
322          DEPTH_QC:Conventions = "q where q =[0,9]" ;
323          DEPTH_QC:_Fillvalue = 0 ;
324     int DEPTH_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
325          DEPTH_QC_FLAGS:long_name = "Quality flags on depth" ;
326          DEPTH_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
327     double JULD(N_OBS) ;
328          JULD:long_name = "Julian day" ;
329          JULD:units = "days since JULD_REFERENCE" ;
330          JULD:Conventions = "relative julian days with decimal part (as parts of day)" ;
331          JULD:_Fillvalue = 99999.f ;
332     char JULD_REFERENCE(STRINGJULD) ;
333          JULD_REFERENCE:long_name = "Date of reference for julian days" ;
334          JULD_REFERENCE:Conventions = "YYYYMMDDHHMMSS" ;
335     int OBSERVATION_QC(N_OBS) ;
336          OBSERVATION_QC:long_name = "Quality on observation" ;
337          OBSERVATION_QC:Conventions = "q where q =[0,9]" ;
338          OBSERVATION_QC:_Fillvalue = 0 ;
339     int OBSERVATION_QC_FLAGS(N_OBS, N_QCF) ;
340          OBSERVATION_QC_FLAGS:long_name = "Quality flags on observation" ;
341          OBSERVATION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
342          OBSERVATION_QC_FLAGS:_Fillvalue = 0 ;
343     int POSITION_QC(N_OBS) ;
344          POSITION_QC:long_name = "Quality on position (latitude and longitude)" ;
345          POSITION_QC:Conventions = "q where q =[0,9]" ;
346          POSITION_QC:_Fillvalue = 0 ;
347     int POSITION_QC_FLAGS(N_OBS, N_QCF) ;
348          POSITION_QC_FLAGS:long_name = "Quality flags on position" ;
349          POSITION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
350          POSITION_QC_FLAGS:_Fillvalue = 0 ;
351     int JULD_QC(N_OBS) ;
352          JULD_QC:long_name = "Quality on date and time" ;
353          JULD_QC:Conventions = "q where q =[0,9]" ;
354          JULD_QC:_Fillvalue = 0 ;
355     int JULD_QC_FLAGS(N_OBS, N_QCF) ;
356          JULD_QC_FLAGS:long_name = "Quality flags on date and time" ;
357          JULD_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
358          JULD_QC_FLAGS:_Fillvalue = 0 ;
359     int ORIGINAL_FILE_INDEX(N_OBS) ;
360          ORIGINAL_FILE_INDEX:long_name = "Index in original data file" ;
361          ORIGINAL_FILE_INDEX:_Fillvalue = -99999 ;
362     float SLA_OBS(N_OBS, N_LEVELS) ;
363          SLA_OBS:long_name = "Sea level anomaly" ;
364          SLA_OBS:units = "metre" ;
365          SLA_OBS:_Fillvalue = 99999.f ;
366     float SLA_Hx(N_OBS, N_LEVELS) ;
367          SLA_Hx:long_name = "Model interpolated sea level anomaly" ;
368          SLA_Hx:units = "metre" ;
369          SLA_Hx:_Fillvalue = 99999.f ;
370     int SLA_QC(N_OBS) ;
371          SLA_QC:long_name = "Quality on sea level anomaly" ;
372          SLA_QC:Conventions = "q where q =[0,9]" ;
373          SLA_QC:_Fillvalue = 0 ;
374     int SLA_QC_FLAGS(N_OBS, N_QCF) ;
375          SLA_QC_FLAGS:long_name = "Quality flags on sea level anomaly" ;
376          SLA_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
377          SLA_QC_FLAGS:_Fillvalue = 0 ;
378     int SLA_LEVEL_QC(N_OBS, N_LEVELS) ;
379          SLA_LEVEL_QC:long_name = "Quality for each level on sea level anomaly" ;
380          SLA_LEVEL_QC:Conventions = "q where q =[0,9]" ;
381          SLA_LEVEL_QC:_Fillvalue = 0 ;
382     int SLA_LEVEL_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
383          SLA_LEVEL_QC_FLAGS:long_name = "Quality flags for each level on sea level anomaly" ;
384          SLA_LEVEL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
385          SLA_LEVEL_QC_FLAGS:_Fillvalue = 0 ;
386     int SLA_IOBSI(N_OBS) ;
387          SLA_IOBSI:long_name = "ORCA grid search I coordinate" ;
388     int SLA_IOBSJ(N_OBS) ;
389          SLA_IOBSJ:long_name = "ORCA grid search J coordinate" ;
390     int SLA_IOBSK(N_OBS, N_LEVELS) ;
391          SLA_IOBSK:long_name = "ORCA grid search K coordinate" ;
392     char SLA_GRID(STRINGGRID) ;
393          SLA_GRID:long_name = "ORCA grid search grid (T,U,V)" ;
394     float MDT(N_OBS, N_LEVELS) ;
395          MDT:long_name = "Mean Dynamic Topography" ;
396          MDT:units = "metre" ;
397          MDT:_Fillvalue = 99999.f ;
398
399// global attributes:
400          :title = "NEMO observation operator output" ;
401          :Convention = "NEMO unified observation operator output" ;
402}
403\end{clines}
404
405To use Sea Level Anomaly (SLA) data the mean dynamic topography (MDT) must be provided in a separate file defined on
406the model grid called \ifile{slaReferenceLevel}.
407The MDT is required in order to produce the model equivalent sea level anomaly from the model sea surface height.
408Below is an example header for this file (on the ORCA025 grid).
409
410\begin{clines}
411dimensions:
412        x = 1442 ;
413        y = 1021 ;
414variables:
415        float nav_lon(y, x) ;
416                nav_lon:units = "degrees_east" ;
417        float nav_lat(y, x) ;
418                nav_lat:units = "degrees_north" ;
419        float sossheig(y, x) ;
420                sossheig:_FillValue = -1.e+30f ;
421                sossheig:coordinates = "nav_lon nav_lat" ;
422                sossheig:long_name = "Mean Dynamic Topography" ;
423                sossheig:units = "metres" ;
424                sossheig:grid = "orca025T" ;
425\end{clines}
426
427\subsection{Sea surface temperature feedback file}
428
429\begin{clines}
430netcdf sst_01 {
431dimensions:
432     N_OBS = 33099 ;
433     N_LEVELS = 1 ;
434     N_VARS = 1 ;
435     N_QCF = 2 ;
436     N_ENTRIES = 1 ;
437     STRINGNAM = 8 ;
438     STRINGGRID = 1 ;
439     STRINGWMO = 8 ;
440     STRINGTYP = 4 ;
441     STRINGJULD = 14 ;
442variables:
443     char VARIABLES(N_VARS, STRINGNAM) ;
444          VARIABLES:long_name = "List of variables in feedback files" ;
445     char ENTRIES(N_ENTRIES, STRINGNAM) ;
446          ENTRIES:long_name = "List of additional entries for each variable in feedback files" ;
447     char STATION_IDENTIFIER(N_OBS, STRINGWMO) ;
448          STATION_IDENTIFIER:long_name = "Station identifier" ;
449     char STATION_TYPE(N_OBS, STRINGTYP) ;
450          STATION_TYPE:long_name = "Code instrument type" ;
451     double LONGITUDE(N_OBS) ;
452          LONGITUDE:long_name = "Longitude" ;
453          LONGITUDE:units = "degrees_east" ;
454          LONGITUDE:_Fillvalue = 99999.f ;
455     double LATITUDE(N_OBS) ;
456          LATITUDE:long_name = "Latitude" ;
457          LATITUDE:units = "degrees_north" ;
458          LATITUDE:_Fillvalue = 99999.f ;
459     double DEPTH(N_OBS, N_LEVELS) ;
460          DEPTH:long_name = "Depth" ;
461          DEPTH:units = "metre" ;
462          DEPTH:_Fillvalue = 99999.f ;
463     int DEPTH_QC(N_OBS, N_LEVELS) ;
464          DEPTH_QC:long_name = "Quality on depth" ;
465          DEPTH_QC:Conventions = "q where q =[0,9]" ;
466          DEPTH_QC:_Fillvalue = 0 ;
467     int DEPTH_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
468          DEPTH_QC_FLAGS:long_name = "Quality flags on depth" ;
469          DEPTH_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
470     double JULD(N_OBS) ;
471          JULD:long_name = "Julian day" ;
472          JULD:units = "days since JULD_REFERENCE" ;
473          JULD:Conventions = "relative julian days with decimal part (as parts of day)" ;
474          JULD:_Fillvalue = 99999.f ;
475     char JULD_REFERENCE(STRINGJULD) ;
476          JULD_REFERENCE:long_name = "Date of reference for julian days" ;
477          JULD_REFERENCE:Conventions = "YYYYMMDDHHMMSS" ;
478     int OBSERVATION_QC(N_OBS) ;
479          OBSERVATION_QC:long_name = "Quality on observation" ;
480          OBSERVATION_QC:Conventions = "q where q =[0,9]" ;
481          OBSERVATION_QC:_Fillvalue = 0 ;
482     int OBSERVATION_QC_FLAGS(N_OBS, N_QCF) ;
483          OBSERVATION_QC_FLAGS:long_name = "Quality flags on observation" ;
484          OBSERVATION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
485          OBSERVATION_QC_FLAGS:_Fillvalue = 0 ;
486     int POSITION_QC(N_OBS) ;
487          POSITION_QC:long_name = "Quality on position (latitude and longitude)" ;
488          POSITION_QC:Conventions = "q where q =[0,9]" ;
489          POSITION_QC:_Fillvalue = 0 ;
490     int POSITION_QC_FLAGS(N_OBS, N_QCF) ;
491          POSITION_QC_FLAGS:long_name = "Quality flags on position" ;
492          POSITION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
493          POSITION_QC_FLAGS:_Fillvalue = 0 ;
494     int JULD_QC(N_OBS) ;
495          JULD_QC:long_name = "Quality on date and time" ;
496          JULD_QC:Conventions = "q where q =[0,9]" ;
497          JULD_QC:_Fillvalue = 0 ;
498     int JULD_QC_FLAGS(N_OBS, N_QCF) ;
499          JULD_QC_FLAGS:long_name = "Quality flags on date and time" ;
500          JULD_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
501          JULD_QC_FLAGS:_Fillvalue = 0 ;
502     int ORIGINAL_FILE_INDEX(N_OBS) ;
503          ORIGINAL_FILE_INDEX:long_name = "Index in original data file" ;
504          ORIGINAL_FILE_INDEX:_Fillvalue = -99999 ;
505     float SST_OBS(N_OBS, N_LEVELS) ;
506          SST_OBS:long_name = "Sea surface temperature" ;
507          SST_OBS:units = "Degree centigrade" ;
508          SST_OBS:_Fillvalue = 99999.f ;
509     float SST_Hx(N_OBS, N_LEVELS) ;
510          SST_Hx:long_name = "Model interpolated sea surface temperature" ;
511          SST_Hx:units = "Degree centigrade" ;
512          SST_Hx:_Fillvalue = 99999.f ;
513     int SST_QC(N_OBS) ;
514          SST_QC:long_name = "Quality on sea surface temperature" ;
515          SST_QC:Conventions = "q where q =[0,9]" ;
516          SST_QC:_Fillvalue = 0 ;
517     int SST_QC_FLAGS(N_OBS, N_QCF) ;
518          SST_QC_FLAGS:long_name = "Quality flags on sea surface temperature" ;
519          SST_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
520          SST_QC_FLAGS:_Fillvalue = 0 ;
521     int SST_LEVEL_QC(N_OBS, N_LEVELS) ;
522          SST_LEVEL_QC:long_name = "Quality for each level on sea surface temperature" ;
523          SST_LEVEL_QC:Conventions = "q where q =[0,9]" ;
524          SST_LEVEL_QC:_Fillvalue = 0 ;
525     int SST_LEVEL_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
526          SST_LEVEL_QC_FLAGS:long_name = "Quality flags for each level on sea surface temperature" ;
527          SST_LEVEL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
528          SST_LEVEL_QC_FLAGS:_Fillvalue = 0 ;
529     int SST_IOBSI(N_OBS) ;
530          SST_IOBSI:long_name = "ORCA grid search I coordinate" ;
531     int SST_IOBSJ(N_OBS) ;
532          SST_IOBSJ:long_name = "ORCA grid search J coordinate" ;
533     int SST_IOBSK(N_OBS, N_LEVELS) ;
534          SST_IOBSK:long_name = "ORCA grid search K coordinate" ;
535     char SST_GRID(STRINGGRID) ;
536          SST_GRID:long_name = "ORCA grid search grid (T,U,V)" ;
537
538// global attributes:
539          :title = "NEMO observation operator output" ;
540          :Convention = "NEMO unified observation operator output" ;
541}
542\end{clines}
543
544\section{Theoretical details}
545\label{sec:OBS_theory}
546
547\subsection{Horizontal interpolation and averaging methods}
548
549For most observation types, the horizontal extent of the observation is small compared to the model grid size and so
550the model equivalent of the observation is calculated by interpolating from
551the four surrounding grid points to the observation location.
552Some satellite observations (\eg\ microwave satellite SST data, or satellite SSS data) have a footprint which
553is similar in size or larger than the model grid size (particularly when the grid size is small).
554In those cases the model counterpart should be calculated by averaging the model grid points over
555the same size as the footprint.
556\NEMO\ therefore has the capability to specify either an interpolation or an averaging
557(for surface observation types only).
558
559The main namelist option associated with the interpolation/averaging is \np{nn_2dint}{nn\_2dint}.
560This default option can be set to values from 0 to 6.
561Values between 0 to 4 are associated with interpolation while values 5 or 6 are associated with averaging.
562\begin{itemize}
563\item \np[=0]{nn_2dint}{nn\_2dint}: Distance-weighted interpolation
564\item \np[=1]{nn_2dint}{nn\_2dint}: Distance-weighted interpolation (small angle)
565\item \np[=2]{nn_2dint}{nn\_2dint}: Bilinear interpolation (geographical grid)
566\item \np[=3]{nn_2dint}{nn\_2dint}: Bilinear remapping interpolation (general grid)
567\item \np[=4]{nn_2dint}{nn\_2dint}: Polynomial interpolation
568\item \np[=5]{nn_2dint}{nn\_2dint}: Radial footprint averaging with diameter specified in the namelist as
569  \texttt{rn\_[var]\_avglamscl} in degrees or metres (set using \texttt{ln\_[var]\_fp\_indegs})
570\item \np[=6]{nn_2dint}{nn\_2dint}: Rectangular footprint averaging with E/W and N/S size specified in
571  the namelist as \texttt{rn\_[var]\_avglamscl} and \texttt{rn\_[var]\_avgphiscl} in degrees or metres
572  (set using \texttt{ln\_[var]\_fp\_indegs})
573\end{itemize}
574Replace \texttt{[var]} in the last two options with the observation type (sla, sst, sss or sic) for
575which the averaging is to be performed (see namelist example above).
576The \np{nn_2dint}{nn\_2dint} default option can be overridden for surface observation types using
577namelist values \texttt{nn\_2dint\_[var]} where \texttt{[var]} is the observation type.
578
579Below is some more detail on the various options for interpolation and averaging available in \NEMO.
580
581\subsubsection{Horizontal interpolation}
582
583Consider an observation point ${\mathrm P}$ with longitude and latitude (${\lambda_{}}_{\mathrm P}$, $\phi_{\mathrm P}$) and
584the four nearest neighbouring model grid points ${\mathrm A}$, ${\mathrm B}$, ${\mathrm C}$ and ${\mathrm D}$ with
585longitude and latitude ($\lambda_{\mathrm A}$, $\phi_{\mathrm A}$),($\lambda_{\mathrm B}$, $\phi_{\mathrm B}$) etc.
586All horizontal interpolation methods implemented in \NEMO\ estimate the value of a model variable $x$ at point $P$ as
587a weighted linear combination of the values of the model variables at the grid points ${\mathrm A}$, ${\mathrm B}$ etc.:
588
589\begin{align*}
590  {x_{}}_{\mathrm P} =
591\frac{1}{w} \left( {w_{}}_{\mathrm A} {x_{}}_{\mathrm A} +
592{w_{}}_{\mathrm B} {x_{}}_{\mathrm B} +
593{w_{}}_{\mathrm C} {x_{}}_{\mathrm C} +
594{w_{}}_{\mathrm D} {x_{}}_{\mathrm D} \right)
595\end{align*}
596
597where ${w_{}}_{\mathrm A}$, ${w_{}}_{\mathrm B}$ etc. are the respective weights for the model field at
598points ${\mathrm A}$, ${\mathrm B}$ etc., and $w = {w_{}}_{\mathrm A} + {w_{}}_{\mathrm B} + {w_{}}_{\mathrm C} + {w_{}}_{\mathrm D}$.
599
600Four different possibilities are available for computing the weights.
601
602\begin{enumerate}
603
604\item [1.] {\bfseries Great-Circle distance-weighted interpolation.}
605  The weights are computed as a function of the great-circle distance $s(P, \cdot)$ between $P$ and
606  the model grid points $A$, $B$ etc.
607  For example, the weight given to the field ${x_{}}_{\mathrm A}$ is specified as the product of the distances
608  from ${\mathrm P}$ to the other points:
609
610  \begin{alignat*}{2}
611    {w_{}}_{\mathrm A} = s({\mathrm P}, {\mathrm B}) \, s({\mathrm P}, {\mathrm C}) \, s({\mathrm P}, {\mathrm D})
612  \end{alignat*}
613
614  where
615
616  \begin{alignat*}{2}
617    s\left({\mathrm P}, {\mathrm M} \right) & = & \hspace{0.25em} \cos^{-1} \! \left\{
618               \sin {\phi_{}}_{\mathrm P} \sin {\phi_{}}_{\mathrm M}
619             + \cos {\phi_{}}_{\mathrm P} \cos {\phi_{}}_{\mathrm M}
620               \cos ({\lambda_{}}_{\mathrm M} - {\lambda_{}}_{\mathrm P})
621                   \right\}
622   \end{alignat*}
623
624   and $M$ corresponds to $B$, $C$ or $D$.
625   A more stable form of the great-circle distance formula for small distances ($x$ near 1)
626   involves the arcsine function (\eg\ see p.~101 of \citet{daley.barker_bk01}:
627
628   \begin{alignat*}{2}
629     s\left( {\mathrm P}, {\mathrm M} \right) = \sin^{-1} \! \left\{ \sqrt{ 1 - x^2 } \right\}
630   \end{alignat*}
631
632   where
633
634   \begin{alignat*}{2}
635     x = {a_{}}_{\mathrm M} {a_{}}_{\mathrm P} + {b_{}}_{\mathrm M} {b_{}}_{\mathrm P} + {c_{}}_{\mathrm M} {c_{}}_{\mathrm P}
636   \end{alignat*}
637
638   and
639
640   \begin{alignat*}{3}
641   & {a_{}}_{\mathrm M} & = && \quad \sin {\phi_{}}_{\mathrm M}, \\
642   & {a_{}}_{\mathrm P} & = && \quad \sin {\phi_{}}_{\mathrm P}, \\
643   & {b_{}}_{\mathrm M} & = && \quad \cos {\phi_{}}_{\mathrm M} \cos {\phi_{}}_{\mathrm M}, \\
644   & {b_{}}_{\mathrm P} & = && \quad \cos {\phi_{}}_{\mathrm P} \cos {\phi_{}}_{\mathrm P}, \\
645   & {c_{}}_{\mathrm M} & = && \quad \cos {\phi_{}}_{\mathrm M} \sin {\phi_{}}_{\mathrm M}, \\
646   & {c_{}}_{\mathrm P} & = && \quad \cos {\phi_{}}_{\mathrm P} \sin {\phi_{}}_{\mathrm P}.
647   \end{alignat*}
648
649\item [2.] {\bfseries Great-Circle distance-weighted interpolation with small angle approximation.}
650  Similar to the previous interpolation but with the distance $s$ computed as
651  \begin{alignat*}{2}
652    s\left( {\mathrm P}, {\mathrm M} \right)
653    & = & \sqrt{ \left( {\phi_{}}_{\mathrm M} - {\phi_{}}_{\mathrm P} \right)^{2}
654                                      + \left( {\lambda_{}}_{\mathrm M} - {\lambda_{}}_{\mathrm P} \right)^{2}
655                                      \cos^{2} {\phi_{}}_{\mathrm M} }
656  \end{alignat*}
657  where $M$ corresponds to $A$, $B$, $C$ or $D$.
658
659\item [3.] {\bfseries Bilinear interpolation for a regular spaced grid.}
660  The interpolation is split into two 1D interpolations in the longitude and latitude directions, respectively.
661
662\item [4.] {\bfseries Bilinear remapping interpolation for a general grid.}
663  An iterative scheme that involves first mapping a quadrilateral cell into
664  a cell with coordinates (0,0), (1,0), (0,1) and (1,1).
665  This method is based on the \href{https://github.com/SCRIP-Project/SCRIP}{SCRIP interpolation package}.
666
667\end{enumerate}
668
669\subsubsection{Horizontal averaging}
670
671For each surface observation type:
672\begin{itemize}
673\item The standard grid-searching code is used to find the nearest model grid point to the observation location
674  (see next subsection).
675\item The maximum number of grid points required for that observation in each local grid domain is calculated. Some of these points may later turn out to have zero weight depending on the shape of the footprint.
676\item The longitudes and latitudes of the grid points surrounding the nearest model grid box are extracted using
677  existing MPI routines.
678\item The weights for each grid point associated with each observation are calculated,
679  either for radial or rectangular footprints.
680  For grid points completely within the footprint, the weight is one;
681  for grid points completely outside the footprint, the weight is zero.
682  For grid points which are partly within the footprint the ratio between the area of the footprint within
683  the grid box and the total area of the grid box is used as the weight.
684\item The weighted average of the model grid points associated with each observation is calculated,
685  and this is then given as the model counterpart of the observation.
686\end{itemize}
687
688Examples of the weights calculated for an observation with rectangular and radial footprints are shown in
689\autoref{fig:OBS_avgrec} and~\autoref{fig:OBS_avgrad}.
690
691\begin{figure}
692  \centering
693  \includegraphics[width=0.66\textwidth]{Fig_OBS_avg_rec}
694  \caption[Observational weights with a rectangular footprint]{
695    Weights associated with each model grid box (blue lines and numbers)
696    for an observation at -170.5\deg{E}, 56.0\deg{N} with a rectangular footprint of 1\deg\ x 1\deg.}
697  \label{fig:OBS_avgrec}
698\end{figure}
699% >>>>>>>>>>>>>>>>>>>>>>>>>>>>
700
701\begin{figure}
702  \centering
703  \includegraphics[width=0.66\textwidth]{Fig_OBS_avg_rad}
704  \caption[Observational weights with a radial footprint]{
705    Weights associated with each model grid box (blue lines and numbers)
706    for an observation at -170.5\deg{E}, 56.0\deg{N} with a radial footprint with diameter 1\deg.}
707  \label{fig:OBS_avgrad}
708\end{figure}
709
710\subsection{Grid search}
711
712For 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.
713Therefore, it is not always straightforward to determine the grid points surrounding any given observational position.
714Before the interpolation can be performed, a search algorithm is then required to determine the corner points of
715the quadrilateral cell in which the observation is located.
716This is the most difficult and time consuming part of the 2D interpolation procedure.
717A robust test for determining if an observation falls within a given quadrilateral cell is as follows.
718Let ${\mathrm P}({\lambda_{}}_{\mathrm P} ,{\phi_{}}_{\mathrm P} )$ denote the observation point,
719and let ${\mathrm A}({\lambda_{}}_{\mathrm A} ,{\phi_{}}_{\mathrm A} )$, ${\mathrm B}({\lambda_{}}_{\mathrm B} ,{\phi_{}}_{\mathrm B} )$,
720${\mathrm C}({\lambda_{}}_{\mathrm C} ,{\phi_{}}_{\mathrm C} )$ and ${\mathrm D}({\lambda_{}}_{\mathrm D} ,{\phi_{}}_{\mathrm D} )$
721denote the bottom left, bottom right, top left and top right corner points of the cell, respectively.
722To determine if P is inside the cell, we verify that the cross-products
723\begin{align*}
724  \begin{array}{lllll}
725    {{\mathbf r}_{}}_{\mathrm PA} \times {{\mathbf r}_{}}_{\mathrm PC}
726    & = & [({\lambda_{}}_{\mathrm A}\; -\; {\lambda_{}}_{\mathrm P} )
727          ({\phi_{}}_{\mathrm C}   \; -\; {\phi_{}}_{\mathrm P} )
728          - ({\lambda_{}}_{\mathrm C}\; -\; {\lambda_{}}_{\mathrm P} )
729          ({\phi_{}}_{\mathrm A}   \; -\; {\phi_{}}_{\mathrm P} )] \; \widehat{\mathbf k} \\
730    {{\mathbf r}_{}}_{\mathrm PB} \times {{\mathbf r}_{}}_{\mathrm PA}
731    & = & [({\lambda_{}}_{\mathrm B}\; -\; {\lambda_{}}_{\mathrm P} )
732          ({\phi_{}}_{\mathrm A}   \; -\; {\phi_{}}_{\mathrm P} )
733          - ({\lambda_{}}_{\mathrm A}\; -\; {\lambda_{}}_{\mathrm P} )
734          ({\phi_{}}_{\mathrm B}   \; -\; {\phi_{}}_{\mathrm P} )] \; \widehat{\mathbf k} \\
735    {{\mathbf r}_{}}_{\mathrm PC} \times {{\mathbf r}_{}}_{\mathrm PD}
736    & = & [({\lambda_{}}_{\mathrm C}\; -\; {\lambda_{}}_{\mathrm P} )
737          ({\phi_{}}_{\mathrm D}   \; -\; {\phi_{}}_{\mathrm P} )
738          - ({\lambda_{}}_{\mathrm D}\; -\; {\lambda_{}}_{\mathrm P} )
739          ({\phi_{}}_{\mathrm C}   \; -\; {\phi_{}}_{\mathrm P} )] \; \widehat{\mathbf k} \\
740    {{\mathbf r}_{}}_{\mathrm PD} \times {{\mathbf r}_{}}_{\mathrm PB}
741    & = & [({\lambda_{}}_{\mathrm D}\; -\; {\lambda_{}}_{\mathrm P} )
742          ({\phi_{}}_{\mathrm B}   \; -\; {\phi_{}}_{\mathrm P} )
743          - ({\lambda_{}}_{\mathrm B}\; -\; {\lambda_{}}_{\mathrm P} )
744          ({\phi_{}}_{\mathrm D}  \;  - \; {\phi_{}}_{\mathrm P} )] \; \widehat{\mathbf k} \\
745  \end{array}
746  % \label{eq:OBS_cross}
747\end{align*}
748point in the opposite direction to the unit normal $\widehat{\mathbf k}$
749(\ie\ that the coefficients of $\widehat{\mathbf k}$ are negative),
750where ${{\mathbf r}_{}}_{\mathrm PA}$, ${{\mathbf r}_{}}_{\mathrm PB}$, etc. correspond to
751the vectors between points P and A, P and B, etc..
752The method used is similar to the method used in the \href{https://github.com/SCRIP-Project/SCRIP}{SCRIP interpolation package}.
753
754In order to speed up the grid search, there is the possibility to construct a lookup table for a user specified resolution.
755This lookup table contains the lower and upper bounds on the $i$ and $j$ indices to
756be searched for on a regular grid.
757For each observation position, the closest point on the regular grid of this position is computed and
758the $i$ and $j$ ranges of this point searched to determine the precise four points surrounding the observation.
759
760\subsection{Parallel aspects of horizontal interpolation}
761\label{subsec:OBS_parallel}
762
763For horizontal interpolation, there is the basic problem that
764the observations are unevenly distributed on the globe.
765In \NEMO\ the model grid is divided into subgrids (or domains) where
766each subgrid is executed on a single processing element with explicit message passing for
767exchange of information along the domain boundaries when running on a massively parallel processor (MPP) system.
768
769For observations there is no natural distribution since the observations are not equally distributed on the globe.
770Two options have been made available:
7711) geographical distribution;
772and 2) round-robin.
773
774\subsubsection{Geographical distribution of observations among processors}
775
776\begin{figure}
777  \centering
778  \includegraphics[width=0.66\textwidth]{Fig_ASM_obsdist_local}
779  \caption[Observations with the geographical distribution]{
780    Example of the distribution of observations with
781    the geographical distribution of observational data}
782  \label{fig:OBS_local}
783\end{figure}
784
785This is the simplest option in which the observations are distributed according to
786the domain of the grid-point parallelization.
787\autoref{fig:OBS_local} shows an example of the distribution of the {\em in situ} data on processors with
788a different colour for each observation on a given processor for a 4 $\times$ 2 decomposition with ORCA2.
789The grid-point domain decomposition is clearly visible on the plot.
790
791The advantage of this approach is that all information needed for horizontal interpolation is available without
792any MPP communication.
793This is under the assumption that we are dealing with point observations and only using a $2 \times 2$ grid-point stencil for
794the interpolation (\eg\ bilinear interpolation).
795For higher order interpolation schemes this is no longer valid.
796A disadvantage with the above scheme is that the number of observations on each processor can be very different.
797If the cost of the actual interpolation is expensive relative to the communication of data needed for interpolation,
798this could lead to load imbalance.
799
800\subsubsection{Round-robin distribution of observations among processors}
801
802\begin{figure}
803  \centering
804  \includegraphics[width=0.66\textwidth]{Fig_ASM_obsdist_global}
805  \caption[Observations with the round-robin distribution]{
806    Example of the distribution of observations with
807    the round-robin distribution of observational data.}
808  \label{fig:OBS_global}
809\end{figure}
810
811An alternative approach is to distribute the observations equally among processors and
812use message passing in order to retrieve the stencil for interpolation.
813The simplest distribution of the observations is to distribute them using a round-robin scheme.
814\autoref{fig:OBS_global} shows the distribution of the {\em in situ} data on processors for
815the round-robin distribution of observations with a different colour for each observation on a given processor for
816a 4 $\times$ 2 decomposition with ORCA2 for the same input data as in \autoref{fig:OBS_local}.
817The observations are now clearly randomly distributed on the globe.
818In order to be able to perform horizontal interpolation in this case,
819a subroutine has been developed that retrieves any grid points in the global space.
820
821\subsection{Vertical interpolation operator}
822
823Vertical interpolation is achieved using either a cubic spline or linear interpolation.
824For the cubic spline, the top and bottom boundary conditions for the second derivative of
825the interpolating polynomial in the spline are set to zero.
826At the bottom boundary, this is done using the land-ocean mask.
827
828For profile observation types we do both vertical and horizontal interpolation. \NEMO\ has a generalised vertical coordinate system this means the vertical level depths can vary with location. Therefore, it is necessary first to perform vertical interpolation of the model value to the observation depths for each of the four surrounding grid points. After this the model values, at these points, at the observation depth, are horizontally interpolated to the observation location.
829
830%\usepackage{framed}
831
832\section{Standalone observation operator}
833\label{sec:OBS_sao}
834
835\subsection{Concept}
836
837The observation operator maps model variables to observation space. This is normally done while the model is running, i.e. online, it is possible to apply this mapping offline without running the model with the \textbf{standalone observation operator} (SAO). The process is divided into an initialisation phase, an interpolation phase and an output phase.
838During the interpolation phase the SAO populates the model arrays by
839reading saved model fields from disk. The interpolation and the output phases use the same OBS code described in the preceding sections.
840
841There are two ways of exploiting the standalone capacity.
842The first is to mimic the behaviour of the online system by supplying model fields at
843regular intervals between the start and the end of the run.
844This approach results in a single model counterpart per observation.
845This kind of usage produces feedback files the same file format as the online observation operator.
846The second is to take advantage of the ability to run offline by calculating
847multiple model counterparts for each observation.
848In this case it is possible to consider all forecasts verifying at the same time.
849By forecast, we mean any method which produces an estimate of physical reality which is not an observed value.
850
851%--------------------------------------------------------------------------------------------------------
852% sao.exe
853%--------------------------------------------------------------------------------------------------------
854
855\subsection{Using the standalone observation operator}
856
857\subsubsection{Building}
858
859In addition to \emph{OPA\_SRC} the SAO requires the inclusion of the \emph{SAO\_SRC} directory.
860\emph{SAO\_SRC} contains a replacement \mdl{nemo} and \mdl{nemogcm} which
861overwrites the resultant \textbf{nemo.exe}.
862Note this a similar approach to that taken by the standalone surface scheme \emph{SAS\_SRC} and the offline TOP model \emph{OFF\_SRC}.
863
864%--------------------------------------------------------------------------------------------------------
865% Running
866%--------------------------------------------------------------------------------------------------------
867\subsubsection{Running}
868
869The simplest way to use the executable is to edit and append the \textbf{sao.nml} namelist to
870a full \NEMO\ namelist and then to run the executable as if it were nemo.exe.
871
872%--------------------------------------------------------------------------------------------------------
873% Configuration section
874%--------------------------------------------------------------------------------------------------------
875\subsection{Configuring the standalone observation operator}
876The observation files and settings understood by \nam{obs}{obs} have been outlined in the online observation operator section.
877In addition is a further namelist \nam{sao}{sao} which used to set the input model fields for the SAO
878
879\subsubsection{Single field}
880
881In the SAO the model arrays are populated at appropriate time steps via input files.
882At present, \textbf{tsn} and \textbf{sshn} are populated by the default read routines.
883These routines will be expanded upon in future versions to allow the specification of any model variable.
884As such, input files must be global versions of the model domain with
885\textbf{votemper}, \textbf{vosaline} and optionally \textbf{sshn} present.
886
887For each field read there must be an entry in the \nam{sao}{sao} namelist specifying
888the name of the file to read and the index along the \emph{time\_counter}.
889For example, to read the second time counter from a single file the namelist would be.
890
891\begin{forlines}
892!----------------------------------------------------------------------
893!       namsao Standalone obs_oper namelist
894!----------------------------------------------------------------------
895!   sao_files    specifies the files containing the model counterpart
896!   nn_sao_idx   specifies the time_counter index within the model file
897&namsao
898   sao_files = "foo.nc"
899   nn_sao_idx = 2
900/
901\end{forlines}
902
903\subsubsection{Multiple fields per run}
904
905Model field iteration is controlled via \textbf{nn\_sao\_freq} which
906specifies the number of model steps at which the next field gets read.
907For example, if 12 hourly fields are to be interpolated in a setup where 288 steps equals 24 hours.
908
909\begin{forlines}
910!----------------------------------------------------------------------
911!       namsao Standalone obs_oper namelist
912!----------------------------------------------------------------------
913!   sao_files    specifies the files containing the model counterpart
914!   nn_sao_idx   specifies the time_counter index within the model file
915!   nn_sao_freq  specifies number of time steps between read operations
916&namsao
917   sao_files = "foo.nc" "foo.nc"
918   nn_sao_idx = 1 2
919   nn_sao_freq = 144
920/
921\end{forlines}
922
923The above namelist will result in feedback files whose first 12 hours contain the first field of foo.nc and
924the second 12 hours contain the second field.
925
926%\begin{framed}
927\textbf{Note} Missing files can be denoted as "nofile".
928%\end{framed}
929
930A collection of fields taken from a number of files at different indices can be combined at
931a particular frequency in time to generate a pseudo model evolution.
932If all that is needed is a single model counterpart at a regular interval then
933the standard SAO is all that is required.
934However, just to note, it is possible to extend this approach by comparing multiple forecasts, analyses, persisted analyses and
935climatologies with the same set of observations.
936This approach is referred to as \emph{Class 4} since it is the fourth metric defined by the GODAE intercomparison project. This requires multiple runs of the SAO and running an additional utility (not currently in the \NEMO\ repository) to combine the feedback files into one class 4 file.
937
938\section{Observation utilities}
939\label{sec:OBS_obsutils}
940
941For convenience some tools for viewing and processing of observation and feedback files are provided in
942the \NEMO\ repository.
943These tools include OBSTOOLS which are a collection of \fortran\ programs which are helpful to deal with feedback files.
944They do such tasks as observation file conversion, printing of file contents,
945some basic statistical analysis of feedback files.
946The other main tool is an IDL program called dataplot which uses a graphical interface to
947visualise observations and feedback files.
948OBSTOOLS and dataplot are described in more detail below.
949
950\subsection{Obstools}
951
952A series of \fortran\ utilities is provided with \NEMO\ called OBSTOOLS.
953This are helpful in handling observation files and the feedback file output from the observation operator. A brief description of some of the utilities follows
954
955\subsubsection{corio2fb}
956
957The program corio2fb converts profile observation files from the Coriolis format to the standard feedback format.
958It is called in the following way:
959
960\begin{cmds}
961corio2fb.exe outputfile inputfile1 inputfile2 ...
962\end{cmds}
963
964\subsubsection{enact2fb}
965
966The program enact2fb converts profile observation files from the ENACT format to the standard feedback format.
967It is called in the following way:
968
969\begin{cmds}
970enact2fb.exe outputfile inputfile1 inputfile2 ...
971\end{cmds}
972
973\subsubsection{fbcomb}
974
975The program fbcomb combines multiple feedback files produced by individual processors in
976an MPI run of \NEMO\ into a single feedback file.
977It is called in the following way:
978
979\begin{cmds}
980fbcomb.exe outputfile inputfile1 inputfile2 ...
981\end{cmds}
982
983\subsubsection{fbmatchup}
984
985The program fbmatchup will match observations from two feedback files.
986It is called in the following way:
987
988\begin{cmds}
989fbmatchup.exe outputfile inputfile1 varname1 inputfile2 varname2 ...
990\end{cmds}
991
992\subsubsection{fbprint}
993
994The program fbprint will print the contents of a feedback file or files to standard output.
995Selected information can be output using optional arguments.
996It is called in the following way:
997
998\begin{cmds}
999fbprint.exe [options] inputfile
1000
1001options:
1002     -b            shorter output
1003     -q            Select observations based on QC flags
1004     -Q            Select observations based on QC flags
1005     -B            Select observations based on QC flags
1006     -u            unsorted
1007     -s ID         select station ID
1008     -t TYPE       select observation type
1009     -v NUM1-NUM2  select variable range to print by number
1010                      (default all)
1011     -a NUM1-NUM2  select additional variable range to print by number
1012                      (default all)
1013     -e NUM1-NUM2  select extra variable range to print by number
1014                      (default all)
1015     -d            output date range
1016     -D            print depths
1017     -z            use zipped files
1018\end{cmds}
1019
1020\subsubsection{fbsel}
1021
1022The program fbsel will select or subsample observations.
1023It is called in the following way:
1024
1025\begin{cmds}
1026fbsel.exe <input filename> <output filename>
1027\end{cmds}
1028
1029\subsubsection{fbstat}
1030
1031The program fbstat will output summary statistics in different global areas into a number of files.
1032It is called in the following way:
1033
1034\begin{cmds}
1035fbstat.exe [-nmlev] <filenames>
1036\end{cmds}
1037
1038\subsubsection{fbthin}
1039
1040The program fbthin will thin the data to 1 degree resolution.
1041The code could easily be modified to thin to a different resolution.
1042It is called in the following way:
1043
1044\begin{cmds}
1045fbthin.exe inputfile outputfile
1046\end{cmds}
1047
1048\subsubsection{sla2fb}
1049
1050The program sla2fb will convert an AVISO SLA format file to feedback format.
1051It is called in the following way:
1052
1053\begin{cmds}
1054sla2fb.exe [-s type] outputfile inputfile1 inputfile2 ...
1055
1056Option:
1057     -s            Select altimeter data_source
1058\end{cmds}
1059
1060\subsubsection{vel2fb}
1061
1062The program vel2fb will convert TAO/PIRATA/RAMA currents files to feedback format.
1063It is called in the following way:
1064
1065\begin{cmds}
1066vel2fb.exe outputfile inputfile1 inputfile2 ...
1067\end{cmds}
1068
1069\subsection{Building the obstools}
1070
1071To build the obstools use in the tools directory use ./maketools -n OBSTOOLS -m [ARCH].
1072
1073\subsection{Dataplot}
1074
1075An IDL program called dataplot is included which uses a graphical interface to
1076visualise observations and feedback files. Note a similar package has recently developed in python (also called dataplot) which does some of the same things that the IDL dataplot does. Please contact the authors of the this chapter if you are interested in this.
1077
1078It is possible to zoom in, plot individual profiles and calculate some basic statistics.
1079To plot some data run IDL and then:
1080
1081\begin{minted}{idl}
1082IDL> dataplot, "filename"
1083\end{minted}
1084
1085To read multiple files into dataplot,
1086for example multiple feedback files from different processors or from different days,
1087the easiest method is to use the spawn command to generate a list of files which can then be passed to dataplot.
1088
1089\begin{minted}{idl}
1090IDL> spawn, 'ls profb*.nc', files
1091IDL> dataplot, files
1092\end{minted}
1093
1094\autoref{fig:OBS_dataplotmain} shows the main window which is launched when dataplot starts.
1095This is split into three parts.
1096At the top there is a menu bar which contains a variety of drop down menus.
1097Areas - zooms into prespecified regions;
1098plot - plots the data as a timeseries or a T-S diagram if appropriate;
1099Find - allows data to be searched;
1100Config - sets various configuration options.
1101
1102The middle part is a plot of the geographical location of the observations.
1103This will plot the observation value, the model background value or observation minus background value depending on
1104the option selected in the radio button at the bottom of the window.
1105The plotting colour range can be changed by clicking on the colour bar.
1106The title of the plot gives some basic information about the date range and depth range shown,
1107the extreme values, and the mean and RMS values.
1108It is possible to zoom in using a drag-box.
1109You may also zoom in or out using the mouse wheel.
1110
1111The bottom part of the window controls what is visible in the plot above.
1112There are two bars which select the level range plotted (for profile data).
1113The other bars below select the date range shown.
1114The bottom of the figure allows the option to plot the mean, root mean square, standard deviation or
1115mean square values.
1116As mentioned above you can choose to plot the observation value, the model background value or
1117observation minus background value.
1118The next group of radio buttons selects the map projection.
1119This can either be regular longitude latitude grid, or north or south polar stereographic.
1120The next group of radio buttons will plot bad observations, switch to salinity and
1121plot density for profile observations.
1122The rightmost group of buttons will print the plot window as a postscript, save it as png, or exit from dataplot.
1123
1124\begin{figure}
1125  \centering
1126  \includegraphics[width=0.66\textwidth]{Fig_OBS_dataplot_main}
1127  \caption{Main window of dataplot}
1128  \label{fig:OBS_dataplotmain}
1129\end{figure}
1130
1131If a profile point is clicked with the mouse button a plot of the observation and background values as
1132a function of depth (\autoref{fig:OBS_dataplotprofile}).
1133
1134\begin{figure}
1135  \centering
1136  \includegraphics[width=0.66\textwidth]{Fig_OBS_dataplot_prof}
1137  \caption[Profile plot from dataplot]{
1138    Profile plot from dataplot produced by right clicking on a point in the main window}
1139  \label{fig:OBS_dataplotprofile}
1140\end{figure}
1141
1142\onlyinsubfile{\input{../../global/epilogue}}
1143
1144\end{document}
Note: See TracBrowser for help on using the repository browser.