From b343b7e51c84010a354396bfcc7ff1a21fd311b3 Mon Sep 17 00:00:00 2001 From: Mark Miesch Date: Fri, 29 Oct 2021 09:13:36 -0600 Subject: [PATCH] Release/soca 1.0.0 (#330) * specify docutils version (#311) * explanation for absolute difference (#285) Co-authored-by: mmiesch * Update and augment MacOS instructions (#283) * Update and augment MacOS instructions * Add admin privileges warning * Remove reference to homebrew mpich. Other edits. * Add some additional module req's * No LAPACK module * Remove LAPACK troubleshooting section * Clarify lmod setup * Clarify lmod setup again Co-authored-by: mmiesch * Documenting the DrawValueFromFile and DrawObsValueFromFile obsfunctions (#276) * ENH: Added basic documentation for DrawObsErrorFromFile and DrawValueFromFile * minor tweeks * MAINT: Self review changes Self review changes to DrawValueFromFile.rst Perhaps we should centrally document obsfuction capability to return different types. * MAINT: Further review changes * MAINT: Self review of DrawObsErrorFromFile.rst * Updated index * MAINT: Self review final * MAINT: Minor changes based on review * MAINT: Minor changes based on review * MAINT: Minor review changes * ENH: Total refactor * Typo * MAINT: Review changes for Mike * MAINT: Review changes for DrawObsErrorFromFile * MAINT: review changes of DrawbsErrorFromFile * MAINT: minor review changes * MAINT: minor review change Co-authored-by: mmiesch * Basic doc skeleton * wip * wip * wip ... ws to github * wip * fixed build warnings * doc for marine ufo * WIP * inpu variables * added a few more var changes * start cleanup, left off at classes:Model * cleanup soca classes * extra space * Documentation to run the soca tutorial (#326) * added tutorial documentation * addressing Maryam's comments * move build section just before tutorial * addressed rev's comments ... I think. * capitalize un-italicify soca Co-authored-by: Travis Sluka Co-authored-by: Clementine Gas <43183478+cmgas@users.noreply.github.com> Co-authored-by: Steven Vahl <42982505+svahl991@users.noreply.github.com> Co-authored-by: Carwyn Pelley Co-authored-by: Guillaume Vernieres Co-authored-by: Travis Sluka --- docs/inside/jedi-components/index.rst | 1 + docs/inside/jedi-components/soca/build.rst | 106 ++++ docs/inside/jedi-components/soca/classes.rst | 525 ++++++++++++++++++ docs/inside/jedi-components/soca/index.rst | 21 + .../jedi-components/soca/introduction.rst | 34 ++ docs/inside/jedi-components/ufo/marineufo.rst | 189 +++++++ docs/inside/jedi-components/ufo/obsops.rst | 13 +- .../obsfunctions/DrawObsErrorFromFile.rst | 78 +++ .../obsfunctions/DrawValueFromFile.rst | 306 ++++++++++ .../ufo/qcfilters/obsfunctions/index.rst | 8 +- docs/inside/jedi-components/ufo/varbc.rst | 133 +---- docs/inside/testing/unit_testing.rst | 6 + .../tutorials/level2/dev-container_soca.rst | 165 ++++++ docs/learning/tutorials/level2/index.rst | 4 +- docs/learning/tutorials/level2/soca.rst | 273 +++++++++ howto/macos/minimum.md | 45 +- requirements.txt | 2 + 17 files changed, 1767 insertions(+), 142 deletions(-) create mode 100644 docs/inside/jedi-components/soca/build.rst create mode 100644 docs/inside/jedi-components/soca/classes.rst create mode 100644 docs/inside/jedi-components/soca/index.rst create mode 100644 docs/inside/jedi-components/soca/introduction.rst create mode 100644 docs/inside/jedi-components/ufo/marineufo.rst create mode 100644 docs/inside/jedi-components/ufo/qcfilters/obsfunctions/DrawObsErrorFromFile.rst create mode 100644 docs/inside/jedi-components/ufo/qcfilters/obsfunctions/DrawValueFromFile.rst create mode 100644 docs/learning/tutorials/level2/dev-container_soca.rst create mode 100644 docs/learning/tutorials/level2/soca.rst diff --git a/docs/inside/jedi-components/index.rst b/docs/inside/jedi-components/index.rst index da99bb9f..833836eb 100644 --- a/docs/inside/jedi-components/index.rst +++ b/docs/inside/jedi-components/index.rst @@ -11,4 +11,5 @@ JEDI Components ufo/index.rst fv3-jedi/index.rst mpas-jedi/index.rst + soca/index.rst configuration/index.rst diff --git a/docs/inside/jedi-components/soca/build.rst b/docs/inside/jedi-components/soca/build.rst new file mode 100644 index 00000000..3f210b00 --- /dev/null +++ b/docs/inside/jedi-components/soca/build.rst @@ -0,0 +1,106 @@ +.. _top-soca-build: + +.. _Building SOCA in Singularity: + +Building SOCA in Singularity +============================== + +This section describes how to configure and compile SOCA inside of a Singularity container. +``ecbuild`` (a wrapper of ``cmake``) is used for the configuration of the build and ``ctest`` to +confirm that the compiled code is working properly. Usage of ``cmake`` and ``ctest`` are described +in the :doc:`JEDI CMake, CTest, and ecbuild ` documentation. + +While SOCA can be complied on various architectures (HPC, workstations, ...), +this section only describes how to compile SOCA inside of a Singularity container. +Instruction on how to install and run Singularity is provided in the :doc:`JEDI development Singularity container +`. + +Download and run a shell inside of a Singularity container: + +.. code-block:: bash + + singularity pull library://jcsda/public/jedi-gnu-openmpi-dev # download the development container + singularity shell -e jedi-gnu-openmpi-dev_latest.sif # run a shell within a singularity container + +Clone the `1.0.0` tag of the SOCA repository + +.. code-block:: console + + git clone --branch 1.0.0 https://github.com/jcsda/soca.git + +This will create a SOCA directory that contains the MOM6 interface to JEDI as well as the +necessary dependencies provided as an ``ecbuild`` bundle in ``soca/bundle/CMakeLists.txt`` + +Default configuration and build of SOCA +----------------------------------------- + +.. code-block:: bash + + mkdir build + cd build + ecbuild ../soca/bundle # configure the build + make -j # compile + ctest # test all JEDI components including `soca` + +Extra build configurations for SOCA +------------------------------------- + +To enable the use of the `Community Radiative Transfer Model (CRTM) `_ +set the build option ``BUILD_CRTM`` for the ``ecbuild`` step above: + +.. code-block:: bash + + ecbuild -DBUILD_CRTM=ON ../soca/bundle + +To enable the use of the biogeochemistry model +`BLING `_ set the build +option ``ENABLE_OCEAN_BGC` for the ``ecbuild`` step above: + +.. code-block:: bash + + ecbuild -DENABLE_OCEAN_BGC=ON ../soca/bundle + +Built executables +----------------- + +After completing the SOCA build, users have access to executables under +``build/bin``, many of which are generated when building the projects on which +SOCA is dependent ( +:doc:`OOPS `, +:doc:`UFO `, +:doc:`SABER `). + +Most of these executables are model-specific implementations of generic applications that +are derived from the :code:`oops::Application` class, i.e., +:code:`oops/src/oops/runs/Application.h`. Descriptions of the generic applications are located under +the :doc:`OOPS Applications ` documentation. Here +we give short synopses of a few specific SOCA implementations. + +- Generic Applications + + - :code:`soca_convertstate.x` (:code:`oops::ConvertState`) + - :code:`soca_dirac.x` (:code:`oops::Dirac`) + - :code:`soca_forecast.x` (:code:`oops::Forecast`): similar to the + :code:`mom6.x` executable, but through the JEDI generic framework via the SOCA interface. + - :code:`soca_enspert.x` (:code:`oops::GenEnsPertB`) + - :code:`soca_ensrecenter.x` (:code:`oops::EnsRecenter`) + - :code:`soca_ensvariance` (:code:`oops::EnsVariance`) + - :code:`soca_hofx.x` (:code:`oops::HofX4D`) + - :code:`soca_hofx3d.x` (:code:`oops::HofX3D`) + - :code:`soca_parameters.x` (:code:`saber::EstimateParams`): used to estimate static + background error covariance and localization matrices + - :code:`soca_staticbinit.x` (:code:`oops::StaticBInit`): used to initialize the covariance model + - :code:`soca_var.x` (:code:`oops::Variational`): carries out many different + flavors of variational data assimilation (3DVar, 3DEnVar, 3DFGAT, 4DEnVar) with a variety of + incremental minimization algorithms + - :code:`soca_letkf.x` (:code:`oops::LocalEnsembleDA`) + - :code:`soca_hybridgain.x` (:code:`oops::HybridGain`) + - :code:`soca_enshofx.x` (:code:`oops::EnsembleApplication`) + +- SOCA specific Applications + + - :code:`soca_checkpoint_model.x` (:code:`soca::CheckpointModel`) + - :code:`soca_gridgen.x` (:code:`soca::GridGen`) + +Most of the SOCA executables are exercised in ctests. As users learn how to use SOCA for +larger-scale applications, it is useful to consider the ctests as examples and templates. diff --git a/docs/inside/jedi-components/soca/classes.rst b/docs/inside/jedi-components/soca/classes.rst new file mode 100644 index 00000000..a56a5fff --- /dev/null +++ b/docs/inside/jedi-components/soca/classes.rst @@ -0,0 +1,525 @@ + .. _top-soca-classes: + +.. _SOCA Classes and Configuration: + +Classes and Configuration +========================= + +This page describes the classes that are implemented in SOCA. It explains in broad terms what +they are responsible for, how they are implemented, the configuration options that are +available for controlling their behavior. + +.. contents:: Table of Contents + :depth: 3 + +.. _SOCA Geometry: + +Geometry +-------- +The ``Geometry`` class is responsible for creating and storing the MOM6 grid structure. The MOM6 +geometry object includes the grid specifcation, generated by calling :code:`MOM_domains_init()` that +lives within the MOM6 model. In practice, ``MOM_domains_init()`` is only called once using the +``soca_gridgen.x`` application which then saves the geometry object to disk for use by the +subsequent applications. + +A complete configuration yaml file for the geometry is given as follows: + +.. code:: yaml + + geometry: + geom_grid_file: soca_gridspec.nc # file name containing the geometry specification for soca + save_local_domain: true # save the local fms grid for each pe's, useful for debugging + full_init: true # call `MOM_domains_init` for a full initialization if true + mom6_input_nml: ./inputnml/input.nml # location of the fms input.nml namelist + fields metadata: ./fields_metadata.yml # list of soca metadata describing the fields + + +.. _SOCA State Increment: + +State / Increment +----------------- + +The ``State`` and ``Increment`` classes in SOCA have a fair amount of overlap between them. The +constructors are largely the same and they share a number of methods, such as read and write and +computing of norms. In order to simplify the code SOCA implements a fortran ``soca_fields`` class +in ``soca/src/soca/Fields/soca_fields_mod.F90`` that both ``State`` and ``Increment`` make use of. + +State +""""" + +``State`` objects are defined by a few keys in a yaml file. All of the options available to instantiate a state +are given in the following table + ++------------------------------+----------------------------------------------------------------------------+ +| state key | Description | ++==============================+============================================================================+ +| ``read_from_file`` | - 0 : set the states to 0 | +| | - 1, 3 : read from files | ++------------------------------+----------------------------------------------------------------------------+ +| ``basename`` | base path to ``ocn_filename``, ``ice_filename``, ``sfc_filename``, and | +| | ``wav_filename`` | ++------------------------------+----------------------------------------------------------------------------+ +| ``ocn_filename`` | MOM6 file name | ++------------------------------+----------------------------------------------------------------------------+ +| ``ice_filename`` | name of file containing the sea ice fields (optional) | ++------------------------------+----------------------------------------------------------------------------+ +| ``sfc_filename`` | name of the file containing the surface fields (optional) | ++------------------------------+----------------------------------------------------------------------------+ +| ``wav_filename`` | name of the file containing significant wave height (optional) | ++------------------------------+----------------------------------------------------------------------------+ +| ``date`` | ISO8601-formatted date | ++------------------------------+----------------------------------------------------------------------------+ +| ``state variables`` | ``[cicen, hicen, socn, tocn, ssh, hocn, uocn, vocn]`` | ++------------------------------+----------------------------------------------------------------------------+ + +where each of the ``state variables`` elements is defined inside the fields metadata file ( +:code:`soca/test/Data/fields_metadata.yml`). This file should not need to be modified unless the user +want to create new field types for use by SCOA. The metadata file specifies the following for each state +variable: + ++------------------------------+----------------------------------------------------------------------------+ +| Field metadata key | Description | ++==============================+============================================================================+ +| :code:`name` | Internal name used by soca code and config files | ++------------------------------+----------------------------------------------------------------------------+ +| :code:`grid` | ``h``, ``u``, or ``v`` (Default: ``h``) | ++------------------------------+----------------------------------------------------------------------------+ +| :code:`masked` | use land mask if true (Default: true) | ++------------------------------+----------------------------------------------------------------------------+ +| :code:`levels` | ``1`` or ``full_ocn`` (Default: ``1``) | ++------------------------------+----------------------------------------------------------------------------+ +| :code:`getval_name` | variable name expected by ``GetValues`` (Default: ) | ++------------------------------+----------------------------------------------------------------------------+ +| :code:`getval_name_surface` | ``GetValues`` variable name for 2D surface of 3D field (Default: ) | ++------------------------------+----------------------------------------------------------------------------+ +| :code:`io_file` | The restart file domain ``ocn``, ``sfc``, or ``ice`` (Default: ) | ++------------------------------+----------------------------------------------------------------------------+ +| :code:`io_name` | The variable name used in the restart IO (Default: ) | ++------------------------------+----------------------------------------------------------------------------+ +| :code:`property` | physical property of the variable ``positive_definite`` (Default: )| ++------------------------------+----------------------------------------------------------------------------+ + +for example, the following snippet of yaml configuration + +.. code:: yaml + + state: + read_from_file: 1 + basename: ./INPUT/ + ocn_filename: MOM.res.nc + ice_filename: cice.res.nc + sfc_filename: sfc.res.nc + wav_filename: wav.res.nc + date: 2018-04-15T00:00:00Z + state variables: [cicen, hicen, socn, tocn, ssh, hocn, uocn, vocn, swh] + +will instantiate a State object valid at ``2018-04-15T00:00:00Z`` +by reading the ocean variables ``[socn, tocn, ssh, hocn, uocn, vocn]`` from ``./INPUT/MOM.res.nc``, +the sea ice variable ``[cicen, hicen]`` from ``./INPUT/cice.res.nc`` and significant wave height +from ``./INPUT/wav.res.nc``. Since the ``State``'s read and write method in SOCA are implemented +using `FMS `_, the provided files for the ocean, sea ice, surface, +and wave will have to be in an FMS compatible format. + + +Increment +""""""""" +The ``Increment`` class defines the control variables and implements +the linear algebra methods necessary to solve the data assimilation problem. +In a similar way to the ``State``, they are instantiated through the use of configuration yaml files. +For example, the yaml snippet + +.. code:: yaml + + analysis variables: [ socn, tocn, ssh, hocn] + +will create an ``Increment`` object with salinity (``socn``), potential temperature (``tocn``) +and sea surface height (``ssh``). The field ``hocn`` represents the layer thickness and is currently +necessary to instantiate an ``Increment``, eventhough it is not currently used. + +.. _SOCA GetValues and LinearGetValues: + +GetValues and LinearGetValues +----------------------------- + +The ``GetValues`` and ``LinearGetValues`` methods are responsible for interpolating the fields +to the observation locations set by the observation operators. There are currently no configurable +parameters for these two classes. + + +.. _SOCA Model: + +Model +----- + +The ``Model`` class is where SOCA interacts with the MOM6 model physics to advance +a state forward in time. There are currently two implementations of the advance step, +one that uses MOM6's time-stepping in-core and is implemented in a similar way +to the MOM6 solo driver, and another one that reads previously generated +backgrounds in lieu of time-stepping. +The choice to interact with the model advance in-core or through files depends +on the application being run. +For example, there are clear benefits running the model advance in-core for +a multiple outer loop variational data assimilation system or when simulating +observations over a specific time window. +However, there is little benefits to including the model for a 3D applications +that only make use of one single background per data assimilation windows. + +Instantiation of ``Model`` objects is controlled through the use of a factory. +The yaml code snippet below illustrates how to instantiate a model object that +will run the time stepping from MOM6 in-core. This ``Model`` name is called +``SOCA``: + +.. code:: yaml + + model: + name: SOCA + tstep: PT1H + advance_mom6: 1 + model variables: [socn, tocn, uocn, vocn, ssh, hocn, + mld, layer_depth] + ++------------------------------+----------------------------------------------------------------------------+ +| model key | Description | ++==============================+============================================================================+ +| ``name`` | - ``SOCA`` - in-core use of MOM6 model advance | +| | - ``PseudoModel`` - model states read in through file IO | ++------------------------------+----------------------------------------------------------------------------+ +| ``tstep`` | the time stepping length for which OOPS interacts with MOM6 | ++------------------------------+----------------------------------------------------------------------------+ +| ``advance_mom6`` | only used for debugging purpose. | +| | ``0``: skip the model advance | +| | ``1``: advance MOM6 | ++------------------------------+----------------------------------------------------------------------------+ +| ``model variables`` | list of variables that will interact with the model | ++------------------------------+----------------------------------------------------------------------------+ + +The other model factory available to use within SOCA is the generic ``PseudoModel`` +from OOPS. This model reads background files that were previously generated by a MOM6 forecast application. +The yaml code snippet below illustrates how to instantiate a ``PseudoModel`` valid for +a 6 hour forecast: + +.. code:: yaml + + model: + name: PseudoModel + tstep: PT1H + state variables: &model_vars [socn, tocn, uocn, vocn, ssh, hocn, + mld, layer_depth] + states: + - date: 2018-04-15T01:00:00Z + basename: ./Data/ + ocn_filename: ocn.mom6.fc.2018-04-15T00:00:00Z.PT1H.nc + read_from_file: 1 + - date: 2018-04-15T02:00:00Z + basename: ./Data/ + ocn_filename: ocn.mom6.fc.2018-04-15T00:00:00Z.PT2H.nc + read_from_file: 1 + - date: 2018-04-15T03:00:00Z + basename: ./Data/ + ocn_filename: ocn.mom6.fc.2018-04-15T00:00:00Z.PT3H.nc + read_from_file: 1 + - date: 2018-04-15T04:00:00Z + basename: ./Data/ + ocn_filename: ocn.mom6.fc.2018-04-15T00:00:00Z.PT4H.nc + read_from_file: 1 + - date: 2018-04-15T05:00:00Z + basename: ./Data/ + ocn_filename: ocn.mom6.fc.2018-04-15T00:00:00Z.PT5H.nc + read_from_file: 1 + - date: 2018-04-15T06:00:00Z + basename: ./Data/ + ocn_filename: ocn.mom6.fc.2018-04-15T00:00:00Z.PT6H.nc + read_from_file: 1 + + +.. _SOCA Linear and nonlinear Variable Changes: + +Linear and nonlinear Variable Changes +------------------------------------- + +Ana2Model +"""""""""" + +The analysis to model variable change is responsible for rotating u/v pairs +from the model grid to north, as well as performing a log transformation +on certain variables. + ++---------------------+--------------------------------------------------------------+ +| Configuration | Description | ++=====================+==============================================================+ +| :code:`rotate` | vector rotation from logical grid to meridional/zonal basis.| +| | Variables are listed in pairs between the ``u`` and ``v`` | +| | parameters. | ++---------------------+--------------------------------------------------------------+ +| :code:`log` | Variables to undergo a log transform | ++---------------------+--------------------------------------------------------------+ + +.. code:: yaml + + - variable change: Ana2Model + rotate: + u: [uocn, taux] + v: [vocn, tauy] + log: + var: [chl] + output variables: *soca_vars + + +Balance +""""""" + +The balance linear variable change is applied to the unbalanced variables +and defines the cross correlation between ocean and sea ice +variables. + ++---------------------------+----------------------------------------------------------------------------------------------+ +| Configuration | Description | ++===========================+==============================================================================================+ +| :code:`dsdtmax` | ignore the dS/dT Jacobian for values greater than :code:`dsdtmax` | ++---------------------------+----------------------------------------------------------------------------------------------+ +| :code:`dsdzmin` | ignore the dS/dT Jacobian if the vertical salinity gradient is less than :code:`dsdzmin` | ++---------------------------+----------------------------------------------------------------------------------------------+ +| :code:`dtdzmin` | ignore the dS/dT Jacobian if the vertical temperature gradient is less than :code:`dtdzmin` | ++---------------------------+----------------------------------------------------------------------------------------------+ +| :code:`nlayers` | set the dynamic height based Jacobian to 0 for the top :code:`nlayers` levels | ++---------------------------+----------------------------------------------------------------------------------------------+ +| :code:`dcdt` | read the sea ice concentration Jacobian from file specified in the yaml configuration | ++---------------------------+----------------------------------------------------------------------------------------------+ + +.. code:: yaml + + variable changes: + - variable change: BalanceSOCA + dsdtmax: 0.1 + dsdzmin: 3.0e-6 + dtdzmin: 1.0e-6 + nlayers: 2 + dcdt: + filename: ./Data/kmask.nc + name: dcdt + input variables: *soca_vars + output variables: *soca_vars + + +BkgErr +"""""" + +This linear variable change reads the diagonal of the background error covariance matrix from a file. + ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------+ +| Configuration | Description | ++===========================+================================================================================================================================+ +| :code:`t_min` | sets the minimum and maximum value of the temperature background error to :code:`t_min` :code:`t_max` | +| :code:`t_max` | | ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------+ +| :code:`s_min` | sets the minimum and maximum value of the unbalanced salinity background error to :code:`s_min` :code:`s_max` | +| :code:`s_max` | | ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------+ +| :code:`ssh_min` | sets the minimum and maximum value of the unbalanced ssh background error to :code:`ssh_min` :code:`ssh_max` | +| :code:`ssh_max` | | ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------+ +| :code:`cicen_min` | sets the minimum and maximum value of the unbalanced ice concentration background error to :code:`cicen_min` :code:`cicen_max` | +| :code:`cicen_max` | | ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------+ +| :code:`hicen_min` | sets the minimum and maximum value of the ice thickness background error to :code:`hicen_min` :code:`hicen_max` | +| :code:`hicen_max` | | ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------+ +| :code:`chl_min` | sets the minimum and maximum value of the chlorophyll background error to :code:`chl_min` :code:`chl_max` | +| :code:`chl_max` | | ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------+ +| :code:`biop_min` | sets the minimum and maximum value of the chlorophyll background error to :code:`biop_min` :code:`biop_max` | +| :code:`biop_max` | | ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------+ +| :code:`swh_min` | sets the minimum and maximum value of the significant wave height background error to :code:`biop_min` :code:`biop_max` | +| :code:`swh_max` | | ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------+ + +.. code:: yaml + + variable changes: + - variable change: BkgErrSOCA + read_from_file: 3 + basename: ./ + ocn_filename: ocn.bkgerror.nc + ice_filename: ice.bkgerror.nc + wav_filename: wav.bkgerror.nc + date: *bkg_date + t_min: 0.0 + t_max: 2.5 + s_min: 0.0 + s_max: 0.2 + ssh_min: 0.0 # std ssh=0 => ssh balance applied as + ssh_max: 0.0 # strong constraint + cicen_min: 0.1 + cicen_max: 0.5 + hicen_min: 10.0 + hicen_max: 100.0 + chl_min: 0.003 + chl_max: 10.0 + biop_min: 0.0 + biop_max: 1.0e-6 + swh_min: 0.1 + swh_max: 1.0 + #fixed_std_sst: 0.005 # OK to create pretty increments + #fixed_std_sss: 0.001 # but that option should not exist! + input variables: *soca_vars + output variables: *soca_vars + + +BkgErrFilt +""""""""""" + +This linear variable change is used in conjunction with a background error covariance matrix +variable change. It returns the identity for varaibles that are not salinity, potential temperature +or sea surface height. + ++---------------------------+----------------------------------------------------------------------+ +| Configuration | Description | ++===========================+======================================================================+ +| :code:`ocean_depth_min` | returns 0 where the ocean depth is less than :code:`ocean_depth_min` | ++---------------------------+----------------------------------------------------------------------+ +| :code:`rescale_bkgerr` | rescaling factor | ++---------------------------+----------------------------------------------------------------------+ +| :code:`efold_z` | exponential e-folding scale | ++---------------------------+----------------------------------------------------------------------+ + +Output: +^^^^^^^ +- 0 for salinity, potential temperature and sea surface height if + the ocean is too shallow (less than :code:`ocean_depth_min`). +- :code:`rescale_bkgerr` * exp(-z/:code:`efold_z`) for salinity, potential temperature and sea surface height + where `z` is the positive ocean depth. +- 1 for variables other than salinity, potential temperature and sea surface height. + + +.. code:: yaml + + variable changes: + - variable change: BkgErrFilt + ocean_depth_min: 0 # [m] + rescale_bkgerr: 1.0 + efold_z: 2500.0 # [m] + input variables: *soca_vars + output variables: *soca_vars + + +BkgErrGodas +"""""""""""" + +This variable change derives the background error from the vertical gradient of the background potential +temperature, with a horizontally varying surface minimum for temperature that is read in from a file. + ++---------------------------+-------------------------------------------------------------------------------------------+ +| Configuration | Description | ++===========================+===========================================================================================+ +| :code:`t_min` / | set minimum and maximum values for the potential temperature background error | +| :code:`t_max` | | ++---------------------------+-------------------------------------------------------------------------------------------+ +| :code:`t_dz` | rescaling of the potential temperature background error | ++---------------------------+-------------------------------------------------------------------------------------------+ +| :code:`t_efold` | e-folding scale for sea surface temperature background error | ++---------------------------+-------------------------------------------------------------------------------------------+ +| :code:`s_min` / | set minimum and maximum values for the unbalanced salinity background error | +| :code:`s_max` | | ++---------------------------+-------------------------------------------------------------------------------------------+ +| :code:`ssh_min` / | set minimum and maximum values for the unbalanced sea surface height background error | +| :code:`ssh_max` | | ++---------------------------+-------------------------------------------------------------------------------------------+ +| :code:`ssh_phi_ex` | set ssh background error to :code:`ssh_max` where \|latitude\| >= :code:`ssh_phi_ex` | ++---------------------------+-------------------------------------------------------------------------------------------+ +| :code:`cicen_min` / | set minimum and maximum values for the unbalanced sea ice concentration background error | +| :code:`cicen_max` | | ++---------------------------+-------------------------------------------------------------------------------------------+ +| :code:`hicen_min` / | set minimum and maximum values for the sea ice thickness background error | +| :code:`hicen_max` | | ++---------------------------+-------------------------------------------------------------------------------------------+ + +.. code:: yaml + + variable changes: + - variable change: BkgErrGODAS + t_min: 0.1 + t_max: 2.0 + t_dz: 20.0 + t_efold: 500.0 + s_min: 0.0 + s_max: 0.25 + ssh_min: 0.0 # value at EQ + ssh_max: 0.1 # value in Extratropics + ssh_phi_ex: 20 # lat of transition from extratropics + cicen_min: 0.1 + cicen_max: 0.5 + hicen_min: 10.0 + hicen_max: 100.0 + input variables: *soca_vars + output variables: *soca_vars + + +HorizFilt +"""""""""" + +This linear variable change applies a 9-point stencil horizontal smoother to a field. + ++---------------------------+--------------------------------------------------+ +| Configuration | Description | ++===========================+==================================================+ +| :code:`niter` | number of iterations | ++---------------------------+--------------------------------------------------+ +| :code:`filter variables` | apply the filter to :code:`filter variables` | ++---------------------------+--------------------------------------------------+ + +.. code:: yaml + + variable changes: + - variable change: HorizFiltSOCA + niter: 2 + filter variables: *soca_vars + input variables: *soca_vars + output variables: *soca_vars + + +Model2GeoVaLs +"""""""""""""" +This class is responsible for converting ``State`` and ``Increment`` fields into the +fields required by ``GetValues`` and ``LinearGetValues``. + +The linear version is a simple identity operator, returning either a full 3D +field, or the top level if a surface field is required. + +The non-linear version, in addition to providing the same identity operators, +returns several derrived values: + +- :code:`distance_from_coast` - distance to the closest land grid box +- :code:`sea_area_fraction` - ``1.0`` where the mask indicates ocean, otherwise ``0.0`` +- :code:`mesoscale_representation_error` - ``dx/R`` +- :code:`surface_temperature_where_sea` - sst in Kelvin +- :code:`sea_floor_depth_below_sea_surface` - vertical summation of the ocean layer thicknesses. + + +VertConv +""""""""" + +This linear variable change applys a vertical convolution to a field. + ++---------------------------+-----------------------------------------------------------------------------------------------------------+ +| Configuration | Description | ++===========================+===========================================================================================================+ +| :code:`Lz_min` | minimum vertical decorrelation scale [m] | ++---------------------------+-----------------------------------------------------------------------------------------------------------+ +| :code:`Lz_mld` | if not 0, Use the mixed layer depth to calculate the vertical decorrelation scale within the mixed layer | ++---------------------------+-----------------------------------------------------------------------------------------------------------+ +| :code:`Lz_mld_max` | limit the application of the mixed layer depth deocrrelation scale to depth less than :code:`Lz_mld_max` | ++---------------------------+-----------------------------------------------------------------------------------------------------------+ +| :code:`scale_layer_thick` | minimum decorrelation scale as a multiple of the layer thickness | ++---------------------------+-----------------------------------------------------------------------------------------------------------+ + +.. code:: yaml + + variable changes: + - variable change: VertConvSOCA + Lz_min: 2.0 + Lz_mld: 1 + Lz_mld_max: 500.0 + scale_layer_thick: 1.5 + input variables: *soca_vars + output variables: *soca_vars diff --git a/docs/inside/jedi-components/soca/index.rst b/docs/inside/jedi-components/soca/index.rst new file mode 100644 index 00000000..61e1b84e --- /dev/null +++ b/docs/inside/jedi-components/soca/index.rst @@ -0,0 +1,21 @@ +###################### +SOCA +###################### + +Sea-ice, Ocean, and Coupled Assimilation (SOCA) is the interface between the generic components of +the JEDI system and MOM6. MOM6 is developed by NOAA's Geophysical Fluid Dynamics Laboratory (GFDL). + +These documents give a high-level overview of the SOCA code repository. A low-level description of +the classes, functions, and subroutines is also available, produced by means of the +`Doxygen document generator `_. + ++----------------------------------------------------------------------------------------+ +| `Doxygen Documentation `_ | ++----------------------------------------------------------------------------------------+ + + +.. toctree:: + + introduction + build + classes diff --git a/docs/inside/jedi-components/soca/introduction.rst b/docs/inside/jedi-components/soca/introduction.rst new file mode 100644 index 00000000..b9b63afb --- /dev/null +++ b/docs/inside/jedi-components/soca/introduction.rst @@ -0,0 +1,34 @@ +.. _top-soca-intro: + +Introduction +============ + +.. _SOCA Overview: + +Overview +-------- + +The Sea-ice, Ocean, and Coupled Assimilation project (SOCA) is the interface between the generic +components of the JEDI system and MOM6. `MOM6 `_ is developed by +NOAA's Geophysical Fluid Dynamics Laboratory (GFDL). Further documentation on the latest version of +the MOM6 model is `provided by GFDL `_ + +As well as all the source code needed to implement JEDI for the MOM6 grid and states, SOCA also +provides all the configuration for running example applications, low resolution testing states and +continuous integration. + +.. _SOCA Applications currently possible with soca: + +Applications currently possible with SOCA +------------------------------------------- +- Observation simulation +- 3DVar with multivariate parametric background error covariance +- EnVar and Hybrid-EnVar +- LETKF +- Biogeochemistry using BLING +- Wave analysis +- Reanalysis with the UFS and GEOS + +Various types of data assimilation are supported as part of the initial release of SOCA and +testing of these are routinely executed in the SOCA ``ctest`` suite. Toy example experiments +with 5-degree resolution are provided as part of the tutorial. diff --git a/docs/inside/jedi-components/ufo/marineufo.rst b/docs/inside/jedi-components/ufo/marineufo.rst new file mode 100644 index 00000000..748cf54f --- /dev/null +++ b/docs/inside/jedi-components/ufo/marineufo.rst @@ -0,0 +1,189 @@ +Absolute dynamic topography +--------------------------- + +Description: +^^^^^^^^^^^^ +This UFO simulates absolute dynamic topography. +It re-references the model's sea surface height to the +observed absolute dynamic topography. The calculated offset is also handeld in the +linear model and its adjoint. +This forward operator currently does not handle eustatic sea level changes. This later feature will +be part of a future release. + +Input variables: +^^^^^^^^^^^^^^^^ + + - sea_surface_height_above_geoid + +Examples of yaml: +^^^^^^^^^^^^^^^^^ + +.. code-block:: yaml + + obs space: + name: ADT + obsdatain: + obsfile: Data/ufo/testinput_tier_1/Jason-2-2018-04-15.nc + simulated variables: [obs_absolute_dynamic_topography] + obs operator: + name: ADT + +Cool skin +--------- + +Description: +^^^^^^^^^^^^ + +The cool skin UFO simulates the latent heat loss at the ocean surface given a bulk ocean surface temperature +and ocean-air fluxes. + +Input variables: +^^^^^^^^^^^^^^^^ + + - sea_surface_temperature + - net_downwelling_shortwave_radiation + - upward_latent_heat_flux_in_air + - upward_sensible_heat_flux_in_air + - net_downwelling_longwave_radiation + - friction_velocity_over_water + +Examples of yaml: +^^^^^^^^^^^^^^^^^ + +.. code-block:: yaml + + obs operator: + name: CoolSkin + obs space: + name: CoolSkin + obsdatain: + obsfile: Data/ufo/testinput_tier_1/coolskin_fake_obs_2018041500.nc + simulated variables: [sea_surface_temperature] + + +Insitu temperature +------------------ + +Description: +^^^^^^^^^^^^ + +This UFO uses the +`The Gibbs SeaWater (GSW) Oceanographic +Toolbox of TEOS-10 `_ +to simulate insitu temperature given sea water potential temperature, salinity and the +cell thicknesses. + +Input variables: +^^^^^^^^^^^^^^^^ + + - sea_water_potential_temperature + - sea_water_salinity + - sea_water_cell_thickness + +Examples of yaml: +^^^^^^^^^^^^^^^^^ + +.. code-block:: yaml + + obs operator: + name: InsituTemperature + obs space: + name: InsituTemperature + obsdatain: + obsfile: Data/ufo/testinput_tier_1/profile_2018-04-15.nc + simulated variables: [sea_water_temperature] + +Vertical Interpolation +---------------------- + +Description: +^^^^^^^^^^^^ + +This UFO is an adaptation of ref :ref:`obsops_vertinterp` for the ocean. The only vertical coordinate currently +suported is depth in absolute value. + +Examples of yaml: +^^^^^^^^^^^^^^^^^ + +.. code-block:: yaml + + + obs operator: + name: MarineVertInterp + obs space: + name: InsituSalinity + obsdatain: + obsfile: Data/ufo/testinput_tier_1/profile_2018-04-15.nc + simulated variables: [sea_water_salinity] + +Sea ice thickness +----------------- + + +Description: +^^^^^^^^^^^^ +The sea ice thickness UFO can simulate sea ice freeboard +or sea ice thickness from categorized ice concentration, thickness and snow depth. + +Input variables when simulating thickness: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + - sea_ice_category_area_fraction + - sea_ice_category_thickness + +Input variables when simulating freeboard: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + - sea_ice_category_area_fraction + - sea_ice_category_thickness + - sea_ice_category_snow_thickness + +Examples of yaml: +^^^^^^^^^^^^^^^^^ + +.. code-block:: yaml + + observations: + - obs space: + name: cryosat2_thickness + obsdatain: + obsfile: Data/ufo/testinput_tier_1/cryosat2-2018-04-15.nc + simulated variables: [sea_ice_thickness] + obs operator: + name: SeaIceThickness + + - obs space: + name: cryosat2_freeboard + obsdatain: + obsfile: Data/ufo/testinput_tier_1/cryosat2-2018-04-15.nc + simulated variables: [sea_ice_freeboard] + obs operator: + name: SeaIceThickness + + +Sea ice fraction +---------------- + +Description: +^^^^^^^^^^^^ +The sea ice fraction UFO returns the aggregate of the input sea ice categories. + +Input variables: +^^^^^^^^^^^^^^^^ + + - sea_ice_category_area_fraction + +Examples of yaml: +^^^^^^^^^^^^^^^^^ + +.. code-block:: yaml + + obs operator: + name: SeaIceFraction + linear obs operator: + name: SeaIceFraction + obs space: + name: SeaIceFraction + obsdatain: + obsfile: Data/ufo/testinput_tier_1/icec-2018-04-15.nc + simulated variables: [sea_ice_area_fraction] diff --git a/docs/inside/jedi-components/ufo/obsops.rst b/docs/inside/jedi-components/ufo/obsops.rst index 039fdc10..830091b8 100644 --- a/docs/inside/jedi-components/ufo/obsops.rst +++ b/docs/inside/jedi-components/ufo/obsops.rst @@ -755,9 +755,9 @@ Scatterometer neutral wind (Met Office) Description: ^^^^^^^^^^^^ -Met Office observation operator for treating scatterometer wind data -as a "neutral" 10m wind, i.e. where the effects of atmospheric stability are neglected. -For each observation we calculate the momentum roughness length using the Charnock relation. +Met Office observation operator for treating scatterometer wind data +as a "neutral" 10m wind, i.e. where the effects of atmospheric stability are neglected. +For each observation we calculate the momentum roughness length using the Charnock relation. We then calculate the Monin-Obukhov stability function for momentum, integrated to the model's lowest wind level. The calculations are dependant upon on whether we have stable or unstable conditions according to the Obukhov Length. The neutral 10m wind components are then calculated @@ -789,7 +789,7 @@ Examples of yaml: References: ^^^^^^^^^^^^^^^^^^^^^^ Cotton, J., 2018. Update on surface wind activities at the Met Office. -Proceedings for the 14 th International Winds Workshop, 23-27 April 2018, Jeju City, South Korea. +Proceedings for the 14 th International Winds Workshop, 23-27 April 2018, Jeju City, South Korea. Available from http://cimss.ssec.wisc.edu/iwwg/iww14/program/index.html. Background Error Vertical Interpolation @@ -873,3 +873,8 @@ Example See the listing in the :ref:`Background Error Vertical Interpolation Example` section of the documentation of the Background Error Vertical Interpolation operator. + +.. + Link to the marine ufo + +.. include:: marineufo.rst diff --git a/docs/inside/jedi-components/ufo/qcfilters/obsfunctions/DrawObsErrorFromFile.rst b/docs/inside/jedi-components/ufo/qcfilters/obsfunctions/DrawObsErrorFromFile.rst new file mode 100644 index 00000000..0543d75d --- /dev/null +++ b/docs/inside/jedi-components/ufo/qcfilters/obsfunctions/DrawObsErrorFromFile.rst @@ -0,0 +1,78 @@ +.. _DrawObsErrorFromFile: + +DrawObsErrorFromFile +==================== +The `DrawObsErrorFromFile` obsfunction is a simple wrapper around the :ref:`DrawValueFromFile` +obsfunction, specifically tailored to derive the observation error values by interpolating an array loaded from a file, +representing the variance or covariance matrix (of which only the diagonal elements are taken into account), indexed +by coordinates whose names correspond to ObsSpace variables. This file can potentially contain a collection ("stack") +of such matrices. + +Particularities of files representing variance or covariance +------------------------------------------------------------ + +In using `DrawObsErrorFromFile`, differently to :ref:`DrawValueFromFile`, we identify +our payload variable to have group `ErrorVariance`. That is, we do not specify the group in the yaml. + +For NetCDF, we additionally support pulling out the diagonals where the file contains a covariance matrix. +We identify whether the input NetCDF represents a covariance matrix by the presence of a `full = "true"` +attribute for our payload variable, then when true, we collapse the first dimension. + +Example +....... +The following NetCDF metadata describes the dependence of a full covariance matrix (with rows and columns +corresponding to channel numbers) on multiple variables (`latitude_band@MetaData`, +`processing_center@MetaData` and `satellite_id@MetaData(index)`): :: + + netcdf mydata { + dimensions: + channel_number = 10 ; + channel_number@MetaData = 10 ; + index = 8 ; + variables: + float air_temperature@ErrorVariance(channel_number, channel_number@MetaData, index) ; + air_temperature@ErrorVariance:coordinates = "latitude_band@MetaData \ + processing_center@MetaData satellite_id@MetaData" ; + string air_temperature@ErrorVariance:full = "true" ; + int index(index) ; + int channel_number(channel_number) ; + int channel_number@MetaData(channel_number@MetaData) ; + int latitude_band@MetaData(index) ; + int processing_center@MetaData(index) ; + int satellite_id@MetaData(index) ; + ... + } + +Notice how a channel_number* describes the outermost two dimensions. The very outermost +dimension is collapsed and discarded after extracting the diagonal elements of the covariance +matrices, so its name can be arbitrary. This allows us to conform to CF conventions, +which forbids multiple axes of an array to be indexed by the same coordinate. +The name of the dimension that remains after the collapse needs to match a variable name or be +set to `channel_number@MetaData` if this dimension is indexed by channel numbers (which aren't +represented by an ObsSpace variable). + +Now we illustrate how we might read and interpolate this data to derive our observation error. This +also demonstrates specifying the :code:`channels` option, resulting in an implicit interpolation by +channel number: + +.. code-block:: yaml + + - Filter: Perform Action + filter variables: + - name: air_temperature + channels: &all_channels 1-3 + action: + name: assign error + error function: + name: DrawObsErrorFromFile@ObsFunction + channels: *all_channels + options: + file: + channels: *all_channels + interpolation: + - name: satellite_id@MetaData + method: exact + - name: processing_center@MetaData + method: exact + - name: latitude_band@MetaData + method: nearest diff --git a/docs/inside/jedi-components/ufo/qcfilters/obsfunctions/DrawValueFromFile.rst b/docs/inside/jedi-components/ufo/qcfilters/obsfunctions/DrawValueFromFile.rst new file mode 100644 index 00000000..a46b3689 --- /dev/null +++ b/docs/inside/jedi-components/ufo/qcfilters/obsfunctions/DrawValueFromFile.rst @@ -0,0 +1,306 @@ +.. _DrawValueFromFile: + +DrawValueFromFile +================= +The purpose of this obsfunction is to produce values by interpolating an array loaded from a file, +indexed by coordinates whose names correspond to ObsSpace variables. + +Values produced by this ObsFunction must be `float`, `int` or `std::string`, though coordinates +themselves can be defined as `float`, `int`, `std::string` or `util::DateTime`. + +Note that the return type of the obsfunction is specified in the group name:: + + DrawValueFromFile@ObsFunction -> Float return + DrawValueFromFile@IntObsFunction -> Integer return + DrawValueFromFile@StringObsFunction -> String return + +Example 1 (minimal) +................... +Here is an illustrative example where we derive some new variable in ObsSpace by +extracting data from a CSV file column identified by the :code:`group` option (`DerivedObsValue` +is chosen in the examples below). + +.. code-block:: yaml + + - filter: Variable Assignment + assignments: + - name: + function: + name: DrawValueFromFile@ObsFunction + options: + file: # path to the CSV/NetCDF file + group: DerivedObsValue # group with the payload variable + interpolation: + - name: satellite_id@MetaData + method: exact + +and the CSV file, located at :code:``, might look like this: + +.. code-block:: + + station_id@MetaData,air_temperature@DerivedObsValue + string,float + ABC,0.1 + DEF,0.2 + GHI,0.3 + +The input file is loaded and at each location, the value of `air_temperature@DerivedObsValue` is extracted by + +* selecting the row of the CSV file in which the value in the :code:`station_id@MetaData` column + matches exactly the value of the :code:`station_id@MetaData` ObsSpace variable at that location and +* taking the value of the :code:`air_temperature@DerivedObsValue` column from the selected row. + +It is possible to customize this process in several ways by + +* making the `air_temperature@DerivedObsValue` dependent on more than one variable (see :ref:`interpolate example 2` below). +* using other interpolation methods than exact match (for example nearest-neighbor match or linear interpolation). +* using a NetCDF rather than a CSV input file via the :code:`file` option. + +:code:`options` +............... + +* :code:`group`: Group to identify the payload array (array being extracted/interpolated). + This allows us to hold more than 1 payload per file if we were so inclined as long as each belongs to a different group. +* :code:`channels`: (Optional) List of channel numbers to match from our payload variable. See :ref:`interpolate example 2` below. +* :code:`file`: Path to an input NetCDF or CSV file. The input file formats are described in more detail below. +* :code:`interpolation`: A list of one or more elements indicating how to map specific ObsSpace + variables to slices of arrays loaded from the input file. This list is described in more detail below. + +.. _DataExtractorInputFileFormats: + +Input file formats +.................. +Supported file formats (backends) include NetCDF and CSV. Here we go into a little detail about these +formats, described in detail below. + +CSV +!!! + +An input CSV file should have the following structure: + +* First line: comma-separated column names in ioda-v1 style (:code:`var@Group`) or ioda-v2 style + (:code:`Group/var`) +* Second line: comma-separated column data types (datetime, float, int or string) +* Further lines: comma-separated data entries. + +The number of entries in each line should be the same. The column order does not matter. One of the +columns should belong to the group specified in the :code:`group` option, indicating the payload array. +Its data type should be either :code:`float` or :code:`int`. +The values from the other columns (sometimes called `coordinates` below) are compared against ObsSpace +variables with the same names to determine the row or rows from which the payload is +extracted at each location. The details of this comparison (e.g. whether an exact match is +required, the nearest match is used, or piecewise linear interpolation is performed) depend on the +:code:`interpolation` option described below. + +Notes: + +* A column containing channel numbers (which aren't stored in a separate ObsSpace variable) + should be labelled :code:`channel_number@MetaData` or :code:`MetaData/channel_number`. + +* Single underscores serve as placeholders for missing values; for example, the following row + + .. code-block:: + + ABC,_,_ + + contains missing values in the second and third columns. + +NetCDF +!!!!!! + +ioda-v1 and ioda-v2-style NetCDF files are supported. ioda-v1-style files should have the +following structure: + +* They contain a 1D, 2D or 3D payload array of type :code:`float` or :code:`int` or + :code:`std::string` with unique group name (that is, a name ending with :code:`@`). + +* Each dimension of this array should be indexed by at least one 1D coordinate array. Coordinates + can be of type :code:`float`, :code:`int` or :code:`string`. Datetimes should be represented as + ISO-8601 strings (e.g. "2001-01-01T00:00:00Z"). Coordinate names should correspond to names of ObsSpace variables. Use the name + :code:`channel_number@MetaData` for channel numbers (for which there is no dedicated ObsSpace + variable). + +ioda-v2-style files are similar except that + +* Our payload array should be placed in the :code:`` group (rather than + with a :code:`@` suffix). +* Coordinate variables should be placed in appropriate groups, e.g. :code:`MetaData`. Because + of the limitations of the NetCDF file format, these variables can only be used as auxiliary + coordinates of the payload variable (listed in its :code:`coordinates` attribute). + + +.. _DrawValueFromFileInterpolation: + +The :code:`interpolation` option +................................ + +This list indicates which ObsSpace variables, and in which order, will be used as criteria for the extract step. + +Each element of this list should have the following attributes: + +* :code:`name`: Name of an ObsSpace variable (and of a coordinate present in the input CSV or NetCDF + file). +* :code:`method`: Method used to map values of this variable at individual location to matching slices + of the payload array loaded from the input file. This can be one of: + + - :code:`exact`: Selects slices where the coordinate matches exactly the value of the specified + ObsSpace variable. + + If no match is found, an error is reported unless there are slices where the indexing + coordinate is set to the missing value placeholder; in this case these slices are selected + instead. This can be used to define a fallback value (used if there is no exact match). + + This is the only method that can be used for variables of type :code:`string`. + + - :code:`nearest`: Selects slices where the coordinate is closest to the value of the + specified ObsSpace variable. + + In case of a tie (e.g. if the value of the ObsSpace variable is 3 and the coordinate contains + values 2 and 4, but not 3), the smaller of the candidate coordinate values is used (in this + example, 2). This behaviour is arbitrarily chosen. + + - :code:`least upper bound`: Select slices corresponding to the least value of the coordinate + greater than or equal to the value of the specified ObsSpace variable. + + - :code:`greatest upper bound`: Select slices corresponding to the greatest value of the coordinate + less than or equal to the value of the specified ObsSpace variable. + + - :code:`linear`: Performs a piecewise linear interpolation along the dimension indexed by the + specified ObsSpace variable. + + This method is supported only by the obs function producing a float (not an int or a string). + It can only be used for the final indexing variable, since it does not select slices, but + produces the final result (a single value). + + - :code:`bilinear`: Performs a bilinear interpolation along two dimensions indexed by the ObsSpace + variables. + + This method is supported only by the obs function producing a float (not an int or a string). + It can only be used for the final two indexing variables, since it does not select slices, but + produces the final result (a single value). + + * :code:`extrapolation mode`: Chosen behaviour in the case where an extraction step leads to extrapolation. + + By default (i.e. where no extrapolation is specified), no extrapolation is performed. That is, an + exception is thrown where the point being extracted lies beyond the coordinate value range for the + chosen interpolation algorithm. + Various extrapolation modes are available, detailed below. + + - :code:`error`: Throw an exception. This is the default behaviour when extrapolation mode is undefined. + + - :code:`nearest`: Pick nearest index. + + - :code:`missing`: Return a missing value indicator. Any subsequent extraction stages are then ignored. + + +At each location the criterion variables specified in the :code:`interpolation` list are inspected +in order, successively restricting the range of selected slices. An error is reported if the end +result is an empty range of slices or (unless linear interpolation is used for the last criterion +variable) a range containing more than one slice. + +Note: If the :code:`channels` option has been specified, the channel number is implicitly used as the +first criterion variable and needs to match exactly a value from the :code:`channel_number@MetaData` coordinate. + +The following examples illustrate more advanced usage of this obsfunction. + +.. _interpolate example 2: + +Example 2 (multi-channel) +......................... +Here we illustrate how we might extend our first example by having multiple +channels as well as additional variables over which the payload varies. + +.. code-block:: yaml + + - filter: Variable Assignment + assignments: + - name: + function: + name: DrawValueFromFile@ObsFunction + channels: &all_channels 1-3 + options: + file: # path to the CSV/NetCDF file + channels: *all_channels + group: DerivedObsValue # group with the payload variable + interpolation: + - name: satellite_id@MetaData + method: exact + - name: processing_center@MetaData + method: exact + - name: air_pressure@MetaData + method: linear + +Note the channel selection, using standard yaml syntax. Internally, channel number +extraction is an 'exact' match step, done before any user defined interpolation takes place. +Since there is no channel number variable in ObsSpace, we instead expect input data containing +channel information to be described by the name `channel_number@MetaData` as mentioned in +:ref:`here `. + +This might be described by a CSV similar to: :: + + station_id@MetaData,air_pressure@MetaData,channel_number@MetaData,mydata@DerivedObsValue + string,float,int,float + ABC,30000,0, 0.1 + ABC,60000,0, 0.2 + ... + +Our NetCDF might look something like: :: + + netcdf mydata { + dimensions: + index = 10 ; + variables: + float mydata@DerivedObsValue(index) ; + int index(index) ; + int channel_number@MetaData(index) ; + int satellite_id@MetaData(index) ; + float air_pressure@MetaData(index) ; + ... + } + + +Example 3 (extrapolation) +......................... +This time, we demonstrate utilising various extrapolation methods for our extract/interpolation +steps: + +.. code-block:: yaml + + - filter: Variable Assignment + assignments: + - name: + function: + name: DrawValueFromFile@ObsFunction + options: + file: # path to the CSV/NetCDF file + group: DerivedObsValue # group with the payload variable + interpolation: + - name: satellite_id@MetaData + method: exact + extrapolation mode: error + - name: longitude@MetaData + method: nearest + extrapolation mode: missing + - name: latitude@MetaData + method: nearest + extrapolation mode: nearest + +Example 4 (bilinear interpolation) +.................................. +Next we demonstrate the use of bilinear interpolation of two variables: + +.. code-block:: yaml + + - filter: Variable Assignment + assignments: + - name: + function: + name: DrawValueFromFile@ObsFunction + options: + file: # path to the CSV/NetCDF file + group: DerivedObsValue # group with the payload variable + interpolation: + - name: longitude@MetaData + method: bilinear + - name: latitude@MetaData + method: bilinear diff --git a/docs/inside/jedi-components/ufo/qcfilters/obsfunctions/index.rst b/docs/inside/jedi-components/ufo/qcfilters/obsfunctions/index.rst index c4938a64..d590ccc2 100644 --- a/docs/inside/jedi-components/ufo/qcfilters/obsfunctions/index.rst +++ b/docs/inside/jedi-components/ufo/qcfilters/obsfunctions/index.rst @@ -101,6 +101,11 @@ filters into separate parts would have an obfuscating effect. :ref:`WindDirAngleDiff ` Compute wind direction angle different between observation and model +:ref:`DrawValueFromFile ` + Derive values by interpolating an array loaded from a file, indexed by coordinates whose names correspond to ObsSpace variables + +:ref:`DrawObsErrorFromFile ` + Derive observation error values by interpolating an array loaded from a file, representing the variance or covariance matrix (of which only the diagonal elements are taken into account), indexed by coordinates whose names correspond to ObsSpace variables. This file can potentially contain a collection ("stack") of such matrices. .. toctree:: :hidden: @@ -112,6 +117,8 @@ filters into separate parts would have an obfuscating effect. CLWRetMW CLWRetMW_SSMIS CLWRetSymmetricMW + DrawObsErrorFromFile + DrawValueFromFile HydrometeorCheckAMSUA HydrometeorCheckATMS InterChannelConsistencyCheck @@ -137,4 +144,3 @@ filters into separate parts would have an obfuscating effect. SetSurfaceType TropopauseEstimate WindDirAngleDiff - diff --git a/docs/inside/jedi-components/ufo/varbc.rst b/docs/inside/jedi-components/ufo/varbc.rst index 1e3a4db1..38aeec15 100644 --- a/docs/inside/jedi-components/ufo/varbc.rst +++ b/docs/inside/jedi-components/ufo/varbc.rst @@ -14,7 +14,7 @@ Linear combination formulation .. math:: - \vec{y} = H(\vec{x}) + \sum_{i=0}^{N} \beta_i p_i(\vec{x}) + \tilde{\vec{e}_o} + \vec{y} = H(\vec{x}) + \sum_{i=0}^{N} \beta_i p_i(\vec{x}) + \tilde{\vec{e}_o} with scalar coefficients :math:`\beta_i, i = 0, . . . ,N` . The selection of predictors :math:`p_i(\vec{x}), i = 1, . . . ,N` is flexible and depends on the instrument and channel. @@ -46,14 +46,14 @@ Adjoint of the bias model In the incremental formulation of the variational analysis, nonlinear observation operators are linearized about the latest outer-loop estimate :math:`\overline{\vec{x}}` of :math:`\vec{x}` . Similarly, for the modified operator we use .. math:: - + H(\vec{x}, \beta) \approx H(\overline{\vec{x}}, \beta) & = H(\overline{\vec{x}}) + \sum_{i=0}^{N} \beta_i p_i(\overline{\vec{x}}) \\ & = H(\overline{\vec{x}}) + \mathcal{P}(\overline{\vec{x}}) \cdot \vec{\beta} where :math:`\mathcal{P}(\overline{\vec{x}})` is a :math:`m × n` predictor matrix consisting of :math:`n` predictors evaluated on :math:`m` observation locations. - The modification to :math:`H(\vec{x})` is therefore additive and linear in the bias parameters, and its adjoint with respect to these additional control parameters is trivial to implement. - + The modification to :math:`H(\vec{x})` is therefore additive and linear in the bias parameters, and its adjoint with respect to these additional control parameters is trivial to implement. + For the linear predictor model :eq:`Hop`, the derivatives with respect to the parameters are simply the values of the predictors at the observation locations .. math:: @@ -95,14 +95,14 @@ Background error covariance .. note:: - - For example, taking :math:`N_j = 10,000` for all parameters, the system will adapt quickly to changes in the bias for a clean channel generating thousands of radiances per analysis cycle. - - On the other hand, it will respond slowly to a cloudy channel that generates only a few hundreds of data per cycle. + - For example, taking :math:`N_j = 10,000` for all parameters, the system will adapt quickly to changes in the bias for a clean channel generating thousands of radiances per analysis cycle. + - On the other hand, it will respond slowly to a cloudy channel that generates only a few hundreds of data per cycle. .. note:: - - When the :math:`N_j` are sufficiently large (say, :math:`N_j >> 100` ), the effect of neglecting off-diagonal elements of the parameter background error covariance matrix should be insignificant. This is because :math:`\mathcal{O}(N_j)` observations are used to estimate just a few bias parameters; the estimation errors will be small even when the estimation is suboptimal. - - The situation is, of course, very different for the state estimation, which can be extremely sensitive to the specification of the background error covariances, especially in data-sparse areas. + - When the :math:`N_j` are sufficiently large (say, :math:`N_j >> 100` ), the effect of neglecting off-diagonal elements of the parameter background error covariance matrix should be insignificant. This is because :math:`\mathcal{O}(N_j)` observations are used to estimate just a few bias parameters; the estimation errors will be small even when the estimation is suboptimal. + - The situation is, of course, very different for the state estimation, which can be extremely sensitive to the specification of the background error covariances, especially in data-sparse areas. VarBC example +++++++++++++++++++++++++ @@ -141,7 +141,7 @@ To use the bias correction in an observation operator, add the :code:`obs bias` Here is the detailed explanation: 1. Defines the predictors (required) - + Here, we defined 6 predictors to be used for VarBC, which are :code:`constant`, :code:`emissivity`, and 1st, 2nd, 3rd, 4th order :code:`scan_angle`, respectively. To find what predictor functions are available, please refer to directory :code:`ufo/src/ufo/predictors/`. .. code-block:: yaml @@ -292,119 +292,16 @@ a particular bias-corrected variable and should have the following attributes: * :code:`name`: Name of a bias-corrected variable. * :code:`channels`: (Optional) List of channel numbers of the bias-corrected variable. -* :code:`file`: Path to an input NetCDF or CSV file. The input file formats are described in more detail below. -* :code:`interpolation` A list of one or more elements indicating how to map specific ObsSpace variables to slices of arrays loaded from the input file. This list is described in more detail below. +* :code:`file`: Path to an input NetCDF or CSV file. See :ref:`here ` + for supported file formats. However, note that unlike :ref:`DrawValueFromFile`, + we don't specify the group name corresponding to our payload array. We expect it to be ``ObsBias``. +* :code:`interpolation`: A list of one or more elements indicating how to map specific + ObsSpace variables to slices of arrays loaded from the input file. See + :ref:`here ` for further details. The predictor produces zeros for all bias-corrected variables missing from the :code:`corrected variables` list. -Input file formats -.................. - -CSV -!!! - -An input CSV file should have the following structure: - -* First line: comma-separated column names in ioda-v1 style (:code:`var@Group`) or ioda-v2 style - (:code:`Group/var`) -* Second line: comma-separated column data types (datetime, float, int or string) -* Further lines: comma-separated data entries. - -The number of entries in each line should be the same. The column order does not matter. One of the -columns should belong to the :code:`ObsBias` group and contain the bias corrections to use in -specific circumstances. Its data type should be either :code:`float` or :code:`int`. The values -from the other columns (sometimes called `coordinates` below) are compared against ObsSpace -variables with the same names to determine the row or rows from which the bias correction is -extracted at each location. The details of this comparison (e.g. whether an exact match is -required, the nearest match is used, or piecewise linear interpolation is performed) depend on the -:code:`interpolation` option described below. - -Notes: - -* A column containing channel numbers (which aren't stored in a separate ObsSpace variable) - should be labelled :code:`channel_number@MetaData` or :code:`MetaData/channel_number`, as shown - in :ref:`interpolate example 3` below. - -* Single underscores serve as placeholders for missing values; for example, the following row - - .. code-block:: - - ABC,_,_ - - contains missing values in the second and third columns. - -NetCDF -!!!!!! - -ioda-v1 and ioda-v2-style NetCDF files are supported. ioda-v1-style files should have the -following structure: - -* They should contain exactly one 1D or 2D array of type :code:`float` with a name ending with - :code:`@ObsBias` and containing bias corrections. - -* Each dimension of this array should be indexed by at least one 1D coordinate array. Coordinates - can be of type :code:`float`, :code:`int` or :code:`string`. Datetimes should be represented as - ISO-8601 strings. Coordinate names should correspond to names of ObsSpace variables. Use the name - :code:`channel_number@MetaData` for channel numbers (for which there is no dedicated ObsSpace - variable). - -ioda-v2-style files are similar except that - -* Bias corrections should be stored in an array placed in the :code:`ObsBias` group (rather than - with a :code:`@ObsBias` suffix). -* Coordinate variables should be placed in appropriate groups, e.g. :code:`MetaData`. Because - of the limitations of the NetCDF file format, these variables can only be used as auxiliary - coordinates of the payload variable (listed in its :code:`coordinates` attribute). - -The :code:`interpolation` option -................................ - -This list indicates which ObsSpace variables, and in which order, will be used as criteria determining the value produced by the predictor. - -Each element of this list should have the following attributes: - -* :code:`name`: Name of an ObsSpace variable (and of a coordinate present in the input CSV or NetCDF - file). -* :code:`method`: Method used to map values of this variable at individual location to matching slices - of the bias correction array loaded from the input file. This can be one of: - - - :code:`exact`: Selects slices where the coordinate matches exactly the value of the specified - ObsSpace variable. - - If no match is found, an error is reported unless there are slices where the indexing - coordinate is set to the missing value placeholder; in this case these slices are selected - instead. This can be used to define a fallback value (used if there is no exact match), as shown - in :ref:`interpolate example 4` below. - - This is the only method that can be used for variables of type :code:`string`. - - - :code:`nearest`: Selects slices where the coordinate is closest to the value of the - specified ObsSpace variable. - - In case of a tie (e.g. if the value of the ObsSpace variable is 3 and the coordinate contains - values 2 and 4, but not 3), the smaller of the candidate coordinate values is used (in this - example, 2). - - - :code:`least upper bound`: Select slices corresponding to the least value of the coordinate - greater than or equal to the value of the specified ObsSpace variable. - - - :code:`greatest upper bound`: Select slices corresponding to the greatest value of the coordinate - less than or equal to the value of the specified ObsSpace variable. - - - :code:`linear`: Performs a piecewise linear interpolation along the dimension indexed by the - specified ObsSpace variable. - - This method can only be used in the last element of the :code:`interpolation` list. - -At each location the criterion variables specified in the :code:`interpolation` list are inspected -in order, successively restricting the range of selected slices. An error is reported if the end -result is an empty range of slices or (unless linear interpolation is used for the last criterion -variable) a range containing more than one slice. - -Note: If the :code:`channels` option has been specified, the channel number is implicitly used as the -first criterion variable and needs to match exactly a value from the :code:`channel_number@MetaData` coordinate. - The following examples illustrate more advanced applications of this predictor. Example 2 (multiple criterion variables, linear interpolation) diff --git a/docs/inside/testing/unit_testing.rst b/docs/inside/testing/unit_testing.rst index 90d5f289..9e57bd4d 100644 --- a/docs/inside/testing/unit_testing.rst +++ b/docs/inside/testing/unit_testing.rst @@ -402,6 +402,12 @@ The test channel output and the reference file are compared line-by-line, and mu relative_difference = |reference - test|/(0.5*(reference + test)) +You may choose to use :code:`float absolute tolerance` if you prefer, and in this case the comparison will be done using the absolute difference instead of relative for all the float numbers in the test. This can be useful when comparing very small numbers too close to zero. If you specify both :code:`float relative tolerance` and :code:`float absolute tolerance` in the yaml file, the absolute comparison will be used and a warning will be generated. + +.. code:: bash + + absolute_difference = |reference - test| + If the test channel fails to match the reference file, an exception from a sub-class of :code:`oops::TestReferenceError` containing relevant information about the cause of the mismatch is thrown. Additional options for the :code:`test:` YAML sub-section: diff --git a/docs/learning/tutorials/level2/dev-container_soca.rst b/docs/learning/tutorials/level2/dev-container_soca.rst new file mode 100644 index 00000000..8dce5419 --- /dev/null +++ b/docs/learning/tutorials/level2/dev-container_soca.rst @@ -0,0 +1,165 @@ +.. _top-tut-dev-container-soca: + +Tutorial: Build and Test the MOM6 interface to JEDI (SOCA) +========================================================== + +Learning Goals: + - How to download and run/enter a JEDI development container + - How to build the JEDI code from source + - How to run the JEDI unit test suite + +Prerequisites: + - read the :doc:`tutorial overview <../index>` + +Follow the instructions provided in :ref:`Building SOCA in Singularity` but +before proceeding, you may wish to take a few moments to :ref:`get to know the container `. + +From the build directory, run the SOCA test suite + +.. code-block:: console + + cd soca + ctest + +you should see an output similar to this one: + +.. code-block:: console + + Test project /home/gvernier/sandboxes/SOCA-1.0.0/build.soca/soca + Start 1: soca_coding_norms + 1/62 Test #1: soca_coding_norms ....................... Passed 1.12 sec + Start 2: test_soca_subsample_netcdf + 2/62 Test #2: test_soca_subsample_netcdf .............. Passed 4.45 sec + Start 3: test_soca_gridgen_small + 3/62 Test #3: test_soca_gridgen_small ................. Passed 0.44 sec + Start 4: test_soca_gridgen + 4/62 Test #4: test_soca_gridgen ....................... Passed 0.48 sec + Start 5: test_soca_convertstate + 5/62 Test #5: test_soca_convertstate .................. Passed 0.37 sec + Start 6: test_soca_convertstate_changevar + 6/62 Test #6: test_soca_convertstate_changevar ........ Passed 0.34 sec + Start 7: test_soca_forecast_identity + 7/62 Test #7: test_soca_forecast_identity ............. Passed 0.56 sec + Start 8: test_soca_forecast_mom6 + 8/62 Test #8: test_soca_forecast_mom6 ................. Passed 1.45 sec + Start 9: test_soca_forecast_mom6_bgc + 9/62 Test #9: test_soca_forecast_mom6_bgc ............. Passed 1.83 sec + Start 10: test_soca_forecast_pseudo + 10/62 Test #10: test_soca_forecast_pseudo ............... Passed 0.30 sec + Start 11: test_soca_static_socaerror_init + 11/62 Test #11: test_soca_static_socaerror_init ......... Passed 2.47 sec + Start 12: test_soca_static_socaerrorlowres_init + 12/62 Test #12: test_soca_static_socaerrorlowres_init ... Passed 0.60 sec + Start 13: test_soca_balance_mask + 13/62 Test #13: test_soca_balance_mask .................. Passed 0.30 sec + Start 14: test_soca_create_kmask + 14/62 Test #14: test_soca_create_kmask .................. Passed 0.17 sec + Start 15: test_soca_enspert + 15/62 Test #15: test_soca_enspert ....................... Passed 4.64 sec + Start 16: test_soca_makeobs + 16/62 Test #16: test_soca_makeobs ....................... Passed 1.22 sec + Start 17: test_soca_geometry + 17/62 Test #17: test_soca_geometry ...................... Passed 0.19 sec + Start 18: test_soca_geometry_iterator + 18/62 Test #18: test_soca_geometry_iterator ............. Passed 0.19 sec + Start 19: test_soca_geometryatm + 19/62 Test #19: test_soca_geometryatm ................... Passed 0.17 sec + Start 20: test_soca_state + 20/62 Test #20: test_soca_state ......................... Passed 1.04 sec + Start 21: test_soca_getvalues + 21/62 Test #21: test_soca_getvalues ..................... Passed 0.35 sec + Start 22: test_soca_model + 22/62 Test #22: test_soca_model ......................... Passed 1.86 sec + Start 23: test_soca_modelaux + 23/62 Test #23: test_soca_modelaux ...................... Passed 0.17 sec + Start 24: test_soca_increment + 24/62 Test #24: test_soca_increment ..................... Passed 0.28 sec + Start 25: test_soca_lineargetvalues + 25/62 Test #25: test_soca_lineargetvalues ............... Passed 0.29 sec + Start 26: test_soca_errorcovariance + 26/62 Test #26: test_soca_errorcovariance ............... Passed 0.30 sec + Start 27: test_soca_linearmodel + 27/62 Test #27: test_soca_linearmodel ................... Passed 1.18 sec + Start 28: test_soca_varchange_ana2model + 28/62 Test #28: test_soca_varchange_ana2model ........... Passed 0.25 sec + Start 29: test_soca_varchange_balance + 29/62 Test #29: test_soca_varchange_balance ............. Passed 0.34 sec + Start 30: test_soca_varchange_balance_TSSSH + 30/62 Test #30: test_soca_varchange_balance_TSSSH ....... Passed 0.33 sec + Start 31: test_soca_varchange_bkgerrfilt + 31/62 Test #31: test_soca_varchange_bkgerrfilt .......... Passed 0.23 sec + Start 32: test_soca_varchange_horizfilt + 32/62 Test #32: test_soca_varchange_horizfilt ........... Passed 0.27 sec + Start 33: test_soca_varchange_bkgerrsoca + 33/62 Test #33: test_soca_varchange_bkgerrsoca .......... Passed 0.39 sec + Start 34: test_soca_varchange_bkgerrgodas + 34/62 Test #34: test_soca_varchange_bkgerrgodas ......... Passed 2.71 sec + Start 35: test_soca_varchange_vertconv + 35/62 Test #35: test_soca_varchange_vertconv ............ Passed 0.32 sec + Start 36: test_soca_obslocalization + 36/62 Test #36: test_soca_obslocalization ............... Passed 0.23 sec + Start 37: test_soca_ensvariance + 37/62 Test #37: test_soca_ensvariance ................... Passed 0.60 sec + Start 38: test_soca_parameters_bump_loc + 38/62 Test #38: test_soca_parameters_bump_loc ........... Passed 0.69 sec + Start 39: test_soca_ensrecenter + 39/62 Test #39: test_soca_ensrecenter ................... Passed 0.66 sec + Start 40: test_soca_hybridgain + 40/62 Test #40: test_soca_hybridgain .................... Passed 0.53 sec + Start 41: test_soca_parameters_bump_cor_nicas + 41/62 Test #41: test_soca_parameters_bump_cor_nicas ..... Passed 1.46 sec + Start 42: test_soca_dirac_soca_cov + 42/62 Test #42: test_soca_dirac_soca_cov ................ Passed 1.26 sec + Start 43: test_soca_dirac_socahyb_cov + 43/62 Test #43: test_soca_dirac_socahyb_cov ............. Passed 1.54 sec + Start 44: test_soca_dirac_horizfilt + 44/62 Test #44: test_soca_dirac_horizfilt ............... Passed 0.35 sec + Start 45: test_soca_hofx_3d + 45/62 Test #45: test_soca_hofx_3d ....................... Passed 0.78 sec + Start 46: test_soca_hofx_4d + 46/62 Test #46: test_soca_hofx_4d ....................... Passed 1.31 sec + Start 47: test_soca_hofx_4d_pseudo + 47/62 Test #47: test_soca_hofx_4d_pseudo ................ Passed 0.54 sec + Start 48: test_soca_enshofx + 48/62 Test #48: test_soca_enshofx ....................... Passed 1.28 sec + Start 49: test_soca_3dvar_soca + 49/62 Test #49: test_soca_3dvar_soca .................... Passed 6.44 sec + Start 50: test_soca_3dvarbump + 50/62 Test #50: test_soca_3dvarbump ..................... Passed 4.04 sec + Start 51: test_soca_3dvar_godas + 51/62 Test #51: test_soca_3dvar_godas ................... Passed 5.18 sec + Start 52: test_soca_addincrement + 52/62 Test #52: test_soca_addincrement .................. Passed 0.28 sec + Start 53: test_soca_3dvarlowres_soca + 53/62 Test #53: test_soca_3dvarlowres_soca .............. Passed 4.69 sec + Start 54: test_soca_diffstates + 54/62 Test #54: test_soca_diffstates .................... Passed 0.34 sec + Start 55: test_soca_3dvarfgat + 55/62 Test #55: test_soca_3dvarfgat ..................... Passed 5.97 sec + Start 56: test_soca_3dvarfgat_pseudo + 56/62 Test #56: test_soca_3dvarfgat_pseudo .............. Passed 3.34 sec + Start 57: test_soca_3dhyb + 57/62 Test #57: test_soca_3dhyb ......................... Passed 2.80 sec + Start 58: test_soca_3dhybfgat + 58/62 Test #58: test_soca_3dhybfgat ..................... Passed 4.81 sec + Start 59: test_soca_letkf_observer + 59/62 Test #59: test_soca_letkf_observer ................ Passed 1.84 sec + Start 60: letkf_observer_post + 60/62 Test #60: letkf_observer_post ..................... Passed 0.47 sec + Start 61: test_soca_letkf_solver + 61/62 Test #61: test_soca_letkf_solver .................. Passed 0.58 sec + Start 62: test_soca_checkpointmodel + 62/62 Test #62: test_soca_checkpointmodel ............... Passed 0.52 sec + + 100% tests passed, 0 tests failed out of 62 + + Label Time Summary: + executable = 11.10 sec*proc (20 tests) + mpi = 11.10 sec*proc (20 tests) + script = 68.43 sec*proc (40 tests) + soca = 79.53 sec*proc (60 tests) + + Total Test time (real) = 84.20 sec + +Each of the ctest run multiple unit tests covering more than 90% of the SOCA code. +If you get test failures you may wish to consult the :doc:`FAQ <../../../FAQ/FAQ>`. diff --git a/docs/learning/tutorials/level2/index.rst b/docs/learning/tutorials/level2/index.rst index 6a5af365..6760a6f9 100644 --- a/docs/learning/tutorials/level2/index.rst +++ b/docs/learning/tutorials/level2/index.rst @@ -10,4 +10,6 @@ For users who wish to download and build the JEDI code themselves, with the help dev-container dev-container_mpas_jedi hofx-mpas - envar-mpas \ No newline at end of file + envar-mpas + dev-container_soca + soca diff --git a/docs/learning/tutorials/level2/soca.rst b/docs/learning/tutorials/level2/soca.rst new file mode 100644 index 00000000..55ef978b --- /dev/null +++ b/docs/learning/tutorials/level2/soca.rst @@ -0,0 +1,273 @@ +.. _top-tut-soca: + +Tutorial: Running the SOCA tutorial +=================================== + +Learning Goals: + - Perform all the necessary steps to run a low resolution variational data assimilation system with SOCA + +Prerequisites: + - :doc:`Build and Test the MOM6 interface to JEDI (SOCA) ` + +Overview +-------- + +In this tutorial we will be running several different applications that are necessary to run one cycle +of a 3DVar system and 3 cycles of a 3DVar FGAT. + +The scenario of the tutorial is as follows, +generate synthetic observations from a perturbed MOM6 forecast and subsequently +assimilate the synthetic observations using the unperturbed background as +initial conditions. + +After succesfully compiling SOCA, in the build directory, you should see a ``tutorial`` folder. ``cd`` into it. + +.. code-block:: console + + cd soca/tutorial + +along with ``cmake`` related files, it should contain the folowing scripts and yaml configuration files +needed to run the tutorial + +.. code-block:: console + + ├── bin # symbolic link to the JEDI executables + ├── config # static yaml configurations + │   ├── 3dvar.yaml # 3DVAR configuration example + │   ├── gridgen.yaml # `soca` grid generation + │   ├── pert_ic.yaml # B-matrix randomization + │   ├── staticb.yaml # horizontal convolution + │   └── synthetic_obs.yaml # generate synthetic obs + ├── Data # folder containing static MOM6 and SOCA files + ├── tutorial_3dvarfgat.sh # 3DVAR FGAT driver for multiple cycles + ├── tutorial_3dvar.sh # 3DVAR driver, analysis only + ├── tutorial_bump_op.sh # initialize the horizontal convolution + ├── tutorial_gridgen.sh # generate the grid and save it to disk + ├── tutorial_make_observations.sh # generate synthetic observations + ├── tutorial_perturb_ic.sh # perturb IC by randomizing the B-matrix + ├── tutorial_plot.py # observation and state space plotting tools + ├── tutorial_synthetic_observations.py # generate random locations for synthetic observations + └── tutorial_tools.sh # generate dynamic yaml configurations + +Step 1: Grid Generation +----------------------- +This step is required in order to save the `MOM6` geometry in a file for subsequent use. +To generate the grid, run + +.. code-block:: console + + ./tutorial_gridgen.sh + +if you open the ``tutorial_gridgen.sh`` script, you will see that it executes the ``soca_gridgen.x`` +application on two cores + +.. code-block:: bash + + OMP_NUM_THREADS=1 mpirun -np 2 ../bin/soca_gridgen.x ../config/gridgen.yaml + +with the yaml file ``gridgen.yaml`` as argument: + +.. code-block:: yaml + + geometry: + geom_grid_file: soca_gridspec.nc # name of the output file that contains the geometry information + save_local_domain: true # save the local FMS domains if true + full_init: true # directive to the MOM6 initialization. The grid generation process + # needs a complete initialization of MOM6 + mom6_input_nml: ./inputnml/input.nml # location of the FMS Fortran namelist + fields metadata: ./fields_metadata.yml # location of the field metatdata yaml file + +The ``tutorial_gridgen.sh`` script will create a ``scratch_gridgen`` +folder in which the application is executed, as well as create +a ``./static/soca_gridspec.nc`` NetCDF grid file. Using ``ncdump`` to investigate the metadata will +show that the file contains a subset of the usual MOM6 geometry definition. + +Under ``scratch_gridgen`` you will also find two NetCDF files, ``geom_output_00000.nc`` and +``geom_output_00001.nc`` which contain the local FMS geometry, one file per MPI worker. This output is controlled +by the yaml key ``save_local_domain`` and can be turned off by setting it to ``false`` +or simply commenting it out. + +While running the tutorial applications, you will see this type of warnings from ``MOM6``: + +.. code-block:: console + + WARNING from PE 0: ... + +They can be ignored. + +Step 2: Initialize the correlation operator using the NICAS method +------------------------------------------------------------------ +This step is a core part of the background error covariance model that will be used in the next steps +of this tutorial. To generate the horizontal correlation operator, run + +.. code-block:: console + + ./tutorial_bump_op.sh + +The files necessary to subsequently initialize this operator are saved under ``static/bump/``. +These files are currently layout dependent. If you were to modify the number of processors used to run this +applications, all subsequent applications making use of this operator will have to be run on the same number +of cores. + +The ``tutorial_bump_op.sh`` scripts executes the following JEDI applications on two cores + +.. code-block:: console + + OMP_NUM_THREADS=1 mpirun -np 2 ../bin/soca_staticbinit.x ../config/staticb.yaml + +with the yaml file ``staticb.yaml`` as argument. A relevant snippet of that yaml file +that controls the horizontal correlation operator is shown below: + +.. code-block:: yaml + + analysis variables: &ana_vars [socn, tocn, ssh] # yaml anchor defining the control variables + + background error: + covariance model: SocaError # name of the covariance factory in soca + analysis variables: *ana_vars # variables for which a correlation operator will be implemented + date: *date # date of the background + + [...] + + correlation: + - name: ocn # horizontal correlation for the ocean + base value: 300.0e3 # minimum decorrelation length scale + rossby mult: 1.0 # sets the decorrelation scale to base value + rossby mult * Rossby radius + min grid mult: 2.0 # impose the minimun decorrelation to span at least 2 grid boxes + min value: 200.0e3 # minimum value for the decorrelation (not used in this case) + variables: [tocn, socn, ssh] # variables on which to apply the correlation operator + +the yaml key ``base value``, ``rossby mult`` and ``min grid mult`` can be adjusted to modify the +horizontal decorrelation length scale. + +Step 3: Randomize a B-matrix to generate a perturbed initial condition +---------------------------------------------------------------------- +To generate a perturbation we will randomize a static B-matrix. This is done by running + +.. code-block:: console + + ./tutorial_perturb_ic.sh + +it will generate an unrealistically large perturbed ocean state (the goal of the tutorial is not science!) that +will be used in the next step to initialize a forecast and generate synthetic observations. + +The JEDI application ``soca_enspert.x`` is used inside of the ``tutorial_perturb_ic.sh`` script in the following way + +.. code-block:: bash + + OMP_NUM_THREADS=1 mpirun -np 2 ../bin/soca_enspert.x ../config/pert_ic.yaml + +taking the ``pert_ic.yaml`` file as argument. +One can vary the amplitude of the perturbation by editing the ``background error`` section +of the yaml file. The relevant snippet of yaml blocks is shown below. + +.. code-block:: yaml + + background error: + covariance model: SocaError + date: *date + analysis variables: &soca_vars [socn, tocn, ssh, hocn] + bump: + verbosity: main + datadir: ./bump + strategy: specific_univariate + load_nicas_local: 1 + perturbation scales: + tocn: 10.0 + socn: 10.0 + ssh: 0.0 + +Under the ``perturbation scales`` section of the yaml file above, the ``tocn`` and ``socn`` keys represent the +scaling of the perturbation. Choose a number on the order of 1 if you wish to generate a realistic perturbed +ocean state and re-run the ``tutorial_perturb_ic.sh`` script. + +Step 4: Generate synthetic observations +--------------------------------------- +In this step of the tutorial, we will generate synthetic observations by driving the +``MOM6-solo`` model using the ``soca_hofx.x`` executable. `ioda` observation files are +created at the time and locations specified +in ``tutorial_synthetic_observations.py``. This application uses generic +observation operators from the UFO repository. To generate the synthetic observations, run the +``tutorial_make_observations.sh`` script: + +.. code-block:: console + + ./tutorial_make_observations.sh + +A ``obs`` directory is created and should contain the following `ioda` observation files: + +.. code-block:: console + + ├── adt.nc4 # absolute dynamic topography + ├── insitu.S.nc4 # salinity profiles + ├── insitu.T.nc4 # insitu temperature profiles + ├── sss.nc4 # sea surface salinity + └── sst.nc4 # sea surface temperature + +Step 5: 3DVar example +--------------------- +To run the 3DVAR example, execute the ``tutorial_3dvar.sh`` script: + +.. code-block:: console + + ./tutorial_3dvar.sh + +this script perform a 3D variational minimization using the ``soca_var.x`` +executable for a 24 hour window using the observations generated above. +The executable takes ``config/3dvar.yaml`` yaml configuration file as an +argument. + +The JEDI application ``soca_var.x`` is used inside of the ``tutorial_3dvar.sh`` script in the following way + +.. code-block:: bash + + OMP_NUM_THREADS=1 mpirun -np 2 ../bin/soca_var.x ../config/3dvar.yaml + +taking the ``3dvar.yaml`` file as argument. This file controls, among other things, the +data assimilation window length which can be adjusted by changing the value of the +``window length`` key. The relevant yaml snippet is shown below: + +.. code-block:: yaml + + [...] + cost function: + cost type: 3D-Var # cost function type + window begin: &date_begin 2018-04-14T12:00:00Z # starting date of the DA window + window length: P1D # length of the DA window (1 day) + # to adjust to a 6 hour window for example, + # replace with PT6H + [...] + +A few figures of surface increments are plotted at the end of the script after +the 3DVAR step is done: + +.. code-block:: console + + $ ls scratch_3dvar/*.png + scratch_3dvar/incr.ssh.png scratch_3dvar/incr.sss.png scratch_3dvar/incr.sst.png + +They represent increments for sea surface height, sea surface salinity and sea surface temperature, +respectively. + +Step 5: 3DVar FGAT example +-------------------------- +This part of the tutorial is used to show an example of configuration of a +data assimilation experiment cycling through 3 days. +The data assimilation window is 24 hours and the synthetic observations assimilated are +sea surface temperature, sea surface salinity, insitu temperature and salinity and +absolute dynamic topography. +To run the 3DVar FGAT tutorial, execute the ``tutorial_3dvarfgat.sh`` script: + +.. code-block:: console + + ./tutorial_3dvarfgat.sh + +The student is encouraged to have a look inside of the ``tutorial_3dvarfgat.sh`` script to follow +the steps that enable a cycling system. + +Similarly to the `3DVAR` example, figures of surface increments for outer iterations 1 and 2 +can be found in ``./scratch_3dvarfgat/incr.[1-2].ssh.png``, +``./scratch_3dvarfgat/incr.[1-2].sss.png`` and ``./scratch_3dvarfgat/incr.[1-2].sst.png``. + +Statistics of global mean absolute error of each observation space assimilated can be found +in ``./scratch_3dvarfgat/*global_mae.png``. diff --git a/howto/macos/minimum.md b/howto/macos/minimum.md index 56347bfe..76ec9c52 100644 --- a/howto/macos/minimum.md +++ b/howto/macos/minimum.md @@ -1,6 +1,7 @@ ## Minimum steps for working with JEDI natively on Mac OS Tested on *MacOS 10.15.7 (Catalina).* +**Note:** Some steps of this process require administrator privileges for the Mac. If you do not have administrator privileges, you will need to work closely with someone who does, both for the initial installation and for ongoing jedi-stack maintenance. You might instead consider [installing vagrant](https://jointcenterforsatellitedataassimilation-jedi-docs.readthedocs-hosted.com/en/latest/using/jedi_environment/vagrant.html) and then using the [JEDI Singularity containers](https://jointcenterforsatellitedataassimilation-jedi-docs.readthedocs-hosted.com/en/latest/using/jedi_environment/singularity.html) for JEDI on your Mac, as this will be an easier environment to maintain without administrator privileges. ### Basic tools @@ -17,8 +18,11 @@ openssl@1.1 wget ``` -Make sure the proper line for initializing lmod is included in your `.bashrc` or `.zshrc` file. -While editing the file, add the following lines in preparation for the next step: +Note that some bundles (e.g. `fv3-bundle`) require OpenMP. If you need that, also install `libomp` using homebrew. + +Make sure to add the appropriate `lmod` init script to your shell as described on the [lmod homebrew formula page](https://formulae.brew.sh/formula/lmod). + +While editing your shell initialization file for the `lmod` init script, also add the following lines in preparation for the next step: ```bash export JEDI_OPT=/opt/modules module use $JEDI_OPT/modulefiles/core @@ -39,7 +43,8 @@ export JEDI_COMPILER="clang/12.0.0" export JEDI_MPI="mpich/3.3.2" ``` -In the past I used to work with `mpich` installed from homebrew but it doesn't seem to work anymore. +Note: this document is written with these compiler/mpi selections assumed, as well as other default settings in `config_mac.sh`. You will need to modify these instructions if you make edits to that file. + If any modules are already loaded, clear them with `module purge` before proceeding. Then from the `buildscripts` directory, run: ```bash ./setup_modules.sh mac @@ -50,19 +55,15 @@ If you have errors with the compiler when running the script, you may need to se export CPATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/ ``` -Now you can go to the second step and build the JEDI stack itself. You need to edit `buildscripts/config/choose_modules.sh` to select the components you want. For this minimum configuration, I chose: +Now you can go to the second step and build the JEDI stack itself. You need to edit `buildscripts/config/choose_modules.sh` to select the components you want. The `choose_modules.sh` file has been organized with a minimal jedi-stack section at the top, so you should set all the variables in that section to `Y`, except for those corresponding to packages that you have already installed using homebrew above or that have been provided by MacOS (LAPACK). So only the following packages from the "Minimal JEDI Stack" section should be set to "N": +- CMAKE +- GITLFS +- LAPACK +- EIGEN3 -```bash -export STACK_BUILD_SZIP=Y -export STACK_BUILD_ZLIB=Y -export STACK_BUILD_HDF5=Y -export STACK_BUILD_PNETCDF=Y -export STACK_BUILD_NETCDF=Y -export STACK_BUILD_NCCMP=Y -export STACK_BUILD_ECBUILD=Y -export STACK_BUILD_GSL_LITE=Y -``` -and set everything else to `N`. You will need more if you want to run the ioda converters (requires bufr...) or MPAS (PIO...). +Note: You will need more modules selected if you want to run certain bundles. Some additional requirements include: +- For `mpas-bundle`: PIO +- For `soca-science`: NCO Then from the `buildscripts` directory, run: ```bash @@ -99,10 +100,8 @@ ctest the modules "individually" as described above. If this happens to you, try this additional setup: In addition to the `STACK_BUILD` variables listed above, also set the following variables to `Y` in `choose_modules.sh` -before running `./setup_modules.sh mac`: +before running `./build_stack.sh mac`: ```bash -STACK_BUILD_LAPACK -STACK_BUILD_BUFR STACK_BUILD_JSON STACK_BUILD_JSON_SCHEMA_VALIDATOR ``` @@ -112,6 +111,8 @@ To your shell setup script, add the following: module use //jedi-stack/modulefiles/apps ``` +Edit the `//jedi-stack/modulefiles/apps/jedi/clang-mpich.lua` file to remove the `load("lapack")` line. + Then you can load a set of jedi modules with the command: ```bash module load jedi/clang-mpich @@ -122,3 +123,11 @@ Now clear your `CMakeCache.txt` from your build directory and try to build again **Troubleshooting 2** If, when building a bundle, you get an error containing wording like `...your binary is not an allowed client of /usr/lib/libcrypto.dylib`, it means that the linker is trying to link to the macOS OpenSSL libraries (which is not allowed) instead of the homebrew-installed openssl libraries. One solution to this problem is to add the option `-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl` to your `ecbuild` command for the bundle. + +**Troubleshooting 3** +Some people have encountered errors like this while building the jedi-stack: +```bash +sudo: 4294967295: invalid value +sudo: error initializing audit plugin sudoers_audit +``` +This appears to be an [intermittent, unresolved MacOS issue](https://discussions-cn-prz.apple.com/en/thread/252518458). Try, try again. diff --git a/requirements.txt b/requirements.txt index 03357462..6ea686a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ ### Required python packages for our documentation ### sphinxcontrib-bibtex +sphinx_rtd_theme==0.5.2 +docutils==0.16