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 trunk/DOC/TexFiles/Chapters – NEMO

source: trunk/DOC/TexFiles/Chapters/Chap_OBS.tex @ 2541

Last change on this file since 2541 was 2483, checked in by djlea, 13 years ago

Documentation fixes for OBS and ASM

File size: 35.5 KB
Line 
1% ================================================================
2% Chapter observation operator (OBS)
3% ================================================================
4\chapter{Observation and model comparison (OBS)}
5\label{OBS}
6
7Authors: D. Lea, M. Martin, K. Mogensen, A. Vidard, A. Weaver...   % do we keep that ?
8
9\minitoc
10
11
12\newpage
13$\ $\newline    % force a new line
14
15The observation and model comparison code (OBS) reads in observation files
16(profile temperature and salinity, sea surface temperature, sea level anomaly,
17sea ice concentration, and velocity) and calculates  an interpolated model equivalent
18value at the observation location and nearest model timestep. The OBS code is
19called from \np{opa.F90} in order to initialise the model and to calculate the
20model equivalent values for observations on the 0th timestep. The code is then
21called again after each timestep from \np{step.F90}. The code was originally
22developed for use with NEMOVAR.
23
24For all data types a 2D horizontal  interpolator is needed
25to interpolate the model fields to the observation location.
26For {\em in situ} profiles, a 1D vertical interpolator is needed in addition to
27provide model fields at the observation depths. Currently this only works in
28z-level model configurations, but is being developed to work with a
29generalised vertical coordinate system.
30Temperature data from moored buoys (TAO, TRITON, PIRATA) in the
31ENACT/ENSEMBLES data-base are available as daily averaged quantities. For this
32type of observation the
33observation operator will compare such observations to the model temperature
34fields averaged over one day. The relevant observation type may be specified in the namelist
35using \np{endailyavtypes}. Otherwise the model value from the nearest
36timestep to the observation time is used.
37
38The resulting data are saved in a ``feedback'' file (or files) which can be used
39for model validation and verification and also to provide information for data
40assimilation. This code is controlled by the namelist \textit{nam\_obs}. To
41build with the OBS code active \key{diaobs} must be set.
42
43Section~\ref{OBS_example} introduces a test example of the observation operator
44code including where to obtain data and how to setup the namelist.
45Section~\ref{OBS_details} introduces some more technical details of the
46different observation types used and also shows a more complete namelist.
47Finally section~\ref{OBS_theory} introduces some of the theoretical aspects of
48the observation operator including interpolation methods and running on multiple
49processors.
50
51% ================================================================
52% Example
53% ================================================================
54\section{Running the observation operator code example}
55\label{OBS_example}
56
57This section describes an example of running the observation operator code using
58profile data which can be freely downloaded. It shows how to adapt an
59existing run and build of NEMO to run the observation operator.
60
61\begin{enumerate}
62\item Compile NEMO with \key{diaobs} set.
63
64\item Download some ENSEMBLES EN3 data from
65\href{http://www.hadobs.org}{http://www.hadobs.org}. Choose observations which are
66valid for the period of your test run because the observation operator compares
67the model and observations for a matching date and time.
68
69\item Add the following to the NEMO namelist to run the observation
70operator on this data. Set the \np{enactfiles} namelist parameter to the
71observation  file name (or link in to \np{profiles\_01\.nc}):
72\end{enumerate}
73
74%------------------------------------------namobs_example-----------------------------------------------------
75\namdisplay{namobs_example}
76%-------------------------------------------------------------------------------------------------------------
77
78The option \np{ln\_t3d} and \np{ln\_s3d} switch on the temperature and salinity
79profile observation operator code. The \np{ln\_ena} switch turns on the reading
80of ENACT/ENSEMBLES type profile data. The filename or array of filenames are
81specified using the \np{enactfiles} variable. The model grid points for a
82particular  observation latitude and longitude are found using the grid
83searching part of the code. This can be expensive, particularly for large
84numbers of observations, setting \np{ln\_grid\_search\_lookup} allows the use of
85a lookup table which is saved into an ``xypos`` file (or files). This will need
86to be generated the first time if it does not exist in the run directory.
87However, once produced it will significantly speed up future grid searches.
88Setting \np{ln\_grid\_global} means that the code distributes the observations
89evenly between processors. Alternatively each processor will work with
90observations located within the model subdomain.
91
92The NEMOVAR system contains utilities to plot the feedback files, convert and
93recombine the files. These are available on request from the NEMOVAR team.
94
95\section{Technical details}
96\label{OBS_details}
97
98Here we show a more complete example namelist and also show the NetCDF headers
99of the observation
100files that may be used with the observation operator
101
102%------------------------------------------namobs--------------------------------------------------------
103\namdisplay{namobs}
104%-------------------------------------------------------------------------------------------------------------
105
106This name list uses the "feedback" type observation file input format for
107profile, sea level anomaly and sea surface temperature data. All the
108observation files must be in NetCDF format. Some example headers (produced using
109\mbox{\textit{ncdump~-h}}) for profile
110data, sea level anomaly and sea surface temperature are in the following
111subsections.
112
113\subsection{Profile feedback type observation file header}
114
115\begin{alltt}
116\tiny
117\begin{verbatim}
118netcdf profiles_01 {
119dimensions:
120     N_OBS = 603 ;
121     N_LEVELS = 150 ;
122     N_VARS = 2 ;
123     N_QCF = 2 ;
124     N_ENTRIES = 1 ;
125     N_EXTRA = 1 ;
126     STRINGNAM = 8 ;
127     STRINGGRID = 1 ;
128     STRINGWMO = 8 ;
129     STRINGTYP = 4 ;
130     STRINGJULD = 14 ;
131variables:
132     char VARIABLES(N_VARS, STRINGNAM) ;
133          VARIABLES:long_name = "List of variables in feedback files" ;
134     char ENTRIES(N_ENTRIES, STRINGNAM) ;
135          ENTRIES:long_name = "List of additional entries for each variable in feedback files" ;
136     char EXTRA(N_EXTRA, STRINGNAM) ;
137          EXTRA:long_name = "List of extra variables" ;
138     char STATION_IDENTIFIER(N_OBS, STRINGWMO) ;
139          STATION_IDENTIFIER:long_name = "Station identifier" ;
140     char STATION_TYPE(N_OBS, STRINGTYP) ;
141          STATION_TYPE:long_name = "Code instrument type" ;
142     double LONGITUDE(N_OBS) ;
143          LONGITUDE:long_name = "Longitude" ;
144          LONGITUDE:units = "degrees_east" ;
145          LONGITUDE:_Fillvalue = 99999.f ;
146     double LATITUDE(N_OBS) ;
147          LATITUDE:long_name = "Latitude" ;
148          LATITUDE:units = "degrees_north" ;
149          LATITUDE:_Fillvalue = 99999.f ;
150     double DEPTH(N_OBS, N_LEVELS) ;
151          DEPTH:long_name = "Depth" ;
152          DEPTH:units = "metre" ;
153          DEPTH:_Fillvalue = 99999.f ;
154     int DEPTH_QC(N_OBS, N_LEVELS) ;
155          DEPTH_QC:long_name = "Quality on depth" ;
156          DEPTH_QC:Conventions = "q where q =[0,9]" ;
157          DEPTH_QC:_Fillvalue = 0 ;
158     int DEPTH_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
159          DEPTH_QC_FLAGS:long_name = "Quality flags on depth" ;
160          DEPTH_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
161     double JULD(N_OBS) ;
162          JULD:long_name = "Julian day" ;
163          JULD:units = "days since JULD_REFERENCE" ;
164          JULD:Conventions = "relative julian days with decimal part (as parts of day)" ;
165          JULD:_Fillvalue = 99999.f ;
166     char JULD_REFERENCE(STRINGJULD) ;
167          JULD_REFERENCE:long_name = "Date of reference for julian days" ;
168          JULD_REFERENCE:Conventions = "YYYYMMDDHHMMSS" ;
169     int OBSERVATION_QC(N_OBS) ;
170          OBSERVATION_QC:long_name = "Quality on observation" ;
171          OBSERVATION_QC:Conventions = "q where q =[0,9]" ;
172          OBSERVATION_QC:_Fillvalue = 0 ;
173     int OBSERVATION_QC_FLAGS(N_OBS, N_QCF) ;
174          OBSERVATION_QC_FLAGS:long_name = "Quality flags on observation" ;
175          OBSERVATION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
176          OBSERVATION_QC_FLAGS:_Fillvalue = 0 ;
177     int POSITION_QC(N_OBS) ;
178          POSITION_QC:long_name = "Quality on position (latitude and longitude)" ;
179          POSITION_QC:Conventions = "q where q =[0,9]" ;
180          POSITION_QC:_Fillvalue = 0 ;
181     int POSITION_QC_FLAGS(N_OBS, N_QCF) ;
182          POSITION_QC_FLAGS:long_name = "Quality flags on position" ;
183          POSITION_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
184          POSITION_QC_FLAGS:_Fillvalue = 0 ;
185     int JULD_QC(N_OBS) ;
186          JULD_QC:long_name = "Quality on date and time" ;
187          JULD_QC:Conventions = "q where q =[0,9]" ;
188          JULD_QC:_Fillvalue = 0 ;
189     int JULD_QC_FLAGS(N_OBS, N_QCF) ;
190          JULD_QC_FLAGS:long_name = "Quality flags on date and time" ;
191          JULD_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
192          JULD_QC_FLAGS:_Fillvalue = 0 ;
193     int ORIGINAL_FILE_INDEX(N_OBS) ;
194          ORIGINAL_FILE_INDEX:long_name = "Index in original data file" ;
195          ORIGINAL_FILE_INDEX:_Fillvalue = -99999 ;
196     float POTM_OBS(N_OBS, N_LEVELS) ;
197          POTM_OBS:long_name = "Potential temperature" ;
198          POTM_OBS:units = "Degrees Celsius" ;
199          POTM_OBS:_Fillvalue = 99999.f ;
200     float POTM_Hx(N_OBS, N_LEVELS) ;
201          POTM_Hx:long_name = "Model interpolated potential temperature" ;
202          POTM_Hx:units = "Degrees Celsius" ;
203          POTM_Hx:_Fillvalue = 99999.f ;
204     int POTM_QC(N_OBS) ;
205          POTM_QC:long_name = "Quality on potential temperature" ;
206          POTM_QC:Conventions = "q where q =[0,9]" ;
207          POTM_QC:_Fillvalue = 0 ;
208     int POTM_QC_FLAGS(N_OBS, N_QCF) ;
209          POTM_QC_FLAGS:long_name = "Quality flags on potential temperature" ;
210          POTM_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
211          POTM_QC_FLAGS:_Fillvalue = 0 ;
212     int POTM_LEVEL_QC(N_OBS, N_LEVELS) ;
213          POTM_LEVEL_QC:long_name = "Quality for each level on potential temperature" ;
214          POTM_LEVEL_QC:Conventions = "q where q =[0,9]" ;
215          POTM_LEVEL_QC:_Fillvalue = 0 ;
216     int POTM_LEVEL_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
217          POTM_LEVEL_QC_FLAGS:long_name = "Quality flags for each level on potential temperature" ;
218          POTM_LEVEL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
219          POTM_LEVEL_QC_FLAGS:_Fillvalue = 0 ;
220     int POTM_IOBSI(N_OBS) ;
221          POTM_IOBSI:long_name = "ORCA grid search I coordinate" ;
222     int POTM_IOBSJ(N_OBS) ;
223          POTM_IOBSJ:long_name = "ORCA grid search J coordinate" ;
224     int POTM_IOBSK(N_OBS, N_LEVELS) ;
225          POTM_IOBSK:long_name = "ORCA grid search K coordinate" ;
226     char POTM_GRID(STRINGGRID) ;
227          POTM_GRID:long_name = "ORCA grid search grid (T,U,V)" ;
228     float PSAL_OBS(N_OBS, N_LEVELS) ;
229          PSAL_OBS:long_name = "Practical salinity" ;
230          PSAL_OBS:units = "PSU" ;
231          PSAL_OBS:_Fillvalue = 99999.f ;
232     float PSAL_Hx(N_OBS, N_LEVELS) ;
233          PSAL_Hx:long_name = "Model interpolated practical salinity" ;
234          PSAL_Hx:units = "PSU" ;
235          PSAL_Hx:_Fillvalue = 99999.f ;
236     int PSAL_QC(N_OBS) ;
237          PSAL_QC:long_name = "Quality on practical salinity" ;
238          PSAL_QC:Conventions = "q where q =[0,9]" ;
239          PSAL_QC:_Fillvalue = 0 ;
240     int PSAL_QC_FLAGS(N_OBS, N_QCF) ;
241          PSAL_QC_FLAGS:long_name = "Quality flags on practical salinity" ;
242          PSAL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
243          PSAL_QC_FLAGS:_Fillvalue = 0 ;
244     int PSAL_LEVEL_QC(N_OBS, N_LEVELS) ;
245          PSAL_LEVEL_QC:long_name = "Quality for each level on practical salinity" ;
246          PSAL_LEVEL_QC:Conventions = "q where q =[0,9]" ;
247          PSAL_LEVEL_QC:_Fillvalue = 0 ;
248     int PSAL_LEVEL_QC_FLAGS(N_OBS, N_LEVELS, N_QCF) ;
249          PSAL_LEVEL_QC_FLAGS:long_name = "Quality flags for each level on practical salinity" ;
250          PSAL_LEVEL_QC_FLAGS:Conventions = "NEMOVAR flag conventions" ;
251          PSAL_LEVEL_QC_FLAGS:_Fillvalue = 0 ;
252     int PSAL_IOBSI(N_OBS) ;
253          PSAL_IOBSI:long_name = "ORCA grid search I coordinate" ;
254     int PSAL_IOBSJ(N_OBS) ;
255          PSAL_IOBSJ:long_name = "ORCA grid search J coordinate" ;
256     int PSAL_IOBSK(N_OBS, N_LEVELS) ;
257          PSAL_IOBSK:long_name = "ORCA grid search K coordinate" ;
258     char PSAL_GRID(STRINGGRID) ;
259          PSAL_GRID:long_name = "ORCA grid search grid (T,U,V)" ;
260     float TEMP(N_OBS, N_LEVELS) ;
261          TEMP:long_name = "Insitu temperature" ;
262          TEMP:units = "Degrees Celsius" ;
263          TEMP:_Fillvalue = 99999.f ;
264
265// global attributes:
266          :title = "NEMO observation operator output" ;
267          :Convention = "NEMO unified observation operator output" ;
268}
269\end{verbatim}
270\end{alltt}
271
272\subsection{Sea level anomaly feedback type observation file header}
273
274\begin{alltt}
275\tiny
276\begin{verbatim}
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{verbatim}
397\end{alltt}
398
399The mean dynamic
400topography (MDT) must be provided in a separate file defined on the model grid
401 called {\it slaReferenceLevel.nc}. The MDT is required in
402order to produce the model equivalent sea level anomaly from the model sea
403surface height. Below is an example header for this file (on the ORCA025 grid).
404
405\begin{alltt}
406\tiny
407\begin{verbatim}
408dimensions:
409        x = 1442 ;
410        y = 1021 ;
411variables:
412        float nav_lon(y, x) ;
413                nav_lon:units = "degrees_east" ;
414        float nav_lat(y, x) ;
415                nav_lat:units = "degrees_north" ;
416        float sossheig(y, x) ;
417                sossheig:_FillValue = -1.e+30f ;
418                sossheig:coordinates = "nav_lon nav_lat" ;
419                sossheig:long_name = "Mean Dynamic Topography" ;
420                sossheig:units = "metres" ;
421                sossheig:grid = "orca025T" ;
422\end{verbatim}
423\end{alltt}
424
425\subsection{Sea surface temperature feedback type observation file header}
426
427\begin{alltt}
428\tiny
429\begin{verbatim}
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{verbatim}
543\end{alltt}
544
545\section{Theoretical details}
546\label{OBS_theory}
547
548\subsection{Horizontal interpolation methods}
549
550Consider an observation point ${\rm P}$ with
551with longitude and latitude $({\lambda_{}}_{\rm P}, \phi_{\rm P})$ and the
552four nearest neighbouring model grid points ${\rm A}$, ${\rm B}$, ${\rm C}$ 
553and ${\rm D}$ with longitude and latitude ($\lambda_{\rm A}$, $\phi_{\rm A}$),
554($\lambda_{\rm B}$, $\phi_{\rm B}$) etc.
555All horizontal interpolation methods implemented in NEMO
556estimate the value of a model variable $x$ at point $P$ as
557a weighted linear combination of the values of the model
558variables at the grid points ${\rm A}$, ${\rm B}$ etc.:
559\begin{eqnarray}
560{x_{}}_{\rm P} & \hspace{-2mm} = \hspace{-2mm} & 
561\frac{1}{w} \left( {w_{}}_{\rm A} {x_{}}_{\rm A} +
562                   {w_{}}_{\rm B} {x_{}}_{\rm B} +
563                   {w_{}}_{\rm C} {x_{}}_{\rm C} +
564                   {w_{}}_{\rm D} {x_{}}_{\rm D} \right)
565\end{eqnarray}
566where ${w_{}}_{\rm A}$, ${w_{}}_{\rm B}$ etc. are the respective weights for the
567model field at points ${\rm A}$, ${\rm B}$ etc., and
568$w = {w_{}}_{\rm A} + {w_{}}_{\rm B} + {w_{}}_{\rm C} + {w_{}}_{\rm D}$.
569
570Four different possibilities are available for computing the weights.
571
572\begin{enumerate}
573
574\item[1.] {\bf Great-Circle distance-weighted interpolation.} The weights
575  are computed as a function of the great-circle distance $s(P, \cdot)$ 
576  between $P$ and the model grid points $A$, $B$ etc. For example,
577  the weight given to the field ${x_{}}_{\rm A}$ is specified as the
578  product of the distances from ${\rm P}$ to the other points:
579  \begin{eqnarray}
580  {w_{}}_{\rm A} = s({\rm P}, {\rm B}) \, s({\rm P}, {\rm C}) \, s({\rm P}, {\rm D})
581  \nonumber
582  \end{eqnarray}
583  where
584  \begin{eqnarray}
585   s\left ({\rm P}, {\rm M} \right )
586     & \hspace{-2mm} = \hspace{-2mm} & 
587      \cos^{-1} \! \left\{ 
588               \sin {\phi_{}}_{\rm P} \sin {\phi_{}}_{\rm M}
589             + \cos {\phi_{}}_{\rm P} \cos {\phi_{}}_{\rm M} 
590               \cos ({\lambda_{}}_{\rm M} - {\lambda_{}}_{\rm P})
591                   \right\}
592   \end{eqnarray}
593   and $M$ corresponds to $B$, $C$ or $D$.
594   A more stable form of the great-circle distance formula for
595   small distances ($x$ near 1) involves the arcsine function
596   ($e.g.$ see p.~101 of \citet{Daley_Barker_Bk01}:
597   \begin{eqnarray}
598   s\left( {\rm P}, {\rm M} \right)
599     & \hspace{-2mm} = \hspace{-2mm} & 
600      \sin^{-1} \! \left\{ \sqrt{ 1 - x^2 } \right\}
601   \nonumber
602   \end{eqnarray}
603   where
604   \begin{eqnarray}
605    x & \hspace{-2mm} = \hspace{-2mm} & 
606      {a_{}}_{\rm M} {a_{}}_{\rm P} + {b_{}}_{\rm M} {b_{}}_{\rm P} + {c_{}}_{\rm M} {c_{}}_{\rm P}
607   \nonumber
608   \end{eqnarray}
609   and
610   \begin{eqnarray}
611      {a_{}}_{\rm M} & \hspace{-2mm} = \hspace{-2mm} & \sin {\phi_{}}_{\rm M},
612      \nonumber \\
613      {a_{}}_{\rm P} & \hspace{-2mm} = \hspace{-2mm} & \sin {\phi_{}}_{\rm P},
614      \nonumber \\
615      {b_{}}_{\rm M} & \hspace{-2mm} = \hspace{-2mm} & \cos {\phi_{}}_{\rm M} \cos {\phi_{}}_{\rm M},
616      \nonumber \\
617      {b_{}}_{\rm P} & \hspace{-2mm} = \hspace{-2mm} & \cos {\phi_{}}_{\rm P} \cos {\phi_{}}_{\rm P},
618      \nonumber \\
619      {c_{}}_{\rm M} & \hspace{-2mm} = \hspace{-2mm} & \cos {\phi_{}}_{\rm M} \sin {\phi_{}}_{\rm M},
620      \nonumber \\
621      {c_{}}_{\rm P} & \hspace{-2mm} = \hspace{-2mm} & \cos {\phi_{}}_{\rm P} \sin {\phi_{}}_{\rm P}.
622      \nonumber
623   \nonumber
624  \end{eqnarray}
625
626\item[2.] {\bf Great-Circle distance-weighted interpolation with small angle
627  approximation.} Similar to the previous interpolation but with the
628  distance $s$ computed as
629  \begin{eqnarray}
630    s\left( {\rm P}, {\rm M} \right)
631     & \hspace{-2mm} = \hspace{-2mm} & 
632      \sqrt{ \left( {\phi_{}}_{\rm M} - {\phi_{}}_{\rm P} \right)^{2} 
633      + \left( {\lambda_{}}_{\rm M} - {\lambda_{}}_{\rm P} \right)^{2}
634        \cos^{2} {\phi_{}}_{\rm M} }
635  \end{eqnarray}
636  where $M$ corresponds to $A$, $B$, $C$ or $D$.
637
638\item[3.] {\bf Bilinear interpolation for a regular spaced grid.} The
639  interpolation is split into two 1D interpolations in the longitude
640  and latitude directions, respectively.
641
642\item[4.] {\bf Bilinear remapping interpolation for a general grid.} An
643  iterative scheme that involves first mapping a quadrilateral cell
644  into a cell with coordinates (0,0), (1,0), (0,1) and (1,1). This
645  method is based on the SCRIP interpolation package \citep{Jones_1998}.
646 
647\end{enumerate}
648
649\subsection{Grid search}
650
651For many grids used by the NEMO model, such as the ORCA family,
652the horizontal grid coordinates $i$ and $j$ are not simple functions
653of latitude and longitude. Therefore, it is not always straightforward
654to determine the grid points surrounding any given observational position.
655Before the interpolation can be performed, a search
656algorithm is then required to determine the corner points of
657the quadrilateral cell in which the observation is located.
658This is the most difficult and time consuming part of the
6592D interpolation procedure.
660A robust test for determining if an observation falls
661within a given quadrilateral cell is as follows. Let
662${\rm P}({\lambda_{}}_{\rm P} ,{\phi_{}}_{\rm P} )$ denote the observation point,
663and let ${\rm A}({\lambda_{}}_{\rm A} ,{\phi_{}}_{\rm A} )$,
664${\rm B}({\lambda_{}}_{\rm B} ,{\phi_{}}_{\rm B} )$,
665${\rm C}({\lambda_{}}_{\rm C} ,{\phi_{}}_{\rm C} )$ 
666and
667${\rm D}({\lambda_{}}_{\rm D} ,{\phi_{}}_{\rm D} )$ denote
668the bottom left, bottom right, top left and top right
669corner points of the cell, respectively.
670To determine if P is inside
671the cell, we verify that the cross-products
672\begin{eqnarray}
673\begin{array}{lllll}
674{{\bf r}_{}}_{\rm PA} \times {{\bf r}_{}}_{\rm PC}
675& = & [({\lambda_{}}_{\rm A}\; -\; {\lambda_{}}_{\rm P} )
676      ({\phi_{}}_{\rm C}   \; -\; {\phi_{}}_{\rm P} )
677    - ({\lambda_{}}_{\rm C}\; -\; {\lambda_{}}_{\rm P} )
678      ({\phi_{}}_{\rm A}   \; -\; {\phi_{}}_{\rm P} )] \; \widehat{\bf k} \\
679{{\bf r}_{}}_{\rm PB} \times {{\bf r}_{}}_{\rm PA}
680& = & [({\lambda_{}}_{\rm B}\; -\; {\lambda_{}}_{\rm P} )
681      ({\phi_{}}_{\rm A}   \; -\; {\phi_{}}_{\rm P} )
682    - ({\lambda_{}}_{\rm A}\; -\; {\lambda_{}}_{\rm P} )
683      ({\phi_{}}_{\rm B}   \; -\; {\phi_{}}_{\rm P} )] \; \widehat{\bf k} \\
684{{\bf r}_{}}_{\rm PC} \times {{\bf r}_{}}_{\rm PD}
685& = & [({\lambda_{}}_{\rm C}\; -\; {\lambda_{}}_{\rm P} )
686      ({\phi_{}}_{\rm D}   \; -\; {\phi_{}}_{\rm P} )
687    - ({\lambda_{}}_{\rm D}\; -\; {\lambda_{}}_{\rm P} )
688      ({\phi_{}}_{\rm C}   \; -\; {\phi_{}}_{\rm P} )] \; \widehat{\bf k} \\
689{{\bf r}_{}}_{\rm PD} \times {{\bf r}_{}}_{\rm PB}
690& = & [({\lambda_{}}_{\rm D}\; -\; {\lambda_{}}_{\rm P} )
691      ({\phi_{}}_{\rm B}   \; -\; {\phi_{}}_{\rm P} )
692    - ({\lambda_{}}_{\rm B}\; -\; {\lambda_{}}_{\rm P} )
693      ({\phi_{}}_{\rm D}  \;  - \; {\phi_{}}_{\rm P} )] \; \widehat{\bf k} \\
694\end{array}
695\label{eq:cross}
696\end{eqnarray}
697point in the opposite direction to the unit normal
698$\widehat{\bf k}$ (i.e., that the coefficients of
699$\widehat{\bf k}$ are negative),
700where ${{\bf r}_{}}_{\rm PA}$, ${{\bf r}_{}}_{\rm PB}$,
701etc. correspond to the vectors between points P and A,
702P and B, etc.. The method used is
703similar to the method used in
704the SCRIP interpolation package \citep{Jones_1998}.
705
706In order to speed up the grid search, there is the possibility to construct
707a lookup table for a user specified resolution. This lookup
708table contains the lower and upper bounds on the $i$ and $j$ indices
709to be searched for on a regular grid. For each observation position,
710the closest point on the regular grid of this position is computed and
711the $i$ and $j$ ranges of this point searched to determine the precise
712four points surrounding the observation.
713
714\subsection{Parallel aspects of horizontal interpolation}
715
716For horizontal interpolation, there is the basic problem that the
717observations are unevenly distributed on the globe. In numerical
718models, it is common to divide the model grid into subgrids (or
719domains) where each subgrid is executed on a single processing element
720with explicit message passing for exchange of information along the
721domain boundaries when running on a massively parallel processor (MPP)
722system. This approach is used by \NEMO.
723
724For observations there is no natural distribution since the
725observations are not equally distributed on the globe.
726Two options have been made available: 1) geographical distribution;
727and 2) round-robin.
728
729\subsubsection{Geographical distribution of observations among processors}
730
731%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
732\begin{figure}      \begin{center}
733\includegraphics[width=10cm,height=12cm,angle=-90.]{./TexFiles/Figures/Fig_ASM_obsdist_local}
734\caption{      \label{fig:obslocal}
735Example of the distribution of observations with the geographical distribution of observational data.} 
736\end{center}      \end{figure}
737%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
738
739This is the simplest option in which the observations are distributed according
740to the domain of the grid-point parallelization. Figure~\ref{fig:obslocal}
741shows an example of the distribution of the {\em in situ} data on processors
742with a different colour for each observation
743on a given processor for a 4 $\times$ 2 decomposition with ORCA2.
744The grid-point domain decomposition is clearly visible on the plot.
745
746The advantage of this approach is that all
747information needed for horizontal interpolation is available without
748any MPP communication. Of course, this is under the assumption that
749we are only using a $2 \times 2$ grid-point stencil for the interpolation
750(e.g., bilinear interpolation). For higher order interpolation schemes this
751is no longer valid. A disadvantage with the above scheme is that the number of
752observations on each processor can be very different. If the cost of
753the actual interpolation is expensive relative to the communication of
754data needed for interpolation, this could lead to load imbalance.
755
756\subsubsection{Round-robin distribution of observations among processors}
757
758%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
759\begin{figure}     \begin{center}
760\includegraphics[width=10cm,height=12cm,angle=-90.]{./TexFiles/Figures/Fig_ASM_obsdist_global}
761\caption{      \label{fig:obsglobal}
762Example of the distribution of observations with the round-robin distribution of observational data.}
763\end{center}     \end{figure}
764%>>>>>>>>>>>>>>>>>>>>>>>>>>>>
765
766An alternative approach is to distribute the observations equally
767among processors and use message passing in order to retrieve
768the stencil for interpolation. The simplest distribution of the observations
769is to distribute them using a round-robin scheme. Figure~\ref{fig:obsglobal}
770shows the distribution of the {\em in situ} data on processors for the
771round-robin distribution of observations with a different colour for
772each observation on a given processor for a 4 $\times$ 2 decomposition
773with ORCA2 for the same input data as in Fig.~\ref{fig:obslocal}.
774The observations are now clearly randomly distributed on the globe.
775In order to be able to perform horizontal interpolation in this case,
776a subroutine has been developed that retrieves any grid points in the
777global space.
778
779\subsection{Vertical interpolation operator}
780
781The vertical interpolation is achieved using either a cubic spline or
782linear interpolation. For the cubic spline, the top and
783bottom boundary conditions for the second derivative of the
784interpolating polynomial in the spline are set to zero.
785At the bottom boundary, this is done using the land-ocean mask.
Note: See TracBrowser for help on using the repository browser.