Skip to content

Commit

Permalink
Account for integer MetaData/stationIdentification (#206)
Browse files Browse the repository at this point in the history
* integer MetaData/stationIdentification

* remove output

* add new files
  • Loading branch information
ctgh authored May 20, 2024
1 parent b30d912 commit bcd0f03
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 8 deletions.
3 changes: 3 additions & 0 deletions src/opsinputs/VarObsWriterParameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<bool> varobsLengthIsIC_PLevels{"varobs_length_is_IC_PLevels", false, this};

/// Set to true if MetaData/stationIdentification is an integer instead of a string.
oops::Parameter<bool> StationIDIntToString{"station_ID_int_to_string", false, this};

/// Update OPS flag to output the varbc predictors
oops::Parameter<bool> outputVarBCPredictors{"output_varbc_predictors", false, this};

Expand Down
44 changes: 37 additions & 7 deletions src/opsinputs/opsinputs_fill_mod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -1854,29 +1856,57 @@ 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)
do i = 1, JediToOpsLayoutMapping % NumOpsObs
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
Expand Down
6 changes: 5 additions & 1 deletion src/opsinputs/opsinputs_varobswriter_mod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
25 changes: 25 additions & 0 deletions test/generate_unittest_netcdfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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')
Expand Down
Binary file not shown.
27 changes: 27 additions & 0 deletions test/testinput/001_VarField_pstar_stationID_integer.yaml
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit bcd0f03

Please sign in to comment.