Changes between Initial Version and Version 1 of OMI_Callback_obs_pdafomi_PDAF3


Ignore:
Timestamp:
May 27, 2025, 3:07:55 PM (8 weeks ago)
Author:
lnerger
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • OMI_Callback_obs_pdafomi_PDAF3

    v1 v1  
     1= PDAF-OMI: The file callback_obs_pdafomi.F90 =
     2
     3{{{
     4#!html
     5<div class="wiki-toc">
     6<h4>PDAF-OMI Guide</h4>
     7<ol><li><a href="PDAF_OMI_Overview_PDAF3">Overview</a></li>
     8<li>callback_obs_pdafomi.F90</li>
     9<li><a href="OMI_observation_modules_PDAF3">Observation Modules</a></li>
     10<li><a href="OMI_observation_operators_PDAF3">Observation operators</a></li>
     11<li><a href="OMI_error_checking_PDAF3">Checking error status</a></li>
     12<li><a href="OMI_debugging_PDAF3">Debugging functionality</a></li>
     13<li><a href="ImplementationofAnalysisStep">Implementing the analysis step</a></li>
     14<li><a href="OMI_nondiagonal_observation_error_covariance_matrices">Using nondiagonal R-matrices</a></li>
     15<li><a href="Porting_to_OMI_PDAF3">Porting an existing implemention to OMI</a></li>
     16<li><a href="nondiagonal_observation_error_covariance_matrices_PDAF3">Using nondiagonal R-matrices</a></</ol>
     17</div>
     18}}}
     19
     20[[PageOutline(2-3,Contents of this page)]]
     21
     22The file `callback_obs_pdafomi.F90` contains all those routines that are directly called by PDAF as call-back routines. In the example codes we use all routines with the suffix _pdafomi to distinguish them from routine from existing implementation where the suffix is typically _pdaf.
     23
     24The file `templates/omi/callback_obs_pdafomi.F90` provides a template for implementing the routines. A compact example can be found in `tutorial/online_2D_serialmodel/`.
     25
     26The routines are mainly pass-through routines. Thus, one typically includes the observation-specific routine with ‘use’ and then calls this routine. However, there is small additional functionality in the different routines which has to be handled when implementing the routine or adding an observation type.
     27
     28In the descriptions below we use 'TYPE' as a generic label for an observation type. When implemeting an observation type, one replace this by an actual name. For example for sea surface temperature (sst) observations, one could replace TYPE by 'sst' and write e.g. `init_dim_obs_sst`.
     29
     30
     31== init_dim_obs_pdafomi ==
     32
     33The routine is called at the beginning of each analysis step.  For PDAF, it has to initialize the size `dim_obs_p` of the observation vector according to the current time step. Apart from this routine will initialize overall observation information.  In this routine one just calls `init_dim_obs_TYPE` for each observation type.
     34
     35The '''interface''' for this routine is:
     36{{{
     37SUBROUTINE init_dim_obs_pdafomi(step, dim_obs_p)
     38
     39  INTEGER, INTENT(in)  :: step       ! Current time step
     40  INTEGER, INTENT(out) :: dim_obs_p  ! Dimension of observation vector
     41}}}
     42
     43In this routine we declare a dimension variable `dim_obs_TYPE` for each observation type. This is initialized by the corresponding routine `init_dim_obs_TYPE`. The sum of these individual dimensions yields the total number of observations, which is returned to PDAF.
     44
     45
     46The '''implementation steps''' are:
     471. Include the observation-specific routine `init_dim_obs_TYPE` and the variable `assim_TYPE` from the observation-module with 'use'
     481. Declare a dimension variable `dim_obs_TYPE` and initialize it to 0
     491. Add a call to the observation-specific routine init_dim_obs_TYPE with the condition `IF (assim_TYPE)`
     501. add `dim_obs_TYPE` to the final sum computing `dim_obs`.
     51
     52As an '''example''', in `tutorial/online_2D_serialmodel/` we have three observations, named A, B, and C. In `init_dim_obs_pdafomi` we find the lines
     53{{{
     54SUBROUTINE init_dim_obs_pdafomi(step, dim_obs)
     55
     56  USE obs_A_pdafomi, ONLY: assim_A, init_dim_obs_A
     57  USE obs_B_pdafomi, ONLY: assim_B, init_dim_obs_B
     58  USE obs_C_pdafomi, ONLY: assim_C, init_dim_obs_C
     59
     60  ... argument declarations omitted ...
     61
     62  INTEGER :: dim_obs_A ! Observation dimensions
     63  INTEGER :: dim_obs_B ! Observation dimensions
     64  INTEGER :: dim_obs_C ! Observation dimensions
     65
     66  dim_obs_A = 0
     67  dim_obs_B = 0
     68  dim_obs_C = 0
     69
     70  IF (assim_A) CALL init_dim_obs_A(step, dim_obs_A)
     71  IF (assim_B) CALL init_dim_obs_B(step, dim_obs_B)
     72  IF (assim_C) CALL init_dim_obs_C(step, dim_obs_C)
     73
     74  dim_obs = dim_obs_A + dim_obs_B + dim_obs_C
     75}}}
     76
     77
     78'''Notes:'''
     79 - The variable `assim_TYPE` indicates whether a particular observation type is assimilated. It is usually set in `init_pdaf`, or by reading from the command line or a namelist file.
     80 - The obs-module can have either a specific name for `init_dim_obs_TYPE` or a generic name. If the generic name `init_dim_obs` is used one can apply a name conversion `init_dim_obs_TYPE => init_dim_obs`.
     81
     82
     83
     84== obs_op_pdafomi ==
     85
     86The routine is called during the analysis step. It has to perform the operation of the observation operator acting on a state vector that is provided as `state_p`. The observed state has to be returned in `m_state_p`. In this routine one just calls `obs_op_TYPE` for each observation type.
     87
     88The '''interface''' for this routine is:
     89{{{
     90SUBROUTINE obs_op_pdafomi(step, dim_p, dim_obs_p, state_p, m_state_p)
     91
     92  INTEGER, INTENT(in) :: step               ! Currrent time step
     93  INTEGER, INTENT(in) :: dim_p              ! PE-local dimension of state
     94  INTEGER, INTENT(in) :: dim_obs_p          ! Dimension of observed state
     95  REAL, INTENT(in)    :: state_p(dim_p)     ! PE-local model state
     96  REAL, INTENT(out) :: m_state_p(dim_obs_p) ! PE-local observed state
     97}}}
     98
     99The '''implementation steps''' are:
     1001. Include the observation-specific routine `obs_op_TYPE` from the observation-module with 'use'
     1011. Add a call to the observation-specific routine `obs_op_TYPEz
     102
     103As an '''example''', in `tutorial/online_2D_serialmodel/` we have
     104{{{
     105SUBROUTINE obs_op_pdafomi(step, dim_p, dim_obs, state_p, ostate)
     106
     107  USE obs_A_pdafomi, ONLY: obs_op_A
     108  USE obs_B_pdafomi, ONLY: obs_op_B
     109  USE obs_C_pdafomi, ONLY: obs_op_C
     110
     111  ... argument declarations omitted ...
     112
     113  CALL obs_op_A(dim_p, dim_obs, state_p, ostate)
     114  CALL obs_op_B(dim_p, dim_obs, state_p, ostate)
     115  CALL obs_op_C(dim_p, dim_obs, state_p, ostate)
     116}}}
     117
     118'''Notes:'''
     119 - The arguments in the calls to `obs_op_TYPE` are input arguments to `obs_op_pdafomi`. They are just passed on.
     120 - The order of the calls to `obs_op_TYPE` is not relevant because the setup of the overall full observation vector is defined by the order of the calls in init_dim_obs_pdafomi. Anyway, it's good practice to keep the order of the calls consistent.
     121 - We don't need an IF-statement with `assim_TYPE` here. The check is done within each obs-module.
     122
     123
     124== init_dim_obs_l_pdafomi ==
     125
     126In this routine one just calls `init_dim_obs_l_TYPE` for each observation type. The routine is only required for domain-localized filters (like LESTKF, LETKF, LNETF).
     127
     128The '''implementation steps''' are:
     1291. Include the observation-specific routine `init_dim_obs_l_TYPE` from the observation-module with 'use'
     1301. Add a call to the observation-specific routine init_dim_obs_l_TYPE
     131
     132As an '''example''', in `tutorial/online_2D_serialmodel/` we have
     133{{{
     134SUBROUTINE init_dim_obs_l_pdafomi(domain_p, step, dim_obs, dim_obs_l)
     135
     136  USE obs_A_pdafomi, ONLY: init_dim_obs_l_A
     137  USE obs_B_pdafomi, ONLY: init_dim_obs_l_B
     138  USE obs_C_pdafomi, ONLY: init_dim_obs_l_C
     139
     140  ... argument declarations omitted ...
     141
     142  CALL init_dim_obs_l_A(domain_p, step, dim_obs, dim_obs_l)
     143  CALL init_dim_obs_l_B(domain_p, step, dim_obs, dim_obs_l)
     144  CALL init_dim_obs_l_C(domain_p, step, dim_obs, dim_obs_l)
     145}}}
     146
     147'''Notes:'''
     148 - The order of the calls to `init_dim_obs_l_TYPE` defines the order in which the observations are stored in the local observation vector. The calling order does not need to be the same as in the other routines, but it's good practive to keep the order of the calls consistent.
     149
     150== localize_covar_pdafomi ==
     151
     152In this routine one calls `localize_covar_TYPE` for each observation type. The routine is only required for the localized EnKF and performs covariance localization.
     153
     154The '''implementation steps''' are:
     1551. Include the observation-specific routine `localize_covar_TYPE` from the observation-module with 'use'
     1561. Initialize the array `coords` which holds the coordinates of all elements of the state vector for the current process domain
     1571. Add a call to the observation-specific routine localize_covar_TYPE
     158
     159As an '''example''', in `tutorial/online_2D_serialmodel/` we have
     160{{{
     161SUBROUTINE localize_covar_pdafomi(dim_p, dim_obs, HP_p, HPH)
     162
     163  USE obs_A_pdafomi, ONLY: localize_covar_A
     164  USE obs_B_pdafomi, ONLY: localize_covar_B
     165  USE obs_C_pdafomi, ONLY: localize_covar_C
     166
     167  ... argument declarations omitted ...
     168
     169  REAL, ALLOCATABLE :: coords_p(:,:) ! Coordinates of PE-local state vector entries
     170
     171  ALLOCATE(coords_p(2, dim_p))
     172  coords_p = ...                     ! Initialize coords_p
     173
     174  CALL localize_covar_A(dim_p, dim_obs, HP_p, HPH, coords_p)
     175  CALL localize_covar_B(dim_p, dim_obs, HP_p, HPH, coords_p)
     176  CALL localize_covar_C(dim_p, dim_obs, HP_p, HPH, coords_p)
     177
     178  DEALLOCATE(coords_p)
     179}}}
     180
     181'''Notes:'''
     182 - Instead of allocating and filling the coordinate array `coords_p` in this routine one could also do it once in `init_pdaf` and declare the array in the module `mod_assimilation`.
     183 - The order of the calls to `obs_op_TYPE` is not relevant because the setup of the overall full observation vector is defined by the order of the calls in init_dim_obs_pdafomi. Anyway, it's good practice to keep the order of the calls consistent.
     184
     185
     186
     187== obs_op_lin_pdafomi ==
     188
     189The routine is called during the analysis step of the 3D-Var methods and it is only required in this case (3D-Var methods have been added with PDAF V2.0). It has to perform the operation of the linearized observation operator acting on a state vector that is provided as `state_p`. The observed state has to be returned in `m_state_p`. In this routine one just calls `obs_op_lin_TYPE` for each observation type.
     190
     191The '''interface''' for this routine is:
     192{{{
     193SUBROUTINE obs_op_lin_pdafomi(step, dim_p, dim_obs_p, state_p, m_state_p)
     194
     195  INTEGER, INTENT(in) :: step               ! Currrent time step
     196  INTEGER, INTENT(in) :: dim_p              ! PE-local dimension of state
     197  INTEGER, INTENT(in) :: dim_obs_p          ! Dimension of observed state
     198  REAL, INTENT(in)    :: state_p(dim_p)     ! PE-local model state
     199  REAL, INTENT(out) :: m_state_p(dim_obs_p) ! PE-local observed state
     200}}}
     201
     202
     203The '''implementation steps''' are the same as for `obs_op_pdafomi`.
     204
     205An '''example''' is provided in `tutorial/variational/online_2D_serialmodel/`.
     206
     207'''Notes:'''
     208 - The arguments in the calls to `obs_op_lin_TYPE` are input arguments to `obs_op_pdafomi`. They are just passed on.
     209 - The order of the calls to `obs_op_TYPE` is not relevant because the setup of the overall full observation vector is defined by the order of the calls in init_dim_obs_pdafomi. Anyway, it's good practice to keep the order of the calls consistent.
     210 - We don't need an IF-statement with `assim_TYPE` here. The check is done within each obs-module.
     211 - If the full observation operator for the observation type is linear by itself, one can just call `obs_op_TYPE`. Thus, no additional routine inside the observation module is required in this case.
     212
     213
     214== obs_op_adj_pdafomi ==
     215
     216The routine is called during the analysis step of the 3D-Var methods and it is only required in this case (3D-Var methods have been added with PDAF V2.0). It has to perform the operation of the adjoint observation operator acting on an observation vector that is provided as `m_state_p`. The resulting state vector has to be returned in `state_p`. In this routine one just calls `obs_op_adj_TYPE` for each observation type.
     217
     218The '''interface''' for this routine is:
     219{{{
     220SUBROUTINE obs_op_adj_pdafomi(step, dim_p, dim_obs_p, state_p, m_state_p)
     221
     222  INTEGER, INTENT(in) :: step               ! Currrent time step
     223  INTEGER, INTENT(in) :: dim_p              ! PE-local dimension of state
     224  INTEGER, INTENT(in) :: dim_obs_p          ! Dimension of observed state
     225  REAL, INTENT(in)    :: m_state_p(dim_obs_p) ! PE-local full observed state
     226  REAL, INTENT(inout) :: state_p(dim_p)     ! PE-local model state
     227}}}
     228
     229
     230The '''implementation steps''' are the same as for `obs_op_pdafomi`.
     231
     232An '''example''' is provided in `tutorial/variational/online_2D_serialmodel/`.
     233
     234'''Notes:'''
     235 - The arguments in the calls to `obs_op_adj_TYPE` are input arguments to `obs_op_adj_pdafomi`. They are just passed on.
     236 - The order of the calls to `obs_op_adj_TYPE` is not relevant because the setup of the overall full observation vector is defined by the order of the calls in init_dim_obs_pdafomi. Anyway, it's good practice to keep the order of the calls consistent.
     237 - We don't need an IF-statement with `assim_TYPE` here. The check is done within each obs-module.
     238
     239
     240
     241
     242
     243== deallocate_obs_pdafomi ==
     244
     245The file callback_obs_pdafomi.F90 also contains a routine deallocate_obs_pdafomi. Each obs-module allocates arrays in the observation type `obs_f` and `deallocate_obs_pdafomi` is used to deallocate the different observation-specific arrays after the analysis step.
     246
     247|| [[span(style=color: #FF0000, '''Note:''' Calling `deallocate_obs_pdafomi` is only required in PDAF V1.16. It is no longer required to call it in PDAF V2.0 and later)]] ||
     248
     249The '''implementation steps''' are:
     2501. Include the observation-specific type `thisobs` from the observation-module with 'use' apply a name conversion like `obs_TYPE => thisobs`
     2511. add a call to `PDAFomi_deallocate_obs` giving the observation-specific `obs_TYPE` as argument.
     2521. To perform the deallocation, insert a call to deallocate_obs_pdafomi at the end of the routine `prepoststep_pdaf`.
     253
     254As an '''example''', in `tutorial/online_2D_serialmodel/` we have
     255{{{
     256SUBROUTINE deallocate_obs_pdafomi(step)
     257
     258  USE PDAFomi, ONLY: PDAFomi_deallocate_obs
     259  USE obs_A_pdafomi, ONLY: obs_A => thisobs
     260  USE obs_B_pdafomi, ONLY: obs_B => thisobs
     261  USE obs_C_pdafomi, ONLY: obs_C => thisobs
     262
     263  ... argument declarations omitted ...
     264
     265  CALL PDAFomi_deallocate_obs(obs_A)
     266  CALL PDAFomi_deallocate_obs(obs_B)
     267  CALL PDAFomi_deallocate_obs(obs_C)
     268}}}