Changes between Initial Version and Version 1 of ImplementAnalysisLocal


Ignore:
Timestamp:
Nov 16, 2020, 1:36:45 PM (3 years ago)
Author:
lnerger
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • ImplementAnalysisLocal

    v1 v1  
     1= Implementation of the Analysis Step for the Local Filters =
     2
     3{{{
     4#!html
     5<div class="wiki-toc">
     6<h4>Implementation Guide</h4>
     7<ol><li><a href="ImplementationGuide">Main page</a></li>
     8<li><a href="AdaptParallelization">Adaptation of the parallelization</a></li>
     9<li><a href="InitPdaf">Initialization of PDAF</a></li>
     10<li><a href="ModifyModelforEnsembleIntegration">Modifications for ensemble integration</a></li>
     11<li><a href="ImplementationofAnalysisStep">Implementation of the analysis step</a></li>
     12<ol>
     13<li><a href="ImplementAnalysisGlobal">Implementation for Global Filters</a></li>
     14<li>Implementation for Local Filters</li>
     15<li><a href="ImplementAnalysislenkf">Implementation for LEnKF</a></li>
     16</ol>
     17<li><a href="AddingMemoryandTimingInformation">Memory and timing information</a></li>
     18<li><a href="EnsembleGeneration">Ensemble Generation</a></li>
     19<li><a href="DataAssimilationDiagnostics">Diagnostics</a></li>
     20</ol>
     21</div>
     22}}}
     23
     24
     25[[PageOutline(2-3,Contents of this page)]]
     26
     27== Overview ==
     28
     29With Version 1.16 of PDAF we introduced PDAF-OMI (observation module infrastructure). With OMI we provide generic routines for the analysis step, which only distinguish global and local filters. This page describes the implementation of the analysis step for domain-local filters (LESTKF, LETKF, LNETF, LSEIK).
     30
     31For the analysis step of the local filters, several operations related to the observations are needed. These operations are requested by PDAF by calls to routines supplied by the user and provided in the OMI structure.  The names of the required routines are specified in the call to the routine `PDAF_assimilate_local` in the fully-parallel implementation (or `PDAF_put_state_local` for the 'flexible' implementation) described below. With regard to the parallelization, all these routines (except `U_collect_state`, `U_distribute_state`, and `U_next_observation`) are executed by the filter processes (`filterpe=.true.`) only.
     32
     33For completeness we discuss here all user-supplied routines that are specified in the interface to `PDAF_assimilate_local`. Many of the routines are identical to those used for the global filters. Hence, when the user-supplied routines for the global filters have been already implemented, one can base on these routines to speed up the implementation. Due to this, it can also be reasonable to first fully implement a global filter version and subsequently implement the corresponding localized filter by modifying and extending the global routines.
     34
     35
     36== `PDAF_assimilate_local` ==
     37
     38The general aspects of the filter-specific routines `PDAF_assimilate_*` have been described on the page [ModifyModelforEnsembleIntegration Modification of the model code for the ensemble integration] and its sub-page on [InsertAnalysisStep inserting the analysis step].  The routine is used in the fully-parallel implementation variant of the data assimilation system. When the 'flexible' implementation variant is used, the routines `PDAF_put_state_*' is used as described further below.
     39The interface for the routine `PDAF_assimilate_local` contains several routine names for routines that operate on the local analysis domains (marked by `_l` at the end of the routine name). In addition, there are names for routines that consider all available observations required to perform local analyses with LESTKF within some sub-domain of a domain-decomposed model (marked by `_f` at the end of the routine name). In case of a serial execution of the assimilation program, these will be all globally available observations. However, if the program is executed with parallelization, this might be a smaller set of observations.
     40
     41To explain the  difference, it is assumed, for simplicity, that a local analysis domain consists of a single vertical column of the model grid. In addition, we assume that the domain decomposition splits the global model domain by vertical boundaries as is typical for ocean models and that the observations are spatially distributed observations of model fields that are part of the state vector.  Under these assumptions, the situation is the following: When a model uses domain decomposition, the LESTKF is executed such that for each model sub-domain a loop over all local analysis domains (e.g. vertical columns) that belong to the model sub-domain is performed. As each model sub-domain is treated by a different process, all loops are executed parallel to each other.
     42
     43For the update of each single vertical column, observations from some larger domain surrounding the vertical column are required. If the influence radius for the observations is sufficiently small there will be vertical columns for which the relevant observations reside completely inside the model sub-domain of the process. However, if a vertical column is considered that is located close to the boundary of the model sub-domain, there will be some observations that don't belong spatially to the local model sub-domain, but to a neighboring model sub-domain. Nonetheless, these observations are required on the local model sub-domain. A simple way to handle this situation is to initialize for each process all globally available observations, together with their coordinates. While this method is simple, it can also become inefficient if the assimilation program is executed using a large number of processes. As for an initial implementation it is usually not the concern to obtain the highest parallel efficiency, the description below assumes that 'full' refers to the global model domain.
     44
     45The interface when using one of the local filters is the following:
     46{{{
     47  SUBROUTINE PDAF_assimilate_lestkf(U_collect_state, U_distribute_state, U_init_dim_obs_f, U_obs_op_f, &
     48                                  U_prepoststep, U_init_n_domains, U_init_dim_l, &
     49                                  U_init_dim_obs_l, U_g2l_state, U_l2g_state, &
     50                                  U_next_observation, status)
     51}}}
     52with the following arguments:
     53 * [#U_collect_statecollect_state_pdaf.F90 U_collect_state]: The name of the user-supplied routine that initializes a state vector from the array holding the ensemble of model states from the model fields. This is basically the inverse operation to `U_distribute_state` used in [ModifyModelforEnsembleIntegration#PDAF_get_state PDAF_get_state] and also here.
     54 * [#U_distribute_statedistribute_state_pdaf.F90 U_distribute_state]:  The name of a user supplied routine that initializes the model fields from the array holding the ensemble of model state vectors.
     55 * [#U_init_dim_obs_finit_dim_obs_f_pdaf.F90 U_init_dim_obs_f]: The name of the user-supplied routine that provides the size of the full observation vector
     56 * [#U_obs_op_fobs_op_f_pdaf.F90 U_obs_op_f]: The name of the user-supplied routine that acts as the full observation operator on some state vector
     57 * [#U_init_obs_finit_obs_f_pdaf.F90 U_init_obs_f]: The name of the user-supplied routine that initializes the full vector of observations
     58 * [#U_init_obs_linit_obs_l_pdaf.F90 U_init_obs_l]: The name of the user-supplied routine that initializes the vector of observations for a local analysis domain
     59 * [#U_prepoststepprepoststep_ens_pdaf.F90 U_prepoststep]: The name of the pre/poststep routine as in `PDAF_get_state`
     60 * [#U_prodRinvA_lprodrinva_l_pdaf.F90 U_prodRinvA_l]: The name of the user-supplied routine that computes the product of the inverse of the observation error covariance matrix with some matrix provided to the routine by PDAF.
     61 * [#U_init_n_domainsinit_n_domains_pdaf.F90 U_init_n_domains]: The name of the routine that provides the number of local analysis domains
     62 * [#U_init_dim_linit_dim_l_pdaf.F90 U_init_dim_l]: The name of the routine that provides the state dimension for a local analysis domain
     63 * [#U_init_dim_obs_linit_dim_obs_l_pdaf.F90 U_init_dim_obs_l]: The name of the routine that initializes the size of the observation vector for a local analysis domain
     64 * [#U_g2l_stateg2l_state_pdaf.F90 U_g2l_state]: The name of the routine that initializes a local state vector from the global state vector
     65 * [#U_l2g_statel2g_state_pdaf.F90 U_l2g_state]: The name of the routine that initializes the corresponding part of the global state vector from the the provided local state vector
     66 * [#U_g2l_obsg2l_obs_pdaf.F90 U_g2l_obs]: The name of the routine that initializes a local observation vector from a full observation vector
     67 * [#U_init_obsvarinit_obsvar_pdaf.F90 U_init_obsvar]: The name of the user-supplied routine that provides a global mean observation error variance (This routine will only be executed, if an adaptive forgetting factor is used)
     68 * [#U_init_obsvar_linit_obsvar_l_pdaf.F90 U_init_obsvar_l]: The name of the user-supplied routine that provides a mean observation error variance for the local analysis domain (This routine will only be executed, if a local adaptive forgetting factor is used)
     69 * [#U_next_observationnext_observation.F90 U_next_observation]: The name of a user supplied routine that initializes the variables `nsteps`, `timenow`, and `doexit`. The same routine is also used in `PDAF_get_state`.
     70 * `status`: The integer status flag. It is zero, if `PDAF_assimilate_lestkf` is exited without errors.
     71
     72Note:
     73 * The order of the routine names does not show the order in which these routines are executed. See the [#Executionorderofuser-suppliedroutines section on the order of the execution] at the bottom of this page.
     74
     75
     76
     77== `PDAF_put_state_lestkf` ==
     78
     79When the 'flexible' implementation variant is chosen for the assimilation system, the routine `PDAF_put_state_lestkf` has to be used instead of `PDAF_assimilate_lestkf`. The general aspects of the filter specific routines `PDAF_put_state_*` have been described on the page [ModifyModelforEnsembleIntegration Modification of the model code for the ensemble integration]. The interface of the routine is identical with that of `PDAF_assimilate_lestkf` with the exception the specification of the user-supplied routines `U_distribute_state` and `U_next_observation` are missing.
     80
     81The interface when using the LESTKF algorithm is the following:
     82{{{
     83  SUBROUTINE PDAF_put_state_lestkf(U_collect_state, U_init_dim_obs_f, U_obs_op_f, U_init_obs_f, &
     84                                  U_init_obs_l, U_prepoststep, U_prodRinvA_l, U_init_n_domains, &
     85                                  U_init_dim_l, U_init_dim_obs_l, &
     86                                  U_g2l_state, U_l2g_state, U_g2l_obs, &
     87                                  U_init_obsvar, U_init_obsvar_l, status)
     88}}}
     89
     90== User-supplied routines ==
     91
     92Here, all user-supplied routines are described that are required in the call to `PDAF_assimilate_lestkf` or `PDAF_put_state_lestkf`. For some of the generic routines, we link to the page on [ModifyModelforEnsembleIntegration modifying the model code for the ensemble integration].
     93
     94To indicate user-supplied routines we use the prefix `U_`. In the template directory `templates/` as well as in the example implementation in `testsuite/src/dummymodel_1D` these routines exist without the prefix, but with the extension `_pdaf.F90`. In the section titles below we provide the name of the template file in parentheses.
     95
     96In the subroutine interfaces some variables appear with the suffix `_p` (short for 'process'). This suffix indicates that the variable is particular to a model sub-domain, if a domain decomposed model is used. Thus, the value(s) in the variable will be different for different model sub-domains. In addition, there will be variables with the suffix `_f` (for 'full') and with the suffix `_l` (for 'local').
     97
     98=== `U_collect_state` (collect_state_pdaf.F90) ===
     99
     100This routine is independent from the filter algorithm used.
     101See the mape on [InsertAnalysisStep#U_collect_statecollect_state_pdaf.F90 inserting the analysis step] for the description of this routine.
     102
     103=== `U_distribute_state` (distribute_state_pdaf.F90) ===
     104
     105This routine is independent of the filter algorithm used.
     106See the page on [InsertAnalysisStep#U_distribute_statedistribute_state_pdaf.F90 inserting the analysis step] for the description of this routine.
     107
     108
     109=== `U_init_dim_obs_f` (init_dim_obs_f_pdaf.F90) ===
     110
     111This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm.
     112
     113The interface for this routine is:
     114{{{
     115SUBROUTINE init_dim_obs_f(step, dim_obs_f)
     116
     117  INTEGER, INTENT(in)  :: step       ! Current time step
     118  INTEGER, INTENT(out) :: dim_obs_f  ! Dimension of full observation vector
     119}}}
     120
     121The routine is called at the beginning of each analysis step, before the loop over all local analysis domains is entered.  It has to initialize the size `dim_obs_f` of the full observation vector according to the current time step. For simplicity, `dim_obs_f` can be the size for the global model domain.
     122
     123Some hints:
     124 * It can be useful to not only determine the size of the observation vector at this point. One can also already gather information about the location of the observations, which can be used later, e.g. to implement the observation operator. In addition, one can already prepare an array that holds the full observation vector. This can be used later by `U_init_obs_l` to initialize a local vector of observations by selecting the relevant parts of the full observation vector. The required arrays can be defined in a module like `mod_assimilation`.
     125 * The routine is similar to `init_dim_obs` used in the global filters. However, if the global filter is used with a domain-decomposed model, it only initializes the size of the observation vector for the local model sub-domain. This is different for the local filters, as the local analysis also requires observational data from neighboring model sub-domains. Nonetheless, one can base on an implemented routine `init_dim_obs` to implement `init_dim_obs_f`.
     126
     127=== `U_obs_op_f` (obs_op_f_pdaf.F90) ===
     128
     129This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm.
     130
     131The interface for this routine is:
     132{{{
     133SUBROUTINE obs_op_f(step, dim_p, dim_obs_f, state_p, m_state_f)
     134
     135  INTEGER, INTENT(in) :: step               ! Currrent time step
     136  INTEGER, INTENT(in) :: dim_p              ! PE-local dimension of state
     137  INTEGER, INTENT(in) :: dim_obs_f          ! Dimension of the full observed state
     138  REAL, INTENT(in)    :: state_p(dim_p)     ! PE-local model state
     139  REAL, INTENT(out) :: m_state_f(dim_obs_f) ! Full observed state
     140}}}
     141
     142The routine is called during the analysis step, before the loop over the local analysis domain is entered. It has to perform the operation of the observation operator acting on a state vector, which is provided as `state_p`. The observed state has to be returned in `m_state_f`. It is the observed state corresponding to the 'full' observation vector.
     143
     144Hint:
     145 * The routine is similar to `init_dim_obs` used for the global filters. However, with a domain-decomposed model `m_state_f` will contain parts of the state vector from neighboring model sub-domains. To make these parts accessible, some parallel communication will be necessary (The state information for a neighboring model sub-domain, will be in the memory of the process that handles that sub-domain). The example implementation in `testsuite/dummymodel_1d` uses the function `MPI_AllGatherV` for this communication.
     146
     147=== `U_init_obs_f` (init_obs_f_pdaf.F90) ===
     148
     149This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm.
     150The routine is only called if the globally adaptive forgetting factor is used (`type_forget=1` in the example implementation). For the local filters there is also the alternative to use locally adaptive forgetting factors (`type_forget=2` in the example implementation)
     151
     152The interface for this routine is:
     153{{{
     154SUBROUTINE init_obs_f(step, dim_obs_f, observation_f)
     155
     156  INTEGER, INTENT(in) :: step                     ! Current time step
     157  INTEGER, INTENT(in) :: dim_obs_f                ! Dimension of full observation vector
     158  REAL, INTENT(out)   :: observation_f(dim_obs_f) ! Full observation vector
     159}}}
     160
     161The routine is called during the analysis step before the loop over the local analysis domains is entered. It has to provide the full vector of observations in `observation_f` for the current time step. The caller is the routine that computes an adaptive forgetting factor (PDAF_set_forget).
     162
     163Hints:
     164 * As for the other 'full' routines: While the global counterpart of this routine (`init_obs`) has to initialize the observation vector only for the local model sub-domain, the 'full' routine has to include observations that spatially belong to neighboring model sub-domains. As an easy choice one can simply initialize a vector of all globally available observations.
     165 * If the adaptive forgetting factor is not used, this routine only has to exist. However, no functionality is required.
     166
     167
     168=== `U_init_obs_l` (init_obs_l_pdaf.F90) ===
     169
     170This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm.
     171
     172The interface for this routine is:
     173{{{
     174SUBROUTINE init_obs_l(domain_p, step, dim_obs_l, observation_l)
     175
     176  INTEGER, INTENT(in) :: domain_p                 ! Current local analysis domain
     177  INTEGER, INTENT(in) :: step                     ! Current time step
     178  INTEGER, INTENT(in) :: dim_obs_l                ! Local dimension of observation vector
     179  REAL, INTENT(out)   :: observation_l(dim_obs_l) ! Local observation vector
     180}}}
     181
     182The routine is called during the analysis step during the loop over the local analysis domain.
     183It has to provide the vector of observations for the analysis in the local analysis domain with index `domain_p` in `observation_l` for the current time step.
     184
     185Hints:
     186 * For parallel efficiency, the LESTKF algorithm is implemented in a way that first the full vectors are initialized. These are then restricted to the local analysis domain during the loop over all local analysis domains. Thus, if the full vector of observations has been initialized before `U_init_obs_l` is executed (e.g. by `U_init_dim_obs_f`), the operations performed in this routine will be to select the part of the full observation vector that is relevant for the current local analysis domain.
     187 * The routine `U_init_dim_obs_l` is executed before this routine. Thus, if that routine already prepares the information which elements of `observation_f` are needed for `observation_l`, this information can be used efficiently here.
     188
     189
     190=== `U_prepoststep` (prepoststep_ens_pdaf.F90) ===
     191
     192This routine can be identical to that used for the global ESTKF algorithm, which has already been described on the [ModifyModelforEnsembleIntegration#U_prepoststepprepoststep_ens.F90 page on modifying the model code for the ensemble integration]. For completeness, the description is repeated:
     193
     194The interface of the routine is identical for all filters. However, the particular operations that are performed in the routine can be specific for each filter algorithm.
     195
     196The interface for this routine is
     197{{{
     198SUBROUTINE prepoststep(step, dim_p, dim_ens, dim_ens_p, dim_obs_p, &
     199                       state_p, Uinv, ens_p, flag)
     200
     201  INTEGER, INTENT(in) :: step        ! Current time step
     202                         ! (When the routine is called before the analysis -step is provided.)
     203  INTEGER, INTENT(in) :: dim_p       ! PE-local state dimension
     204  INTEGER, INTENT(in) :: dim_ens     ! Size of state ensemble
     205  INTEGER, INTENT(in) :: dim_ens_p   ! PE-local size of ensemble
     206  INTEGER, INTENT(in) :: dim_obs_p   ! PE-local dimension of observation vector
     207  REAL, INTENT(inout) :: state_p(dim_p) ! PE-local forecast/analysis state
     208                                     ! The array 'state_p' is not generally not initialized in the case of SEIK/EnKF/ETKF/ESTKF.
     209                                     ! It can be used freely in this routine.
     210  REAL, INTENT(inout) :: Uinv(dim_ens-1, dim_ens-1) ! Inverse of matrix U
     211  REAL, INTENT(inout) :: ens_p(dim_p, dim_ens)      ! PE-local state ensemble
     212  INTEGER, INTENT(in) :: flag        ! PDAF status flag
     213}}}
     214
     215The routine `U_prepoststep` is called once at the beginning of the assimilation process. In addition, it is called during the assimilation cycles before the analysis step and after the ensemble transformation. The routine is called by all filter processes (that is `filterpe=1`).
     216
     217The routine provides for the user the full access to the ensemble of model states. Thus, user-controlled pre- and post-step operations can be performed.  For example the forecast and the analysis states and ensemble covariance matrix can be analyzed, e.g. by computing the estimated variances. In addition, the estimates can be written to disk.
     218
     219Hint:
     220 * If a user considers to perform adjustments to the estimates (e.g. for balances), this routine is the right place for it.
     221 * Only for the SEEK filter the state vector (`state_p`) is initialized. For all other filters, the array is allocated, but it can be used freely during the execution of `U_prepoststep`.
     222 * The interface has a difference for LETKF and LESTKF: For the LETKF, the array `Uinv` has size `dim_ens` x `dim_ens`. In contrast it has size `dim_ens-1` x `dim_ens-1` for the LESTKF.
     223 * The interface through which `U_prepoststep` is called does not include the array of smoothed ensembles. In order to access the smoother ensemble array one has to set a pointer to it using a call to the routine `PDAF_get_smootherens` (see page on [AuxiliaryRoutines auxiliary routines])
     224
     225
     226
     227=== `U_prodRinvA_l` (prodrinva_l_pdaf.F90) ===
     228
     229This routine is used by the local filters (LSEIK, LETKF, LESTKF). There is a slight difference between LESTKF and LETKF for this routine, which is described below.
     230
     231The interface for this routine is:
     232{{{
     233SUBROUTINE prodRinvA_l(domain_p, step, dim_obs_l, rank, obs_l, A_l, C_l)
     234
     235  INTEGER, INTENT(in) :: domain_p             ! Current local analysis domain
     236  INTEGER, INTENT(in) :: step                 ! Current time step
     237  INTEGER, INTENT(in) :: dim_obs_l            ! Dimension of local observation vector
     238  INTEGER, INTENT(in) :: rank                 ! Rank of initial covariance matrix
     239  REAL, INTENT(in)    :: obs_l(dim_obs_l)     ! Local vector of observations
     240  REAL, INTENT(inout) :: A_l(dim_obs_l, rank) ! Input matrix from analysis routine
     241  REAL, INTENT(out)   :: C_l(dim_obs_l, rank) ! Output matrix
     242}}}
     243
     244The routine is called during the loop over the local analysis domains. In the algorithm, the product of the inverse of the observation error covariance matrix with some matrix has to be computed. For the SEIK filter this matrix holds the observed part of the ensemble perturbations for the local analysis domain of index `domain_p`. The matrix is provided as `A_l`. The product has to be given as `C_l`.
     245
     246This routine is also the place to perform observation localization. To initialize a vector of weights, the routine `PDAF_local_weight` can be called. The procedure is used in the example implementation and also demonstrated in the template routine.
     247
     248Hints:
     249 * The routine is a local variant of the routine `U_prodRinvA`. Thus if that routine has been implemented before, it can be adapted here for the local filter.
     250 * The routine does not require that the product is implemented as a real matrix-matrix product. Rather, the product can be implemented in its most efficient form. For example, if the observation error covariance matrix is diagonal, only the multiplication of the diagonal with matrix `A_l` has to be implemented.
     251 * The observation vector `obs_l` is provided through the interface for cases where the observation error variance is relative to the actual value of the observations.
     252 * The interface has a difference for LESTKF and LETKF: For LETKF the third argument is the ensemble size (`dim_ens`), while for LESTKF it is the rank (`rank`) of the covariance matrix (usually ensemble size minus one). In addition, the second dimension of `A_l` and `C_l` has size `dim_ens` for LETKF, while it is `rank` for LESTKF.  (Practically, one can usually ignore this difference as the fourth argument of the interface can be named arbitrarily in the routine.)
     253
     254
     255=== `U_init_n_domains` (init_n_domains_pdaf.F90) ===
     256
     257This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm.
     258
     259The interface for this routine is:
     260{{{
     261SUBROUTINE init_n_domains(step, n_domains_p)
     262
     263  INTEGER, INTENT(in)  :: step        ! Current time step
     264  INTEGER, INTENT(out) :: n_domains_p ! Number of analysis domains for local model sub-domain
     265}}}
     266
     267The routine is called during the analysis step before the loop over the local analysis domains is entered.
     268It has to provide the number of local analysis domains. In case of a domain-decomposed model the number of local analysis domain for the model sub-domain of the calling process has to be initialized.
     269
     270Hints:
     271 * As a simple case, if the localization is only performed horizontally, the local analysis domains can be single vertical columns of the model grid. In this case, `n_domains_p` is simply the number of vertical columns in the local model sub-domain.
     272
     273
     274=== `U_init_dim_l` (init_dim_l_pdaf.F90) ===
     275
     276This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm.
     277
     278The interface for this routine is:
     279{{{
     280SUBROUTINE init_dim_l(step, domain_p, dim_l)
     281
     282  INTEGER, INTENT(in)  :: step        ! Current time step
     283  INTEGER, INTENT(in)  :: domain_p    ! Current local analysis domain
     284  INTEGER, INTENT(out) :: dim_l       ! Local state dimension
     285}}}
     286
     287The routine is called during the loop over the local analysis domains in the analysis step.
     288It has to provide in `dim_l` the dimension of the state vector for the local analysis domain with index `domain_p`.
     289
     290Hints:
     291 * If a local analysis domain is a single vertical column of the model grid, the size of the state in the local analysis domain will be just the number of vertical grid points at this location.
     292
     293
     294=== `U_init_dim_obs_l` (init_dim_obs_l_pdaf.F90) ===
     295
     296This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm.
     297
     298The interface for this routine is:
     299{{{
     300SUBROUTINE init_dim_obs_l(domain_p, step, dim_obs_f, dim_obs_l)
     301
     302  INTEGER, INTENT(in)  :: domain_p   ! Current local analysis domain
     303  INTEGER, INTENT(in)  :: step       ! Current time step
     304  INTEGER, INTENT(in)  :: dim_obs_f  ! Full dimension of observation vector
     305  INTEGER, INTENT(out) :: dim_obs_l  ! Local dimension of observation vector
     306}}}
     307
     308The routine is called during the loop over the local analysis domains in the analysis step.
     309It has to initialize in `dim_obs_l` the size of the observation vector used for the local analysis domain with index `domain_p`.
     310
     311Some hints:
     312 * Usually, the observations to be considered for a local analysis are those which reside within some distance from the local analysis domain. Thus, if the local analysis domain is a single vertical column of the model grid and if the model grid is a regular ij-grid, then one could use some range of i/j indices to select the observations and determine the local number of them. More generally, one can compute the physical distance of an observation from the local analysis domain and decide on this basis, if the observation has to be considered.
     313 * In the loop over the local analysis domains, the routine is always called before `U_init_obs_l` is executed. Thus, as `U_init_dim_obs_l` has to check which observations should be used for the local analysis domain, one can already initialize an integer array that stores the index of observations to be considered. This index should be the position of the observation in the array `observation_f`. With this, the initialization of the local observation vector in `U_init_obs_l` can be sped up.
     314 * For PDAF, we could not join the routines `U_init_dim_obs_l` and `U_init_obs_l`, because the array for the local observations is allocated internally to PDAF after its size has been determined in `U_init_dim_obs_l`.
     315
     316
     317=== `U_g2l_state` (g2l_state_pdaf.F90) ===
     318
     319This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm.
     320
     321The interface for this routine is:
     322{{{
     323SUBROUTINE g2l_state(step, domain_p, dim_p, state_p, dim_l, state_l)
     324
     325  INTEGER, INTENT(in) :: step           ! Current time step
     326  INTEGER, INTENT(in) :: domain_p       ! Current local analysis domain
     327  INTEGER, INTENT(in) :: dim_p          ! State dimension for model sub-domain
     328  INTEGER, INTENT(in) :: dim_l          ! Local state dimension
     329  REAL, INTENT(in)    :: state_p(dim_p) ! State vector for model sub-domain
     330  REAL, INTENT(out)   :: state_l(dim_l) ! State vector on local analysis domain
     331}}}
     332
     333The routine is called during the loop over the local analysis domains in the analysis step. It has to provide the local state vector `state_l` that corresponds to the local analysis domain with index `domain_p`. Provided to the routine is the state vector `state_p`. With a domain decomposed model, this is the state for the local model sub-domain.
     334
     335Hints:
     336 * In the simple case that a local analysis domain is a single vertical column of the model grid, the operation in this routine would be to take out of `state_p` the data for the vertical column indexed by `domain_p`.
     337
     338
     339=== `U_l2g_state` (l2g_state_pdaf.F90) ===
     340
     341This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm.
     342
     343The interface for this routine is:
     344{{{
     345SUBROUTINE l2g_state(step, domain_p, dim_l, state_l, dim_p, state_p)
     346
     347  INTEGER, INTENT(in) :: step           ! Current time step
     348  INTEGER, INTENT(in) :: domain_p       ! Current local analysis domain
     349  INTEGER, INTENT(in) :: dim_p          ! State dimension for model sub-domain
     350  INTEGER, INTENT(in) :: dim_l          ! Local state dimension
     351  REAL, INTENT(in)    :: state_p(dim_p) ! State vector for model sub-domain
     352  REAL, INTENT(out)   :: state_l(dim_l) ! State vector on local analysis domain
     353}}}
     354
     355The routine is called during the loop over the local analysis domains in the analysis step. It has to initialize the part of the global state vector `state_p` that corresponds to the local analysis domain with index `domain_p`. Provided to the routine is the state vector `state_l` for the local analysis domain.
     356
     357Hints:
     358 * In the simple case that a local analysis domain is a single vertical column of the model grid, the operation in this routine would be to write into `state_p` the data for the vertical column indexed by `domain_p`.
     359
     360
     361=== `U_g2l_obs` (g2l_obs_pdaf.F90) ===
     362
     363This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm.
     364
     365The interface for this routine is:
     366{{{
     367SUBROUTINE g2l_obs(domain_p, step, dim_obs_f, dim_obs_l, mstate_f, mstate_l)
     368
     369  INTEGER, INTENT(in) :: domain_p              ! Current local analysis domain
     370  INTEGER, INTENT(in) :: step                  ! Current time step
     371  INTEGER, INTENT(in) :: dim_obs_f             ! Dimension of full observation vector for model sub-domain
     372  INTEGER, INTENT(in) :: dim_obs_l             ! Dimension of observation vector for local analysis domain
     373  REAL, INTENT(in)    :: mstate_f(dim_obs_f)   ! Full observation vector for model sub-domain
     374  REAL, INTENT(out)   :: mstate_l(dim_obs_l)   ! Observation vector for local analysis domain
     375}}}
     376
     377The routine is called during the loop over the local analysis domains in the analysis step. It has to provide a local observation vector `mstate_l` for the observation domain that corresponds to the local analysis domain with index `domain_p`. Provided to the routine is the full observation vector `mstate_f` from which the local part has to be extracted.
     378
     379Hints:
     380 * The  vector `mstate_f` that is provided to the routine is one of the observed state vectors that are produced by `U_obs_op_f`.
     381 * Some operations performed here are analogous to those required to initialize a local vector of observations in `U_init_obs_l`. If that routine reads first a full vector of observations (e.g. in `U_init_dim_obs_f`), this vector has to be restricted to the relevant observations for the current local analysis domain. For this operation, one can for example initialize an index array when `U_init_dim_obs_l` is executed. (Which happens before `U_g2l_obs`)
     382
     383
     384=== `U_init_obsvar` (init_obsvar_pdaf.F90) ===
     385
     386This routine is used by the global filter algorithms SEIK, ETKF, and ESTKF as well as the local filters LSEIK, LETKF, ad LESTKF. The routine is only called if the adaptive forgetting factor is used (`type_forget=1` in the example implementation). The difference in this routine between global and local filters is that the global filters use 'global' while the local filters use 'full' quantities.
     387
     388The interface for this routine is:
     389{{{
     390SUBROUTINE init_obsvar(step, dim_obs_f, obs_f, meanvar_f)
     391
     392  INTEGER, INTENT(in) :: step             ! Current time step
     393  INTEGER, INTENT(in) :: dim_obs_f        ! Full dimension of observation vector
     394  REAL, INTENT(in)    :: obs_f(dim_obs_f) ! Full observation vector
     395  REAL, INTENT(out)   :: meanvar_f        ! Mean observation error variance
     396}}}
     397
     398The routine is called in the local filters before the loop over all local analysis domains is entered. The call is by the routine that computes an adaptive forgetting factor (`PDAF_set_forget`).
     399The routine has to initialize an average full observation error variance, which should be consistent with the observation vector initialized in `U_init_ob_full`.
     400
     401
     402Hints:
     403 * For a model with domain-decomposition one might use the mean variance for the model sub-domain of the calling process. Alternatively one can compute a mean variance for the full model domain using MPI communication (e.g. the function `MPI_allreduce`).
     404 * The observation vector `obs_p` is provided to the routine for the case that the observation error variance is relative to the value of the observations.
     405 * If the adaptive forgetting factor is not used, this routine has only to exist for the compilation, but it does not need functionality.
     406
     407
     408=== `U_init_obsvar_l` (init_obsvar_l_pdaf.F90) ===
     409
     410This routine is used by all filter algorithms with domain-localization (LSEIK, LETKF, LESTKF) and is independent of the particular algorithm. The routine is only called if the local adaptive forgetting factor is used (`type_forget=2` in the example implementation).
     411
     412The interface for this routine is:
     413{{{
     414SUBROUTINE init_obsvar_l(domain_p, step, dim_obs_l, obs_l, meanvar_l)
     415
     416  INTEGER, INTENT(in) :: domain_p         ! Current local analysis domain
     417  INTEGER, INTENT(in) :: step             ! Current time step
     418  INTEGER, INTENT(in) :: dim_obs_l        ! Local dimension of observation vector
     419  REAL, INTENT(in)    :: obs_l(dim_obs_l) ! Local observation vector
     420  REAL, INTENT(out)   :: meanvar_l        ! Mean local observation error variance
     421}}}
     422
     423The routine is called in the local filters during the loop over all local analysis domains by the routine that computes a local adaptive forgetting factor (`PDAF_set_forget_l`). The routine has to initialize a local mean observation error variance for all observations used for the analysis in the current local analysis domain.
     424
     425Hints:
     426 * If the local adaptive forgetting factor is not used, this routine has only to exist for the compilation, but it does not need functionality.
     427
     428
     429=== `U_next_observation` (next_observation_pdaf.F90) ===
     430
     431This routine is independent of the filter algorithm used.
     432See the page on [InsertAnalysisStep#U_next_observationnext_observation_pdaf.F90 inserting the analysis step] for the description of this routine.
     433
     434
     435== Execution order of user-supplied routines ==
     436
     437The user-supplied routines are executed in the order listed below. The order can be important as some routines can perform preparatory work for routines executed later on during the analysis. For example, `U_init_dim_obs_local` can prepare an index array that provides the information how to localize a 'full' vector of observations. Some hints one the efficient implementation strategy are given with the descriptions of the routine interfaces above.
     438
     439Before the analysis step is called the following is executed:
     440 1. [#U_collect_statecollect_state_pdaf.F90 U_collect_state] (called once for each ensemble member)
     441
     442When the ensemble integration of the forecast is completed, the analysis step is executed. Before the loop over all local analysis domains, the following routines are executed:
     443 1. [#U_prepoststepprepoststep_ens_pdaf.F90 U_prepoststep] (Call to act on the forecast ensemble, called with negative value of the time step)
     444 1. [#U_init_n_domainsinit_n_domains_pdaf.F90 U_init_n_domains]
     445 1. [#U_init_dim_obs_finit_dim_obs_f_pdaf.F90 U_init_dim_obs_f]
     446 1. [#U_obs_op_fobs_op_f_pdaf.F90 U_obs_op_f] (Called `dim_ens` times; once for each ensemble member)
     447 1. [#U_init_obs_finit_obs_f_pdaf.F90 U_init_obs_f] (Only executed, if the global adaptive forgetting factor is used (`type_forget=1` in the example implemention))
     448 1. [#U_init_obsvarinit_obsvar_pdaf.F90 U_init_obsvar] (Only executed, if the global adaptive forgetting factor is used (`type_forget=1` in the example implemention))
     449
     450In the loop over all local analysis domains, it is executed for each local analysis domain:
     451 1. [#U_init_dim_linit_dim_l_pdaf.F90 U_init_dim_l]
     452 1. [#U_init_dim_obs_linit_dim_obs_l_pdaf.F90 U_init_dim_obs_l]
     453 1. [#U_g2l_stateg2l_state_pdaf.F90 U_g2l_state] (Called `dim_ens+1` times: Once for each ensemble member and once for the mean state estimate)
     454 1. [#U_g2l_obsg2l_obs_pdaf.F90 U_g2l_obs] (A single call to localize the mean observed state)
     455 1. [#U_init_obs_linit_obs_l_pdaf.F90 U_init_obs_l]
     456 1. [#U_g2l_obsg2l_obs_pdaf.F90 U_g2l_obs] (`dim_ens` calls: one call to localize the observed part of each ensemble member)
     457 1. [#U_init_obsvar_linit_obsvar_l_pdaf.F90 U_init_obsvar_l] (Only called, if the local adaptive forgetting factor is used (`type_forget=2` in the example implementation))
     458 1. [#U_prodRinvA_lprodrinva_l_pdaf.F90 U_prodRinvA_l]
     459 1. [#U_l2g_statel2g_state_pdaf.F90 U_l2g_state] (Called `dim_ens+1` times: Once for each ensemble member and once for the mean state estimate)
     460
     461After the loop over all local analysis domains, it is executed:
     462 1. [#U_prepoststepprepoststep_ens_pdaf.F90 U_prepoststep] (Call to act on the analysis ensemble, called with (positive) value of the time step)
     463
     464In case of the routine `PDAF_assimilate_lestkf`, the following routines are executed after the analysis step:
     465 1. [#U_distribute_statedistribute_state_pdaf.F90 U_distribute_state]
     466 1. [#U_next_observationnext_observation_pdaf.F90 U_next_observation]