From b30d9128a182b522fb8da84617e29e665f5378b5 Mon Sep 17 00:00:00 2001 From: Michael Cooke <48374999+mikecooke77@users.noreply.github.com> Date: Thu, 9 May 2024 09:33:49 +0100 Subject: [PATCH 1/6] Changes needed for the VarBc code sprint at JCSDA (#200) * First change attempt * Fix spacing issue --- src/opsinputs/opsinputs_varobswriter_mod.F90 | 62 +++++++++--------- test/generate_unittest_netcdfs.py | 2 +- .../testinput/080_VarField_biaspredictors.nc4 | Bin 20179 -> 20179 bytes 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/opsinputs/opsinputs_varobswriter_mod.F90 b/src/opsinputs/opsinputs_varobswriter_mod.F90 index 4f0bab50..c112d709 100644 --- a/src/opsinputs/opsinputs_varobswriter_mod.F90 +++ b/src/opsinputs/opsinputs_varobswriter_mod.F90 @@ -1487,37 +1487,37 @@ subroutine opsinputs_varobswriter_fillpredictors( & integer :: ii, jj integer, parameter :: maxpred = 31 character(len=*), parameter :: PredictorBaseName(1:maxpred) = (/ & - "constant ", & - "thickness_850_300hPa ", & - "thickness_200_50hPa ", & - "Tskin ", & - "total_column_water ", & - "Legendre_order_1 ", & - "Legendre_order_2 ", & - "Legendre_order_3 ", & - "Legendre_order_4 ", & - "Legendre_order_5 ", & - "Legendre_order_6 ", & - "orbital_angle_order_1_cos ", & - "orbital_angle_order_1_sin ", & - "orbital_angle_order_2_cos ", & - "orbital_angle_order_2_sin ", & - "orbital_angle_order_3_cos ", & - "orbital_angle_order_3_sin ", & - "orbital_angle_order_4_cos ", & - "orbital_angle_order_4_sin ", & - "orbital_angle_order_5_cos ", & - "orbital_angle_order_5_sin ", & - "orbital_angle_order_6_cos ", & - "orbital_angle_order_6_sin ", & - "orbital_angle_order_7_cos ", & - "orbital_angle_order_7_sin ", & - "orbital_angle_order_8_cos ", & - "orbital_angle_order_8_sin ", & - "orbital_angle_order_9_cos ", & - "orbital_angle_order_9_sin ", & - "orbital_angle_order_10_cos", & - "orbital_angle_order_10_sin" /) + "constant ", & + "thickness_850_300hPa ", & + "thickness_200_50hPa ", & + "Tskin ", & + "total_column_water ", & + "legendre_order_1 ", & + "legendre_order_2 ", & + "legendre_order_3 ", & + "legendre_order_4 ", & + "legendre_order_5 ", & + "legendre_order_6 ", & + "satelliteOrbitalAngle_order_1_cos ", & + "satelliteOrbitalAngle_order_1_sin ", & + "satelliteOrbitalAngle_order_2_cos ", & + "satelliteOrbitalAngle_order_2_sin ", & + "satelliteOrbitalAngle_order_3_cos ", & + "satelliteOrbitalAngle_order_3_sin ", & + "satelliteOrbitalAngle_order_4_cos ", & + "satelliteOrbitalAngle_order_4_sin ", & + "satelliteOrbitalAngle_order_5_cos ", & + "satelliteOrbitalAngle_order_5_sin ", & + "satelliteOrbitalAngle_order_6_cos ", & + "satelliteOrbitalAngle_order_6_sin ", & + "satelliteOrbitalAngle_order_7_cos ", & + "satelliteOrbitalAngle_order_7_sin ", & + "satelliteOrbitalAngle_order_8_cos ", & + "satelliteOrbitalAngle_order_8_sin ", & + "satelliteOrbitalAngle_order_9_cos ", & + "satelliteOrbitalAngle_order_9_sin ", & + "satelliteOrbitalAngle_order_10_cos", & + "satelliteOrbitalAngle_order_10_sin" /) character(len=150) :: JediVarGroupWithSatId ! Body: diff --git a/test/generate_unittest_netcdfs.py b/test/generate_unittest_netcdfs.py index 5c2ffd76..ecb3d207 100644 --- a/test/generate_unittest_netcdfs.py +++ b/test/generate_unittest_netcdfs.py @@ -674,7 +674,7 @@ def copy_var_to_var(Group, invarname, outvarname, filename): output_2d_normal_var_to_netcdf ('brightnessTemperature', ['constant_satid_5Predictor', 'constant_satid_8Predictor', 'thickness_850_300hPa_satid_5Predictor','thickness_850_300hPa_satid_8Predictor', 'thickness_200_50hPa_satid_5Predictor', 'thickness_200_50hPa_satid_8Predictor', - 'Legendre_order_1_satid_5Predictor', 'Legendre_order_1_satid_8Predictor'], + 'legendre_order_1_satid_5Predictor', 'legendre_order_1_satid_8Predictor'], 'testinput/080_VarField_biaspredictors.nc4', predictors=True) output_2d_simulated_var_to_netcdf('bendingAngle', 'testinput/071_VarField_bendingangle.nc4', add_occulting_satid=True) output_2d_normal_var_to_netcdf('impactParameterRO', 'MetaData', 'testinput/072_VarField_impactparam.nc4') diff --git a/test/testinput/080_VarField_biaspredictors.nc4 b/test/testinput/080_VarField_biaspredictors.nc4 index 76692c16f7dc1f0346f1048f85a6be2d44986701..382a073e10801551ffcc443b3b06f26807207b98 100644 GIT binary patch delta 459 zcmcaSm+|sk#tBEYEcJ|ZGE&k^Z4LDdP4tWe1Q>uI!w^I=FnB^J28Q{9iJLaQw`LJW zQ@)_@m&s;Z)}34|-(p(CChr#v+3Y8f%gD0PUe<5(e!+{3EX>z8TY<%22(M+DyjIL$ z@>d|X6*rjN3dCoDSX9Dbax4%p1>(0rY$|CmxfY0zN(L|m@N8C;lHuNLz@f!B*;aKw za|-jb&Hq*ZGO|eZwWdr~^i0{DqH&s;+4{nl$woRlEYn}V)CY?m(|O3q;>P!R#^eHR zi^=txqMLu{?Pp?HZ}3ri@@~UmE`cDwVul7L1_qPKyhaj}4U9zDtZ&ac&fqiI+enSY zhhfIq&59gujGK2Gr?RlfZdL!aS;eB1g+jB`qI z!8~OrMkbc6Rp0+j)^M?52@k#81r|Qz;>5_vFqz-&9!v10WShw!-E<@a4*1`8^Kfxu zkQIamHPA_AXJ77{Z07F7m@~Q3-Iy_F^ICUH7M3WuI!w^I=FnB^J28P(8WTuVptyzT8 zl+V4yHFdKs>rO6~8_V{%Pu?#Wve{1{myw0B^HbyI{el-6Srj(Ny#kBB5MIl~$UoUn zRDAMOF#|>+FzYCgB?@MJ1+pZ-ELCv>MrklB6v&bTvs!^HMKEhCkfj1!G9X7Xf3&y>w6 z8mF0=>rbzkY^0;Z!gjE>5G;C3=OH7DW{Awf$pzXLlj}7_H~-Mv&%|Q9VIJ4y-G;#m z`5)LC80vu`B+bBefvt-{l!<}CoZ-vq4c!brK&HuLJtJ|pDFq5E7#b#f8>z8WF)Oof zR^)JF+`QX3m4)U1RUiA!Di)V12hl>+~tROW0 yfX=be)R&uV=I+GkGr7{;n9*nRT6aqpmN(&wfnam|d_d-Gp6F}G$g+BdtqcH`5u=F! From bcd0f0317e03b5c7990138d1635f4580e6ff1fd9 Mon Sep 17 00:00:00 2001 From: Chris Thomas <32307951+ctgh@users.noreply.github.com> Date: Mon, 20 May 2024 14:21:09 +0100 Subject: [PATCH 2/6] Account for integer `MetaData/stationIdentification` (#206) * integer MetaData/stationIdentification * remove output * add new files --- src/opsinputs/VarObsWriterParameters.h | 3 ++ src/opsinputs/opsinputs_fill_mod.F90 | 44 +++++++++++++++--- src/opsinputs/opsinputs_varobswriter_mod.F90 | 6 ++- test/CMakeLists.txt | 3 ++ test/generate_unittest_netcdfs.py | 25 ++++++++++ .../001_VarField_pstar_stationID_integer.nc4 | Bin 0 -> 10072 bytes .../001_VarField_pstar_stationID_integer.yaml | 27 +++++++++++ 7 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 test/testinput/001_VarField_pstar_stationID_integer.nc4 create mode 100644 test/testinput/001_VarField_pstar_stationID_integer.yaml diff --git a/src/opsinputs/VarObsWriterParameters.h b/src/opsinputs/VarObsWriterParameters.h index 0e6b9926..3020f63d 100644 --- a/src/opsinputs/VarObsWriterParameters.h +++ b/src/opsinputs/VarObsWriterParameters.h @@ -76,6 +76,9 @@ class VarObsWriterParameters : public oops::ObsFilterParametersBase { /// length of each output profile is set to the length of the profiles in the ObsSpace. oops::Parameter varobsLengthIsIC_PLevels{"varobs_length_is_IC_PLevels", false, this}; + /// Set to true if MetaData/stationIdentification is an integer instead of a string. + oops::Parameter StationIDIntToString{"station_ID_int_to_string", false, this}; + /// Update OPS flag to output the varbc predictors oops::Parameter outputVarBCPredictors{"output_varbc_predictors", false, this}; diff --git a/src/opsinputs/opsinputs_fill_mod.F90 b/src/opsinputs/opsinputs_fill_mod.F90 index 49bef460..9f544501 100644 --- a/src/opsinputs/opsinputs_fill_mod.F90 +++ b/src/opsinputs/opsinputs_fill_mod.F90 @@ -1837,12 +1837,14 @@ end subroutine opsinputs_fill_fillinteger !> Name of the JEDI variable used to populate \p String1. !> \param[in] JediGroup !> Group of the JEDI variable used to populate \p String1. -!> +!> \param[in] ConvertIntToSTring +!> Convert an integer-valued ObsSpace vector to a string. !> \note This function returns early (without a warning) if the specified JEDI variable is not found. !> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield !> are not found. subroutine opsinputs_fill_fillstring( & - Hdr, OpsVarName, JediToOpsLayoutMapping, StringLen, String1, ObsSpace, JediVarName, JediVarGroup) + Hdr, OpsVarName, JediToOpsLayoutMapping, StringLen, String1, ObsSpace, JediVarName, JediVarGroup, & + ConvertIntToSTring) implicit none ! Subroutine arguments: @@ -1854,17 +1856,33 @@ subroutine opsinputs_fill_fillstring( & type(c_ptr), value, intent(in) :: ObsSpace character(len=*), intent(in) :: JediVarName character(len=*), intent(in) :: JediVarGroup +logical, optional, intent(in) :: ConvertIntToString ! Local declarations: character(len=StringLen) :: VarValue(JediToOpsLayoutMapping % NumJediObs) +integer(integer64) :: IntVarValue(JediToOpsLayoutMapping % NumJediObs) integer :: i +logical :: IntToString +character(len=20) :: IntAsString ! Body: + + if (obsspace_has(ObsSpace, JediVarGroup, JediVarName)) then + if (present(ConvertIntToString)) then + IntToString = ConvertIntToString + else + IntToString = .false. + end if + ! Retrieve data from JEDI - call opsinputs_obsspace_get_db_string(ObsSpace, JediVarGroup, JediVarName, & - int(StringLen, kind=c_int), VarValue) + if (IntToString) then + call obsspace_get_db(ObsSpace, JediVarGroup, JediVarName, IntVarValue) + else + call opsinputs_obsspace_get_db_string(ObsSpace, JediVarGroup, JediVarName, & + int(StringLen, kind=c_int), VarValue) + end if ! Fill the OPS data structures call Ops_Alloc(Hdr, OpsVarName, JediToOpsLayoutMapping % NumOpsObs, String1) @@ -1872,11 +1890,23 @@ subroutine opsinputs_fill_fillstring( & if (JediToOpsLayoutMapping % ConvertRecordsToMultilevelObs) then if (JediToOpsLayoutMapping % RecordStarts(i + 1) > JediToOpsLayoutMapping % RecordStarts(i)) then ! This record is non-empty. Use the first location from that record. - String1(i) = VarValue(JediToOpsLayoutMapping % LocationsOrderedByRecord( & - JediToOpsLayoutMapping % RecordStarts(i))) + if (IntToString) then + write(IntAsString,"(I0)") & + IntVarValue(JediToOpsLayoutMapping % LocationsOrderedByRecord( & + JediToOpsLayoutMapping % RecordStarts(i))) + String1(i) = IntAsString + else + String1(i) = VarValue(JediToOpsLayoutMapping % LocationsOrderedByRecord( & + JediToOpsLayoutMapping % RecordStarts(i))) + end if end if else - String1(i) = VarValue(i) + if (IntToString) then + write(IntAsString,"(I0)") IntVarValue(i) + String1(i) = IntAsString + else + String1(i) = VarValue(i) + end if end if end do end if diff --git a/src/opsinputs/opsinputs_varobswriter_mod.F90 b/src/opsinputs/opsinputs_varobswriter_mod.F90 index c112d709..fd5b6593 100644 --- a/src/opsinputs/opsinputs_varobswriter_mod.F90 +++ b/src/opsinputs/opsinputs_varobswriter_mod.F90 @@ -155,6 +155,7 @@ module opsinputs_varobswriter_mod logical :: RequireTForTheta logical :: FillObsTypeFromOpsSubType logical :: VarobsLengthIsIC_PLevels + logical :: StationIDIntToString character(len=100) :: latitudeName character(len=100) :: longitudeName @@ -313,6 +314,8 @@ function opsinputs_varobswriter_create(self, f_conf, comm_is_valid, comm, channe call f_conf % get_or_die("varobs_length_is_IC_PLevels", self % VarobsLengthIsIC_PLevels) +call f_conf % get_or_die("station_ID_int_to_string", self % StationIDIntToString) + call f_conf % get_or_die("size_of_varobs_array", self % size_of_varobs_array) call f_conf % get_or_die("compress_var_channels", self % compressVarChannels) @@ -738,7 +741,8 @@ subroutine opsinputs_varobswriter_populateobservations( & if (obsspace_has(ObsSpace, "MetaData", "stationIdentification")) then call opsinputs_fill_fillstring(Ob % Header % Callsign, "Callsign", JediToOpsLayoutMapping, & - LenCallSign, Ob % Callsign, ObsSpace, "stationIdentification", "MetaData") + LenCallSign, Ob % Callsign, ObsSpace, "stationIdentification", "MetaData", & + self % StationIDIntToString) else if (obsspace_has(ObsSpace, "MetaData", "satelliteIdentifier")) then call opsinputs_varobswriter_fillsatid(Ob, ObsSpace, JediToOpsLayoutMapping) call Ops_Alloc(Ob % Header % Callsign, "Callsign", JediToOpsLayoutMapping % NumOpsObs, Ob % Callsign) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a85ce1f1..4fa7d9d7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -106,6 +106,9 @@ set_tests_properties(test_opsinputs_varobswriter_setup PROPERTIES FIXTURES_SETUP ADD_WRITER_TEST(NAME varobswriter_001_VarField_pstar YAML 001_VarField_pstar.yaml DATA 001_VarField_pstar.nc4) +ADD_WRITER_TEST(NAME varobswriter_001_VarField_pstar_stationID_integer + YAML 001_VarField_pstar_stationID_integer.yaml + DATA 001_VarField_pstar_stationID_integer.nc4) ADD_WRITER_TEST(NAME varobswriter_002_VarField_temperature_Surface YAML 002_VarField_temperature_Surface.yaml DATA 002_VarField_temperature_Surface.nc4) diff --git a/test/generate_unittest_netcdfs.py b/test/generate_unittest_netcdfs.py index ecb3d207..303e69b7 100644 --- a/test/generate_unittest_netcdfs.py +++ b/test/generate_unittest_netcdfs.py @@ -69,6 +69,30 @@ def output_1d_simulated_var_to_netcdf(var_name, file_name, with_bias=False): f.close() +def output_1d_simulated_var_to_netcdf_stationID_integer(var_name, file_name): + f = nc4.Dataset(file_name, 'w', format="NETCDF4") + + nlocs = 4 + f.createDimension('Location', nlocs) + + var = f.createVariable('MetaData/latitude', 'f', ('Location',)) + var[:] = [21, 22, -23, 24] + var = f.createVariable('MetaData/longitude', 'f', ('Location',)) + var[:] = [31, 32, 33, 34] + var = f.createVariable('MetaData/time', 'f', ('Location',)) + minute = 1 / 60. + var[:] = [1 * minute, 2 * minute, 3 * minute, 4 * minute] + var = f.createVariable('MetaData/stationIdentification', 'i', ('Location',)) + var[:] = [1, 2, 3, 4] + var = f.createVariable('ObsValue/' + var_name, 'f', ('Location',)) + obsVal = [1.1, missing_float, 1.3, 1.4] + var[:] = obsVal + var = f.createVariable('ObsError/' + var_name, 'f', ('Location',)) + var[:] = [0.1, missing_float, 0.3, 0.4] + f.date_time = 2018010100 + + f.close() + def output_1d_simulated_vars_to_netcdf(var_name_1, var_name_2, file_name): f = nc4.Dataset(file_name, 'w', format="NETCDF4") @@ -640,6 +664,7 @@ def copy_var_to_var(Group, invarname, outvarname, filename): if __name__ == "__main__": # VarObs output_1d_simulated_var_to_netcdf('surfacePressure', 'testinput/001_VarField_pstar.nc4') # Surface + output_1d_simulated_var_to_netcdf_stationID_integer('surfacePressure', 'testinput/001_VarField_pstar_stationID_integer.nc4') output_1d_simulated_var_to_netcdf('airTemperatureAt2M', 'testinput/002_VarField_temperature_Surface.nc4') output_2d_simulated_var_to_netcdf('airTemperature', 'testinput/002_VarField_temperature_RadarZ.nc4') output_1d_simulated_var_to_netcdf('relativeHumidityAt2M', 'testinput/003_VarField_rh_Surface.nc4') diff --git a/test/testinput/001_VarField_pstar_stationID_integer.nc4 b/test/testinput/001_VarField_pstar_stationID_integer.nc4 new file mode 100644 index 0000000000000000000000000000000000000000..03038252af23786944c23ed6431905b224310075 GIT binary patch literal 10072 zcmeHNZ)jUp6hFyZv$yzWI@j2#lf70pMQ7-`IwqR6S(2{Z(xfC~3_loOn-}*W%bPE+ zRfcX35n3$xdHP|B%s)6pa36#U>Oh##A|m?DevtWTqB2FqKh$&Hz4xWf*2<&-3HOk^ z^WMGZo_p@^oOko*_ojzZgB!zlhJ&gKLKe9ky_dE0@Q&NhY=0*=l*$LSi@|QMO4A4zY%pM0?#Jx)o@&5`@M%#5HsA7N4UaT!;|i zt9Nht`agyrx{JI8d{=74a4mPDWL^uhX+m3>fwx#Z-B7WsPkI)A@Ij$YX2A!*I@daG ze$3a)LXUFOJVkGU^4{-a#$E=!;FGH`IZZb8fmk^O^&9bZd*o3QBZMWVvX*iZK zRxx9`kUpS*g6RKN&?ul{)^x{9<-U}4+$upkV#hGiz2I<8luSo{2g9)Q-!as0fMJ-> zRqkh=e|}cIjl3!W*g~2?L0X`>a-%;p+svg z*1TOEE}2!=DqG{;)g|5QgwVndv)-u28)d|Fjg;XUKQTKHcapdb)ZAF@h*6m^&vi44 zbNTa6aa*oVT|D^(`PS0ZK>79xu$WDbI`#?EaV-Rk3XwdJ-$~PPLI3>R zT%4|7IeT^=p6^2wDG~vRfJ8tdAQ6xV{Lc{}%15x8KC#YY)@F#YS0DmCL^kHrgXw%a zn@kryvT+Z7Eg%vB`5mKXx^>pkr*%Q4exH>^E>f@uLJK-wfYeC&2)0d!&9@co%&IZFx8CX(b)r6Lf0N_(h45GhsWH+6}*`Jv!@yKV|WH9#vV(4M)(ALf`C$b4g!b?0zBf=I?*pcB&akA8n1K6U%$`wO@W)HR&G_ YYrK|87u>SYYn^m|KjcO5`W1cgAE3Lq`v3p{ literal 0 HcmV?d00001 diff --git a/test/testinput/001_VarField_pstar_stationID_integer.yaml b/test/testinput/001_VarField_pstar_stationID_integer.yaml new file mode 100644 index 00000000..30e798d7 --- /dev/null +++ b/test/testinput/001_VarField_pstar_stationID_integer.yaml @@ -0,0 +1,27 @@ +time window: + begin: 2018-01-01T00:00:00Z + end: 2018-01-01T02:00:00Z + +observations: + - obs space: + name: Surface + obsdatain: + engine: + type: H5File + obsfile: Data/001_VarField_pstar_stationID_integer.nc4 + simulated variables: [surfacePressure] + obs filters: + # Set the flag of observations with missing values to "pass": we want to check if these + # values are encoded correctly in the VarObsFile. + - filter: Reset Flags to Pass + flags_to_reset: [10, 15] # missing, Hfailed + - filter: VarObs Writer + # Convert integer station ID to string. + station_ID_int_to_string: true + general_mode: debug + - filter: VarObs Checker + expected_main_table_columns: + Callsign: ["1", "2", "3", "4"] + HofX: ObsValue # just a placeholder -- not used, but needed to force calls to postFilter. + benchmarkFlag: 1000 # just to keep the ObsFilters test happy + flaggedBenchmark: 0 From f8e68f613a34cf2f3ebc3f8a21039f943dd7f1c2 Mon Sep 17 00:00:00 2001 From: Michael Cooke <48374999+mikecooke77@users.noreply.github.com> Date: Mon, 20 May 2024 17:56:34 +0100 Subject: [PATCH 3/6] Fixes the failures associated with oops ObsVariables introduction (#207) Code now compiling --- src/opsinputs/CxWriter.cc | 3 +-- src/opsinputs/CxWriter.h | 5 +++-- src/opsinputs/CxWriter.interface.F90 | 5 +++-- src/opsinputs/CxWriter.interface.h | 3 ++- src/opsinputs/VarObsWriter.cc | 3 +-- src/opsinputs/VarObsWriter.h | 5 +++-- src/opsinputs/VarObsWriter.interface.F90 | 5 +++-- src/opsinputs/VarObsWriter.interface.h | 3 ++- src/opsinputs/opsinputs_cxwriter_mod.F90 | 5 +++-- src/opsinputs/opsinputs_fill_mod.F90 | 3 ++- src/opsinputs/opsinputs_obsdatavector_f.cc | 6 +++--- src/opsinputs/opsinputs_obsdatavector_f.h | 5 +++-- src/opsinputs/opsinputs_varobswriter_mod.F90 | 5 +++-- test/opsinputs/CxChecker.h | 5 +++-- test/opsinputs/ResetFlagsToPass.cc | 1 - test/opsinputs/ResetFlagsToPass.h | 5 +++-- test/opsinputs/VarObsChecker.cc | 1 - test/opsinputs/VarObsChecker.h | 5 +++-- 18 files changed, 41 insertions(+), 32 deletions(-) diff --git a/src/opsinputs/CxWriter.cc b/src/opsinputs/CxWriter.cc index 2018f867..1ca7058a 100644 --- a/src/opsinputs/CxWriter.cc +++ b/src/opsinputs/CxWriter.cc @@ -13,7 +13,6 @@ #include "ioda/ObsDataVector.h" #include "ioda/ObsSpace.h" #include "ioda/ObsVector.h" -#include "oops/base/Variables.h" #include "oops/util/Logger.h" #include "opsinputs/CxWriterParameters.h" #include "opsinputs/LocalEnvironment.h" @@ -93,7 +92,7 @@ void CxWriter::postFilter(const ufo::GeoVaLs & gv, ufo::Variables filtervars; for (const ufo::Variable &var : parameters_.variables_for_qc.value().get()) filtervars += var; - ioda::ObsDataVector flags(obsdb_, filtervars.toOopsVariables()); + ioda::ObsDataVector flags(obsdb_, filtervars.toOopsObsVariables()); for (int ivar = 0; ivar < flags.nvars(); ivar++) { const std::string varname = flags.varnames()[ivar]; flags[varname] = flags_->operator[](varname); diff --git a/src/opsinputs/CxWriter.h b/src/opsinputs/CxWriter.h index b9891821..c0ece6da 100644 --- a/src/opsinputs/CxWriter.h +++ b/src/opsinputs/CxWriter.h @@ -11,6 +11,7 @@ #include #include "ioda/ObsDataVector.h" +#include "oops/base/ObsVariables.h" #include "oops/base/Variables.h" #include "oops/interface/ObsFilterBase.h" #include "oops/util/ObjectCounter.h" @@ -64,7 +65,7 @@ class CxWriter : public oops::interface::ObsFilterBase, void checkFilterData(const oops::FilterStage filterStage) override {} oops::Variables requiredVars() const override {return geovars_;} - oops::Variables requiredHdiagnostics() const override {return extradiagvars_;} + oops::ObsVariables requiredHdiagnostics() const override {return extradiagvars_;} private: void print(std::ostream &) const override; @@ -77,7 +78,7 @@ class CxWriter : public oops::interface::ObsFilterBase, ioda::ObsSpace & obsdb_; oops::Variables geovars_; - oops::Variables extradiagvars_; + oops::ObsVariables extradiagvars_; std::shared_ptr> flags_; std::shared_ptr> obsErrors_; diff --git a/src/opsinputs/CxWriter.interface.F90 b/src/opsinputs/CxWriter.interface.F90 index f5cf7e73..7728fb0d 100644 --- a/src/opsinputs/CxWriter.interface.F90 +++ b/src/opsinputs/CxWriter.interface.F90 @@ -10,6 +10,7 @@ module opsinputs_cxwriter_mod_c c_bool, & c_int, & c_ptr +use obs_variables_mod, only: obs_variables use oops_variables_mod, only: oops_variables use opsinputs_cxwriter_mod, only: & opsinputs_cxwriter, & @@ -112,13 +113,13 @@ subroutine opsinputs_cxwriter_post_c(c_self, c_obspace, c_geovals, c_flags, & type(opsinputs_cxwriter), pointer :: self type(ufo_geovals), pointer :: geovals -type(oops_variables) :: f_varnames +type(obs_variables) :: f_varnames call opsinputs_cxwriter_registry%get(c_self, self) call ufo_geovals_registry%get(c_geovals, geovals) ! Obtain simulated variable names. -f_varnames = oops_variables(c_varnames) +f_varnames = obs_variables(c_varnames) call opsinputs_cxwriter_post(self, c_obspace, geovals, c_flags, & f_varnames, c_hofx) diff --git a/src/opsinputs/CxWriter.interface.h b/src/opsinputs/CxWriter.interface.h index 96d4cfe9..d8fe3d4f 100644 --- a/src/opsinputs/CxWriter.interface.h +++ b/src/opsinputs/CxWriter.interface.h @@ -7,6 +7,7 @@ #define OPSINPUTS_CXWRITER_INTERFACE_H_ #include "ioda/ObsSpace.h" +#include "oops/base/ObsVariables.h" #include "oops/base/Variables.h" #include "ufo/Fortran.h" @@ -37,7 +38,7 @@ extern "C" { const ufo::F90goms &, const ioda::ObsDataVector &flags, const int &nvars, const int &nlocs, - const oops::Variables &varnames, const double *hofx); + const oops::ObsVariables &varnames, const double *hofx); } // extern C } // namespace opsinputs diff --git a/src/opsinputs/VarObsWriter.cc b/src/opsinputs/VarObsWriter.cc index 69e350e2..d254f145 100644 --- a/src/opsinputs/VarObsWriter.cc +++ b/src/opsinputs/VarObsWriter.cc @@ -15,7 +15,6 @@ #include "ioda/ObsDataVector.h" #include "ioda/ObsSpace.h" #include "ioda/ObsVector.h" -#include "oops/base/Variables.h" #include "oops/mpi/mpi.h" #include "oops/util/IntSetParser.h" #include "oops/util/Logger.h" @@ -121,7 +120,7 @@ void VarObsWriter::postFilter(const ufo::GeoVaLs & gv, ufo::Variables filtervars; for (const ufo::Variable &var : parameters_.variables_for_qc.value().get()) filtervars += var; - ioda::ObsDataVector flags(obsdb_, filtervars.toOopsVariables()); + ioda::ObsDataVector flags(obsdb_, filtervars.toOopsObsVariables()); for (int ivar = 0; ivar < flags.nvars(); ivar++) { std::string varname = flags.varnames()[ivar]; flags[varname] = flags_->operator[](varname); diff --git a/src/opsinputs/VarObsWriter.h b/src/opsinputs/VarObsWriter.h index 585dbb42..6c4d214b 100644 --- a/src/opsinputs/VarObsWriter.h +++ b/src/opsinputs/VarObsWriter.h @@ -13,6 +13,7 @@ #include #include "ioda/ObsDataVector.h" +#include "oops/base/ObsVariables.h" #include "oops/base/Variables.h" #include "oops/interface/ObsFilterBase.h" #include "oops/util/ObjectCounter.h" @@ -73,7 +74,7 @@ class VarObsWriter : public oops::interface::ObsFilterBase, void checkFilterData(const oops::FilterStage filterStage) override {} oops::Variables requiredVars() const override {return geovars_;} - oops::Variables requiredHdiagnostics() const override {return extradiagvars_;} + oops::ObsVariables requiredHdiagnostics() const override {return extradiagvars_;} private: void print(std::ostream &) const override; @@ -86,7 +87,7 @@ class VarObsWriter : public oops::interface::ObsFilterBase, ioda::ObsSpace & obsdb_; oops::Variables geovars_; - oops::Variables extradiagvars_; + oops::ObsVariables extradiagvars_; std::shared_ptr> flags_; std::shared_ptr> obsErrors_; std::vector varchannels_; diff --git a/src/opsinputs/VarObsWriter.interface.F90 b/src/opsinputs/VarObsWriter.interface.F90 index b4e920e2..eb4bd6ff 100644 --- a/src/opsinputs/VarObsWriter.interface.F90 +++ b/src/opsinputs/VarObsWriter.interface.F90 @@ -44,6 +44,7 @@ function opsinputs_varobswriter_create_c(c_self, c_conf, c_comm_is_valid, c_comm c_varlist, c_varlist_diags) & bind(c,name='opsinputs_varobswriter_create_f90') use oops_variables_mod +use obs_variables_mod implicit none integer(c_int), intent(inout) :: c_self type(c_ptr), value, intent(in) :: c_conf @@ -61,14 +62,14 @@ function opsinputs_varobswriter_create_c(c_self, c_conf, c_comm_is_valid, c_comm type(fckit_configuration) :: f_conf integer(gc_int_kind) :: f_comm type(oops_variables) :: f_varlist -type(oops_variables) :: f_varlist_diags +type(obs_variables) :: f_varlist_diags call opsinputs_varobswriter_registry%setup(c_self, self) f_conf = fckit_configuration(c_conf) f_comm = c_comm f_varlist = oops_variables(c_varlist) -f_varlist_diags = oops_variables(c_varlist_diags) +f_varlist_diags = obs_variables(c_varlist_diags) if (opsinputs_varobswriter_create(self, f_conf, c_comm_is_valid, f_comm, c_channels, & f_varlist, f_varlist_diags)) then opsinputs_varobswriter_create_c = 1 diff --git a/src/opsinputs/VarObsWriter.interface.h b/src/opsinputs/VarObsWriter.interface.h index a3103e4d..73281395 100644 --- a/src/opsinputs/VarObsWriter.interface.h +++ b/src/opsinputs/VarObsWriter.interface.h @@ -9,6 +9,7 @@ #include #include "ioda/ObsSpace.h" +#include "oops/base/ObsVariables.h" #include "oops/base/Variables.h" #include "ufo/Fortran.h" @@ -34,7 +35,7 @@ extern "C" { const MPI_Fint &comm, const int &nchannels, const int *channels, - oops::Variables &, oops::Variables &); + oops::Variables &, oops::ObsVariables &); void opsinputs_varobswriter_delete_f90(F90check &); void opsinputs_varobswriter_prior_f90(const F90check &, const ioda::ObsSpace &, const ufo::F90goms &); diff --git a/src/opsinputs/opsinputs_cxwriter_mod.F90 b/src/opsinputs/opsinputs_cxwriter_mod.F90 index 6767bbbe..67738a66 100644 --- a/src/opsinputs/opsinputs_cxwriter_mod.F90 +++ b/src/opsinputs/opsinputs_cxwriter_mod.F90 @@ -22,6 +22,7 @@ module opsinputs_cxwriter_mod use obsspace_mod, only: & obsspace_get_db, & obsspace_get_nlocs +use obs_variables_mod, only: obs_variables use oops_variables_mod, only: oops_variables use opsinputs_cxfields_mod use opsinputs_fill_mod, only: & @@ -173,7 +174,7 @@ module opsinputs_cxwriter_mod type(ufo_geovals), pointer :: GeoVals type(opsinputs_jeditoopslayoutmapping) :: JediToOpsLayoutMapping - type(oops_variables) :: varnames + type(obs_variables) :: varnames real(c_double), pointer :: hofx(:, :) end type opsinputs_cxwriter @@ -501,7 +502,7 @@ subroutine opsinputs_cxwriter_post(self, ObsSpace, GeoVals, Flags, varnames, hof type(c_ptr), value, intent(in) :: ObsSpace type(ufo_geovals), intent(in), pointer :: GeoVals type(c_ptr), value, intent(in) :: Flags -type(oops_variables), intent(in) :: varnames +type(obs_variables), intent(in) :: varnames real(c_double), intent(in), target :: hofx(:, :) ! Local declarations: diff --git a/src/opsinputs/opsinputs_fill_mod.F90 b/src/opsinputs/opsinputs_fill_mod.F90 index 9f544501..e016154e 100644 --- a/src/opsinputs/opsinputs_fill_mod.F90 +++ b/src/opsinputs/opsinputs_fill_mod.F90 @@ -17,6 +17,7 @@ module opsinputs_fill_mod use obsspace_mod, only: & obsspace_has, & obsspace_get_db +use obs_variables_mod, only: obs_variables use oops_variables_mod, only: oops_variables use ufo_geovals_mod, only: & ufo_geoval, & @@ -1487,7 +1488,7 @@ subroutine opsinputs_fill_fillreal2dfromgeovalorhofx( & character(len=*), intent(in) :: JediVarName type(opsinputs_jeditoopslayoutmapping), intent(in) :: JediToOpsLayoutMapping real(c_double), intent(in) :: hofx(:, :) -type(oops_variables), intent(in) :: varnames +type(obs_variables), intent(in) :: varnames character(len=*), intent(in), optional :: JediObsName logical, intent(in), optional :: WriteHofXIntoCX diff --git a/src/opsinputs/opsinputs_obsdatavector_f.cc b/src/opsinputs/opsinputs_obsdatavector_f.cc index 0be6a677..b918bc98 100644 --- a/src/opsinputs/opsinputs_obsdatavector_f.cc +++ b/src/opsinputs/opsinputs_obsdatavector_f.cc @@ -24,7 +24,7 @@ int opsinputs_obsdatavector_nlocs_f(const ioda::ObsDataVector &vec) { } template -const oops::Variables * opsinputs_obsdatavector_varnames_f( +const oops::ObsVariables * opsinputs_obsdatavector_varnames_f( const ioda::ObsDataVector &vec) { return &vec.varnames(); } @@ -50,7 +50,7 @@ int opsinputs_obsdatavector_int_nlocs_f(const ioda::ObsDataVector &vec) { return opsinputs_obsdatavector_nlocs_f(vec); } -const oops::Variables * opsinputs_obsdatavector_int_varnames_f( +const oops::ObsVariables * opsinputs_obsdatavector_int_varnames_f( const ioda::ObsDataVector &vec) { return opsinputs_obsdatavector_varnames_f(vec); } @@ -70,7 +70,7 @@ int opsinputs_obsdatavector_float_nlocs_f(const ioda::ObsDataVector &vec) return opsinputs_obsdatavector_nlocs_f(vec); } -const oops::Variables * opsinputs_obsdatavector_float_varnames_f( +const oops::ObsVariables * opsinputs_obsdatavector_float_varnames_f( const ioda::ObsDataVector &vec) { return opsinputs_obsdatavector_varnames_f(vec); } diff --git a/src/opsinputs/opsinputs_obsdatavector_f.h b/src/opsinputs/opsinputs_obsdatavector_f.h index 408c0e50..460480ac 100644 --- a/src/opsinputs/opsinputs_obsdatavector_f.h +++ b/src/opsinputs/opsinputs_obsdatavector_f.h @@ -15,6 +15,7 @@ namespace ioda { } // namespace ioda namespace oops { + class ObsVariables; class Variables; } // namespace oops @@ -22,7 +23,7 @@ namespace opsinputs { extern "C" { int opsinputs_obsdatavector_int_nlocs_f(const ioda::ObsDataVector &vec); - const oops::Variables * opsinputs_obsdatavector_int_varnames_f( + const oops::ObsVariables * opsinputs_obsdatavector_int_varnames_f( const ioda::ObsDataVector &vec); bool opsinputs_obsdatavector_int_has_f(const ioda::ObsDataVector &vec, const char *variable); @@ -31,7 +32,7 @@ extern "C" { const size_t &length, int* data); int opsinputs_obsdatavector_float_nlocs_f(const ioda::ObsDataVector &vec); - const oops::Variables * opsinputs_obsdatavector_float_varnames_f( + const oops::ObsVariables * opsinputs_obsdatavector_float_varnames_f( const ioda::ObsDataVector &vec); bool opsinputs_obsdatavector_float_has_f(const ioda::ObsDataVector &vec, const char *variable); diff --git a/src/opsinputs/opsinputs_varobswriter_mod.F90 b/src/opsinputs/opsinputs_varobswriter_mod.F90 index fd5b6593..5856a791 100644 --- a/src/opsinputs/opsinputs_varobswriter_mod.F90 +++ b/src/opsinputs/opsinputs_varobswriter_mod.F90 @@ -25,6 +25,7 @@ module opsinputs_varobswriter_mod obsspace_get_gnlocs, & obsspace_get_nlocs, & obsspace_has +use obs_variables_mod, only: obs_variables use oops_variables_mod, only: oops_variables use opsinputs_fill_mod, only: & opsinputs_fill_fillcoord2d, & @@ -219,7 +220,7 @@ function opsinputs_varobswriter_create(self, f_conf, comm_is_valid, comm, channe integer(gc_int_kind), intent(in) :: comm integer(c_int), intent(in) :: channels(:) type(oops_variables), intent(inout) :: geovars ! GeoVaLs required by the VarObsWriter. -type(oops_variables), intent(inout) :: diagvars ! HofXDiags required by the VarObsWriter. +type(obs_variables), intent(inout) :: diagvars ! HofXDiags required by the VarObsWriter. logical :: opsinputs_varobswriter_create ! Local declarations: @@ -622,7 +623,7 @@ subroutine opsinputs_varobswriter_addrequireddiagvars(self, diagvars) ! Subroutine arguments: type(opsinputs_varobswriter), intent(in) :: self -type(oops_variables), intent(inout) :: diagvars +type(obs_variables), intent(inout) :: diagvars ! Local declarations: integer(integer64) :: VarFields(ActualMaxVarfield) diff --git a/test/opsinputs/CxChecker.h b/test/opsinputs/CxChecker.h index 1355c08b..53bf8ca9 100644 --- a/test/opsinputs/CxChecker.h +++ b/test/opsinputs/CxChecker.h @@ -14,6 +14,7 @@ #include "../opsinputs/CxCheckerParameters.h" #include "ioda/ObsDataVector.h" +#include "oops/base/ObsVariables.h" #include "oops/base/Variables.h" #include "oops/interface/ObsFilterBase.h" #include "oops/util/ObjectCounter.h" @@ -70,7 +71,7 @@ class CxChecker : public oops::interface::ObsFilterBase, void checkFilterData(const oops::FilterStage filterStage) override {} oops::Variables requiredVars() const override {return geovars_;} - oops::Variables requiredHdiagnostics() const override {return extradiagvars_;} + oops::ObsVariables requiredHdiagnostics() const override {return extradiagvars_;} private: struct PrintCxFileOutput; @@ -94,7 +95,7 @@ class CxChecker : public oops::interface::ObsFilterBase, ioda::ObsSpace & obsdb_; oops::Variables geovars_; - oops::Variables extradiagvars_; + oops::ObsVariables extradiagvars_; std::shared_ptr> flags_; std::shared_ptr> obsErrors_; diff --git a/test/opsinputs/ResetFlagsToPass.cc b/test/opsinputs/ResetFlagsToPass.cc index 87a2c295..e4da069c 100644 --- a/test/opsinputs/ResetFlagsToPass.cc +++ b/test/opsinputs/ResetFlagsToPass.cc @@ -9,7 +9,6 @@ #include "ioda/ObsDataVector.h" #include "ioda/ObsSpace.h" -#include "oops/base/Variables.h" #include "oops/util/IntSetParser.h" // for contains() #include "oops/util/Logger.h" #include "ufo/filters/QCflags.h" diff --git a/test/opsinputs/ResetFlagsToPass.h b/test/opsinputs/ResetFlagsToPass.h index 715e0fac..9fae44c7 100644 --- a/test/opsinputs/ResetFlagsToPass.h +++ b/test/opsinputs/ResetFlagsToPass.h @@ -13,6 +13,7 @@ #include "../opsinputs/ResetFlagsToPassParameters.h" #include "ioda/ObsDataVector.h" +#include "oops/base/ObsVariables.h" #include "oops/base/Variables.h" #include "oops/interface/ObsFilterBase.h" #include "oops/util/ObjectCounter.h" @@ -62,14 +63,14 @@ class ResetFlagsToPass : public oops::interface::ObsFilterBase, void checkFilterData(const oops::FilterStage filterStage) override {} oops::Variables requiredVars() const override {return geovars_;} - oops::Variables requiredHdiagnostics() const override {return extradiagvars_;} + oops::ObsVariables requiredHdiagnostics() const override {return extradiagvars_;} private: void print(std::ostream &) const override; ioda::ObsSpace & obsdb_; oops::Variables geovars_; - oops::Variables extradiagvars_; + oops::ObsVariables extradiagvars_; std::shared_ptr> flags_; ResetFlagsToPassParameters parameters_; diff --git a/test/opsinputs/VarObsChecker.cc b/test/opsinputs/VarObsChecker.cc index ce4a4a08..a0820c4a 100644 --- a/test/opsinputs/VarObsChecker.cc +++ b/test/opsinputs/VarObsChecker.cc @@ -19,7 +19,6 @@ #include "ioda/ObsDataVector.h" #include "ioda/ObsSpace.h" -#include "oops/base/Variables.h" #include "oops/mpi/mpi.h" #include "oops/util/Logger.h" diff --git a/test/opsinputs/VarObsChecker.h b/test/opsinputs/VarObsChecker.h index 82a55d50..1f2f64c4 100644 --- a/test/opsinputs/VarObsChecker.h +++ b/test/opsinputs/VarObsChecker.h @@ -13,6 +13,7 @@ #include "../opsinputs/VarObsCheckerParameters.h" #include "ioda/ObsDataVector.h" +#include "oops/base/ObsVariables.h" #include "oops/base/Variables.h" #include "oops/interface/ObsFilterBase.h" #include "oops/util/ObjectCounter.h" @@ -69,7 +70,7 @@ class VarObsChecker : public oops::interface::ObsFilterBase, void checkFilterData(const oops::FilterStage filterStage) override {} oops::Variables requiredVars() const override {return geovars_;} - oops::Variables requiredHdiagnostics() const override {return extradiagvars_;} + oops::ObsVariables requiredHdiagnostics() const override {return extradiagvars_;} private: struct PrintVarObsOutput; @@ -87,7 +88,7 @@ class VarObsChecker : public oops::interface::ObsFilterBase, ioda::ObsSpace & obsdb_; oops::Variables geovars_; - oops::Variables extradiagvars_; + oops::ObsVariables extradiagvars_; std::shared_ptr> flags_; std::shared_ptr> obsErrors_; From bae4d46844cc58337518cfb55cfa688d97e773ad Mon Sep 17 00:00:00 2001 From: Chris Thomas <32307951+ctgh@users.noreply.github.com> Date: Wed, 22 May 2024 14:07:19 +0100 Subject: [PATCH 4/6] Update global surface CX namelist (#208) * update global CX namelist * add cloud_bulk, cf, cl * update CX table --- etc/global/cx/Surface.nl | 49 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/etc/global/cx/Surface.nl b/etc/global/cx/Surface.nl index 1ec9b744..443b0e77 100644 --- a/etc/global/cx/Surface.nl +++ b/etc/global/cx/Surface.nl @@ -1,5 +1,48 @@ &CXControlNL -cxfields_remove=23, 25, 31, 90, 1235, 3208, 3247, 3255, 3464, 3465, 8223, 8225, 9203, 9204, 9217, 9219, 16222, 20000, 20001, 20002 -cxfields_add=266, 267, 268 - +! All variables below are found in OPS cx outputs for surface processing. Not all are +! necessary for JOPA. +! +! Surface Variables: +! CX Index CX Index Name STASH code for here In OPS cx and required for JOPA? +! ----------------------------------------------------------------------------------------- +! 1 IndexCxorog 33 Yes +! 2 IndexCxpstar 1 Yes +! 3 IndexCxt2 3236 Yes +! 4 IndexCxrh2 3245 Yes +! 5 IndexCxu10 3209 Yes +! 6 IndexCxv10 3210 Yes +! 8 IndexCxvis 3247 No +! 13 IndexCxTskinSea 24 Yes +! 16 IndexCxpmsl 16222 No +! 17 IndexCxSeaIce 31 No +! 22 IndexCxPSurfParamA 20000 No +! 23 IndexCxPSurfParamB 20001 No +! 24 IndexCxCloudAmount 9217 No +! 42 IndexCxSnowAmount 23 No +! 45 IndexCxSWradiation 1235 No +! 46 IndexCxBLheight 25 No +! 48 IndexCxLowCloudAmount 9203 No +! 49 IndexCxMedCloudAmount 9204 No +! 50 IndexCxLowCloudBase 9219 No +! 56 IndexCxObukhovLength 3464 No +! 57 IndexCxFrictionVel 3465 No +! 58 IndexCxLapseRate 20002 No +! +! Upper-air variables: +! CX Index CX Index Name STASH code for here In OPS cx and required for JOPA? +! ----------------------------------------------------------------------------------------- +! 1 IndexCxtheta 4 Yes +! 3 IndexCxu 2 Yes +! 4 IndexCxv 3 Yes +! 5 IndexCxq 10 Yes +! 11 IndexCxp 407 Yes +! 29 IndexCxqcf 12 Yes +! 30 IndexCxqcl 254 Yes +! 31 IndexCxcloud_bulk 266 Yes +! 34 IndexCxCf 267 Yes +! 35 IndexCxCl 268 Yes +! 36 IndexCxRichNumber 3208 No +! 37 IndexCxSoilMoisture 8223 No +! 38 IndexCxSoilTemp 8225 No +CxFields=33,1,3236,3245,3209,3210,24,4,2,3,10,407,12,254,266,267,268 / From db2f670c3d0ff4930a293d592757ad8b0c521af0 Mon Sep 17 00:00:00 2001 From: Josh Colclough <109143205+mo-joshuacolclough@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:52:50 +0100 Subject: [PATCH 5/6] Changes required for addition of `oops::Variable`. Targeted merge: 11/06/24 (#210) Changes to fix segfaults --- src/opsinputs/opsinputs_obsdatavector_mod.F90 | 14 +++++++------- src/opsinputs/opsinputs_utils_mod.F90 | 4 ++-- src/opsinputs/opsinputs_varobswriter_mod.F90 | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/opsinputs/opsinputs_obsdatavector_mod.F90 b/src/opsinputs/opsinputs_obsdatavector_mod.F90 index 8fc00346..f24d7344 100644 --- a/src/opsinputs/opsinputs_obsdatavector_mod.F90 +++ b/src/opsinputs/opsinputs_obsdatavector_mod.F90 @@ -6,7 +6,7 @@ module opsinputs_obsdatavector_mod -use oops_variables_mod, only: oops_variables +use obs_variables_mod, only: obs_variables use string_f_c_mod, only: f_c_string use, intrinsic :: iso_c_binding, only: c_char, c_int, c_float, c_ptr, c_size_t @@ -38,13 +38,13 @@ end function opsinputs_obsdatavector_int_nlocs !> Return an object wrapping the list of names of variables held in this ObsDataVector object. -type(oops_variables) function opsinputs_obsdatavector_int_varnames(c_vec) +type(obs_variables) function opsinputs_obsdatavector_int_varnames(c_vec) !use, intrinsic :: iso_c_binding, only: c_ptr - !use oops_variables_mod + !use obs_variables_mod implicit none type(c_ptr), value, intent(in) :: c_vec - opsinputs_obsdatavector_int_varnames = oops_variables(c_opsinputs_obsdatavector_int_varnames(c_vec)) + opsinputs_obsdatavector_int_varnames = obs_variables(c_opsinputs_obsdatavector_int_varnames(c_vec)) end function opsinputs_obsdatavector_int_varnames !> Return true if this ObsDataVector object contains a given variable. @@ -93,14 +93,14 @@ end function opsinputs_obsdatavector_float_nlocs !> Return an object wrapping the list of names of variables held in this ObsDataVector object. -type(oops_variables) function opsinputs_obsdatavector_float_varnames(c_vec) +type(obs_variables) function opsinputs_obsdatavector_float_varnames(c_vec) !use, intrinsic :: iso_c_binding - use oops_variables_mod + use obs_variables_mod implicit none type(c_ptr), value, intent(in) :: c_vec opsinputs_obsdatavector_float_varnames = & - oops_variables(c_opsinputs_obsdatavector_float_varnames(c_vec)) + obs_variables(c_opsinputs_obsdatavector_float_varnames(c_vec)) end function opsinputs_obsdatavector_float_varnames !> Return true if this ObsDataVector object contains a given variable. diff --git a/src/opsinputs/opsinputs_utils_mod.F90 b/src/opsinputs/opsinputs_utils_mod.F90 index b05a9b31..9f1a550e 100644 --- a/src/opsinputs/opsinputs_utils_mod.F90 +++ b/src/opsinputs/opsinputs_utils_mod.F90 @@ -6,7 +6,7 @@ module opsinputs_utils_mod use, intrinsic :: iso_c_binding, only: c_int32_t -use oops_variables_mod, only: oops_variables +use obs_variables_mod, only: obs_variables use ufo_vars_mod, only: MAXVARLEN use opsinputs_obsdatavector_mod, only: & opsinputs_obsdatavector_int_varnames, & @@ -62,7 +62,7 @@ subroutine opsinputs_utils_fillreportflags( & integer(kind=integer64), intent(out) :: ReportFlags(:) ! Local declarations: -type(oops_variables) :: ObsVariables +type(obs_variables) :: ObsVariables character(max_varname_length) :: VarName integer :: NumObsVariables integer :: iVar, iOpsObs, iJediObsInRecord, iJediObs diff --git a/src/opsinputs/opsinputs_varobswriter_mod.F90 b/src/opsinputs/opsinputs_varobswriter_mod.F90 index 5856a791..48d4fbc0 100644 --- a/src/opsinputs/opsinputs_varobswriter_mod.F90 +++ b/src/opsinputs/opsinputs_varobswriter_mod.F90 @@ -1365,7 +1365,7 @@ subroutine opsinputs_varobswriter_findchannelspassingqc( & ! Local declarations: integer :: NumChannels -type(oops_variables) :: Variables +type(obs_variables) :: Variables character(max_varname_length) :: VariableName integer :: NumVariables, NumMultichannelVariables integer :: iMultichannelVariable, iChannel, iVariable, iObs From 0c512bd92210e421a056b5055336da23e9407e4d Mon Sep 17 00:00:00 2001 From: Chris Thomas <32307951+ctgh@users.noreply.github.com> Date: Mon, 8 Jul 2024 16:47:04 +0100 Subject: [PATCH 6/6] 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 --- etc/ukv/cx/Radar.nl | 8 ++ etc/ukv/varobs/Radar.nl | 10 ++ src/opsinputs/opsinputs_cxfields_mod.F90 | 2 +- src/opsinputs/opsinputs_fill_mod.F90 | 122 +++++++++++++++--- src/opsinputs/opsinputs_varobswriter_mod.F90 | 38 ++++-- test/CMakeLists.txt | 15 ++- test/generate_unittest_netcdfs.py | 53 +++++++- .../testinput/063_VarField_radialVelocity.nc4 | Bin 0 -> 15676 bytes .../063_VarField_radialVelocity.yaml | 44 +++++++ test/testinput/066_VarField_radarobazim.nc4 | Bin 15987 -> 0 bytes test/testinput/066_VarField_radarobazim.yaml | 69 ---------- .../Radar.nl | 3 + .../cx_ukvnamelist_radar_doppler_wind.nc4 | Bin 0 -> 9348 bytes ...writer_ukvnamelist_radar_doppler_wind.yaml | 41 ++++++ .../varobs_ukvnamelist_radar_doppler_wind.nc4 | Bin 0 -> 12493 bytes ...writer_ukvnamelist_radar_doppler_wind.yaml | 47 +++++++ 16 files changed, 342 insertions(+), 110 deletions(-) create mode 100644 etc/ukv/cx/Radar.nl create mode 100644 etc/ukv/varobs/Radar.nl create mode 100644 test/testinput/063_VarField_radialVelocity.nc4 create mode 100644 test/testinput/063_VarField_radialVelocity.yaml delete mode 100644 test/testinput/066_VarField_radarobazim.nc4 delete mode 100644 test/testinput/066_VarField_radarobazim.yaml create mode 100644 test/testinput/VarObsWriterNamelists_063_VarField_radialVelocity/Radar.nl create mode 100644 test/testinput/cx_ukvnamelist_radar_doppler_wind.nc4 create mode 100644 test/testinput/cxwriter_ukvnamelist_radar_doppler_wind.yaml create mode 100644 test/testinput/varobs_ukvnamelist_radar_doppler_wind.nc4 create mode 100644 test/testinput/varobswriter_ukvnamelist_radar_doppler_wind.yaml diff --git a/etc/ukv/cx/Radar.nl b/etc/ukv/cx/Radar.nl new file mode 100644 index 00000000..10cd24bd --- /dev/null +++ b/etc/ukv/cx/Radar.nl @@ -0,0 +1,8 @@ +&CXControlNL +! These STASH codes correspond to the following variables: +! 2: upper-air u +! 3: upper-air v +! 33: orography +! 150: upper-air w +CxFields=2,3,33,150 +/ diff --git a/etc/ukv/varobs/Radar.nl b/etc/ukv/varobs/Radar.nl new file mode 100644 index 00000000..7dd44fc0 --- /dev/null +++ b/etc/ukv/varobs/Radar.nl @@ -0,0 +1,10 @@ +&VarobsControlNL +! These indices correspond to the following variables: +! 63: Radial velocity +! 64: Beam tilt (elevation in OPS terminology) +! 65: Gate range +! 66: Gate azimuth +! 69: Station identifier +! 75: Station elevation (altitude above MSL in OPS terminology) +Varfields=63,64,65,66,69,75 +/ diff --git a/src/opsinputs/opsinputs_cxfields_mod.F90 b/src/opsinputs/opsinputs_cxfields_mod.F90 index 86743976..9361680d 100644 --- a/src/opsinputs/opsinputs_cxfields_mod.F90 +++ b/src/opsinputs/opsinputs_cxfields_mod.F90 @@ -63,7 +63,7 @@ module opsinputs_cxfields_mod character(len=*), parameter, public :: opsinputs_cxfields_rh = var_rh character(len=*), parameter, public :: opsinputs_cxfields_u = var_u character(len=*), parameter, public :: opsinputs_cxfields_v = var_v -character(len=*), parameter, public :: opsinputs_cxfields_w = opsinputs_cxfields_unknown +character(len=*), parameter, public :: opsinputs_cxfields_w = var_w character(len=*), parameter, public :: opsinputs_cxfields_q = var_q character(len=*), parameter, public :: opsinputs_cxfields_qc = opsinputs_cxfields_unknown character(len=*), parameter, public :: opsinputs_cxfields_p_bar = var_prs diff --git a/src/opsinputs/opsinputs_fill_mod.F90 b/src/opsinputs/opsinputs_fill_mod.F90 index e016154e..f2404abc 100644 --- a/src/opsinputs/opsinputs_fill_mod.F90 +++ b/src/opsinputs/opsinputs_fill_mod.F90 @@ -65,6 +65,7 @@ module opsinputs_fill_mod opsinputs_fill_fillelementtypefromsimulatedvariable, & opsinputs_fill_fillelementtype2dfromsimulatedvariable, & opsinputs_fill_fillinteger, & + opsinputs_fill_fillinteger2d, & opsinputs_fill_fillreal, & opsinputs_fill_fillreal2d, & opsinputs_fill_fillrealfromgeoval, & @@ -580,11 +581,11 @@ end subroutine opsinputs_fill_fillelementtype2dfromsimulatedvariable !> \param[in] JediValueVarName !> Name of the JEDI variable containing observation values. !> \param[in] JediValueGroup -!> Group of the JEDI variable containing observation values. +!> Group name of the JEDI variable containing observation values. !> \param[in] JediErrorVarName !> (Optional) Name of the JEDI variable containing observation errors. !> \param[in] JediErrorGroup -!> (Optional) Group of the JEDI variable containing observation errors. +!> (Optional) Group name of the JEDI variable containing observation errors. !> \param[in] PackPGEs !> Optional; true by default. If set to false, PGEs won't be stored in packed form. !> 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 !> \param[in] JediValueVarName !> Name of the JEDI variable containing observation values. !> \param[in] JediValueGroup -!> Group of the JEDI variable containing observation values. +!> Group name of the JEDI variable containing observation values. !> \param[in] JediErrorVarName !> (Optional) Name of the JEDI variable containing observation errors. !> \param[in] JediErrorGroup -!> (Optional) Group of the JEDI variable containing observation errors. +!> (Optional) Group name of the JEDI variable containing observation errors. !> \param[in] PackPGEs !> Optional; true by default. If set to false, PGEs won't be stored in packed form. !> 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 !> \param[in] JediValueVarName !> Name of the JEDI variable containing observation values. !> \param[in] JediValueGroup -!> Group of the JEDI variable containing observation values. +!> Group name of the JEDI variable containing observation values. !> \param[in] LevelsAreTopToBottom !> A logical to specify if the levels being passed in are top to bottom in the atmosphere. !> \param[in] JediErrorVarName !> (Optional) Name of the JEDI variable containing observation errors. !> \param[in] JediErrorGroup -!> (Optional) Group of the JEDI variable containing observation errors. +!> (Optional) Group name of the JEDI variable containing observation errors. !> !> \note This function returns early (without a warning) if the specified JEDI variable is not found. !> 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 !> \param[in] JediVarName !> Name of the JEDI variable used to populate \p Real1. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Real1. +!> Group name of the JEDI variable used to populate \p Real1. !> !> \note This function returns early (without a warning) if the specified JEDI variable is not found. !> 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 !> variable with no channel suffix (in which case \p Real2 will have only a single row) or a set !> of variables with suffixes corresponding to the indices specified in \p Channels. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Real2. +!> Group name of the JEDI variable used to populate \p Real2. !> \param[in] compressVarChannels !> Whether to apply var channel compression (No NaN spaces between channels) !> \param[in] sizeOfVarobsArray @@ -1165,7 +1166,7 @@ end subroutine opsinputs_fill_fillreal2d_norecords !> \param[in] JediVarName !> Name of the JEDI variable used to populate \p Real2. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Real2. +!> Group name of the JEDI variable used to populate \p Real2. !> !> \note This function returns early (without a warning) if the specified JEDI variable is not found. !> 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 !> \param[inout] Hdr !> Header to be populated. !> \param[in] OpsVarName -!> Name of the OB_type field to which \p Real1 corresponds. +!> Name of the OB_type field to which \p Real2 corresponds. !> \param[in] JediToOpsLayoutMapping !> Data needed to map JEDI locations stored on the current PE to OPS observations. !> \param[inout] Real2 @@ -1254,7 +1255,7 @@ end subroutine opsinputs_fill_fillreal2d_records !> suffix (in which case \p Real2 will have only a single row) or a set of variables with !> suffixes corresponding to the indices specified in \p Channels. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Real2. +!> Group name of the JEDI variable used to populate \p Real2. !> !> \note This function returns early (without a warning) if the specified JEDI variable is not found. !> 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 !> \param[in] JediVarName !> Name of the JEDI variable used to populate \p Int1. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Int1. +!> Group name of the JEDI variable used to populate \p Int1. !> !> \note This function returns early (without a warning) if the specified JEDI variable is not found. !> 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( & end if end subroutine opsinputs_fill_fillinteger + +! ------------------------------------------------------------------------------ +!> Populate a 2D array of integers and its header from a JEDI variable. +!> +!> \param[inout] Hdr +!> Header to be populated. +!> \param[in] OpsVarName +!> Name of the OB_type field to which \p Int2 corresponds. +!> \param[in] JediToOpsLayoutMapping +!> Data needed to map JEDI locations stored on the current PE to OPS observations. +!> \param[inout] Int2 +!> Pointer to the array to be populated. +!> \param[in] ObsSpace +!> Pointer to ioda::ObsSpace object containing the specified JEDI variable. The variable can +!> have either no channel suffix (in which case \p Int2 will have only a single row) or suffixes +!> representing the indices specified in \p Channels. +!> \param[in] Channels +!> Indices returned by ioda::ObsSpace::obsvariables().channels(). +!> \param[in] VarobsLength +!> Length of varobs profile. +!> \param[in] JediVarName +!> Name of the JEDI variable used to populate \p Int2. If each JEDI location needs to be mapped +!> to a separate OPS observation, this can represent either a single variable with no channel +!> suffix (in which case \p Int2 will have only a single row) or a set of variables with +!> suffixes corresponding to the indices specified in \p Channels. +!> \param[in] JediGroup +!> Group name of the JEDI variable used to populate \p Int2. +!> +!> \note This function returns early (without a warning) if the specified JEDI variable is not found. +!> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield +!> are not found. +subroutine opsinputs_fill_fillinteger2d( & + Hdr, OpsVarName, JediToOpsLayoutMapping, Int2, ObsSpace, Channels, & + VarobsLength, JediVarName, JediVarGroup) +implicit none + +! Subroutine arguments: +type(ElementHeader_Type), intent(inout) :: Hdr +character(len=*), intent(in) :: OpsVarName +type(opsinputs_jeditoopslayoutmapping), intent(in) :: JediToOpsLayoutMapping +integer(integer64), pointer, intent(out) :: Int2(:,:) +type(c_ptr), value, intent(in) :: ObsSpace +integer(c_int), intent(in) :: Channels(:) +integer(integer64), intent(in) :: VarobsLength +character(len=*), intent(in) :: JediVarName +character(len=*), intent(in) :: JediVarGroup +! todo(someone): add optional arguments used in opsinputs_fill_fillreal2d if there is a need. + +! Local declarations: +integer(kind=c_int) :: VarValue(JediToOpsLayoutMapping % NumJediObs) +integer(kind=c_int) :: CurrentVarValue +integer(kind=c_int) :: MissingInt +integer :: i +integer :: numchans + +! Body: + +MissingInt = missing_value(0_c_int32_t) + +! todo(someone): add this if needed +if (JediToOpsLayoutMapping % ConvertRecordsToMultilevelObs) then + call abor1_ftn("must extend opsinputs_fill_fillreal2d to deal with multi-level observations") +end if + +! todo(someone): make this configurable if required +numchans = 1 + +if (obsspace_has(ObsSpace, JediVarGroup, JediVarName)) then + ! Retrieve data from JEDI + call obsspace_get_db(ObsSpace, JediVarGroup, JediVarName, VarValue) + + ! Fill the OPS data structures + call Ops_Alloc(Hdr, OpsVarName, JediToOpsLayoutMapping % NumOpsObs, Int2, & + num_levels = int(numchans, kind=integer64)) + do i = 1, JediToOpsLayoutMapping % NumOpsObs + CurrentVarValue = VarValue(i) + if (CurrentVarValue /= MissingInt) Int2(i, 1) = CurrentVarValue + end do +end if +end subroutine opsinputs_fill_fillinteger2d + ! ------------------------------------------------------------------------------ !> Populate a 1D array of strings and its header from a JEDI variable. @@ -1837,7 +1919,7 @@ end subroutine opsinputs_fill_fillinteger !> \param[in] JediVarName !> Name of the JEDI variable used to populate \p String1. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p String1. +!> Group name of the JEDI variable used to populate \p String1. !> \param[in] ConvertIntToSTring !> Convert an integer-valued ObsSpace vector to a string. !> \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 !> \param[in] JediVarName !> Name of the JEDI variable used to populate \p Real1. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Real1. +!> Group name of the JEDI variable used to populate \p Real1. !> \param[in] ReferenceTime !> Reference time. JEDI datetimes will be converted into offsets from this time. !> @@ -2010,7 +2092,7 @@ end subroutine opsinputs_fill_filltimeoffsets !> variable with no channel suffix (in which case \p Real2 will have only a single row) or a set !> of variables with suffixes corresponding to the indices specified in \p Channels. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Real2. +!> Group name of the JEDI variable used to populate \p Real2. !> \param[in] ReferenceTime !> Reference time. JEDI datetimes will be converted into offsets from this time. !> @@ -2085,7 +2167,7 @@ end subroutine opsinputs_fill_filltimeoffsets2d_norecords !> \param[in] JediVarName !> Name of the JEDI variable used to populate \p Real2. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Real2. +!> Group name of the JEDI variable used to populate \p Real2. !> \param[in] ReferenceTime !> Reference time. JEDI datetimes will be converted into offsets from this time. !> @@ -2181,7 +2263,7 @@ end subroutine opsinputs_fill_filltimeoffsets2d_records !> suffix (in which case \p Real2 will have only a single row) or a set of variables with !> suffixes corresponding to the indices specified in \p Channels. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Real2. +!> Group name of the JEDI variable used to populate \p Real2. !> \param[in] ReferenceTime !> Reference time. JEDI datetimes will be converted into offsets from this time. !> @@ -2249,7 +2331,7 @@ end subroutine opsinputs_fill_filltimeoffsets2d !> variable with no channel suffix (in which case \p Coord2 will have only a single row) or a set !> of variables with suffixes corresponding to the indices specified in \p Channels. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Coord2. +!> Group name of the JEDI variable used to populate \p Coord2. !> !> \note This function returns early (without a warning) if the specified JEDI variable is not found. !> 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 !> \param[in] JediVarName !> Name of the JEDI variable used to populate \p Coord2. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Coord2. +!> Group name of the JEDI variable used to populate \p Coord2. !> !> \note This function returns early (without a warning) if the specified JEDI variable is not found. !> 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 !> suffix (in which case \p Coord2 will have only a single row) or a set of variables with !> suffixes corresponding to the indices specified in \p Channels. !> \param[in] JediGroup -!> Group of the JEDI variable used to populate \p Coord2. +!> Group name of the JEDI variable used to populate \p Coord2. !> !> \note This function returns early (without a warning) if the specified JEDI variable is not found. !> We rely on warnings printed by the OPS code whenever data needed to output a requested varfield diff --git a/src/opsinputs/opsinputs_varobswriter_mod.F90 b/src/opsinputs/opsinputs_varobswriter_mod.F90 index 48d4fbc0..4ed47721 100644 --- a/src/opsinputs/opsinputs_varobswriter_mod.F90 +++ b/src/opsinputs/opsinputs_varobswriter_mod.F90 @@ -35,6 +35,7 @@ module opsinputs_varobswriter_mod opsinputs_fill_fillelementtypefromsimulatedvariable, & opsinputs_fill_fillelementtype2dfromsimulatedvariable, & opsinputs_fill_fillinteger, & + opsinputs_fill_fillinteger2d, & opsinputs_fill_fillreal, & opsinputs_fill_fillreal2d, & opsinputs_fill_fillrealfromgeoval, & @@ -1013,8 +1014,17 @@ subroutine opsinputs_varobswriter_populateobservations( & ! TODO(someone): handle this varfield ! call Ops_Alloc(Ob % Header % SBUVozone, "SBUVozone", Ob % Header % NumObsLocal, Ob % SBUVozone) case (VarField_RadialVelocity) - ! TODO(someone): handle this varfield - ! call Ops_Alloc(Ob % Header % RadialVelocSO, "RadialVelocSO", Ob % Header % NumObsLocal, Ob % RadialVelocSO) + ! Write DerivedObsValue/radialVelocity to both Ob % RadialVelocSO and Ob % RadialVelocity. + ! This ensures that the code in deps/ops/stubs/OpsMod_Varobs/Ops_VarobPGEs.inc works correctly. + ! The logical `RadWind_SuperOb` is always false in opsinputs, but is true in operational OPS. + ! By default that results in PGEs not being filled correctly. Writing out both OPS variables + ! fixes the problem. + call opsinputs_fill_fillelementtype2dfromsimulatedvariable( & + Ob % Header % RadialVelocSO, "RadialVelocSO", JediToOpsLayoutMapping, Ob % RadialVelocSO, & + ObsSpace, self % channels, Flags, ObsErrors, self % VarobsLength, "radialVelocity", "ObsValue") + call opsinputs_fill_fillelementtype2dfromsimulatedvariable( & + Ob % Header % RadialVelocity, "RadialVelocity", JediToOpsLayoutMapping, Ob % RadialVelocity, & + ObsSpace, self % channels, Flags, ObsErrors, self % VarobsLength, "radialVelocity", "ObsValue") case (VarField_Reflectivity) ! TODO(someone): handle this varfield ! call Ops_Alloc(Ob % Header % ReflectivitySO, "ReflectivitySO", Ob % Header % NumObsLocal, Ob % ReflectivitySO) @@ -1025,21 +1035,25 @@ subroutine opsinputs_varobswriter_populateobservations( & ! TODO(someone): handle this varfield ! call Ops_Alloc(Ob % Header % ReflectivityI, "ReflectivityI", Ob % Header % NumObsLocal, Ob % ReflectivityI) case (VarField_RadarBeamElev) - ! TODO(someone): handle this varfield - ! call Ops_Alloc(Ob % Header % RadarBeamElev, "RadarBeamElev", Ob % Header % NumObsLocal, Ob % RadarBeamElev) + call opsinputs_fill_fillreal2d( & + Ob % Header % RadarBeamElev, "RadarBeamElev", JediToOpsLayoutMapping, Ob % RadarBeamElev, & + ObsSpace, self % channels, self % VarobsLength, "beamTiltAngle", "MetaData") case (VarField_RadarObRange) - ! TODO(someone): handle this varfield - ! call Ops_Alloc(Ob % Header % RadarObRange, "RadarObRange", Ob % Header % NumObsLocal, Ob % RadarObRange) + call opsinputs_fill_fillreal2d( & + Ob % Header % RadarObRange, "RadarObRange", JediToOpsLayoutMapping, Ob % RadarObRange, & + ObsSpace, self % channels, self % VarobsLength, "gateRange", "MetaData") case (VarField_RadarObAzim) call opsinputs_fill_fillreal2d( & - Ob % Header % RadarObAzim, "RadarObAzim", JediToOpsLayoutMapping, Ob % RadarObAzim, & - ObsSpace, self % channels, self % VarobsLength, "radarAzimuth", "MetaData") + Ob % Header % RadarObAzim, "RadarObAzim", JediToOpsLayoutMapping, Ob % RadarObAzim, & + ObsSpace, self % channels, self % VarobsLength, "beamAzimuthAngle", "MetaData") case (VarField_RadIdent) - ! TODO(someone): handle this varfield - ! call Ops_Alloc(Ob % Header % RadIdent, "RadIdent", Ob % Header % NumObsLocal, Ob % RadIdent) + call opsinputs_fill_fillinteger2d( & + Ob % Header % RadIdent, "RadIdent", JediToOpsLayoutMapping, Ob % RadIdent, & + ObsSpace, self % channels, self % VarobsLength, "stationIdentification", "MetaData") case (VarField_RadAltAboveMSL) - ! TODO(someone): handle this varfield - ! call Ops_Alloc(Ob % Header % RadAltAboveMSL, "RadAltAboveMSL", Ob % Header % NumObsLocal, Ob % RadAltAboveMSL) + call opsinputs_fill_fillreal2d( & + Ob % Header % RadAltAboveMSL, "RadAltAboveMSL", JediToOpsLayoutMapping, Ob % RadAltAboveMSL, & + ObsSpace, self % channels, self % VarobsLength, "stationElevation", "MetaData") case (VarField_RadNoiseLvl) ! TODO(someone): handle this varfield ! call Ops_Alloc(Ob % Header % RadNoiseLvl, "RadNoiseLvl", Ob % Header % NumObsLocal, Ob % RadNoiseLvl) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4fa7d9d7..cd69bf8d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -217,9 +217,10 @@ ADD_WRITER_TEST(NAME varobswriter_057_VarField_emissivity YAML 057_VarField_emissivity.yaml NAMELIST VarObsWriterNamelists_057_VarField_emissivity/IASI.nl DATA 057_VarField_emissivity.nc4) -ADD_WRITER_TEST(NAME varobswriter_066_VarField_radarobazim - YAML 066_VarField_radarobazim.yaml - DATA 066_VarField_radarobazim.nc4) +ADD_WRITER_TEST(NAME varobswriter_063_VarField_radialVelocity + YAML 063_VarField_radialVelocity.yaml + NAMELIST VarObsWriterNamelists_063_VarField_radialVelocity/Radar.nl + DATA 063_VarField_radialVelocity.nc4) ADD_WRITER_TEST(NAME varobswriter_067_VarField_GPS_Station_Height YAML 067_VarField_GPS_Station_Height.yaml DATA 067_VarField_GPS_Station_Height.nc4) @@ -363,6 +364,10 @@ ADD_WRITER_TEST(NAME varobswriter_ukvnamelist_surfacecloud YAML varobswriter_ukvnamelist_surfacecloud.yaml NAMELIST ../../etc/ukv/varobs/SurfaceCloud.nl DATA varobs_ukvnamelist_surfacecloud.nc4) +ADD_WRITER_TEST(NAME varobswriter_ukvnamelist_radar_doppler_wind + YAML varobswriter_ukvnamelist_radar_doppler_wind.yaml + NAMELIST ../../etc/ukv/varobs/Radar.nl + DATA varobs_ukvnamelist_radar_doppler_wind.nc4) ### CxWriter tests @@ -669,6 +674,10 @@ ADD_WRITER_TEST(NAME cxwriter_ukvnamelist_surface YAML cxwriter_ukvnamelist_surface.yaml NAMELIST ../../etc/ukv/cx/Surface.nl DATA cx_ukvnamelist_surface.nc4 dummy.nc4) +ADD_WRITER_TEST(NAME cxwriter_ukvnamelist_radar_doppler_wind + YAML cxwriter_ukvnamelist_radar_doppler_wind.yaml + NAMELIST ../../etc/ukv/cx/Radar.nl + DATA cx_ukvnamelist_radar_doppler_wind.nc4 dummy.nc4) ### Tests of auxiliary classes diff --git a/test/generate_unittest_netcdfs.py b/test/generate_unittest_netcdfs.py index 303e69b7..2915876b 100644 --- a/test/generate_unittest_netcdfs.py +++ b/test/generate_unittest_netcdfs.py @@ -16,7 +16,7 @@ missing_float_nc = 9.969209968386869e+36 -def output_1d_simulated_var_to_netcdf(var_name, file_name, with_bias=False): +def output_1d_simulated_var_to_netcdf(var_name, file_name, with_bias=False, radar_doppler_wind=False): f = nc4.Dataset(file_name, 'w', format="NETCDF4") nlocs = 4 @@ -34,9 +34,31 @@ def output_1d_simulated_var_to_netcdf(var_name, file_name, with_bias=False): minute = 1 / 60. var[:] = [1 * minute, 2 * minute, 3 * minute, 4 * minute] - var = f.createVariable('MetaData/stationIdentification', str, ('Location')) - for i, s in enumerate(["station_1", "station_2", "station_3", "station_4"]): - var[i] = s + # Station ID + if radar_doppler_wind: + # The radar Doppler wind processing uses integers for station identification because + # `MetaData/stationIdentification` is mapped to the ODB variable `rad_ident`, + # which is an integer. + var = f.createVariable('MetaData/stationIdentification', 'i', ('Location')) + var[:] = [1, 2, 3, 4] + else: + # In all other cases, `MetaData/stationIdentification` is a string. + var = f.createVariable('MetaData/stationIdentification', str, ('Location')) + for i, s in enumerate(["station_1", "station_2", "station_3", "station_4"]): + var[i] = s + + # Extra variables for radar + if radar_doppler_wind: + var = f.createVariable('MetaData/radar_family', 'i', ('Location',)) + var[:] = [11, 12, 13, 14] + var = f.createVariable('MetaData/beamTiltAngle', 'i', ('Location',)) + var[:] = [11, 12, 13, 14] + var = f.createVariable('MetaData/gateRange', 'i', ('Location',)) + var[:] = [11, 12, 13, 14] + var = f.createVariable('MetaData/beamAzimuthAngle', 'i', ('Location',)) + var[:] = [11, 12, 13, 14] + var = f.createVariable('MetaData/stationElevation', 'i', ('Location',)) + var[:] = [11, 12, 13, 14] var = f.createVariable('ObsValue/' + var_name, 'f', ('Location',)) obsVal = [1.1, missing_float, 1.3, 1.4] @@ -64,6 +86,7 @@ def output_1d_simulated_var_to_netcdf(var_name, file_name, with_bias=False): if biasVal[i] == missing_float: biascorr[i] = obsVal[i] var[:] = biascorr + f.date_time = 2018010100 f.close() @@ -694,7 +717,7 @@ def copy_var_to_var(Group, invarname, outvarname, filename): output_2d_simulated_var_to_netcdf('probability', 'testinput/053_VarField_awpriorpcorrect.nc4') output_2d_normal_var_to_netcdf ('emissivity', 'OneDVar', 'testinput/057_VarField_emissivity.nc4', use_chans=True) # 54 VarField_NumChans and 55 VarField_ChanNum: separate files not necessary - output_2d_normal_var_to_netcdf ('radarAzimuth', 'MetaData', 'testinput/066_VarField_radarobazim.nc4', with_radar_family=True) + output_1d_simulated_var_to_netcdf ('radialVelocity', 'testinput/063_VarField_radialVelocity.nc4', radar_doppler_wind=True) output_2d_normal_var_to_netcdf ('liquidWaterContent', 'OneDVar', 'testinput/068_VarField_clw.nc4', use_levs=True) output_2d_normal_var_to_netcdf ('brightnessTemperature', ['constant_satid_5Predictor', 'constant_satid_8Predictor', 'thickness_850_300hPa_satid_5Predictor','thickness_850_300hPa_satid_8Predictor', @@ -844,6 +867,21 @@ def copy_var_to_var(Group, invarname, outvarname, filename): copy_var_to_var('ObsValue', 'potentialTemperature', 'airTemperature', 'testinput/varobs_globalnamelist_aircraft.nc4') copy_var_to_var('ObsError', 'potentialTemperature', 'airTemperature', 'testinput/varobs_globalnamelist_aircraft.nc4') + # Radar doppler wind - UKV + output_full_varobs_to_netcdf(['MetaData/latitude', + 'MetaData/longitude', + 'MetaData/beamTiltAngle', + 'MetaData/gateRange', + 'MetaData/beamAzimuthAngle', + 'MetaData/stationElevation', + 'ObsValue/radialVelocity', 'ObsError/radialVelocity'], + [], + ['MetaData/stationIdentification'], + 'testinput/varobs_ukvnamelist_radar_doppler_wind.nc4') + + + + # Cx output_1d_simulated_var_to_netcdf('dummy', 'testinput/dummy.nc4') output_1d_geoval_to_netcdf ('surface_altitude', 'testinput/001_SurfaceCxField_Orog.nc4') @@ -1079,3 +1117,8 @@ def copy_var_to_var(Group, invarname, outvarname, filename): ['potential_temperature', 'eastward_wind', 'northward_wind', 'specific_humidity', 'air_pressure_levels', 'mass_content_of_cloud_liquid_water_in_atmosphere_layer'], 'testinput/cx_globalnamelist_screen.nc4') + + # Radar doppler wind - UKV + output_full_cx_to_netcdf(['surface_altitude'], + ['eastward_wind', 'northward_wind', 'upward_air_velocity'], + 'testinput/cx_ukvnamelist_radar_doppler_wind.nc4') diff --git a/test/testinput/063_VarField_radialVelocity.nc4 b/test/testinput/063_VarField_radialVelocity.nc4 new file mode 100644 index 0000000000000000000000000000000000000000..72a20cfdecc3612468a5f2a697072b5fa87a9482 GIT binary patch literal 15676 zcmeHOeQXrR6@Pm^ABQ>M(uCSIsBHLj-N?lSQ%bOj?|f%l9JcFo+$2=kYkO@jJ&5+xoXhb4de;QqW@m5>75qVD++-+QGj!nX>~%k;!w z3BW{|NDWOPlgek*1*Xs_pr9J>tC*tBf}%fv{mQ-KR_BAJm64jJNi-NHj*D(1W8QN6 zQe+hc9ZLOB`Y@gq`zgoc@rZ){Pf%`=#$;dyE?OcA76pNG^5ei7Dybnahy>wSeLRk7 zGCtKID#y5?d26I4-rU;K6%W_PB8pt!Rpd&c1_g=HkvnDThg?|Pp_EPjJ@(g*7h1zj zTezj3f-RM`&ncF5G;>udjmi6-f9xbx73ijhYfvn1sil5vgmmea?!tpx)v+Uy(edBV zk@X{Lzcde5+>rv|NT)-EHRFnW?^mCj)u{A;Xh<4CB4cn83zFpugg#luf}Y6M~EbK`DOARYPIp;+_sI6Qa2u*`NNHDErmQfh?0|IF2Bds7>biYIp_bbfUmM=+kuOi zHG1xHCGk)4^rV_B8~NfARNqocYhE6C0%@bqNO$!cI}^zV_pgx3K3yvDd^^9#G}^deTz|0#b31uh%$Kt%^5tYQ3iZm=r2PWO%BH$w6BH$w6BH$vB zhrn#DPz^a?g-Wbp6j-6U=iU=Pm@O>!Isgl?Zc_k@2af6EvxUWe2Vf!AstRDS$#-r2 z4PqhIYJ<3tB-g%lD4wu-i%+F{v#Yn1;?>)O4!}UH%a!L14tdFQ4ZprL(^wpJ02X2` zavCi5|Krs+XBvw$4!}aJi%x^Z#Y^!&N~)Y23I1-TQ90oNRK%+EG^o5Xy84Zo#^SOA zun;Tj(_j(m-BvQu{{tO08tFa#P`S1tcbNI?yQRUIM(w-xR{60H*3x#Z1}e^*B1=z;?5{6e@=;8><;UTT98(CwU)6*7mL!SQFFed_M#xi2dYb5H8^95_szB!VnDLX(^oDyC)2<Q;*`*laDoa zIsl@NbrZxGob?N5%d?+de$39&zS{|vtV8w!^j=FC$xbsl*qg8(ylt%l?VAn(@5kH9 zzM6H(d+zhHSv0nZU~`y#PnqNX)}BnKksLNhltb&;mpf^2%n9vfHHV{34I$gXobn!- zw=tMS$Dc(1RcpA<99O+V^D@wLlY^-Nk=L!uN;NO{H~&!D%w&esW>TO{cyqhF7Wx^F zEaMW~{zVx}c*-{SnJFvLpOAjDk1S_B?wnIP8){zetW&!gewfFmhHpGF1j$9Q{-MOq zVQYu*QhZ;{KAM-icTlx5k~DXT=8msch5uipndwE}u2Fb6r5Amr{HGVPy=b0lo;^l0 z3+?S1ETCQ#Nv8+Xr-3>S4RW010u?@;K z)^?SjO|NR{{U;vepY{6WT^qZIpAUi-_&*?laVs;KJZcCeA3V(0CY;B;4Ub8fO84Exe z^x=kuE}DU5CeX(~Ise@yB!#w7yx-e2LJH+W+b>~ckME)o!0FCq9kazi-2n^~KK2F1 zyuhkoM#(IJ5!zZv`&TRkzC99+v`1RPkuJG^<&!vLP#;2r7#Y)^M--luBi`p?@6u8# z(s+~gS(5v;mt<^U-X*{>Ki_dVex~CzKge;KpWrynPimazeIT6X9Uq+L4KtkPXDv=o zH|FIt(4G%e1rK$+@bnEb@*{s0U*iBKicK5*S%ksMi;MphxnD4HjM(T@M)LL(jz4aU OwC4|HohvmpU;Yn@+}I5O literal 0 HcmV?d00001 diff --git a/test/testinput/063_VarField_radialVelocity.yaml b/test/testinput/063_VarField_radialVelocity.yaml new file mode 100644 index 00000000..1d98369f --- /dev/null +++ b/test/testinput/063_VarField_radialVelocity.yaml @@ -0,0 +1,44 @@ +time window: + begin: 2018-01-01T00:00:00Z + end: 2018-01-01T02:00:00Z + +observations: + - obs space: + name: Radar + obsdatain: + engine: + type: H5File + obsfile: Data/063_VarField_radialVelocity.nc4 + simulated variables: [radialVelocity] + obs filters: + # Set the flag of observations with missing values to "pass": we want to check if these + # values are encoded correctly in the VarObsFile. + - filter: Reset Flags to Pass + flags_to_reset: [10, 15] # missing, Hfailed + # Reject observation 3: we want to check if it is omitted from the VarObs file, as expected. + - filter: Domain Check + where: + - variable: + name: MetaData/latitude + minvalue: 0.0 + - filter: VarObs Writer + reject_obs_with_any_variable_failing_qc: true + namelist_directory: testinput/VarObsWriterNamelists_021_VarField_surface + general_mode: debug + station_ID_int_to_string: true + - filter: VarObs Checker + expected_main_table_columns: + # Only observations 1, 2 and 4 are passed; observation 3 is rejected by the domain check + field: ["63","64","65","66","69","75","63","64","65","66","69","75","63","64","65","66","69","75"] + ob value: ["1.10000","11.00000","11.00000","11.00000","1.00000","11.00000","-1073741824.00000", + "12.00000","12.00000","12.00000","2.00000","12.00000","1.40000","14.00000","14.00000","14.00000","4.00000","14.00000"] + lat: ["21.00000","21.00000","21.00000","21.00000","21.00000","21.00000","22.00000","22.00000", + "22.00000","22.00000","22.00000","22.00000","24.00000","24.00000","24.00000","24.00000","24.00000","24.00000"] + lon: ["31.00000","31.00000","31.00000","31.00000","31.00000","31.00000","32.00000","32.00000", + "32.00000","32.00000","32.00000","32.00000","34.00000","34.00000","34.00000","34.00000","34.00000","34.00000"] + time: ["-3540.00000","-3540.00000","-3540.00000","-3540.00000","-3540.00000","-3540.00000","-3480.00000","-3480.00000", + "-3480.00000","-3480.00000","-3480.00000","-3480.00000","-3360.00000","-3360.00000","-3360.00000","-3360.00000","-3360.00000","-3360.00000"] + Callsign: ["1","1","1","1","1","1","2","2","2","2","2","2","4","4","4","4","4","4"] + HofX: ObsValue # just a placeholder -- not used, but needed to force calls to postFilter. + benchmarkFlag: 1000 # just to keep the ObsFilters test happy + flaggedBenchmark: 0 diff --git a/test/testinput/066_VarField_radarobazim.nc4 b/test/testinput/066_VarField_radarobazim.nc4 deleted file mode 100644 index ed0a81a701b295fa03d536b51ccaa5b36dc06deb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15987 zcmeGj4N#m%^?i46T+U0N0YXv|I80+nj2Ln>CKK)g9Cv^vK)HyvWqfVXWimXl5YMvC}bQXEf7EGd60S{%OW4_!D&!%{XKHX=-$gOcN)=)QRuy?)x}C zNCH!!2EQG?+uirQeY@X#Z+G8&yA0OX29`SRbXe?m;B;N3q*p>VsTU{P#s{10Yg;YO zla}`in3WrG6JzeMfJT_MLi*J*=$DecG2R(UMdPu{vJN>pRQRbvNGd2~azP=yy;K4k z7_L*yUky~YTEI94u7CM+hsMP4mu}UxJR)GxG<`@+$eKqZzN4gAkOOc*fgK7CA$F$t z7OR7Xx(rIT69s@)@qGZ?f6fj2cfOzStzZK?(e^b~2ZNA{Ao_F*KD7-y{Y}A!=BD&IgcX*dS9jXsX`n7x+~Qe^+-j>B7H|D;7!lY6Grtv^NqTKRwb9;a7;;dwk|!=PIP4Qseo@gYQ+c>V zz68#1%|rWgYGTz`Hg_os%th<%!o_W~<02``3pu$*BoFJ-^w6p}pyy7~!*nTRItXIj zKvKcNr%4ZOP%E?w;8g<$?KkFNHKAG|552QCv{7c1iKT7bJAAQ z9@5U4t23?{q;5uarZt2J`np50Sfob~w$4;7sUg6TH?_)UU;Vvu73t0vKp2o2>oL}x zegcukiz(RN<)L`<0&sI z-&|JywKI;d5<6%BQfA*mzCMS~saF7A#{3#SP=meWW3PeFyjBM%@p%KEl|QN*92lq^ z9I$&vM;bj?_R!q%e-&Jdfwo-MNXwQiZ) zHp-lxA$V-M(Mj9I_-1-2Vl}2=K9W{eMcM8J;pPD72-2cQoT8r}-a271{YjYP0BuZ2 z$79Eh%~Jc$NGentN`*Yi6Wcd1wpUuS1!>kSx941W1g>eksx+$>;9s9&&!9oMe!?%r zVXV=@4&7l0#4*C*|pi|mm&KmoU+D-;4WB&7&N2;e1zdTjde_B4x4gR zE-Ls-ig<0i6D#Nh6O2+;ESX9~V|(3XLtZQ?f%6fG?K?qFqlO`n_G2QjgJ1Kf12YhY+KSLx{9uJz_cVMEcBQ7H276^OI^> zvy~EqwG10&nDXlq@uZwu=pc54I-)(%RDYooNMW;QeC}1F2>X2?9DTm%(tHTDe{l$v zmd3G*Z+V4KSCXi-j4aA9WwsmC5*ivw|zrU`l&s z4~h5$p&Hv)sP-y;BQ{t9F<;mg;O}Ah9jcuXuB;lJ4o`QA^iVS5D{E;AT!m$HIMZ1n z$>?w%4;crPjP!-VroovG85NX__`+V81}=i>X>g`Py9*^Foi!3X1x`y2B_qCs0+g~K z8DQon2TTr_956Xxa=_$($pMoCCI?Iom>l>&<$ws(Ok9Ry_n$Ad7;}#Q+f?9!xt1C3 z>+S95a34I#@cGQg&ewalpLk4$n%3Sja=!|%fROi1kNiwKWUip1bpw0l9P*|p1xN7* zRmh?WVU%vuC_V*R-uHI@i8&QG$8#4(;4gmo>F=)-GSGj1xhmQz6(IX&3UJGdNG$Bv zm9SYMZc|}X^y%JDe8V-T!ah`{*#4l-{&_4Mh@7?sf6Zgcqyl&BP z?n}QZm%`t!X?GFGf`#TWPKc^(Y_2S~fU)AiYuf>ae zI2uy^aB0alK?(!39HM=wbN6`(`vLM}Arxncif%6g#i6(|v6~f%;>nMW{`;*tU13WqYicO4!lgoT)0Vo_v2r|vmIyNA1+9axM#Dq&DhR~ zE*^!V6Q*>9qLZad`%ZmlJ{0PE@2)~^Ri}QlQm89!feNuXX42+J=c2eden@KI#OC;u zOSvQS!LeuGU5-6nAwP6h9NYAfrkBO(yf_5aGIUFl4&P~ZQnHoM@5IslvP38xN>o1@ z?d?l-w{LE6(`$ggKRH%D_ZKbbH1x#f`j4lZZS1P^V&`0~;VCs;0-GzdO*aU|mjU?c zl73nmC(A1>y~Kyw3dXEslFMT!0-XLJzmYl1grQ#=KHD2;t#3i=mTYZi z99Ec@=yHg}K8Uc$3BtCue65?9s(Ql=4PLz^tyusrT)UE$++bw9;z}ThhAeQ;5=*Xd zj750{wBVIU7nUT(@7EI)fL23FoG%}L^S3p-8Uv8oaT2{Jy0%#gO=k~T;Kx`jfv;c7 zt^vAbR{-DqKG6gEz2P0$;f7;B$Sfo9Taq149049mXL^xw2v@iR)_Fh!};qY^WqvgB>-cKgvM_ zr2#r=sZ#pY9jO$2Geap+<&!IWn7ElQ2nTMuOKj9|hnUMFg>&ko{#zJT3bUn5=%w9qVgY-d0*8sc%nLmanjy3=`!HNUD3(5OF8eGw={0F T44&MRDY%V1TM#v0z)t=P^P;Cu diff --git a/test/testinput/066_VarField_radarobazim.yaml b/test/testinput/066_VarField_radarobazim.yaml deleted file mode 100644 index 0a0a3a3c..00000000 --- a/test/testinput/066_VarField_radarobazim.yaml +++ /dev/null @@ -1,69 +0,0 @@ -time window: - begin: 2018-01-01T00:00:00Z - end: 2018-01-01T02:00:00Z - -observations: - - obs space: - name: Radar - obsdatain: - engine: - type: H5File - obsfile: Data/066_VarField_radarobazim.nc4 - simulated variables: [dummy] - channels: 1, 3 - obs filters: - # Double all observation errors: we want to check if error changes made by filters are - # propagated to VarObs files - - filter: BlackList - action: - name: inflate error - inflation factor: 2.0 - # Set the flag of observations with missing values to "pass": we want to check if these - # values are encoded correctly in the VarObsFile. - - filter: Reset Flags to Pass - flags_to_reset: [10, 15] # missing, Hfailed - # Reject observation 3: we want to check if it is omitted from the VarObs file, as expected. - - filter: Domain Check - where: - - variable: - name: MetaData/latitude - minvalue: 0.0 - - filter: VarObs Writer - reject_obs_with_any_variable_failing_qc: true - use_radar_family: true - general_mode: debug - - filter: VarObs Checker - expected_main_table_columns: - # Only observations 1, 2 and 4 are passed; observation 3 is rejected by the domain check. - # Only levels 1 and 3 are simulated and hence written to the VarObs file. - # In the arrays below, rows denote locations and columns levels. - field: ["66", "66", - "66", "66", - "66", "66"] - level: ["1", "2", - "1", "2", - "1", "2"] - ob value: ["4.10000", "6.10000", - "-1073741824.00000", "6.20000", - "4.40000", "6.40000"] - ob error: ["-1073741824.00000", "-1073741824.00000", - "-1073741824.00000", "-1073741824.00000", - "-1073741824.00000", "-1073741824.00000"] - lat: ["21.00000", "21.00000", - "22.00000", "22.00000", - "24.00000", "24.00000"] - lon: ["31.00000", "31.00000", - "32.00000", "32.00000", - "34.00000", "34.00000"] - time: ["-3540.00000", "-3540.00000", - "-3480.00000", "-3480.00000", - "-3360.00000", "-3360.00000"] - family: ["11", "11", - "12", "12", - "14", "14"] - Callsign: ["station_1", "station_1", - "station_2", "station_2", - "station_4", "station_4"] - HofX: ObsValue # just a placeholder -- not used, but needed to force calls to postFilter. - benchmarkFlag: 1000 # just to keep the ObsFilters test happy - flaggedBenchmark: 0 diff --git a/test/testinput/VarObsWriterNamelists_063_VarField_radialVelocity/Radar.nl b/test/testinput/VarObsWriterNamelists_063_VarField_radialVelocity/Radar.nl new file mode 100644 index 00000000..a7990a74 --- /dev/null +++ b/test/testinput/VarObsWriterNamelists_063_VarField_radialVelocity/Radar.nl @@ -0,0 +1,3 @@ +&VarobsControlNL +Varfields=63,64,65,66,69,75 +/ diff --git a/test/testinput/cx_ukvnamelist_radar_doppler_wind.nc4 b/test/testinput/cx_ukvnamelist_radar_doppler_wind.nc4 new file mode 100644 index 0000000000000000000000000000000000000000..2460718b627f6a8fab736021b38341c4f32f0c6a GIT binary patch literal 9348 zcmeHNO>7%Q6rQym*F??_1V}&;-82Zw0SC(|@1rh^{NqfukMEChe~Y~oTYfmh63P#%N?B5}jbdA)KrQ@QSUgyi_UH z4)7(S%8hs#zVPm0zSW*#O%sze;YD*v`X9v|K0LA;pvI=N!4Mlf3caonj`(~&J`oWJ zu=*%>V!hnP*ki+d8sON89O>Z~aE1m@AufrGk;{ROcp#)Q3`I*BbUaq)XLv^$2mt{ra+zguGg+_hh)}Oc zE8~?wN~e7G+Tf|#MEU@&)OXXBihCNe+%go%CpsS<-^^m1`;o&KJG8m~yqCefxB^WS ztgL6qgm5|eJf!xOuIm#A$ zMK0+sg?{qHbBMgi&*!^DxDymr<|nA5K?_Kg^;l-jJz`c%`6Eubv`@nHROqrpS;Q09 z2j_LD?VM(&bMuTn0g><=55gyeQRP#HVw1!ZTR;bBXlvIoKVOZ#cFD`)?L4pUB5PM= z)^Od}Zk@I8LG-&*3~-Ow+9hGY-*5a$A$;1epR#Y)5P5po(|mZ?TlHE^LK=pb5I!Nh zSs3zCGF>b0!qZO%>IbX^+;MK9yihEXe;3nlqQmHwOY>wSNtHnQ#Pv_!-m0!$vbtOz zA1-oT!4WiQ0XlWPRUg)i#S(-du7Wcco-qmm|+_e7T9P|Izj*W;1+4GW)bSS(}XBrE)hCMCRFP zTjWpapnZ^?;?SBq?exuo>=Z|$`mg(vA4!V;klZWTDUSF8MMbc+eh->HuctZ+0fm4< zKp~(IPzWdl6aoqXg@8gpA)pX=;1ICwlatLxV{*Oq(PS((5dUKNog20tjK^ZR_-Y~w~O7BiZSsIlHk8tC6_7|@>wdk*Y}pkIQ15&EWK+uwjZ1-7rD z|2_9#Z+!>-pTPbj*nfcjFVH^={WCD{GG9Zp@h9BtulNH8xZ03HKp~(IPzWdlb^ro` zWD058UR=!mqY97TF;$54DXj1w5^u;wAm34tWC3yzznvR0InB3$^giCr1v+UiHIKTl*a=p!0_dM3095z#o?E)XE^< bjU-hDW*Zw-hR_(J${?MnL()e!#xDE=z1BRu literal 0 HcmV?d00001 diff --git a/test/testinput/cxwriter_ukvnamelist_radar_doppler_wind.yaml b/test/testinput/cxwriter_ukvnamelist_radar_doppler_wind.yaml new file mode 100644 index 00000000..6fa2e780 --- /dev/null +++ b/test/testinput/cxwriter_ukvnamelist_radar_doppler_wind.yaml @@ -0,0 +1,41 @@ +time window: + begin: 2018-01-01T00:00:00Z + end: 2018-01-01T01:00:00Z + +observations: + - obs space: + name: Radar + obsdatain: + engine: + type: H5File + obsfile: Data/dummy.nc4 + simulated variables: [dummy] + geovals: + filename: Data/cx_ukvnamelist_radar_doppler_wind.nc4 + obs filters: + # Set the flag of observations with missing values to "pass": we want to check if these + # values are encoded correctly in the Cx file. + - filter: Reset Flags to Pass + flags_to_reset: [10] # missing + # Reject observation 3: we want to check if it is omitted from the Cx file, as expected. + - filter: Domain Check + where: + - variable: + name: MetaData/latitude + minvalue: 0.0 + - filter: Cx Writer + namelist_directory: ../etc/ukv/cx + reject_obs_with_any_variable_failing_qc: true + general_mode: debug + geovals_are_top_to_bottom: false + - filter: Cx Checker + expected_surface_variables: ["1"] + expected_upper_air_variables: ["3","4","32"] + expected_main_table_columns: + - # observation 3 is rejected by the tests above hence only 3 (1,2,4) columns + - ["7.10","1.30","1.20","1.10","11.30","11.20","11.10","21.30","21.20","21.10"] + - ["**********","2.30","**********","2.10","12.30","**********","12.10","22.30","**********","22.10"] + - ["7.40","4.30","4.20","4.10","14.30","14.20","14.10","24.30","24.20","24.10"] + HofX: ObsValue # just a placeholder -- not used""but needed to force calls to postFilter. + benchmarkFlag: 1000 # just to keep the ObsFilters test happy + flaggedBenchmark: 0 diff --git a/test/testinput/varobs_ukvnamelist_radar_doppler_wind.nc4 b/test/testinput/varobs_ukvnamelist_radar_doppler_wind.nc4 new file mode 100644 index 0000000000000000000000000000000000000000..cb9df160665ed5a463c165b3e52635f567a6b6d1 GIT binary patch literal 12493 zcmeHNeQZ-z6u+QQVxlooFa|Xki5fI<8lwrGbKgB}_h`u=r1Xz> zx4wJNz2}~L-|wDx-?`_!Cu5P;n(C$143o>n9ITEP>2gk_X`fL;G_`M`LXo^H7U{OR zPuZ^H?RKYNBQfT@+QuYgspGSF-)^vP5WN_62iiS=l@goJT<|y08QzpmZBx>^s$`)4 zYWS_;?QnrKuB0<+N^A1((iD9to=B>LR26Kvy}`e0B%WBESLtt9+u&czoY!Dy$$?i) zu8!1@tb?F-K1-;v@p|^dzh{r|TdnDnBoEd}lEFfKDYq}gJ6y2*T7Vjpmo0X&#g9O# z!i6n1n~irw1m>}URh)@wypFN@WxSichMAEg+RYbA0;mv|a7U=82Sgwq2&oXmB5fO^ zojq+`odZ4LP)C%xw_uyZDtNEX(8ee*^Ipx6Q?K3;HRFYU*$XI!Bdy-JI;v<0taors z_i8CU*EBAtRe3O}GuFk>JL z(9S|wC<)8vZtR*bt%BDevWPh}?s0Iei88d!ZY&79kB^tb+J3pQURexl03dtU;SpKW zlq3VN&P!)k?GJW^W9_63wxTmM?o6#PM8rsvxKqYHdZBhJN^)I=1KXv3@r1br=cTO} z>P!D$KTj84uPPy%^0__{Fh@vsi8OtMkV7b3?sYP-J1VeyQ;fzMs4(}ueTV-uMA?uS zsWp1Gk$~)KIG19Tw)@=F#8aU_U|(qZ_}79y0rbgGBC)Uq+XI36mZ{15mPF!C zK{o;21aw@`3eZYRAh4IyQk!Ku@*c9AFvuR6>qgw-A2)i{JtYcg1{q zfr&)Jhft76KLm76KLm76OG4Fdh8Rw8ccmn>n9-@SDW9GNheG#^2te=v;;c z$$|C-rmAF08&>tPxUvIZ-H@DKyymQ^nn6V#?NyU{NE=Qn+rWd9?5j5@Iu&pO!l=UQ(=(eN&Y5|cjeAGNRgGV2rFNpoIO=aMVH6D3GYZ^wO}uK@=lK( zZ9Tn=ErB+awHSW<3?t6Iv_|Q6$eSx5!cl=Jm;TxBFzc8VlE3v2K zAiqF;M(4-#wz#6{YC<&*>xXYPe z!bAo-@#o(y*3)FMjOoSi4!>Qhl^!dDmFB0JA}f8U@6_j}or2&q?+`@OPT^dRVCH-? z^V4!%m6Lr+GBu>?559a8Hba^)vMYYQf6al{D;pmz)yh9s1}o1uyCN%pqW0qrrNZK! zGQfgQp$HcCPqlS_4DlWBdel?NL3@22zPmyXsiR~12!DMkHyVoU6pX?KJf0V^bh8}A&1jvI*z7BIe*BuaNuFuX-3`KIX(=yeIr9V$j_9bBA zr|~E!`Q)uK*BhR5Aq28{qG;x$cdb|!*68!Ez0K!`|6ZSOz0VK-+{6$@4EH&pC=*}f zdS8I^kt!9J*U0(EUr~e)kV7%3dUP@zB+V}E=U*34^)#s2;rit!ls zdmnl_`G>NiztL9^1+rqXMe;&ZZjLQd44gz#w43OQ-Gj`Ul-*~AKnksreAfpDJr|>C zOCVB=o^kvcuL2jV@L&}~7iyvBct&VoGjL;~??X!&-Nq=uKflde zftqIiZk6Wlj!B?f7*p3l!@8rb(e7wxI67d&)E9vsA}45`oKbYVkqah@y=Onk7TlMr VX%yF>yxcU6V)g{eOFJF${{h^G@u&a* literal 0 HcmV?d00001 diff --git a/test/testinput/varobswriter_ukvnamelist_radar_doppler_wind.yaml b/test/testinput/varobswriter_ukvnamelist_radar_doppler_wind.yaml new file mode 100644 index 00000000..8dc2d502 --- /dev/null +++ b/test/testinput/varobswriter_ukvnamelist_radar_doppler_wind.yaml @@ -0,0 +1,47 @@ +time window: + begin: 2018-01-01T00:00:00Z + end: 2018-01-01T02:00:00Z + +observations: + - obs space: + name: Radar + obsdatain: + engine: + type: H5File + obsfile: Data/varobs_ukvnamelist_radar_doppler_wind.nc4 + simulated variables: [radialVelocity] + observed variables: [radialVelocity] + obs filters: + # Set the flag of observations with missing values to "pass": we want to check if these + # values are encoded correctly in the VarObsFile. + - filter: Reset Flags to Pass + flags_to_reset: [10] # missing + # Blacklist all missing entries in the original profiles (i.e. observation 2) + # This must be run after the Reset Flags to Pass filter, + # which sets the flags of any missing values in the original profiles + # to 'pass'. Therefore this filter is run with the 'defer to post' option set to true. + - filter: BlackList + where: + - variable: + name: MetaData/latitude + value: is_not_valid + defer to post: true + - filter: VarObs Writer + namelist_directory: ../etc/ukv/varobs + general_mode: debug + IC_PLevels: 1 + reject_obs_with_all_variables_failing_qc: true + station_ID_int_to_string: true + - filter: VarObs Checker + expected_main_table_columns: + # Rows are locations, columns are filter variables + # The blacklist prevents the missing ob from being written out + field: [63,64,65,66,69,75, + 63,64,65,66,69,75, + 63,64,65,66,69,75] + ob value: ["67.10000","27.10000","37.10000","47.10000","3.00000","57.10000","67.30000","27.30000","37.30000","47.30000","7.00000","57.30000","67.40000","27.40000","37.40000","47.40000","9.00000","57.40000"] + lat: ["7.10000","7.10000","7.10000","7.10000","7.10000","7.10000","7.30000","7.30000","7.30000","7.30000","7.30000","7.30000","7.40000","7.40000","7.40000","7.40000","7.40000","7.40000"] + lon: ["17.10000","17.10000","17.10000","17.10000","17.10000","17.10000","17.30000","17.30000","17.30000","17.30000","17.30000","17.30000","17.40000","17.40000","17.40000","17.40000","17.40000","17.40000"] + HofX: ObsValue # just a placeholder -- not used, but needed to force calls to postFilter. + benchmarkFlag: 1000 # just to keep the ObsFilters test happy + flaggedBenchmark: 0