Changes between Initial Version and Version 1 of OMI_Callback_obs_pdafomi_PDAF23


Ignore:
Timestamp:
Jun 3, 2025, 12:56:16 PM (4 days ago)
Author:
lnerger
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • OMI_Callback_obs_pdafomi_PDAF23

    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">Overview</a></li>
     8<li>callback_obs_pdafomi.F90</li>
     9<li><a href="OMI_observation_modules">Observation Modules</a></li>
     10<li><a href="OMI_observation_operators">Observation operators</a></li>
     11<li><a href="OMI_error_checking">Checking error status</a></li>
     12<li><a href="OMI_debugging">Debugging functionality</a></li>
     13<li><a href="OMI_ImplementationofAnalysisStep">Implementing the analysis step with OMI</a></li>
     14<ol>
     15<li> <a href="ImplementFilterAnalysisOverview"> General overview for ensemble filters</a></li>
     16<ol>
     17<li><a href="ImplementAnalysisGlobal">Implementation for Global Filters</a></li>
     18<li><a href="ImplementAnalysisLocal">Implementation for Local Filters</a></li>
     19<li><a href="ImplementAnalysislenkfOmi">Implementation for LEnKF</a></li>
     20</ol>
     21<li> <a href="Implement3DVarAnalysisOverview"> General overview for 3D-Var methods</a></li>
     22<ol>
     23<li><a href="ImplementAnalysis_3DVar">Implementation for 3D-Var</a></li>
     24<li><a href="ImplementAnalysis_3DEnVar">Implementation for 3D Ensemble Var</a></li>
     25<li><a href="ImplementAnalysis_Hyb3DVar">Implementation for Hybrid 3D-Var</a></li>
     26</ol>
     27</ol>
     28<li><a href="OMI_nondiagonal_observation_error_covariance_matrices">Using nondiagonal R-matrices</a></li>
     29<li><a href="Porting_to_OMI">Porting an existing implemention to OMI</a></li>
     30<li><a href="PDAFomi_additional_functionality">Additional OMI Functionality</a></li>
     31</ol>
     32</div>
     33}}}
     34
     35[[PageOutline(2-3,Contents of this page)]]
     36
     37The 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.
     38
     39The 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/`.
     40
     41The 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.
     42
     43In 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`.
     44
     45
     46== init_dim_obs_pdafomi ==
     47
     48The 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.
     49
     50The '''interface''' for this routine is:
     51{{{
     52SUBROUTINE init_dim_obs_pdafomi(step, dim_obs_p)
     53
     54  INTEGER, INTENT(in)  :: step       ! Current time step
     55  INTEGER, INTENT(out) :: dim_obs_p  ! Dimension of observation vector
     56}}}
     57
     58In 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.
     59
     60
     61The '''implementation steps''' are:
     621. Include the observation-specific routine `init_dim_obs_TYPE` and the variable `assim_TYPE` from the observation-module with 'use'
     631. Declare a dimension variable `dim_obs_TYPE` and initialize it to 0
     641. Add a call to the observation-specific routine init_dim_obs_TYPE with the condition `IF (assim_TYPE)`
     651. add `dim_obs_TYPE` to the final sum computing `dim_obs`.
     66
     67As 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
     68{{{
     69SUBROUTINE init_dim_obs_pdafomi(step, dim_obs)
     70
     71  USE obs_A_pdafomi, ONLY: assim_A, init_dim_obs_A
     72  USE obs_B_pdafomi, ONLY: assim_B, init_dim_obs_B
     73  USE obs_C_pdafomi, ONLY: assim_C, init_dim_obs_C
     74
     75  ... argument declarations omitted ...
     76
     77  INTEGER :: dim_obs_A ! Observation dimensions
     78  INTEGER :: dim_obs_B ! Observation dimensions
     79  INTEGER :: dim_obs_C ! Observation dimensions
     80
     81  dim_obs_A = 0
     82  dim_obs_B = 0
     83  dim_obs_C = 0
     84
     85  IF (assim_A) CALL init_dim_obs_A(step, dim_obs_A)
     86  IF (assim_B) CALL init_dim_obs_B(step, dim_obs_B)
     87  IF (assim_C) CALL init_dim_obs_C(step, dim_obs_C)
     88
     89  dim_obs = dim_obs_A + dim_obs_B + dim_obs_C
     90}}}
     91
     92
     93'''Notes:'''
     94 - 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.
     95 - 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`.
     96
     97
     98
     99== obs_op_pdafomi ==
     100
     101The 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.
     102
     103The '''interface''' for this routine is:
     104{{{
     105SUBROUTINE obs_op_pdafomi(step, dim_p, dim_obs_p, state_p, m_state_p)
     106
     107  INTEGER, INTENT(in) :: step               ! Currrent time step
     108  INTEGER, INTENT(in) :: dim_p              ! PE-local dimension of state
     109  INTEGER, INTENT(in) :: dim_obs_p          ! Dimension of observed state
     110  REAL, INTENT(in)    :: state_p(dim_p)     ! PE-local model state
     111  REAL, INTENT(out) :: m_state_p(dim_obs_p) ! PE-local observed state
     112}}}
     113
     114The '''implementation steps''' are:
     1151. Include the observation-specific routine `obs_op_TYPE` from the observation-module with 'use'
     1161. Add a call to the observation-specific routine `obs_op_TYPEz
     117
     118As an '''example''', in `tutorial/online_2D_serialmodel/` we have
     119{{{
     120SUBROUTINE obs_op_pdafomi(step, dim_p, dim_obs, state_p, ostate)
     121
     122  USE obs_A_pdafomi, ONLY: obs_op_A
     123  USE obs_B_pdafomi, ONLY: obs_op_B
     124  USE obs_C_pdafomi, ONLY: obs_op_C
     125
     126  ... argument declarations omitted ...
     127
     128  CALL obs_op_A(dim_p, dim_obs, state_p, ostate)
     129  CALL obs_op_B(dim_p, dim_obs, state_p, ostate)
     130  CALL obs_op_C(dim_p, dim_obs, state_p, ostate)
     131}}}
     132
     133'''Notes:'''
     134 - The arguments in the calls to `obs_op_TYPE` are input arguments to `obs_op_pdafomi`. They are just passed on.
     135 - 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.
     136 - We don't need an IF-statement with `assim_TYPE` here. The check is done within each obs-module.
     137
     138
     139== init_dim_obs_l_pdafomi ==
     140
     141In 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).
     142
     143The '''implementation steps''' are:
     1441. Include the observation-specific routine `init_dim_obs_l_TYPE` from the observation-module with 'use'
     1451. Add a call to the observation-specific routine init_dim_obs_l_TYPE
     146
     147As an '''example''', in `tutorial/online_2D_serialmodel/` we have
     148{{{
     149SUBROUTINE init_dim_obs_l_pdafomi(domain_p, step, dim_obs, dim_obs_l)
     150
     151  USE obs_A_pdafomi, ONLY: init_dim_obs_l_A
     152  USE obs_B_pdafomi, ONLY: init_dim_obs_l_B
     153  USE obs_C_pdafomi, ONLY: init_dim_obs_l_C
     154
     155  ... argument declarations omitted ...
     156
     157  CALL init_dim_obs_l_A(domain_p, step, dim_obs, dim_obs_l)
     158  CALL init_dim_obs_l_B(domain_p, step, dim_obs, dim_obs_l)
     159  CALL init_dim_obs_l_C(domain_p, step, dim_obs, dim_obs_l)
     160}}}
     161
     162'''Notes:'''
     163 - 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.
     164
     165== localize_covar_pdafomi ==
     166
     167In this routine one calls `localize_covar_TYPE` for each observation type. The routine is only required for the localized EnKF and performs covariance localization.
     168
     169The '''implementation steps''' are:
     1701. Include the observation-specific routine `localize_covar_TYPE` from the observation-module with 'use'
     1711. Initialize the array `coords` which holds the coordinates of all elements of the state vector for the current process domain
     1721. Add a call to the observation-specific routine localize_covar_TYPE
     173
     174As an '''example''', in `tutorial/online_2D_serialmodel/` we have
     175{{{
     176SUBROUTINE localize_covar_pdafomi(dim_p, dim_obs, HP_p, HPH)
     177
     178  USE obs_A_pdafomi, ONLY: localize_covar_A
     179  USE obs_B_pdafomi, ONLY: localize_covar_B
     180  USE obs_C_pdafomi, ONLY: localize_covar_C
     181
     182  ... argument declarations omitted ...
     183
     184  REAL, ALLOCATABLE :: coords_p(:,:) ! Coordinates of PE-local state vector entries
     185
     186  ALLOCATE(coords_p(2, dim_p))
     187  coords_p = ...                     ! Initialize coords_p
     188
     189  CALL localize_covar_A(dim_p, dim_obs, HP_p, HPH, coords_p)
     190  CALL localize_covar_B(dim_p, dim_obs, HP_p, HPH, coords_p)
     191  CALL localize_covar_C(dim_p, dim_obs, HP_p, HPH, coords_p)
     192
     193  DEALLOCATE(coords_p)
     194}}}
     195
     196'''Notes:'''
     197 - 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`.
     198 - 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.
     199
     200
     201
     202== obs_op_lin_pdafomi ==
     203
     204The 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.
     205
     206The '''interface''' for this routine is:
     207{{{
     208SUBROUTINE obs_op_lin_pdafomi(step, dim_p, dim_obs_p, state_p, m_state_p)
     209
     210  INTEGER, INTENT(in) :: step               ! Currrent time step
     211  INTEGER, INTENT(in) :: dim_p              ! PE-local dimension of state
     212  INTEGER, INTENT(in) :: dim_obs_p          ! Dimension of observed state
     213  REAL, INTENT(in)    :: state_p(dim_p)     ! PE-local model state
     214  REAL, INTENT(out) :: m_state_p(dim_obs_p) ! PE-local observed state
     215}}}
     216
     217
     218The '''implementation steps''' are the same as for `obs_op_pdafomi`.
     219
     220An '''example''' is provided in `tutorial/variational/online_2D_serialmodel/`.
     221
     222'''Notes:'''
     223 - The arguments in the calls to `obs_op_lin_TYPE` are input arguments to `obs_op_pdafomi`. They are just passed on.
     224 - 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.
     225 - We don't need an IF-statement with `assim_TYPE` here. The check is done within each obs-module.
     226 - 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.
     227
     228
     229== obs_op_adj_pdafomi ==
     230
     231The 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.
     232
     233The '''interface''' for this routine is:
     234{{{
     235SUBROUTINE obs_op_adj_pdafomi(step, dim_p, dim_obs_p, state_p, m_state_p)
     236
     237  INTEGER, INTENT(in) :: step               ! Currrent time step
     238  INTEGER, INTENT(in) :: dim_p              ! PE-local dimension of state
     239  INTEGER, INTENT(in) :: dim_obs_p          ! Dimension of observed state
     240  REAL, INTENT(in)    :: m_state_p(dim_obs_p) ! PE-local full observed state
     241  REAL, INTENT(inout) :: state_p(dim_p)     ! PE-local model state
     242}}}
     243
     244
     245The '''implementation steps''' are the same as for `obs_op_pdafomi`.
     246
     247An '''example''' is provided in `tutorial/variational/online_2D_serialmodel/`.
     248
     249'''Notes:'''
     250 - The arguments in the calls to `obs_op_adj_TYPE` are input arguments to `obs_op_adj_pdafomi`. They are just passed on.
     251 - 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.
     252 - We don't need an IF-statement with `assim_TYPE` here. The check is done within each obs-module.
     253
     254
     255
     256
     257
     258== deallocate_obs_pdafomi ==
     259
     260The 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.
     261
     262|| [[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)]] ||
     263
     264The '''implementation steps''' are:
     2651. Include the observation-specific type `thisobs` from the observation-module with 'use' apply a name conversion like `obs_TYPE => thisobs`
     2661. add a call to `PDAFomi_deallocate_obs` giving the observation-specific `obs_TYPE` as argument.
     2671. To perform the deallocation, insert a call to deallocate_obs_pdafomi at the end of the routine `prepoststep_pdaf`.
     268
     269As an '''example''', in `tutorial/online_2D_serialmodel/` we have
     270{{{
     271SUBROUTINE deallocate_obs_pdafomi(step)
     272
     273  USE PDAFomi, ONLY: PDAFomi_deallocate_obs
     274  USE obs_A_pdafomi, ONLY: obs_A => thisobs
     275  USE obs_B_pdafomi, ONLY: obs_B => thisobs
     276  USE obs_C_pdafomi, ONLY: obs_C => thisobs
     277
     278  ... argument declarations omitted ...
     279
     280  CALL PDAFomi_deallocate_obs(obs_A)
     281  CALL PDAFomi_deallocate_obs(obs_B)
     282  CALL PDAFomi_deallocate_obs(obs_C)
     283}}}