Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/bin/ooo
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/bin/ooo	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/bin/ooo	(revision 4245)
@@ -0,0 +1,4 @@
+#!/usr/bin/env python2.7
+import ooo
+if __name__ == '__main__':
+    ooo.main()
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/Makefile
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/Makefile	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/Makefile	(revision 4245)
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Offlineobservationoperator.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Offlineobservationoperator.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/Offlineobservationoperator"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Offlineobservationoperator"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/make.bat
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/make.bat	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/make.bat	(revision 4245)
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
+set I18NSPHINXOPTS=%SPHINXOPTS% source
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+	set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^<target^>` where ^<target^> is one of
+	echo.  html       to make standalone HTML files
+	echo.  dirhtml    to make HTML files named index.html in directories
+	echo.  singlehtml to make a single large HTML file
+	echo.  pickle     to make pickle files
+	echo.  json       to make JSON files
+	echo.  htmlhelp   to make HTML files and a HTML help project
+	echo.  qthelp     to make HTML files and a qthelp project
+	echo.  devhelp    to make HTML files and a Devhelp project
+	echo.  epub       to make an epub
+	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  texinfo    to make Texinfo files
+	echo.  gettext    to make PO message catalogs
+	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  linkcheck  to check all external links for integrity
+	echo.  doctest    to run all doctests embedded in the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Offlineobservationoperator.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Offlineobservationoperator.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "texinfo" (
+	%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+	goto end
+)
+
+if "%1" == "gettext" (
+	%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+:end
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/source/conf.py
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/source/conf.py	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/source/conf.py	(revision 4245)
@@ -0,0 +1,246 @@
+# -*- coding: utf-8 -*-
+#
+# Offline observation operator documentation build configuration file, created by
+# sphinx-quickstart on Mon Oct  7 17:21:35 2013.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('../..'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Offline observation operator'
+copyright = u'2013, Andrew Ryan'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.1'
+# The full version, including alpha/beta/rc tags.
+release = '0.1.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Offlineobservationoperatordoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'Offlineobservationoperator.tex', u'Offline observation operator Documentation',
+   u'Andrew Ryan', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'offlineobservationoperator', u'Offline observation operator Documentation',
+     [u'Andrew Ryan'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'Offlineobservationoperator', u'Offline observation operator Documentation',
+   u'Andrew Ryan', 'Offlineobservationoperator', 'One line description of project.',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'http://docs.python.org/': None}
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/source/index.rst
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/source/index.rst	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/source/index.rst	(revision 4245)
@@ -0,0 +1,23 @@
+.. Offline observation operator documentation master file, created by
+   sphinx-quickstart on Mon Oct  7 17:21:35 2013.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to Offline observation operator's documentation!
+========================================================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   intro
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/source/intro.rst
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/source/intro.rst	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/doc/source/intro.rst	(revision 4245)
@@ -0,0 +1,57 @@
+
+Introduction
+------------
+
+The offline observation operator quick start script involves simple
+computation and manipulation of NEMO namelists.
+
+Quick start script
+------------------
+
+.. code-block:: none
+
+   ooo -h
+   usage: ooo [-h] [-w WORK_DIR] [-f FORECAST_TYPES] [-l LEAD_TIMES]
+              [-o OBS_TYPES] [--class4]
+              DATE NAMELIST
+   
+   positional arguments:
+     DATE                  Run date.
+     NAMELIST              NEMO namelist to edit.
+   
+   optional arguments:
+     -h, --help            show this help message and exit
+     -w WORK_DIR, --work-dir WORK_DIR
+     -f FORECAST_TYPES, --forecast-types FORECAST_TYPES
+                           Choice of forecast,persistence,climatology
+     -l LEAD_TIMES, --lead-times LEAD_TIMES
+                           Forecast lead times
+     -o OBS_TYPES, --obs-types OBS_TYPES
+                           Choice of namobs types.
+     --class4              Flag to choose class 4 file outputs
+     --dry-run             Flag to test namelist building without submitting.
+     --cmd COMMAND         Submit task to run.
+     -v, --verbose         Prints difference between before and after namelists.
+
+
+The above command line utility ``ooo`` can be used to edit **NEMO** namelists. 
+
+Run
+---
+
+.. automodule:: ooo.run
+   :members:
+
+
+Locators
+--------
+
+.. automodule:: ooo.locator
+   :members:
+
+Fortran
+-------
+
+.. automodule:: ooo.nml
+   :members:
+
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/__init__.py
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/__init__.py	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/__init__.py	(revision 4245)
@@ -0,0 +1,3 @@
+import nml
+import locator
+from ooo import main
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/locator.py
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/locator.py	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/locator.py	(revision 4245)
@@ -0,0 +1,151 @@
+"""Locates input files and calculates namelist attributes
+
+    Typically a user will have files distributed throughout the hard drive
+    and it makes little or no sense to try to capture all use cases.
+
+    >>> date = "20130101"
+    >>> namobs = observations(date, types=["profbfiles"])
+
+    >>> namooo, namcl4 = forecasts(date, types=["forecast", "persistence"], lead_times=[12, 36, 60])
+"""
+
+def observations(date, types=None):
+    """Responsible for locating observation files
+
+    Valid **namobs** observation types.
+
+    * profbfiles
+    * sstfbfiles
+    * slafbfiles
+
+    :param date: The verification date in string format ``'%Y%m%d'``
+    :param types: A list of namobs observation types
+
+    :returns: namobs namelist dictionary
+    """
+    namobs = {"ln_t3d": False,
+              "ln_s3d": False,
+              "ln_ena": False,
+              "ln_profb": False,
+              "ln_sst": False,
+              "ln_sstfb": False,
+              "ln_reysst": False,
+              "ln_ghrsst": False,
+              "ln_sla": False,
+              "ln_slafb": False,
+              "ln_sladt": False}
+    if types is None: types = []
+    for obtype in types: 
+        if obtype == "profbfiles":
+            namobs[obtype] = profbfiles(date)
+            namobs["ln_t3d"] = True
+            namobs["ln_s3d"] = True
+            namobs["ln_profb"] = True
+        elif obtype == "sstfbfiles":
+            namobs[obtype] = sstfbfiles(date)
+            namobs["ln_sst"] = True
+            namobs["ln_sstfb"] = True
+        elif obtype == "slafbfiles":
+            namobs[obtype] = slafbfiles(date)
+            namobs["ln_sla"] = True
+            namobs["ln_slafb"] = True
+    return namobs
+
+def profbfiles(date):
+    """Observation file locator stub
+
+    .. note:: User-specified stub
+
+    :param date: The verification date in string format ``'%Y%m%d'``
+    :returns: List of files
+    """
+    files = ['profb.nc']
+    return files
+
+def sstfbfiles(date):
+    """Observation file locator stub
+
+    .. note:: User-specified stub
+
+    :param date: The verification date in string format ``'%Y%m%d'``
+    :returns: List of files
+    """
+    files = ['sstfb.nc']
+    return files
+
+def slafbfiles(date):
+    """Observation file locator stub
+
+    .. note:: User-specified stub
+
+    :param date: The verification date in string format ``'%Y%m%d'``
+    :returns: List of files
+    """
+    files = ['slafb.nc']
+    return files
+
+def forecasts(date, types=None, lead_times=None):
+    """Responsible for locating forecast fields
+
+    :param date: The verification date in string format ``'%Y%m%d'``
+    :param types: A list of forecast system types
+    :param lead_times: A list of lead_times to search for
+
+    :returns: tuple of namelist data, (namooo, namcl4)
+    """
+    namooo = {}
+    namcl4 = {}
+    if types is None: types = []
+    if lead_times is None: lead_times = []
+
+    # Initialise data
+    ooo_files = []
+    nn_ooo_idx = []
+    cl4_vars = []
+    cl4_fcst_idx = []
+
+    # Search for files
+    for type in types:
+        files = []
+        in_indices = []
+        out_indices = []
+        for ilt, lead_time in enumerate(lead_times):
+            file, index = field(date, type=type, lead_time=lead_time)
+            files.append(file)
+            in_indices.append(index)
+            out_indices.append(ilt + 1)
+        # Expand return lists
+        ooo_files += files
+        nn_ooo_idx += in_indices
+        cl4_fcst_idx += out_indices
+        cl4_vars += len(files) * [type]
+
+    # Namoo
+    namooo["ooo_files"] = ooo_files
+    namooo["nn_ooo_idx"] = nn_ooo_idx
+
+    # Namcl4
+    namcl4["cl4_vars"] = cl4_vars
+    namcl4["cl4_fcst_idx"] = cl4_fcst_idx
+
+    return namooo, namcl4
+
+def field(date, type=None, lead_time=None):
+    """Forecast field locator
+
+    Maps verification date and lead time off set to file name and
+    index along file *time_counter*
+
+    .. note:: User-specified stub
+
+    :param date: The verification date in string format ``'%Y%m%d'``
+    :param type: Forecast type
+    :param lead_time: Forecast off set
+
+    :returns: (**path**, **index**)
+    """
+    # Worker function
+    file = 'nofile'
+    index = -1
+    return file, index
+
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/nml.py
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/nml.py	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/nml.py	(revision 4245)
@@ -0,0 +1,479 @@
+"""Collection of Fortran 90 namelist helper functions.
+
+    A common way to interface with a Fortran executable is via
+    an input file called a namelist. This module defines
+    functions which simplify the process of updating and
+    extending namelist data.
+
+    .. note:: This module is especially lightweight and follows the
+              batteries included philosophy. As such, only standard
+              library modules are required to use this code.
+
+    Walkthrough
+    ===========
+
+    New namelist
+    ------------
+
+    A typical usage is to create and update a Fortran namelist on the fly.
+
+    >>> import nml
+    >>> namid = "namfoo"
+    >>> text = nml.new(namid)
+    >>> data = {"x": nml.tostring([1, 2, 3])}
+    >>> text = nml.update(namid, text, data)
+    >>> print text
+    &namfoo
+       x = 1 2 3
+    /
+    <BLANKLINE>
+
+    In the above snippet :func:`tostring` has been used to sanitize the input
+    Python list. This function cleverly maps string data and numeric data to
+    the correct Fortran syntax.
+
+    However, the :func:`new` function takes care of many of the above steps automatically.
+    Where appropriate :func:`sanitize` has been embedded to reduce the need
+    to worry about data format problems. Take for example,
+
+    >>> print nml.new("namfoo", data={"x": range(3)})
+    &namfoo
+       x = 0 1 2
+    /
+    <BLANKLINE>
+
+    Parse existing namelist
+    -----------------------
+
+    In order to update a namelist it is necessary to convert the namelist text into
+    a dictionary of *key, value* pairs which can be manipulated in the usual Pythonic
+    fashion before being piped back out to disk.
+
+    In everyday usage text will be read from files, here however for illustration
+    purposes I have hand written a namelist.
+
+    >>> text = '''
+    ... &namfoo
+    ...     x = y  ! A description of the variables
+    ... /
+    ... &nambar
+    ...     ln_on = .TRUE. ! A description of the variables
+    ... /
+    ... '''
+
+    This can be parsed by invoking the :func:`variables` command.
+
+    >>> nml.variables(text)
+    {'x': 'y', 'ln_on': '.TRUE.'}
+
+    Or by using the :func:`namelists` function to split the file into sub-lists.
+
+    >>> nml.namelists(text)
+    {'namfoo': '&namfoo\\n    x = y  ! A description of the variables\\n/', 'nambar': '&nambar\\n    ln_on = .TRUE. ! A description of the variables\\n/'}
+    >>> sublists = nml.namelists(text)
+    >>> print sublists["nambar"]
+    &nambar
+        ln_on = .TRUE. ! A description of the variables
+    /
+
+    Which can be parsed into a dictionary as before.
+
+    >>> print nml.variables(sublists["nambar"])
+    {'ln_on': '.TRUE.'}
+
+
+    Update/replace data
+    -------------------
+
+    There are two ways of modifying values inside a Fortran namelist. 
+
+    Replace
+        The first is to simply replace a set of variables with new values. This behaviour is accomplished
+        via the :func:`replace` function. This approach simply overwrites existing variables. No knowledge
+        of sub-namelist structure is required to modify a string of text. 
+
+    .. note:: Additional variables will not be added to a namelist via this approach
+
+    Update
+        The second is to extend the set of variables contained within a namelist. This functionality is
+        controlled by the :func:`update` function. Here, variables which are not already specified are
+        added using a templated namelist line.
+
+    .. note:: It is essential to specify which sub-namelist is to be updated before modification takes place
+
+    Pipe to/from file
+    -----------------
+
+    As typical NEMO namelists are no larger than a few tens of kilobytes
+    it makes sense to process namelists as single strings instead of
+    line by line.
+
+    >>> path = "foo.nml"
+    >>> text = nml.new("namfoo")
+
+    To write to a file simply invoke the writer.
+
+    >>> # Write to file
+    >>> nml.writer(path, text)
+
+    To read from a file specify the path to be read.
+
+    >>> # Read from file
+    >>> text = nml.reader(path)
+
+    Join multiple namelists
+    -----------------------
+
+    Since the namelists are regular Python strings there is no need for a 
+    specific *join* function. Namelists can be combined in whatever manner
+    is most pleasing to the eye.
+
+    >>> namoff = nml.new("namoff")
+    >>> namcl4 = nml.new("namcl4")
+    >>> # new line join
+    >>> print "\\n".join([namoff, namcl4])
+    &namoff
+    /
+    <BLANKLINE>
+    &namcl4
+    /
+    <BLANKLINE>
+
+    >>> # Or addition
+    >>> print namoff + namcl4
+    &namoff
+    /
+    &namcl4
+    /
+    <BLANKLINE>
+
+    Module functions
+    ================
+
+"""
+__version__ = "0.1.0"
+import re
+from numbers import Number
+
+def reader(path):
+    """Reads a file into a string
+
+    Reads whole file into single string. Typically, 
+    namelists are small enough to be stored in memory
+    while updates and edits are being performed.
+
+    :param path: Path to input file
+    :returns: entire file as a single string
+
+    """
+    with open(path, "r") as handle:
+        text = handle.read()
+    return text
+
+def writer(path, text):
+    """Writes to a file from a string
+
+    Handy way of piping a processed namelist into
+    a file.
+
+    :param path: Path to output file
+    :param text: Input text to process
+
+    """
+    with open(path, "w") as handle:
+        handle.write(text)
+
+def update(namid, text, data, convert=True):
+    """Extends namelist definition.
+
+    Similar to replace this function alters the values
+    of variables defined within a namelist. In addition to
+    replacing values it also creates definitions if the
+    variable is not found in the namelist. As such, the
+    namelist id must be specified.
+
+    :param namid: Namelist id
+    :param text: Input text to process
+    :param data: Dictionary of variables
+    :keyword convert: Sanitizes input data before replacement takes place
+
+    :returns: Text
+
+    .. seealso:: :func:`replace` :func:`sanitize`
+    """
+    sublists = namelists(text)
+    assert namid in sublists, "Warning: invalid namid specified!"
+
+    # Sanitize inputs
+    if convert:
+        data = sanitize(data)
+
+    # Parse subsection
+    namtext = sublists[namid]
+    subdata = variables(namtext)
+    subvars = subdata.keys()
+
+    # Replace existing variables in namtext
+    tmptext = replace(namtext, data)
+    text = text.replace(namtext, tmptext)
+    namtext = tmptext
+
+    # Identify new variables
+    vars = data.keys()
+    newvars = list(set(vars) - set(subvars))
+    newvars.sort()
+
+    # Append new vars to namid
+    lines = namtext.split("\n")
+    for v in newvars:
+        newline = "   %s = %s" % (v, data[v])
+        lines.insert(-1, newline)
+    newtext = "\n".join(lines)
+
+    # Replace old namtext with new namtext
+    text = text.replace(namtext, newtext)
+    return text
+
+def replace(text, data, convert=True):
+    """Edits existing variables.
+
+    Pattern matches and substitutes variables inside
+    a string of text. This is independent of namid and
+    as such is useful for modifying existing variables.
+    To append new variables the :func:`update` function 
+    is required.
+
+    >>> text = '''
+    ... &namobs
+    ...    ln_sst = .TRUE. ! Logical switch for SST observations
+    ... /
+    ... '''
+    >>> data = {"ln_sst": ".FALSE."}
+    >>> print replace(text, data)
+    <BLANKLINE>
+    &namobs
+       ln_sst = .FALSE. ! Logical switch for SST observations
+    /
+    <BLANKLINE>
+
+    .. note :: This does not append new variables to a namelist
+
+    :param text: string to process
+    :param data: dictionary with which to modify **text**
+    :keyword convert: Sanitizes input data before replacement takes place
+
+    :returns: string with new data values
+
+    .. seealso:: :func:`update`, :func:`sanitize`
+    """
+    if convert:
+        data = sanitize(data)
+    for k, v in data.iteritems():
+        pat = r"(%s\s*=\s*).+?(\s*[!\n])" % (k,)
+        repl = r"\g<1>%s\g<2>" % (v,)
+        text = re.sub(pat, repl, text)
+    return text
+
+def variables(text):
+    """Retrieves dictionary of variables in text.
+
+    >>> text = '''
+    ... &namobs
+    ...    ln_sst = .TRUE. ! Logical switch for SST observations
+    ... /
+    ... '''
+    >>> variables(text)
+    {'ln_sst': '.TRUE.'}
+
+    :param text: Input text to process
+
+    :returns: A dictionary of variable, value pairs.
+
+    """
+    data = {}
+    pairs = re.findall(r"\n\s*(\w+)\s*=\s*(.+?)\s*(?=[!\n])", text)
+    for key, value in pairs:
+        data[key] = value
+    return data
+
+def namelists(text):
+    """Retrieves dictionary of namelists in text.
+
+    Useful for isolating sub-namelists.
+
+    >>> text = '''
+    ... &namobs
+    ...    ln_sst = .TRUE. ! Logical switch for SST observations
+    ... /
+    ... '''
+    >>> namelists(text)
+    {'namobs': '&namobs\\n   ln_sst = .TRUE. ! Logical switch for SST observations\\n/'}
+
+    :param text: Input text to process
+
+    :returns: A dictionary of id, text block key, value pairs
+
+    """
+    # Boundary case
+    if text.startswith("&"):
+        text = "\n" + text
+    # Regular expression
+    results = re.findall(r"\n(&(\w+).*?\n/)", text, re.DOTALL)
+    data = {}
+    for content, namid in results:
+        data[namid] = content
+    return data
+
+def tostring(data):
+    """Maps standard Python data to Fortran namelist format.
+
+    >>> tostring([1, 2, 3])
+    '1 2 3'
+    >>> tostring(["foo.nc", "bar.nc"])
+    "'foo.nc', 'bar.nc'"
+    >>> tostring(True)
+    '.TRUE.'
+
+    :param data: Input Python data
+
+    :returns: Namelist formatted string
+
+    .. seealso:: :func:`sanitize`
+    """
+    if isinstance(data, list):
+        if all_numeric(data):
+            delim = " "
+        else:
+            delim = ", "
+        text = delim.join([convert(item) for item in data])
+    else:
+        text = convert(data)
+    return text
+
+def all_numeric(inputs):
+    # Checks all list entries are numbers
+    flag = True
+    for input in inputs:
+        if not isinstance(input, Number):
+            flag = False
+            break
+    return flag
+
+def numeric(word):
+    # Tests input string is numeric data
+    parts = word.split(" ")
+    try:
+        map(float, parts)
+        flag = True
+    except ValueError:
+        flag = False
+    return flag
+
+def logical(word):
+    # Tests input string is numeric data
+    if word.upper() in [".FALSE.", ".TRUE."]:
+        flag = True
+    else:
+        flag = False
+    return flag
+
+def listed(word):
+    # Tests input string is not a list
+    if ("," in word) or (" " in word):
+        flag = True
+    else:
+        flag = False
+    return flag
+
+def quote(word):
+    word = str(word)
+    if not quoted(word):
+        word = "'%s'" % (word,)
+    return word
+
+def convert(word):
+    # Conversion function
+    if isinstance(word, str):
+        if (quoted(word) or numeric(word) 
+            or logical(word) or listed(word)):
+            result = "%s" % (word,)
+        else:
+            result = quote(word)
+    elif isinstance(word, bool):
+        if word:
+            result = ".TRUE."
+        else:
+            result = ".FALSE."
+    else:
+        result = str(word)
+    return result
+
+def quoted(word):
+    # Checks if string begins/ends with quotation marks
+    if (word.startswith("'") and word.endswith("'")):
+        flag = True
+    elif (word.startswith('"') and word.endswith('"')):
+        flag = True
+    else: 
+        flag = False
+    return flag
+
+def same_type(data):
+    # True if all entries are the same type
+    types = map(type, data)
+    if len(set(types)) == 1:
+        flag = True
+    else:
+        flag = False
+    return flag
+
+def sanitize(data):
+    """Converts dictionary values into Fortran namelist format.
+
+    This is a more typical way to prepare data for inclusion in
+    a Fortran namelist. Instead of manually applying :func:`tostring`
+    to every element of the input data, **sanitize** fixes the entire
+    data set.
+
+    >>> sanitize({"x": True})
+    {'x': '.TRUE.'}
+    >>> 
+
+    :param data: Dictionary to convert
+
+    :returns: Dictionary whose values are in Fortran namelist format
+
+    .. seealso:: :func:`tostring`
+    """
+    replacements = [(k, tostring(v)) for k, v in data.items()]
+    data.update(replacements)
+    return data
+
+def new(namid, data=None, convert=True):
+    """Creates a new Fortran namelist
+
+    >>> new("namobs")
+    '&namobs\\n/\\n'
+    >>> print new("namobs")
+    &namobs
+    /
+    <BLANKLINE>
+
+    :param namid: Name for the new namelist
+
+    :keyword data: Specifies an initial dictionary with which to
+                   populate the namelist
+    :type data: dict
+    :keyword convert: Sanitizes input data before replacement takes place
+
+    :returns: string representation of a Fortran namelist
+    """
+    text = "&{namid}\n/\n".format(namid=namid)
+    if data is not None:
+        text = update(namid, text, data, convert=convert)
+    return text
+
+if __name__ == '__main__':
+    import doctest
+    doctest.testmod()
+
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/ooo.py
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/ooo.py	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/ooo.py	(revision 4245)
@@ -0,0 +1,124 @@
+#!/usr/bin/env python2.7
+
+import os
+import shutil
+
+# Local imports
+import locator
+import nml
+import run
+
+def parse_args():
+    import argparse
+    parser = argparse.ArgumentParser()
+    parser.add_argument("date", metavar="DATE", 
+                        help="Run date.")
+    parser.add_argument("-w", "--work-dir", default=os.getcwd())
+    parser.add_argument("-f", "--forecast-types", default="forecast",
+                        help="Choice of forecast,persistence,climatology")
+    parser.add_argument("-l", "--lead-times", default="12",
+                        help="Forecast lead times")
+    parser.add_argument("-o", "--obs-types", default="profbfiles",
+                        help="Choice of namobs types.")
+    parser.add_argument("--class4", dest="ln_cl4", action="store_true",
+                        help="Flag to choose class 4 file outputs")
+    parser.add_argument("--dry-run", action="store_true",
+                        help="Flag to test namelist building without submitting.")
+    parser.add_argument("--cmd", dest="command", default="./opa",
+                        help="Submit task to run.")
+    parser.add_argument("-v", "--verbose", action="store_true",
+                        help="Prints difference between before and after namelists.")
+    parser.add_argument("namelist", metavar="NAMELIST", 
+                        help="NEMO namelist to edit.")
+    args = parser.parse_args()
+    args.forecast_types = args.forecast_types.split(',')
+    args.obs_types = args.obs_types.split(',')
+    args.lead_times = map(int, args.lead_times.split(','))
+    return args
+
+def printdiff(text1, text2):
+    # Provides nice text difference summary of namelists
+    import difflib
+    lines1 = text1.splitlines()
+    lines2 = text2.splitlines()
+    d = difflib.Differ()
+    result = list(d.compare(lines1, lines2))
+    text = '\n'.join(result)
+    print text
+
+def main():
+    args = parse_args()
+    date = args.date
+    print "Processing", args.namelist, " for", args.date
+    
+    # Move to working directory
+    if not os.path.exists(args.work_dir):
+        os.makedirs(args.work_dir)
+    os.chdir(args.work_dir)
+
+    # Collect forecast files
+    types = args.forecast_types
+    lead_times = args.lead_times
+    namooo, namcl4 = locator.forecasts(date=date,
+                                       types=types,
+                                       lead_times=lead_times)
+
+    # Process NEMO namelist
+    text = nml.reader(args.namelist)
+    sublists = nml.namelists(text)
+
+    # Verbose save original text
+    if args.verbose:
+        original_text = text
+
+    # namooo
+    if "namooo" not in sublists:
+        # Attach boilerplate
+        text += nml.new("namooo")
+    text = nml.update("namooo", text, data=namooo)
+
+    # namcl4
+    if "namcl4" not in sublists:
+        # Attach boilerplate
+        text += nml.new("namcl4")
+    namcl4["cl4_leadtime"] = lead_times
+    namcl4["cl4_date"] = nml.quote(date)
+    namcl4["cl4_match_len"] = len(namcl4["cl4_vars"])
+    namcl4["cl4_fcst_len"] = len(namcl4["cl4_leadtime"])
+    # Add naming convention
+    namcl4["cl4_sys"] = "FOAM"
+    namcl4["cl4_cfg"] = "orca025"
+    namcl4["cl4_vn"] = "'1.0'"
+    namcl4["cl4_prefix"] = "class4"
+    namcl4["cl4_contact"] = "example@example.com"
+    namcl4["cl4_inst"] = "institute"
+    text = nml.update("namcl4", text, data=namcl4)
+
+    # namrun
+    namrun = {"nn_date0": nml.quote(date)}
+    text = nml.update("namrun", text, data=namrun)
+
+    # namobs
+    namobs = locator.observations(date=date,
+                                  types=args.obs_types)
+    namobs["ln_cl4"] = args.ln_cl4
+    text = nml.update("namobs", text, data=namobs)
+
+    # Verbose print namelist differences
+    if args.verbose:
+        printdiff(original_text, text)
+
+    # pipe text to file
+    tmp = args.namelist+".tmp"
+    nml.writer(tmp, text)
+    shutil.move(tmp, args.namelist)
+
+    # Run job
+    if not args.dry_run:
+        run.submit(command=args.command)
+    
+
+
+if __name__ == '__main__':
+    main()
+
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/run.py
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/run.py	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/run.py	(revision 4245)
@@ -0,0 +1,27 @@
+"""
+
+The NEMO offline observation operator is built and runs similarly to the
+online NEMO model.
+ 
+"""
+import subprocess
+import shlex
+import os
+
+class SubmitError(Exception):
+    pass
+
+def submit(command="./opa"):
+    """Simple function that runs the code.
+
+    This can be customised based on the particular environment
+    used to submit MPI or serial tasks. For simplicity, this
+    function calls opa.
+
+    By default, this program runs ``./opa``.
+
+    :returns: retcode
+    """
+    retcode = subprocess.call(shlex.split(command))
+    return retcode
+
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/test_nml.py
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/test_nml.py	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/ooo/test_nml.py	(revision 4245)
@@ -0,0 +1,248 @@
+#!/usr/bin/env python2.7
+import unittest
+import nml
+
+def version(vn):
+    # Converts module version string to int tuple as PEP-440
+    return tuple(map(int, vn.split(".")))
+
+HEADER = """
+!! =====================================
+!! An example FORTRAN 90 namelist
+!! =====================================
+&namex
+"""
+NOHEADER = "&namex\n"
+LOGIC = " ln_test = .TRUE. ! Comment\n"
+NUMERIC = " nn_off_idx = 1 2 3\n"
+NOSPACE = " nn_off_idx=1 2 3\n"
+NEGATIVE = " nn_off_idx = -1 -2 -3\n"
+LIST = " off_files = 'a.nc' 'b.nc' 'c.nc' ! Comment\n"
+STRING = ' contact = "example@nowhere.com" ! Comment\n'
+COMMENT = ' ! x = y '
+FOOTER = "/\n"
+NOFOOTER = "/"
+
+class TestNamelist(unittest.TestCase):
+    def setUp(self):
+        self.logic_text = "\n".join([HEADER, LOGIC, FOOTER])
+        self.numeric_text = "\n".join([HEADER, NUMERIC, FOOTER])
+        self.nospace_text = "\n".join([HEADER, NOSPACE, FOOTER])
+        self.neg_numeric_text = "\n".join([HEADER, NEGATIVE, FOOTER])
+        self.list_text = "\n".join([HEADER, LIST, FOOTER])
+        self.mix_text = "\n".join([HEADER, LIST, NUMERIC, FOOTER])
+        self.string_text = "\n".join([HEADER, STRING, FOOTER])
+        self.comment_text = "\n".join([HEADER, COMMENT, FOOTER])
+        self.no_trail_text = "\n".join([HEADER, NUMERIC, LIST, NOFOOTER])
+
+    def test_should_handle_footer(self):
+        data = nml.variables(self.no_trail_text)
+        truth = {"nn_off_idx": "1 2 3",
+                 "off_files": "'a.nc' 'b.nc' 'c.nc'"}
+        self.assertDictEqual(data, truth)
+
+    def test_mix_data(self):
+        data = nml.variables(self.mix_text)
+        truth = {"nn_off_idx": "1 2 3",
+                 "off_files": "'a.nc' 'b.nc' 'c.nc'"}
+        self.assertDictEqual(data, truth)
+
+    def test_comment_data(self):
+        data = nml.variables(self.comment_text)
+        truth = {}
+        self.assertDictEqual(data, truth)
+
+    def test_logical_data(self):
+        data = nml.variables(self.logic_text)
+        truth = {"ln_test": ".TRUE."}
+        self.assertDictEqual(data, truth)
+
+    def test_numeric_data(self):
+        data = nml.variables(self.numeric_text)
+        truth = {"nn_off_idx": "1 2 3"}
+        self.assertDictEqual(data, truth)
+
+    def test_nospace_data(self):
+        data = nml.variables(self.nospace_text)
+        truth = {"nn_off_idx": "1 2 3"}
+        self.assertDictEqual(data, truth)
+
+    def test_negative_numeric_data(self):
+        data = nml.variables(self.neg_numeric_text)
+        truth = {"nn_off_idx": "-1 -2 -3"}
+        self.assertDictEqual(data, truth)
+
+    def test_string_data(self):
+        data = nml.variables(self.string_text)
+        truth = {"contact": '"example@nowhere.com"'}
+        self.assertDictEqual(data, truth)
+
+    def test_list_data(self):
+        data = nml.variables(self.list_text)
+        truth = {"off_files": "'a.nc' 'b.nc' 'c.nc'"}
+        self.assertDictEqual(data, truth)
+
+    def test_replace_variable_comment(self):
+        FIXTURE = " x = 'y' ! comment \n"
+        RESULT = " x = 'z' ! comment \n"
+        text = nml.replace(FIXTURE, {"x": "z"})
+        self.assertEqual(text, RESULT)
+
+    def test_replace_variable_no_comment(self):
+        FIXTURE = " x = 'y' \n"
+        RESULT = " x = 'z' \n"
+        text = nml.replace(FIXTURE, {"x": "z"})
+        self.assertEqual(text, RESULT)
+
+    def test_replace_variable_no_space(self):
+        FIXTURE = " x='y' \n"
+        RESULT = " x='z' \n"
+        text = nml.replace(FIXTURE, {"x": "z"})
+        self.assertEqual(text, RESULT)
+
+    def test_replace_variable_no_space_comment(self):
+        FIXTURE = " x='y' ! comment \n"
+        RESULT = " x='z' ! comment \n"
+        text = nml.replace(FIXTURE, {"x": "z"})
+        self.assertEqual(text, RESULT)
+
+    @unittest.skipIf(version(nml.__version__) < (1, 0),
+                     "Not implemented in this version")
+    def test_multiline_variable_replace(self):
+        # As a result of a code review
+        FIXTURE = " x = 1, \n     2"
+        RESULT =  " x = 3, \n     4"
+        text = nml.replace(FIXTURE, {"x": [3,4]})
+        self.assertEqual(text, RESULT)
+
+class TestCombinedNamelists(unittest.TestCase):
+    def setUp(self):
+        self.minimal = """&namone
+/"""
+        self.blanks = """
+&namone
+/
+&namtwo
+/
+"""
+        self.contents = """
+&namone
+Content 1
+/
+&namtwo
+Content 2
+/
+"""
+        self.contents_slash = """
+&namone
+Content 1 ! Y/N
+/
+&namtwo
+Content 2
+/
+"""
+    def test_should_select_name_from_minimal_namelist(self):
+        data = nml.namelists(self.minimal)
+        result = {"namone": "&namone\n/"}
+        self.assertDictEqual(data, result)
+
+    def test_should_select_names(self):
+        data = nml.namelists(self.blanks)
+        result = {"namone": "&namone\n/",
+                  "namtwo": "&namtwo\n/"}
+        self.assertDictEqual(data, result)
+
+    def test_should_select_contents(self):
+        data = nml.namelists(self.contents)
+        result = {"namone": "&namone\nContent 1\n/",
+                  "namtwo": "&namtwo\nContent 2\n/"}
+        self.assertDictEqual(data, result)
+
+    def test_should_select_contents_with_forward_slash(self):
+        data = nml.namelists(self.contents_slash)
+        result = {"namone": "&namone\nContent 1 ! Y/N\n/",
+                  "namtwo": "&namtwo\nContent 2\n/"}
+        self.assertDictEqual(data, result)
+
+
+class TestToString(unittest.TestCase):
+    def setUp(self):
+        self.char_list = ["a.nc", "b.nc", "c.nc"]
+        self.num_list = [1, 3, 7]
+        self.char = "foo@bar.com"
+        self.num = 10
+        self.mixed_list = ["foo.nc", -1, True]
+        self.mixed_str_list = map(nml.quote, ["foo.nc", "-1", ".TRUE."])
+
+    def test_should_format_mixed_list(self):
+        data = nml.tostring(self.mixed_list)
+        result = "'foo.nc', -1, .TRUE."
+        self.assertEqual(data, result)
+
+    def test_should_format_numeric_list(self):
+        data = nml.tostring(self.num_list)
+        result = "1 3 7"
+        self.assertEqual(data, result)
+
+    def test_should_format_character_list(self):
+        data = nml.tostring(self.char_list)
+        result = "'a.nc', 'b.nc', 'c.nc'"
+        self.assertEqual(data, result)
+
+    def test_should_format_strings(self):
+        data = nml.tostring(self.char)
+        result = "'%s'" % (self.char,)
+        self.assertEqual(data, result)
+
+    def test_should_format_numbers(self):
+        data = nml.tostring(self.num)
+        result = str(self.num)
+        self.assertEqual(data, result)
+
+    def test_should_not_format_numeric_string(self):
+        input = "3.14159"
+        self.assertEqual(nml.tostring(input), input)
+
+    def test_should_format_logicals(self):
+        data = nml.tostring(True)
+        result = ".TRUE."
+        self.assertEqual(data.upper(), result)
+
+    def test_should_not_format_string_of_list_data(self):
+        for input in ["1 2 3", "1, 2, 3", ".TRUE. .FALSE."]:
+            case = nml.tostring(input)
+            self.assertEqual(case, input)
+
+    def test_should_treat_mixed_numeric_character_data_as_character(self):
+        case = nml.tostring(self.mixed_str_list)
+        result = "'foo.nc', '-1', '.TRUE.'"
+        self.assertEqual(case, result)
+
+class TestUpdateNamelist(unittest.TestCase):
+    def setUp(self):
+        self.empty = """
+&namone
+/
+"""
+        self.single = """
+&namone
+   x = 'y'
+/
+"""
+        self.single_update = """
+&namone
+   x = 'z'
+/
+"""
+
+    def test_should_append_new_variable_to_namelist(self):
+        trial = nml.update("namone", self.empty, {"x": "'y'"})
+        self.assertEqual(trial, self.single)
+
+    def test_should_update_existing_variables(self):
+        trial = nml.update("namone", self.single, {"x": "'z'"})
+        self.assertEqual(trial, self.single_update)
+
+if __name__ == '__main__':
+    unittest.main()
+
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/setup.py
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/setup.py	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/OOO/setup.py	(revision 4245)
@@ -0,0 +1,9 @@
+from distutils.core import setup
+setup(name='Offline observation operator',
+      version='0.1',
+      description='NEMO Offline observation operator',
+      author='Andrew Ryan',
+      author_email='andrew.ryan@metoffice.gov.uk',
+      packages=['ooo',],
+      scripts=['bin/ooo'],
+      )
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/src/c4comb.F90
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/src/c4comb.F90	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/src/c4comb.F90	(revision 4245)
@@ -0,0 +1,702 @@
+PROGRAM c4comb
+   !!---------------------------------------------------------------------
+   !!
+   !!                     ** PROGRAM c4comb **
+   !!
+   !!  ** Purpose : Combine MPI decomposed class4 files into one file
+   !!
+   !!  ** Method  : Use of utilities from obs_utils, ooo_utils.
+   !!
+   !!  ** Action  : 
+   !!
+   !!   Usage:
+   !!     c4comb.exe outputfile inputfile1 inputfile2 ...
+   !!
+   !!   History :
+   !!----------------------------------------------------------------------
+   USE netcdf
+   USE obs_const
+   USE obs_utils
+   USE ooo_utils, ONLY: date_format, obfilldbl
+   USE toolspar_kind
+   IMPLICIT NONE
+   !! Command line setup
+#ifndef NOIARGCPROTO
+   INTEGER,EXTERNAL :: iargc
+#endif
+   INTEGER :: nargs,    & !: number of command line arguments
+            & ia,       & !: argument loop index
+            & ninfiles    !: number of input files
+   !! Routine arguments
+   CHARACTER(len=256) :: cdoutfile
+   CHARACTER(len=256),ALLOCATABLE :: cdinfile(:)
+   !! Routine variables
+   CHARACTER(len=80) :: cpname
+   INTEGER,PARAMETER :: nstr=8, n128=128
+   INTEGER           ::    ncid,   & !: netcdf file id
+                        &  dimid,  & !: netcdf dimension id
+                        &  dpdim,  & !: netcdf dimension ids
+                        &  fcdim,  &
+                        &  vrdim,  &
+                        &  obdim,  &
+                        &  stdim,  &
+                        &  sxdim,  &
+                        &  fdvid,  & !: netcdf variable ids
+                        &  lonid,  &
+                        &  latid,  &
+                        &  depid,  &
+                        &  varid,  &
+                        &  unitid, &
+                        &  obvid,  &
+                        &  fcvid,  &
+                        &  prvid,  &
+                        &  clvid,  &
+                        &  dm2id,  &
+                        &  dm1id,  &
+                        &  mdtid,  &
+                        &  altid,  &
+                        &  qcvid,  &
+                        &  jdvid,  &
+                        &  mjdid,  &
+                        &  typid,  &
+                        &  idvid,  &
+                        &  ndeps,  & !: number depths
+                        &  nfcst,  & !: number forecast
+                        &  nvars,  & !: number variables
+                        &  nobs,   & !: number obs
+                        &  sdeps,  &
+                        &  sobs,   &
+                        &  l_dex,  &
+                        &  u_dex
+
+   INTEGER                   :: iob, idep, istat
+   INTEGER, DIMENSION(2)     :: dim2a, dim2b, dim2c, dim2d
+   INTEGER, DIMENSION(3)     :: dim3a
+   INTEGER, DIMENSION(4)     :: dim4a
+   INTEGER,  ALLOCATABLE, DIMENSION(:)           :: fcday
+   REAL(wp), ALLOCATABLE, DIMENSION(:)           :: modjd
+   !: Global Attributes
+   CHARACTER(len=40)                             :: nam_str, &
+                                                 & version,  &
+                                                 & contact,  &
+                                                 & sys_str,  &
+                                                 & cfg_str,  &
+                                                 & ins_str,  &
+                                                 & val_str,  &
+                                                 & dat_str,  &
+                                                 & obs_str
+   !: Variable Attributes
+   CHARACTER(len=100)                            :: lon_units, &
+                                                 &  lat_units, &
+                                                 &  dep_units, &
+                                                 &  jul_units, &
+                                                 &  mjd_units, &
+                                                 &  fcd_units, &
+                                                 &  lead_comment, &
+                                                 &  fcst_comment, &
+                                                 &  per_comment,  &
+                                                 &  cli_comment,  &
+                                                 &  dm2_comment,  &
+                                                 &  dm1_comment
+   CHARACTER(len=128)                            :: qc_comment,   &
+                                                 &  qc_flag_meaning
+   INTEGER, DIMENSION(2)                         :: qc_flag_value
+
+   !: Global Arrays
+   REAL(wp), ALLOCATABLE, DIMENSION(:)           :: g_lam, &
+                                                 &  g_phi, & 
+                                                 &  gjuld 
+   CHARACTER(len=n128),ALLOCATABLE,DIMENSION(:)  :: gtype
+   CHARACTER(len=nstr),ALLOCATABLE,DIMENSION(:)  ::        &
+                                                 &  g_id,  & 
+                                                 &  gvnam, & 
+                                                 &  gunit
+   REAL(wp), ALLOCATABLE, DIMENSION(:,:)         :: g_dep
+   REAL(wp), ALLOCATABLE, DIMENSION(:,:,:)       :: g3dob, &
+                                                 &  g3dcl, &
+                                                 &  g3mdt, &
+                                                 &  g3alt, &
+                                                 &  g3dm2, &
+                                                 &  g3dm1
+   INTEGER(ik),  ALLOCATABLE, DIMENSION(:,:,:)   :: g3dqc
+   REAL(wp), ALLOCATABLE, DIMENSION(:,:,:,:)     :: g3dmc, &
+                                                 &  g3dpr
+   !: Small Arrays  
+   REAL(wp), ALLOCATABLE, DIMENSION(:)       ::     s_lam, &
+                                                 &  s_phi, & 
+                                                 &  sjuld
+
+   CHARACTER(len=n128),ALLOCATABLE,DIMENSION(:) ::  stype
+   CHARACTER(len=nstr),ALLOCATABLE,DIMENSION(:) ::        &
+                                                 &  s_id 
+
+   REAL(wp), ALLOCATABLE, DIMENSION(:,:)        :: s_dep
+   REAL(wp), ALLOCATABLE, DIMENSION(:,:,:)      :: s3dob, &
+                                                &  s3dcl, &
+                                                &  s3mdt, &
+                                                &  s3alt, &
+                                                &  s3dm2, &
+                                                &  s3dm1
+   INTEGER(ik),  ALLOCATABLE, DIMENSION(:,:,:)  :: s3dqc
+   REAL(wp), ALLOCATABLE, DIMENSION(:,:,:,:)    :: s3dmc, &
+                                                &  s3dpr
+
+   !: File creation logical
+   LOGICAL                                     :: ln_cre
+
+   !: Optional variable logicals
+   LOGICAL                                     :: ln_init, &
+                                                & ln_mdt,  &
+                                                & ln_altbias, &
+                                                & ln_best
+   !! Command name
+   cpname='c4comb.exe'
+
+   !! Process command line
+   nargs = IARGC()
+   IF (nargs /= 2) THEN
+      WRITE(*, *) "Usage: c4comb.exe outputfile inputfile1 inputfile2 ..."
+      CALL abort()
+   END IF
+   CALL GETARG(1, cdoutfile)
+
+   !! Process input files
+   !! Set output file creation to off
+   ln_cre = .false.
+
+   !! Turn optional variables off
+   ln_init = .false.
+   ln_best = .false.
+   ln_altbias = .false.
+   ln_mdt = .false.
+
+   !! Compute size of output file
+   nobs = 0
+   ndeps= 0
+   ALLOCATE( cdinfile( nargs - 1 ) )
+   ninfiles = nargs - 1
+   DO ia = 1, ninfiles
+      CALL GETARG(ia+1, cdinfile(ia))
+      WRITE(*,*) "Opening : ", TRIM(cdinfile(ia))
+      !! Open Netcdf file
+      istat = nf90_open(TRIM(cdinfile(ia)),nf90_nowrite,ncid)
+      IF (istat == nf90_noerr) THEN
+         !! Turn output file creation on
+         ln_cre = .true.
+         !! Get Dimensions
+         CALL chkerr( nf90_inq_dimid(ncid, 'numobs',  dimid),              cpname, __LINE__ )
+         CALL chkerr( nf90_inquire_dimension(ncid,    dimid, len=sobs  ),  cpname, __LINE__ )
+         CALL chkerr( nf90_inq_dimid(ncid, 'numdeps', dimid),              cpname, __LINE__ )
+         CALL chkerr( nf90_inquire_dimension(ncid,    dimid, len=sdeps ),  cpname, __LINE__ )
+         CALL chkerr( nf90_inq_dimid(ncid, 'numfcsts',dimid),              cpname, __LINE__ )
+         CALL chkerr( nf90_inquire_dimension(ncid,    dimid, len=nfcst ),  cpname, __LINE__ )
+         CALL chkerr( nf90_inq_dimid(ncid, 'numvars', dimid),              cpname, __LINE__ )
+         CALL chkerr( nf90_inquire_dimension(ncid,    dimid, len=nvars ),  cpname, __LINE__ )
+         !! Close Netcdf file
+         CALL chkerr( nf90_close(ncid), cpname, __LINE__ )
+         !! Report on file contents
+         WRITE(*,'(2A)')'File = ', TRIM(cdinfile(ia))
+         WRITE(*,'(A,I9,A)')'has', sobs, ' observations'
+         !! Increment size
+         nobs  = nobs + sobs       !: Accumulate number of profiles
+         ndeps = MAX(ndeps, sdeps) !: Define maximum number of levels needed
+      END IF ! istat
+   END DO
+
+   !! Allocate global arrays
+   ALLOCATE( g_phi(nobs),                      &
+          &  g_lam(nobs),                      &
+          &  g_dep(ndeps, nobs),               &
+          &  g3dob(ndeps,        nvars, nobs), &
+          &  g3dmc(ndeps, nfcst, nvars, nobs), &
+          &  g3dpr(ndeps, nfcst, nvars, nobs), &
+          &  g3dcl(ndeps,        nvars, nobs), &
+          &  g3dm2(ndeps,        nvars, nobs), &
+          &  g3dm1(ndeps,        nvars, nobs), &
+          &  g3mdt(ndeps,        nvars, nobs), &
+          &  g3alt(ndeps,        nvars, nobs), &
+          &  g3dqc(ndeps,        nvars, nobs), &
+          &  gjuld(nobs),                      &
+          &  gtype(nobs),                      &
+          &  g_id(nobs),                       &
+          &  gvnam(nvars),                     &
+          &  gunit(nvars) )
+   ALLOCATE(fcday(nfcst), modjd(nfcst))
+
+   !! Fill with missing data value
+   g_dep(:,:)     = 99999.
+   g3dmc(:,:,:,:) = 99999.
+   g3dpr(:,:,:,:) = 99999.
+   g3dob(:,:,:)   = 99999.
+   g3dcl(:,:,:)   = 99999.
+   g3dm2(:,:,:)   = 99999.
+   g3dm1(:,:,:)   = 99999.
+   g3mdt(:,:,:)   = 99999.
+   g3alt(:,:,:)   = 99999.
+   g3dqc(:,:,:)   = NF90_FILL_SHORT
+
+   !! Read in each file
+   !  initialise global matrix indices
+   l_dex = 0
+   u_dex = 0
+
+   !! initialise Global attribute strings
+   nam_str = ''
+   version = ''
+   contact = ''
+   sys_str = ''
+   cfg_str = ''
+   ins_str = ''
+   val_str = ''
+   dat_str = ''
+   obs_str = ''
+
+   !! initialise Variable attribute strings
+   fcd_units = ''
+   lon_units = ''
+   lat_units = ''
+   dep_units = ''
+   jul_units = ''
+   mjd_units = ''
+   lead_comment = ''
+   fcst_comment = ''
+   per_comment  = ''
+   cli_comment  = ''
+   dm2_comment  = ''
+   dm1_comment  = ''
+   qc_comment  = ''
+   qc_flag_meaning  = ''
+
+   DO ia = 1, ninfiles
+      WRITE(*,*) "Opening : ", TRIM(cdinfile(ia))
+      !! Open Netcdf file
+      istat = nf90_open(TRIM(cdinfile(ia)),nf90_nowrite,ncid)
+      IF (istat == nf90_noerr) THEN
+         !! Get Global Attributes
+         CALL chkerr( nf90_get_att(ncid, nf90_global,'title',         nam_str),cpname, __LINE__)
+         CALL chkerr( nf90_get_att(ncid, nf90_global,'version',       version),cpname, __LINE__)
+         CALL chkerr( nf90_get_att(ncid, nf90_global,'contact',       contact),cpname, __LINE__)
+         CALL chkerr( nf90_get_att(ncid, nf90_global,'obs_type',      obs_str),cpname, __LINE__)
+         CALL chkerr( nf90_get_att(ncid, nf90_global,'system',        sys_str),cpname, __LINE__)
+         CALL chkerr( nf90_get_att(ncid, nf90_global,'configuration', cfg_str),cpname, __LINE__)
+         CALL chkerr( nf90_get_att(ncid, nf90_global,'institution',   ins_str),cpname, __LINE__)
+         CALL chkerr( nf90_get_att(ncid, nf90_global,'validity_time', val_str),cpname, __LINE__)
+         !! Get Dimensions of single file
+         CALL chkerr( nf90_inq_dimid(ncid, 'numdeps', dimid),              cpname, __LINE__ )
+         CALL chkerr( nf90_inquire_dimension(ncid,    dimid, len=sdeps ),  cpname, __LINE__ )
+         CALL chkerr( nf90_inq_dimid(ncid, 'numfcsts',dimid),              cpname, __LINE__ )
+         CALL chkerr( nf90_inquire_dimension(ncid,    dimid, len=nfcst ),  cpname, __LINE__ )
+         CALL chkerr( nf90_inq_dimid(ncid, 'numvars', dimid),              cpname, __LINE__ )
+         CALL chkerr( nf90_inquire_dimension(ncid,    dimid, len=nvars ),  cpname, __LINE__ )
+         CALL chkerr( nf90_inq_dimid(ncid, 'numobs',  dimid),              cpname, __LINE__ )
+         CALL chkerr( nf90_inquire_dimension(ncid,    dimid, len=sobs  ),  cpname, __LINE__ )
+         !! Check for Optional variables in first file
+         IF (ia == 1) THEN
+            !! Best estimate
+            istat = nf90_inq_varid(ncid,'best_estimate',dm2id)
+            IF (istat == nf90_noerr) THEN
+               ln_best = .TRUE.
+            ENDIF 
+            !! nrt_analysis
+            istat = nf90_inq_varid(ncid,'nrt_analysis',dm1id)
+            IF (istat == nf90_noerr) THEN
+               ln_init = .TRUE.
+            ENDIF 
+            !! Mean Dynamic Topography
+            istat = nf90_inq_varid(ncid,'mdt_reference',mdtid)
+            IF (istat == nf90_noerr) THEN
+               ln_mdt = .TRUE.
+            ENDIF 
+            !! Altimeter bias
+            istat = nf90_inq_varid(ncid,'altimeter_bias',altid)
+            IF (istat == nf90_noerr) THEN
+               ln_altbias = .TRUE.
+            ENDIF 
+         END IF
+         WRITE(*,*) TRIM(cdinfile(ia)), " contains ", sobs, " observations"
+         WRITE(*,*) TRIM(cdinfile(ia)), " contains ", sdeps, " depths"
+         WRITE(*,*) TRIM(cdinfile(ia)), " contains ", nfcst, " forecasts"
+         WRITE(*,*) TRIM(cdinfile(ia)), " contains ", nvars, " vars"
+         !! Read Variables
+         IF (sobs /= 0) THEN
+            !! Get Variable ids
+            CALL chkerr(nf90_inq_varid(ncid,'leadtime', fdvid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'longitude',   lonid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'latitude',    latid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'depth',       depid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'varname',     varid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'unitname',   unitid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'observation', obvid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'forecast',    fcvid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'persistence', prvid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'climatology', clvid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'qc',          qcvid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'juld',        jdvid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'modeljuld',   mjdid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'type',        typid) ,cpname, __LINE__ )
+            CALL chkerr(nf90_inq_varid(ncid,'id',          idvid) ,cpname, __LINE__ )
+            !! Get variable attributes
+            CALL chkerr(nf90_get_att(ncid, fdvid, 'units', fcd_units) ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, lonid, 'units', lon_units) ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, latid, 'units', lat_units) ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, depid, 'units', dep_units) ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, jdvid, 'units', jul_units) ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, mjdid, 'units', mjd_units) ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, fcvid, 'comment', fcst_comment) ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, prvid, 'comment', per_comment)  ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, clvid, 'comment', cli_comment)  ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, fdvid, 'comment', lead_comment) ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, qcvid, 'comment', qc_comment) ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, qcvid, 'flag_value', qc_flag_value) ,cpname, __LINE__ )
+            CALL chkerr(nf90_get_att(ncid, qcvid, 'flag_meaning', qc_flag_meaning) ,cpname, __LINE__ )
+            !! Optional variables
+            IF (ln_best) THEN
+               CALL chkerr(nf90_inq_varid(ncid,'best_estimate',dm2id) ,cpname, __LINE__ )
+               CALL chkerr(nf90_get_att(ncid, dm2id, 'comment', dm2_comment)  ,cpname, __LINE__ )
+            ENDIF
+            IF (ln_init) THEN
+               CALL chkerr(nf90_inq_varid(ncid,'nrt_analysis', dm1id) ,cpname, __LINE__ )
+               CALL chkerr(nf90_get_att(ncid, dm1id, 'comment', dm1_comment)  ,cpname, __LINE__ )
+            ENDIF
+            IF (ln_mdt) THEN
+               CALL chkerr(nf90_inq_varid(ncid,'mdt_reference', mdtid) ,cpname, __LINE__ )
+            ENDIF
+            IF (ln_altbias) THEN
+               CALL chkerr(nf90_inq_varid(ncid,'altimeter_bias', altid) ,cpname, __LINE__ )
+            ENDIF
+
+            !! Allocate small arrays
+            ALLOCATE( s_lam(sobs), s_phi(sobs),  s_dep(sdeps, sobs),               &
+                   &  s3dob(sdeps,        nvars, sobs), & !: observations 
+                   &  s3dmc(sdeps, nfcst, nvars, sobs), & !: model data
+                   &  s3dpr(sdeps, nfcst, nvars, sobs), & !: persistence
+                   &  s3dcl(sdeps,        nvars, sobs), & !: climatology
+                   &  s3dm2(sdeps,        nvars, sobs), & !: best estimate
+                   &  s3dm1(sdeps,        nvars, sobs), & !: nrt_analysis
+                   &  s3mdt(sdeps,        nvars, sobs), & !: mdt
+                   &  s3alt(sdeps,        nvars, sobs), & !: altbias
+                   &  s3dqc(sdeps,        nvars, sobs), & !: QC
+                   &  sjuld(sobs), stype( sobs),  &
+                   &  s_id(sobs) )
+            !! Fill with missing data value
+            s3dmc(:,:,:,:) = 99999.
+            s3dpr(:,:,:,:) = 99999.
+            s3dob(:,:,:)   = 99999.
+            s3dcl(:,:,:)   = 99999.
+            s3dm2(:,:,:)   = 99999.
+            s3dm1(:,:,:)   = 99999.
+            s3mdt(:,:,:)   = 99999.
+            s3alt(:,:,:)   = 99999.
+            s3dqc(:,:,:)   = NF90_FILL_SHORT
+
+            !! Read variables into small arrays
+            CALL chkerr( nf90_get_var(ncid, fdvid, fcday), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, lonid, s_lam), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, latid, s_phi), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, depid, s_dep), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, obvid, s3dob), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, fcvid, s3dmc), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, prvid, s3dpr), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, clvid, s3dcl), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, qcvid, s3dqc), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, jdvid, sjuld), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, mjdid, modjd), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, typid, stype), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, idvid, s_id),  cpname, __LINE__ )       
+            !! Read unitname and varname into global arrays
+            CALL chkerr( nf90_get_var(ncid, varid, gvnam), cpname, __LINE__ )       
+            CALL chkerr( nf90_get_var(ncid, unitid,gunit), cpname, __LINE__ )       
+            !! Optional variables read
+            IF (ln_best) THEN
+               CALL chkerr( nf90_get_var(ncid, dm2id, s3dm2), cpname, __LINE__ )       
+            ENDIF
+            IF (ln_init) THEN
+               CALL chkerr( nf90_get_var(ncid, dm1id, s3dm1), cpname, __LINE__ )       
+            ENDIF
+            IF (ln_mdt) THEN
+               CALL chkerr( nf90_get_var(ncid, mdtid, s3mdt), cpname, __LINE__ )       
+            ENDIF
+            IF (ln_altbias) THEN
+               CALL chkerr( nf90_get_var(ncid, altid, s3alt), cpname, __LINE__ )       
+            ENDIF
+
+            !! Fill Global arrays
+            !  increment numobs indices
+            l_dex = u_dex + 1
+            u_dex = l_dex + sobs -1
+
+            g_lam(l_dex:u_dex)                          = s_lam(:)
+            g_phi(l_dex:u_dex)                          = s_phi(:)
+            g_dep(1:sdeps,  l_dex:u_dex)                = s_dep(1:sdeps,:)
+            g3dob(1:sdeps,1:nvars,l_dex:u_dex)          = s3dob(1:sdeps,1:nvars,:)
+            g3dmc(1:sdeps,1:nfcst,1:nvars,l_dex:u_dex)  = s3dmc(1:sdeps,1:nfcst,1:nvars,:)
+            g3dpr(1:sdeps,1:nfcst,1:nvars,l_dex:u_dex)  = s3dpr(1:sdeps,1:nfcst,1:nvars,:)
+            g3dcl(1:sdeps,1:nvars,l_dex:u_dex)          = s3dcl(1:sdeps,1:nvars,:)
+            g3dm2(1:sdeps,1:nvars,l_dex:u_dex)          = s3dm2(1:sdeps,1:nvars,:)
+            g3dm1(1:sdeps,1:nvars,l_dex:u_dex)          = s3dm1(1:sdeps,1:nvars,:)
+            g3mdt(1:sdeps,1:nvars,l_dex:u_dex)          = s3mdt(1:sdeps,1:nvars,:)
+            g3alt(1:sdeps,1:nvars,l_dex:u_dex)          = s3alt(1:sdeps,1:nvars,:)
+            g3dqc(1:sdeps,1:nvars,l_dex:u_dex)          = s3dqc(1:sdeps,1:nvars,:)
+            gjuld(l_dex:u_dex)                          = sjuld(:)
+            gtype(l_dex:u_dex)                          = stype(:)
+            g_id(l_dex:u_dex)                           = s_id(:)
+
+            !! Deallocate small array
+            DEALLOCATE( s_lam, s_phi, s_dep, s3dob, s3dmc, s3dpr, s3dcl, s3dqc, s3dm2, s3dm1, s3mdt, s3alt, sjuld, stype, s_id)
+         ENDIF ! sobs    
+         !! Close Netcdf file
+         CALL chkerr( nf90_close(ncid), cpname, __LINE__ )
+      END IF ! istat
+   END DO
+
+   !! Create Output file
+   IF (ln_cre) THEN
+      WRITE(*,*) 'Create the output file, ',trim(cdoutfile)
+      CALL chkerr( nf90_create(trim(cdoutfile),nf90_clobber,ncid),      cpname, __LINE__ )
+      !! Put Global Attributes
+      CALL date_format(dat_str) 
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'title',          trim(nam_str)),cpname, __LINE__)
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'version',        trim(version)),cpname, __LINE__)
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'creation_date',  trim(dat_str)),cpname, __LINE__)
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'contact',        trim(contact)),cpname, __LINE__)
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'obs_type',       trim(obs_str)),cpname, __LINE__)
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'system',         trim(sys_str)),cpname, __LINE__)
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'configuration',  trim(cfg_str)),cpname, __LINE__)
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'institution',    trim(ins_str)),cpname, __LINE__)
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'validity_time',  trim(val_str)),cpname, __LINE__)
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'best_estimate_description', &
+                              &       'analysis produced 2 days behind real time'),cpname, __LINE__)
+      CALL chkerr( nf90_put_att(ncid, nf90_global,'time_interp', 'daily average fields'),cpname, __LINE__)
+      WRITE(*,*) 'Succesfully put global attributes '
+
+      !! Define Dimensions
+      CALL chkerr( nf90_def_dim(ncid, 'numdeps',          ndeps, dpdim) ,cpname, __LINE__ )
+      CALL chkerr( nf90_def_dim(ncid, 'numfcsts',         nfcst, fcdim) ,cpname, __LINE__ )
+      CALL chkerr( nf90_def_dim(ncid, 'numvars',          nvars, vrdim) ,cpname, __LINE__ )
+      CALL chkerr( nf90_def_dim(ncid, 'numobs',           nobs,  obdim) ,cpname, __LINE__ )
+      CALL chkerr( nf90_def_dim(ncid, 'string_length8',   nstr,  stdim) ,cpname, __LINE__ )
+      CALL chkerr( nf90_def_dim(ncid, 'string_length128', n128,  sxdim) ,cpname, __LINE__ )
+      WRITE(*,*) 'Succesfully defined dimensions'
+
+      !! Define possible dimension permutations
+      ! 2d
+      dim2a(:) = (/ dpdim, obdim /) !: (/ ndeps, nobs  /) 
+      dim2b(:) = (/ stdim, obdim /) !: (/ nstr,  nobs  /)
+      dim2c(:) = (/ stdim, vrdim /) !: (/ nstr,  nvars /)
+      dim2d(:) = (/ sxdim, obdim /) !: (/ nstr,  nobs  /)
+      ! 3d
+      dim3a(:) = (/ dpdim, vrdim, obdim/) !: (/ ndeps, nvars, nobs /)
+      ! 4d
+      dim4a(:) = (/ dpdim, fcdim, vrdim, obdim /) !: (/ ndeps, nfcst, nvars, nobs /)
+
+
+      !! Create the variables
+      !  Forecast day
+      CALL chkerr( nf90_def_var(ncid, 'leadtime',  nf90_double, fcdim, fdvid)          ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, fdvid, 'long_name', 'Model forecast day offset') ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, fdvid, 'units',     trim(fcd_units))             ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, fdvid, 'comment',   trim(lead_comment))          ,cpname, __LINE__ )
+      WRITE(*,*) 'leadtime created'
+      !  longitude
+      CALL chkerr( nf90_def_var(ncid, 'longitude',    nf90_float, obdim, lonid)        ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, lonid, 'long_name', 'Longitudes')                ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, lonid, 'units',     trim(lon_units))             ,cpname, __LINE__ )
+      WRITE(*,*) 'lon created'
+      !  latitude
+      CALL chkerr( nf90_def_var(ncid, 'latitude',     nf90_float, obdim, latid)        ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, latid, 'long_name', 'Latitudes')                 ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, latid, 'units',     trim(lat_units))             ,cpname, __LINE__ )
+      WRITE(*,*) 'lat created'
+      !  depth
+      CALL chkerr( nf90_def_var(ncid, 'depth',        nf90_float, dim2a, depid)        ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, depid, 'long_name', 'Depths')                    ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, depid, 'units',     trim(dep_units))             ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, depid, '_FillValue',obfillflt)                    ,cpname, __LINE__ )
+      WRITE(*,*) 'dep created'
+      !  varname
+      CALL chkerr( nf90_def_var(ncid, 'varname',      nf90_char,  dim2c, varid)        ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, varid, 'long_name', 'Variable name')             ,cpname, __LINE__ )
+      WRITE(*,*) 'varname created'
+      !  unitname
+      CALL chkerr( nf90_def_var(ncid, 'unitname',     nf90_char,  dim2c, unitid)        ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid,  unitid, 'long_name', 'Unit name')              ,cpname, __LINE__ )
+      WRITE(*,*) 'unitname created'
+      !  obs
+      CALL chkerr( nf90_def_var(ncid, 'observation', nf90_float,  dim3a,  obvid)        ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, obvid, '_FillValue',obfillflt)                    ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid,  obvid, 'long_name', 'Observation value')         ,cpname, __LINE__ )
+      WRITE(*,*) 'obs created'
+      !  forecast
+      CALL chkerr( nf90_def_var(ncid, 'forecast',    nf90_float,  dim4a,  fcvid)        ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, fcvid, '_FillValue',obfillflt)                    ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, fcvid, 'long_name', 'Model forecast counterpart of obs. value')   ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, fcvid, 'comment',   trim(fcst_comment))           ,cpname, __LINE__ )
+      WRITE(*,*) 'forecast created'
+      !  persistence
+      CALL chkerr( nf90_def_var(ncid, 'persistence', nf90_float,  dim4a,  prvid)        ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, prvid, '_FillValue',obfillflt)                    ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, prvid, 'long_name', 'Model persistence counterpart of obs. value'),cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, prvid, 'comment',   trim(per_comment))            ,cpname, __LINE__ )
+      WRITE(*,*) 'persistence created'
+      !  clim
+      CALL chkerr( nf90_def_var(ncid, 'climatology', nf90_float,  dim3a, clvid)        ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, clvid, '_FillValue',obfillflt)                    ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, clvid, 'long_name', 'Climatological value')       ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, clvid, 'comment',   trim(cli_comment))            ,cpname, __LINE__ )
+      WRITE(*,*) 'clim created'
+      IF (ln_best) THEN
+         !  daym2
+         CALL chkerr( nf90_def_var(ncid, 'best_estimate', nf90_float,  dim3a, dm2id)    ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_att(ncid, dm2id, '_FillValue',obfillflt)                 ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_att(ncid, dm2id, 'long_name', 'Best estimate')           ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_att(ncid, dm2id, 'comment',   trim(dm2_comment))         ,cpname, __LINE__ )
+         WRITE(*,*) 'daym2 created'
+      ENDIF
+      IF (ln_init) THEN
+         !  daym1
+         CALL chkerr( nf90_def_var(ncid, 'nrt_analysis', nf90_float,  dim3a, dm1id)        ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_att(ncid, dm1id, '_FillValue',obfillflt)                    ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_att(ncid, dm1id, 'long_name', 'Near real time analysis')    ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_att(ncid, dm1id, 'comment',   trim(dm1_comment))            ,cpname, __LINE__ )
+         WRITE(*,*) 'daym1 created'
+      ENDIF
+      IF (ln_mdt) THEN
+         !  mdt
+         CALL chkerr( nf90_def_var(ncid, 'mdt_reference', nf90_float,  dim3a, mdtid)      ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_att(ncid, mdtid, '_FillValue',obfillflt)                    ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_att(ncid, mdtid, 'long_name', 'Mean dynamic topography')    ,cpname, __LINE__ )
+         WRITE(*,*) 'mdt created'
+      ENDIF
+      IF (ln_altbias) THEN
+         !  altbias
+         CALL chkerr( nf90_def_var(ncid, 'altimeter_bias', nf90_float,  dim3a, altid)     ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_att(ncid, altid, '_FillValue',obfillflt)                    ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_att(ncid, altid, 'long_name', 'Altimeter bias')             ,cpname, __LINE__ )
+         WRITE(*,*) 'altbias created'
+      ENDIF
+      !  qc
+      CALL chkerr( nf90_def_var(ncid, 'qc',          nf90_short,  dim3a, qcvid)         ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, qcvid, '_FillValue', NF90_FILL_SHORT)             ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, qcvid, 'long_name', 'Quality flags')              ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, qcvid, 'flag_value', qc_flag_value)               ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, qcvid, 'flag_meaning', qc_flag_meaning)           ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, qcvid, 'comment', qc_comment)                     ,cpname, __LINE__ )
+      WRITE(*,*) 'qc created'
+      !  juld
+      CALL chkerr( nf90_def_var(ncid, 'juld',       nf90_double,  obdim, jdvid)         ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, jdvid, '_FillValue',99999.)                       ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, jdvid, 'long_name', 'Observation time in Julian days'),cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, jdvid, 'units',     trim(jul_units))              ,cpname, __LINE__ )
+      WRITE(*,*) 'juld created'
+      !  modeljuld 
+      CALL chkerr( nf90_def_var(ncid, 'modeljuld',  nf90_double,  fcdim, mjdid)         ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, mjdid, 'long_name', 'Model field date in Julian days'),cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, mjdid, 'units',     trim(mjd_units))              ,cpname, __LINE__ )
+      WRITE(*,*) 'modeljuld created'
+      !  type
+      CALL chkerr( nf90_def_var(ncid, 'type',     nf90_char,      dim2d, typid)         ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, typid, 'long_name', 'Observation type')           ,cpname, __LINE__ )
+      WRITE(*,*) 'type created'
+      !  id
+      CALL chkerr( nf90_def_var(ncid, 'id',       nf90_char,      dim2b, idvid)         ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_att(ncid, idvid, 'long_name', 'Observation id')             ,cpname, __LINE__ )
+      WRITE(*,*) 'id created'
+      ! Close Netcdf file 
+      CALL chkerr( nf90_close(ncid) ,cpname, __LINE__ )  
+      !! Fill in the variables
+      CALL chkerr( nf90_open(trim(cdoutfile),nf90_write,ncid),                   cpname, __LINE__ )
+      WRITE(*,*) 'Create the variables ',trim(cdoutfile)
+      !  Forecast day
+      CALL chkerr( nf90_inq_varid(ncid, 'leadtime', fdvid)                ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, fdvid, fcday) ,cpname, __LINE__ )
+      WRITE(*,*) 'forecast day put'
+      !  longitude
+      CALL chkerr( nf90_inq_varid(ncid, 'longitude', lonid)                  ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, lonid, g_lam) ,cpname, __LINE__ )
+      WRITE(*,*) 'lon put'
+      !  latitude
+      CALL chkerr( nf90_inq_varid(ncid, 'latitude', latid)                   ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, latid, g_phi) ,cpname, __LINE__ )
+      WRITE(*,*) 'lat put'
+      !  depth
+      CALL chkerr( nf90_inq_varid(ncid, 'depth',depid)                       ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, depid, g_dep) ,cpname, __LINE__ )
+      WRITE(*,*) 'dep put'
+      ! varname
+      CALL chkerr( nf90_inq_varid(ncid, 'varname', varid)                    ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, varid, gvnam,(/1,1/), (/nstr,nvars/) ) ,cpname, __LINE__ )   
+      WRITE(*,*) 'var put'
+      ! unitname
+      CALL chkerr( nf90_inq_varid(ncid, 'unitname',unitid)                   ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, unitid, gunit,(/1,1/),(/nstr,nvars/) ) ,cpname, __LINE__ )   
+      WRITE(*,*) 'unitnam put'
+      ! obs
+      CALL chkerr( nf90_inq_varid(ncid, 'observation', obvid)                ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, obvid,g3dob ) ,cpname, __LINE__ )   
+      WRITE(*,*) 'obs put'
+      ! clim
+      CALL chkerr( nf90_inq_varid(ncid, 'climatology', clvid)                ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, clvid,g3dcl ) ,cpname, __LINE__ )   
+      WRITE(*,*) 'cli put'
+      IF (ln_best) THEN
+         ! daym2
+         CALL chkerr( nf90_inq_varid(ncid, 'best_estimate',dm2id)            ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_var(ncid, dm2id,g3dm2 ) ,cpname, __LINE__ )   
+         WRITE(*,*) 'daym2 put'
+      ENDIF
+      IF (ln_init) THEN 
+         ! daym1
+         CALL chkerr( nf90_inq_varid(ncid, 'nrt_analysis',dm1id)              ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_var(ncid, dm1id,g3dm1 ) ,cpname, __LINE__ )   
+         WRITE(*,*) 'daym1 put'
+      ENDIF
+      IF (ln_mdt) THEN 
+         ! mdt
+         CALL chkerr( nf90_inq_varid(ncid, 'mdt_reference', mdtid)              ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_var(ncid, mdtid, g3mdt ) ,cpname, __LINE__ )   
+         WRITE(*,*) 'mdt put'
+      ENDIF
+      IF (ln_altbias) THEN 
+         ! altbias
+         CALL chkerr( nf90_inq_varid(ncid, 'altimeter_bias', altid)             ,cpname, __LINE__ )
+         CALL chkerr( nf90_put_var(ncid, altid, g3alt ) ,cpname, __LINE__ )   
+         WRITE(*,*) 'altbias put'
+      ENDIF
+      ! persistence
+      CALL chkerr( nf90_inq_varid(ncid, 'persistence',prvid)                                 ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, prvid, g3dpr, (/1,1,1,1/) ,(/ ndeps,nfcst,nvars,nobs/) ) ,cpname, __LINE__ )   
+      WRITE(*,*) 'per put'
+      ! forecast
+      CALL chkerr( nf90_inq_varid(ncid, 'forecast',fcvid)                                      ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, fcvid, g3dmc, (/1,1,1,1/), (/ ndeps,nfcst,nvars,nobs/) ) ,cpname, __LINE__ )   
+      WRITE(*,*) 'fcst put'
+      ! qc
+      CALL chkerr( nf90_inq_varid(ncid, 'qc', qcvid)                         ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, qcvid,g3dqc ) ,cpname, __LINE__ )   
+      WRITE(*,*) 'qc put'
+      ! juld
+      CALL chkerr( nf90_inq_varid(ncid, 'juld',jdvid)                        ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, jdvid, gjuld) ,cpname, __LINE__ )   
+      WRITE(*,*) 'juld put'
+      ! modeljuld
+      CALL chkerr( nf90_inq_varid(ncid, 'modeljuld', mjdid)                  ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, mjdid, modjd,(/1/),(/nfcst/))          ,cpname, __LINE__ )   
+      WRITE(*,*) 'modjuld put'
+      ! type
+      CALL chkerr( nf90_inq_varid(ncid, 'type', typid)                       ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, typid, gtype,(/1,1/) , (/n128,nobs/) ) ,cpname, __LINE__ )   
+      WRITE(*,*) 'type put'
+      ! id
+      CALL chkerr( nf90_inq_varid(ncid, 'id', idvid)                         ,cpname, __LINE__ )
+      CALL chkerr( nf90_put_var(ncid, idvid, g_id,(/1,1/)  , (/nstr,nobs/) ) ,cpname, __LINE__ )   
+      WRITE(*,*) 'id put'
+      ! Close netcdf file
+      CALL chkerr( nf90_close(ncid),                                          cpname, __LINE__ )
+   END IF ! ln_cre
+   !! Deallocate Global arrays
+   DEALLOCATE( g_lam, g_phi, g_dep, g3dob, g3dmc, g3dpr, g3dcl, g3dm2, g3dm1, g3mdt, g3alt, g3dqc, gjuld, gtype, g_id, gvnam, gunit)
+   DEALLOCATE( fcday, modjd )
+
+   !! Deallocate input argument list
+   DEALLOCATE(cdinfile)
+END PROGRAM c4comb
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/src/obs_const.F90
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/src/obs_const.F90	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/src/obs_const.F90	(revision 4245)
@@ -0,0 +1,1 @@
+link ../../../NEMO/OPA_SRC/OBS/obs_const.F90
Index: branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/src/ooo_utils.F90
===================================================================
--- branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/src/ooo_utils.F90	(revision 4245)
+++ branches/2013/dev_LOCEAN_CMCC_INGV_MERC_UKMO_2013/NEMOGCM/TOOLS/OBSTOOLS/src/ooo_utils.F90	(revision 4245)
@@ -0,0 +1,1 @@
+link ../../../NEMO/OOO_SRC/ooo_utils.F90
