Skip to content

Commit 0c512bd

Browse files
authored
Add files for radar Doppler wind processing (#212)
* radar doppler wind processing * correct radial velocity test * improve comments * modify OPS code that fills radial velocity PGE * write out two radial velocity variables
1 parent db2f670 commit 0c512bd

16 files changed

+342
-110
lines changed

Diff for: etc/ukv/cx/Radar.nl

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
&CXControlNL
2+
! These STASH codes correspond to the following variables:
3+
! 2: upper-air u
4+
! 3: upper-air v
5+
! 33: orography
6+
! 150: upper-air w
7+
CxFields=2,3,33,150
8+
/

Diff for: etc/ukv/varobs/Radar.nl

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
&VarobsControlNL
2+
! These indices correspond to the following variables:
3+
! 63: Radial velocity
4+
! 64: Beam tilt (elevation in OPS terminology)
5+
! 65: Gate range
6+
! 66: Gate azimuth
7+
! 69: Station identifier
8+
! 75: Station elevation (altitude above MSL in OPS terminology)
9+
Varfields=63,64,65,66,69,75
10+
/

Diff for: src/opsinputs/opsinputs_cxfields_mod.F90

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ module opsinputs_cxfields_mod
6363
character(len=*), parameter, public :: opsinputs_cxfields_rh = var_rh
6464
character(len=*), parameter, public :: opsinputs_cxfields_u = var_u
6565
character(len=*), parameter, public :: opsinputs_cxfields_v = var_v
66-
character(len=*), parameter, public :: opsinputs_cxfields_w = opsinputs_cxfields_unknown
66+
character(len=*), parameter, public :: opsinputs_cxfields_w = var_w
6767
character(len=*), parameter, public :: opsinputs_cxfields_q = var_q
6868
character(len=*), parameter, public :: opsinputs_cxfields_qc = opsinputs_cxfields_unknown
6969
character(len=*), parameter, public :: opsinputs_cxfields_p_bar = var_prs

Diff for: src/opsinputs/opsinputs_fill_mod.F90

+102-20
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ module opsinputs_fill_mod
6565
opsinputs_fill_fillelementtypefromsimulatedvariable, &
6666
opsinputs_fill_fillelementtype2dfromsimulatedvariable, &
6767
opsinputs_fill_fillinteger, &
68+
opsinputs_fill_fillinteger2d, &
6869
opsinputs_fill_fillreal, &
6970
opsinputs_fill_fillreal2d, &
7071
opsinputs_fill_fillrealfromgeoval, &
@@ -580,11 +581,11 @@ end subroutine opsinputs_fill_fillelementtype2dfromsimulatedvariable
580581
!> \param[in] JediValueVarName
581582
!> Name of the JEDI variable containing observation values.
582583
!> \param[in] JediValueGroup
583-
!> Group of the JEDI variable containing observation values.
584+
!> Group name of the JEDI variable containing observation values.
584585
!> \param[in] JediErrorVarName
585586
!> (Optional) Name of the JEDI variable containing observation errors.
586587
!> \param[in] JediErrorGroup
587-
!> (Optional) Group of the JEDI variable containing observation errors.
588+
!> (Optional) Group name of the JEDI variable containing observation errors.
588589
!> \param[in] PackPGEs
589590
!> Optional; true by default. If set to false, PGEs won't be stored in packed form.
590591
!> The Ops_VarobPGEs subroutine expects PGEs to be stored in packed form for most varobs fields,
@@ -693,11 +694,11 @@ end subroutine opsinputs_fill_fillelementtypefromnormalvariable
693694
!> \param[in] JediValueVarName
694695
!> Name of the JEDI variable containing observation values.
695696
!> \param[in] JediValueGroup
696-
!> Group of the JEDI variable containing observation values.
697+
!> Group name of the JEDI variable containing observation values.
697698
!> \param[in] JediErrorVarName
698699
!> (Optional) Name of the JEDI variable containing observation errors.
699700
!> \param[in] JediErrorGroup
700-
!> (Optional) Group of the JEDI variable containing observation errors.
701+
!> (Optional) Group name of the JEDI variable containing observation errors.
701702
!> \param[in] PackPGEs
702703
!> Optional; true by default. If set to false, PGEs won't be stored in packed form.
703704
!> The Ops_VarobPGEs subroutine expects PGEs to be stored in packed form for most varobs fields,
@@ -829,13 +830,13 @@ end subroutine opsinputs_fill_fillelementtype2dfromnormalvariable
829830
!> \param[in] JediValueVarName
830831
!> Name of the JEDI variable containing observation values.
831832
!> \param[in] JediValueGroup
832-
!> Group of the JEDI variable containing observation values.
833+
!> Group name of the JEDI variable containing observation values.
833834
!> \param[in] LevelsAreTopToBottom
834835
!> A logical to specify if the levels being passed in are top to bottom in the atmosphere.
835836
!> \param[in] JediErrorVarName
836837
!> (Optional) Name of the JEDI variable containing observation errors.
837838
!> \param[in] JediErrorGroup
838-
!> (Optional) Group of the JEDI variable containing observation errors.
839+
!> (Optional) Group name of the JEDI variable containing observation errors.
839840
!>
840841
!> \note This function returns early (without a warning) if the specified JEDI variable is not found.
841842
!> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield
@@ -950,7 +951,7 @@ end subroutine opsinputs_fill_fillelementtype2dfromnormalvariablewithlevels
950951
!> \param[in] JediVarName
951952
!> Name of the JEDI variable used to populate \p Real1.
952953
!> \param[in] JediGroup
953-
!> Group of the JEDI variable used to populate \p Real1.
954+
!> Group name of the JEDI variable used to populate \p Real1.
954955
!>
955956
!> \note This function returns early (without a warning) if the specified JEDI variable is not found.
956957
!> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield
@@ -1030,7 +1031,7 @@ end subroutine opsinputs_fill_fillreal
10301031
!> variable with no channel suffix (in which case \p Real2 will have only a single row) or a set
10311032
!> of variables with suffixes corresponding to the indices specified in \p Channels.
10321033
!> \param[in] JediGroup
1033-
!> Group of the JEDI variable used to populate \p Real2.
1034+
!> Group name of the JEDI variable used to populate \p Real2.
10341035
!> \param[in] compressVarChannels
10351036
!> Whether to apply var channel compression (No NaN spaces between channels)
10361037
!> \param[in] sizeOfVarobsArray
@@ -1165,7 +1166,7 @@ end subroutine opsinputs_fill_fillreal2d_norecords
11651166
!> \param[in] JediVarName
11661167
!> Name of the JEDI variable used to populate \p Real2.
11671168
!> \param[in] JediGroup
1168-
!> Group of the JEDI variable used to populate \p Real2.
1169+
!> Group name of the JEDI variable used to populate \p Real2.
11691170
!>
11701171
!> \note This function returns early (without a warning) if the specified JEDI variable is not found.
11711172
!> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield
@@ -1235,7 +1236,7 @@ end subroutine opsinputs_fill_fillreal2d_records
12351236
!> \param[inout] Hdr
12361237
!> Header to be populated.
12371238
!> \param[in] OpsVarName
1238-
!> Name of the OB_type field to which \p Real1 corresponds.
1239+
!> Name of the OB_type field to which \p Real2 corresponds.
12391240
!> \param[in] JediToOpsLayoutMapping
12401241
!> Data needed to map JEDI locations stored on the current PE to OPS observations.
12411242
!> \param[inout] Real2
@@ -1254,7 +1255,7 @@ end subroutine opsinputs_fill_fillreal2d_records
12541255
!> suffix (in which case \p Real2 will have only a single row) or a set of variables with
12551256
!> suffixes corresponding to the indices specified in \p Channels.
12561257
!> \param[in] JediGroup
1257-
!> Group of the JEDI variable used to populate \p Real2.
1258+
!> Group name of the JEDI variable used to populate \p Real2.
12581259
!>
12591260
!> \note This function returns early (without a warning) if the specified JEDI variable is not found.
12601261
!> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield
@@ -1764,7 +1765,7 @@ end subroutine opsinputs_fill_fillreal2dfromgeovalformultilevelobs
17641765
!> \param[in] JediVarName
17651766
!> Name of the JEDI variable used to populate \p Int1.
17661767
!> \param[in] JediGroup
1767-
!> Group of the JEDI variable used to populate \p Int1.
1768+
!> Group name of the JEDI variable used to populate \p Int1.
17681769
!>
17691770
!> \note This function returns early (without a warning) if the specified JEDI variable is not found.
17701771
!> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield
@@ -1817,6 +1818,87 @@ subroutine opsinputs_fill_fillinteger( &
18171818
end if
18181819
end subroutine opsinputs_fill_fillinteger
18191820

1821+
1822+
! ------------------------------------------------------------------------------
1823+
!> Populate a 2D array of integers and its header from a JEDI variable.
1824+
!>
1825+
!> \param[inout] Hdr
1826+
!> Header to be populated.
1827+
!> \param[in] OpsVarName
1828+
!> Name of the OB_type field to which \p Int2 corresponds.
1829+
!> \param[in] JediToOpsLayoutMapping
1830+
!> Data needed to map JEDI locations stored on the current PE to OPS observations.
1831+
!> \param[inout] Int2
1832+
!> Pointer to the array to be populated.
1833+
!> \param[in] ObsSpace
1834+
!> Pointer to ioda::ObsSpace object containing the specified JEDI variable. The variable can
1835+
!> have either no channel suffix (in which case \p Int2 will have only a single row) or suffixes
1836+
!> representing the indices specified in \p Channels.
1837+
!> \param[in] Channels
1838+
!> Indices returned by ioda::ObsSpace::obsvariables().channels().
1839+
!> \param[in] VarobsLength
1840+
!> Length of varobs profile.
1841+
!> \param[in] JediVarName
1842+
!> Name of the JEDI variable used to populate \p Int2. If each JEDI location needs to be mapped
1843+
!> to a separate OPS observation, this can represent either a single variable with no channel
1844+
!> suffix (in which case \p Int2 will have only a single row) or a set of variables with
1845+
!> suffixes corresponding to the indices specified in \p Channels.
1846+
!> \param[in] JediGroup
1847+
!> Group name of the JEDI variable used to populate \p Int2.
1848+
!>
1849+
!> \note This function returns early (without a warning) if the specified JEDI variable is not found.
1850+
!> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield
1851+
!> are not found.
1852+
subroutine opsinputs_fill_fillinteger2d( &
1853+
Hdr, OpsVarName, JediToOpsLayoutMapping, Int2, ObsSpace, Channels, &
1854+
VarobsLength, JediVarName, JediVarGroup)
1855+
implicit none
1856+
1857+
! Subroutine arguments:
1858+
type(ElementHeader_Type), intent(inout) :: Hdr
1859+
character(len=*), intent(in) :: OpsVarName
1860+
type(opsinputs_jeditoopslayoutmapping), intent(in) :: JediToOpsLayoutMapping
1861+
integer(integer64), pointer, intent(out) :: Int2(:,:)
1862+
type(c_ptr), value, intent(in) :: ObsSpace
1863+
integer(c_int), intent(in) :: Channels(:)
1864+
integer(integer64), intent(in) :: VarobsLength
1865+
character(len=*), intent(in) :: JediVarName
1866+
character(len=*), intent(in) :: JediVarGroup
1867+
! todo(someone): add optional arguments used in opsinputs_fill_fillreal2d if there is a need.
1868+
1869+
! Local declarations:
1870+
integer(kind=c_int) :: VarValue(JediToOpsLayoutMapping % NumJediObs)
1871+
integer(kind=c_int) :: CurrentVarValue
1872+
integer(kind=c_int) :: MissingInt
1873+
integer :: i
1874+
integer :: numchans
1875+
1876+
! Body:
1877+
1878+
MissingInt = missing_value(0_c_int32_t)
1879+
1880+
! todo(someone): add this if needed
1881+
if (JediToOpsLayoutMapping % ConvertRecordsToMultilevelObs) then
1882+
call abor1_ftn("must extend opsinputs_fill_fillreal2d to deal with multi-level observations")
1883+
end if
1884+
1885+
! todo(someone): make this configurable if required
1886+
numchans = 1
1887+
1888+
if (obsspace_has(ObsSpace, JediVarGroup, JediVarName)) then
1889+
! Retrieve data from JEDI
1890+
call obsspace_get_db(ObsSpace, JediVarGroup, JediVarName, VarValue)
1891+
1892+
! Fill the OPS data structures
1893+
call Ops_Alloc(Hdr, OpsVarName, JediToOpsLayoutMapping % NumOpsObs, Int2, &
1894+
num_levels = int(numchans, kind=integer64))
1895+
do i = 1, JediToOpsLayoutMapping % NumOpsObs
1896+
CurrentVarValue = VarValue(i)
1897+
if (CurrentVarValue /= MissingInt) Int2(i, 1) = CurrentVarValue
1898+
end do
1899+
end if
1900+
end subroutine opsinputs_fill_fillinteger2d
1901+
18201902
! ------------------------------------------------------------------------------
18211903

18221904
!> Populate a 1D array of strings and its header from a JEDI variable.
@@ -1837,7 +1919,7 @@ end subroutine opsinputs_fill_fillinteger
18371919
!> \param[in] JediVarName
18381920
!> Name of the JEDI variable used to populate \p String1.
18391921
!> \param[in] JediGroup
1840-
!> Group of the JEDI variable used to populate \p String1.
1922+
!> Group name of the JEDI variable used to populate \p String1.
18411923
!> \param[in] ConvertIntToSTring
18421924
!> Convert an integer-valued ObsSpace vector to a string.
18431925
!> \note This function returns early (without a warning) if the specified JEDI variable is not found.
@@ -1934,7 +2016,7 @@ end subroutine opsinputs_fill_fillstring
19342016
!> \param[in] JediVarName
19352017
!> Name of the JEDI variable used to populate \p Real1.
19362018
!> \param[in] JediGroup
1937-
!> Group of the JEDI variable used to populate \p Real1.
2019+
!> Group name of the JEDI variable used to populate \p Real1.
19382020
!> \param[in] ReferenceTime
19392021
!> Reference time. JEDI datetimes will be converted into offsets from this time.
19402022
!>
@@ -2010,7 +2092,7 @@ end subroutine opsinputs_fill_filltimeoffsets
20102092
!> variable with no channel suffix (in which case \p Real2 will have only a single row) or a set
20112093
!> of variables with suffixes corresponding to the indices specified in \p Channels.
20122094
!> \param[in] JediGroup
2013-
!> Group of the JEDI variable used to populate \p Real2.
2095+
!> Group name of the JEDI variable used to populate \p Real2.
20142096
!> \param[in] ReferenceTime
20152097
!> Reference time. JEDI datetimes will be converted into offsets from this time.
20162098
!>
@@ -2085,7 +2167,7 @@ end subroutine opsinputs_fill_filltimeoffsets2d_norecords
20852167
!> \param[in] JediVarName
20862168
!> Name of the JEDI variable used to populate \p Real2.
20872169
!> \param[in] JediGroup
2088-
!> Group of the JEDI variable used to populate \p Real2.
2170+
!> Group name of the JEDI variable used to populate \p Real2.
20892171
!> \param[in] ReferenceTime
20902172
!> Reference time. JEDI datetimes will be converted into offsets from this time.
20912173
!>
@@ -2181,7 +2263,7 @@ end subroutine opsinputs_fill_filltimeoffsets2d_records
21812263
!> suffix (in which case \p Real2 will have only a single row) or a set of variables with
21822264
!> suffixes corresponding to the indices specified in \p Channels.
21832265
!> \param[in] JediGroup
2184-
!> Group of the JEDI variable used to populate \p Real2.
2266+
!> Group name of the JEDI variable used to populate \p Real2.
21852267
!> \param[in] ReferenceTime
21862268
!> Reference time. JEDI datetimes will be converted into offsets from this time.
21872269
!>
@@ -2249,7 +2331,7 @@ end subroutine opsinputs_fill_filltimeoffsets2d
22492331
!> variable with no channel suffix (in which case \p Coord2 will have only a single row) or a set
22502332
!> of variables with suffixes corresponding to the indices specified in \p Channels.
22512333
!> \param[in] JediGroup
2252-
!> Group of the JEDI variable used to populate \p Coord2.
2334+
!> Group name of the JEDI variable used to populate \p Coord2.
22532335
!>
22542336
!> \note This function returns early (without a warning) if the specified JEDI variable is not found.
22552337
!> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield
@@ -2318,7 +2400,7 @@ end subroutine opsinputs_fill_fillcoord2d_norecords
23182400
!> \param[in] JediVarName
23192401
!> Name of the JEDI variable used to populate \p Coord2.
23202402
!> \param[in] JediGroup
2321-
!> Group of the JEDI variable used to populate \p Coord2.
2403+
!> Group name of the JEDI variable used to populate \p Coord2.
23222404
!>
23232405
!> \note This function returns early (without a warning) if the specified JEDI variable is not found.
23242406
!> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield
@@ -2390,7 +2472,7 @@ end subroutine opsinputs_fill_fillcoord2d_records
23902472
!> suffix (in which case \p Coord2 will have only a single row) or a set of variables with
23912473
!> suffixes corresponding to the indices specified in \p Channels.
23922474
!> \param[in] JediGroup
2393-
!> Group of the JEDI variable used to populate \p Coord2.
2475+
!> Group name of the JEDI variable used to populate \p Coord2.
23942476
!>
23952477
!> \note This function returns early (without a warning) if the specified JEDI variable is not found.
23962478
!> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield

Diff for: src/opsinputs/opsinputs_varobswriter_mod.F90

+26-12
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ module opsinputs_varobswriter_mod
3535
opsinputs_fill_fillelementtypefromsimulatedvariable, &
3636
opsinputs_fill_fillelementtype2dfromsimulatedvariable, &
3737
opsinputs_fill_fillinteger, &
38+
opsinputs_fill_fillinteger2d, &
3839
opsinputs_fill_fillreal, &
3940
opsinputs_fill_fillreal2d, &
4041
opsinputs_fill_fillrealfromgeoval, &
@@ -1013,8 +1014,17 @@ subroutine opsinputs_varobswriter_populateobservations( &
10131014
! TODO(someone): handle this varfield
10141015
! call Ops_Alloc(Ob % Header % SBUVozone, "SBUVozone", Ob % Header % NumObsLocal, Ob % SBUVozone)
10151016
case (VarField_RadialVelocity)
1016-
! TODO(someone): handle this varfield
1017-
! call Ops_Alloc(Ob % Header % RadialVelocSO, "RadialVelocSO", Ob % Header % NumObsLocal, Ob % RadialVelocSO)
1017+
! Write DerivedObsValue/radialVelocity to both Ob % RadialVelocSO and Ob % RadialVelocity.
1018+
! This ensures that the code in deps/ops/stubs/OpsMod_Varobs/Ops_VarobPGEs.inc works correctly.
1019+
! The logical `RadWind_SuperOb` is always false in opsinputs, but is true in operational OPS.
1020+
! By default that results in PGEs not being filled correctly. Writing out both OPS variables
1021+
! fixes the problem.
1022+
call opsinputs_fill_fillelementtype2dfromsimulatedvariable( &
1023+
Ob % Header % RadialVelocSO, "RadialVelocSO", JediToOpsLayoutMapping, Ob % RadialVelocSO, &
1024+
ObsSpace, self % channels, Flags, ObsErrors, self % VarobsLength, "radialVelocity", "ObsValue")
1025+
call opsinputs_fill_fillelementtype2dfromsimulatedvariable( &
1026+
Ob % Header % RadialVelocity, "RadialVelocity", JediToOpsLayoutMapping, Ob % RadialVelocity, &
1027+
ObsSpace, self % channels, Flags, ObsErrors, self % VarobsLength, "radialVelocity", "ObsValue")
10181028
case (VarField_Reflectivity)
10191029
! TODO(someone): handle this varfield
10201030
! call Ops_Alloc(Ob % Header % ReflectivitySO, "ReflectivitySO", Ob % Header % NumObsLocal, Ob % ReflectivitySO)
@@ -1025,21 +1035,25 @@ subroutine opsinputs_varobswriter_populateobservations( &
10251035
! TODO(someone): handle this varfield
10261036
! call Ops_Alloc(Ob % Header % ReflectivityI, "ReflectivityI", Ob % Header % NumObsLocal, Ob % ReflectivityI)
10271037
case (VarField_RadarBeamElev)
1028-
! TODO(someone): handle this varfield
1029-
! call Ops_Alloc(Ob % Header % RadarBeamElev, "RadarBeamElev", Ob % Header % NumObsLocal, Ob % RadarBeamElev)
1038+
call opsinputs_fill_fillreal2d( &
1039+
Ob % Header % RadarBeamElev, "RadarBeamElev", JediToOpsLayoutMapping, Ob % RadarBeamElev, &
1040+
ObsSpace, self % channels, self % VarobsLength, "beamTiltAngle", "MetaData")
10301041
case (VarField_RadarObRange)
1031-
! TODO(someone): handle this varfield
1032-
! call Ops_Alloc(Ob % Header % RadarObRange, "RadarObRange", Ob % Header % NumObsLocal, Ob % RadarObRange)
1042+
call opsinputs_fill_fillreal2d( &
1043+
Ob % Header % RadarObRange, "RadarObRange", JediToOpsLayoutMapping, Ob % RadarObRange, &
1044+
ObsSpace, self % channels, self % VarobsLength, "gateRange", "MetaData")
10331045
case (VarField_RadarObAzim)
10341046
call opsinputs_fill_fillreal2d( &
1035-
Ob % Header % RadarObAzim, "RadarObAzim", JediToOpsLayoutMapping, Ob % RadarObAzim, &
1036-
ObsSpace, self % channels, self % VarobsLength, "radarAzimuth", "MetaData")
1047+
Ob % Header % RadarObAzim, "RadarObAzim", JediToOpsLayoutMapping, Ob % RadarObAzim, &
1048+
ObsSpace, self % channels, self % VarobsLength, "beamAzimuthAngle", "MetaData")
10371049
case (VarField_RadIdent)
1038-
! TODO(someone): handle this varfield
1039-
! call Ops_Alloc(Ob % Header % RadIdent, "RadIdent", Ob % Header % NumObsLocal, Ob % RadIdent)
1050+
call opsinputs_fill_fillinteger2d( &
1051+
Ob % Header % RadIdent, "RadIdent", JediToOpsLayoutMapping, Ob % RadIdent, &
1052+
ObsSpace, self % channels, self % VarobsLength, "stationIdentification", "MetaData")
10401053
case (VarField_RadAltAboveMSL)
1041-
! TODO(someone): handle this varfield
1042-
! call Ops_Alloc(Ob % Header % RadAltAboveMSL, "RadAltAboveMSL", Ob % Header % NumObsLocal, Ob % RadAltAboveMSL)
1054+
call opsinputs_fill_fillreal2d( &
1055+
Ob % Header % RadAltAboveMSL, "RadAltAboveMSL", JediToOpsLayoutMapping, Ob % RadAltAboveMSL, &
1056+
ObsSpace, self % channels, self % VarobsLength, "stationElevation", "MetaData")
10431057
case (VarField_RadNoiseLvl)
10441058
! TODO(someone): handle this varfield
10451059
! call Ops_Alloc(Ob % Header % RadNoiseLvl, "RadNoiseLvl", Ob % Header % NumObsLocal, Ob % RadNoiseLvl)

0 commit comments

Comments
 (0)