PDAF-OMI Debugging Information
PDAF-OMI Guide
- Overview
- callback_obs_pdafomi.F90
- Observation Modules
- Observation Operators
- Checking error status
- Debugging functionality
- Implementing the analysis step with OMI
- Using nondiagonal R-matrices
- Porting an existing implemention to OMI
- Additional OMI Functionality
Contents of this page
Overview
When implementing an observation with PDAF, or when performing the very first implementation of PDAF with a new model, it is useful to check whether the inputs to the PDAF-routines are correctly used. For this purpose, PDAF-OMI provides a debugging functionality. It allows you to activate debugging output e.g. for a single local analysis domain on a single process of a complex application of a local filter like LETKF.
Note: There is a separate debugging output functionality for PDAF itself. For details see the documentation on PDAF debugging. One can activate the debugging for PDAF and PDAF-OMI separately or can used both in combination.
Activating Debugging Output
Debugging output is activated by a call of the form
USE PDAFomi, ONLY: PDAFomi_set_debug_flag INTEGER :: dbg_id ! Debugging flag: >0 for debug output; =0 for no debug output CALLOMI PDAFomi_set_debug_flag(dbg_id)
In particular this call can be inserted in any routines contained in callback_obs_pdafomi.F90
. Setting the single argument of PDAFomi_set_debug_flag
to a value larger 0 will active the output, while =0 will deactivate it. For the debugging it is useful to keep the number of observations low since for a large number of observations, the output will be very lengthy. This can particularly be the case when using the debugging output in init_dim_obs_pdafomi
or obs_op_pdafomi
. To this end, it can be useful to intentionally reduce the number of observations for the debugging. For the localized filters (LESTKF, LETKF, LNETF, LSEIK) it is recommended to only activate the debugging for a single local analysis domain as shown below. The particular domain index can be chosen e.g. based on the coordinates of the domain, which are usually determined in init_dim_l_pdaf
.
For example to activate debugging in init_dim_obs_l_pdafomi
for the local analysis domain domain_p=10
and filter process 0, one uses
SUBROUTINE init_dim_obs_l_pdafomi(domain_p, step, dim_obs, dim_obs_l) USE PDAFomi, ONLY: PDAFomi_set_debug_flag USE mod_parallel_pdaf, ONLY: mype_filter ... IF (domain_p==10 .AND. mype_filter==0) THEN CALL PDAFomi_set_debug_flag(domain_p) ELSE CALL PDAFomi_set_debug_flag(0) ENDIF ...
Understanding the Debugging Output
The debugging output mainly writes information about the different variables contained in the full data type obs_f
allocated as thisobs
and the local type obs_l
allocate as thisobs_l
. For reference we list the full declaration of these types. When reading the debugging output one can check for the meaning of the variables.
TYPE obs_f ! ---- Mandatory variables to be set in INIT_DIM_OBS ---- INTEGER :: doassim=0 !< Whether to assimilate this observation type INTEGER :: disttype !< Type of distance computation to use for localization INTEGER :: ncoord !< Number of coordinates use for distance computation INTEGER, ALLOCATABLE :: id_obs_p(:,:) !< Indices of process-local observed field in state vector ! ---- Optional variables - they can be set in INIT_DIM_OBS ---- REAL, ALLOCATABLE :: icoeff_p(:,:) !< Interpolation coefficients for obs. operator (optional) REAL, ALLOCATABLE :: domainsize(:) !< Size of domain for periodicity (<=0 for no periodicity) (optional) ! ---- Variables with predefined values - they can be changed in INIT_DIM_OBS ---- INTEGER :: obs_err_type=0 !< Type of observation error: (0) Gauss, (1) Laplace INTEGER :: use_global_obs=1 !< Whether to use (1) global full obs. !< or (0) obs. restricted to those relevant for a process domain REAL :: inno_omit=0.0 !< Omit obs. if squared innovation larger this factor times !< observation variance (only active for >0) REAL :: inno_omit_ivar=1.0e-12 !< Value of inverse variance to omit observation !< (should be much larger than actual observation error variance) ! ---- The following variables are set in the routine PDAFomi_gather_obs --- INTEGER :: dim_obs_p !< number of PE-local observations INTEGER :: dim_obs_f !< number of full observations INTEGER :: dim_obs_g !< global number of observations INTEGER :: off_obs_f !< Offset of this observation in overall full obs. vector INTEGER :: off_obs_g !< Offset of this observation in overall global obs. vector INTEGER :: obsid !< Index of observation over all assimilated observations REAL, ALLOCATABLE :: obs_f(:) !< Full observed field REAL, ALLOCATABLE :: ocoord_f(:,:) !< Coordinates of full observation vector REAL, ALLOCATABLE :: ivar_obs_f(:) !< Inverse variance of full observations INTEGER, ALLOCATABLE :: id_obs_f_lim(:) !< Indices of domain-relevant full obs. in global vector of obs. END TYPE obs_f
TYPE obs_l INTEGER :: dim_obs_l !< number of local observations INTEGER :: off_obs_l !< Offset of this observation in overall local obs. vector INTEGER, ALLOCATABLE :: id_obs_l(:) !< Indices of local observations in full obs. vector REAL, ALLOCATABLE :: distance_l(:) !< Distances of local observations REAL, ALLOCATABLE :: cradius_l(:) !< directional cut-off radii of local observations REAL, ALLOCATABLE :: sradius_l(:) !< directional support radii of local observations REAL, ALLOCATABLE :: ivar_obs_l(:) !< Inverse variance of local observations INTEGER :: locweight !< Specify localization function REAL, ALLOCATABLE :: cradius(:) !< Localization cut-off radius (single value or vector) REAL, ALLOCATABLE :: sradius(:) !< support radius for localization function (single value or vector) END TYPE obs_l
Example output
For illustration we insert the above call to PDAFomi_set_debug flag into the routine init_dim_obs_l_pdafomi
the file callback_obs_pdafomi.F90
in tutorial/online_2D_serialmodel/
. Then we compile and execute the tutorial program with:
mpirun -np 4 ./model_pdaf -dim_ens 4 -filtertype 7 -cradius 5 -locweight 2
The first lines of the debugging output looks like this:
++ OMI-debug set_debug_flag: mype_filter 0 activate 10 ++ OMI-debug: 10 PDAFomi_init_dim_obs_l -- START ++ OMI-debug: 10 PDAFomi_init_dim_obs_l -- count local observations ++ OMI-debug init_dim_obs_l: 10 Re-init dim_obs_l=0 ++ OMI-debug init_dim_obs_l: 10 coords_l 1.0000000000000000 10.000000000000000 ++ OMI-debug init_dim_obs_l: 10 Note: Please ensure that coords_l and observation coordinates have the same unit ++ OMI-debug cnt_dim_obs_l: 10 thisobs%ncoord 2 ++ OMI-debug cnt_dim_obs_l: 10 thisobs_l%cradius 5.0000000000000000 ++ OMI-debug cnt_dim_obs_l: 10 Check for observations within radius ++ OMI-debug comp_dist2: 10 compute Cartesian distance ++ OMI-debug cnt_dim_obs_l: 10 valid observation with coordinates 5.0000000000000000 8.0000000000000000 ++ OMI-debug cnt_dim_obs_l: 10 valid observation with coordinates 5.0000000000000000 12.000000000000000 ++ OMI-debug: 10 PDAFomi_init_dim_obs_l -- initialize local observation arrays ++ OMI-debug comp_dist2: 10 compute Cartesian distance ++ OMI-debug init_dim_obs_l: 10 thisobs_l%dim_obs_l 2 ++ OMI-debug init_dim_obs_l: 10 thisobs_l%id_obs_l 2 3 ++ OMI-debug init_dim_obs_l: 10 thisobs_l%distance_l 4.4721359549995796 4.4721359549995796 ++ OMI-debug: 10 PDAFomi_init_dim_obs_l -- END
The first line
++ OMI-debug set_debug_flag: mype_filter 0 activate 10
is from PDAFomi_set_debug_flag showing that debugging is activates with value 10 (which is values fo domain_p
specified in the call)
The next lines are
++ OMI-debug: 10 PDAFomi_init_dim_obs_l -- START ++ OMI-debug: 10 PDAFomi_init_dim_obs_l -- count local observations ++ OMI-debug init_dim_obs_l: 10 Re-init dim_obs_l=0
show that debugging output for PDAFomi_init_dim_obs_l is shown. Most routines show such a 'START' line. The second line shows that a segment of the routine started, the counting of local observations. The third line states that dim_obs_l=0 is set. This line, as many others shows the name of the subroutine in short form without PDAFomi
at the beginning of the line.
The following lines show variable values
++ OMI-debug init_dim_obs_l: 10 coords_l 1.0000000000000000 10.000000000000000 ++ OMI-debug cnt_dim_obs_l: 10 thisobs%ncoord 2 ++ OMI-debug cnt_dim_obs_l: 10 thisobs_l%cradius 5.0000000000000000
First, we see that the coordinates coords_l
of the grid point corresponding to domain_p=10 are (1.0, 10.0). Further we have two dimensions (thisobs%ncoord=2) and the localization radius is set to 5.0.
In the following lines
++ OMI-debug cnt_dim_obs_l: 10 Check for observations within radius ++ OMI-debug comp_dist2: 10 compute Cartesian distance ++ OMI-debug cnt_dim_obs_l: 10 valid observation with coordinates 5.0000000000000000 8.0000000000000000 ++ OMI-debug cnt_dim_obs_l: 10 valid observation with coordinates 5.0000000000000000 12.000000000000000
it is checked which observations lie within the distance thisobs_l%cradius=5.0 from coords_l=(1.0, 10.0). Two observations with coordinates (5.0, 8.0) and (5.0, 12.0) are found. The following lines
++ OMI-debug: 10 PDAFomi_init_dim_obs_l -- initialize local observation arrays ++ OMI-debug comp_dist2: 10 compute Cartesian distance ++ OMI-debug init_dim_obs_l: 10 thisobs_l%dim_obs_l 2 ++ OMI-debug init_dim_obs_l: 10 thisobs_l%id_obs_l 2 3 ++ OMI-debug init_dim_obs_l: 10 thisobs_l%distance_l 4.4721359549995796 4.4721359549995796
show that observation arrays are initialized. A Cartesian distance is computrd. thisobs_l%dim_obs_l
confirms that 2 local observation were found and they are the elements 2 and 3 of the full observation vector (thisobs_l%id_obs_l= (2, 3)) and the distances are thisobs_l%distance_l=(4.4721359549995796, 4.4721359549995796)
One could now compare this with the input information. Are the values of coords_l correct? Are the coordinates shown those of the second and third observation?
Later in the debugging output (not shown above) we find, for example,
++ OMI-debug: 10 PDAFomi_init_obs_l -- Get local vector of observations ++ OMI-debug g2l_obs: 10 thisobs_l%id_obs_l 2 3 ++ OMI-debug g2l_obs: 10 obs_l -0.84588099999999999 -1.5201499999999999 ++ OMI-debug: 10 PDAFomi_init_obs_l -- Get local vector of inverse obs. variances ++ OMI-debug g2l_obs: 10 thisobs_l%id_obs_l 2 3 ++ OMI-debug g2l_obs: 10 obs_l 4.0000000000000000 4.0000000000000000
These lines are from the internal routine PDAFomi_init_obs_l
, which initializes the local vector of observations. (This is functionality also existing in the 'traditional' form of implementing the observation handling. The documention page about init_obs_l_pdaf explains what is done here.) Important is that not only the local observation vector (two values) is initialized, but also the inverse observation variance (4.0 in this example).
Similarly
++ OMI-debug: 10 PDAFomi_g2l_obs -- START Get local observed ensemble member 1 ++ OMI-debug g2l_obs: 10 thisobs_l%id_obs_l 2 3 ++ OMI-debug g2l_obs: 10 obs_l -0.53940120224649080 0.56425243172725248 ++ OMI-debug: 10 PDAFomi_g2l_obs -- END
shows the localization of the observed ensemble member 1. This is performed in the internal routine PDAFomi_g2l_obs
(see the page about g2l_obs_pdaf). There is analogous output for all of the 4 ensemble states.