IODA
ObsIoWrite.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2018 UCAR
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  */
7 
8 #ifndef TEST_IO_OBSIOWRITE_H_
9 #define TEST_IO_OBSIOWRITE_H_
10 
11 #include <algorithm>
12 #include <functional>
13 #include <map>
14 #include <memory>
15 #include <numeric>
16 #include <string>
17 #include <utility>
18 #include <vector>
19 
20 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
21 
22 #include "eckit/config/LocalConfiguration.h"
23 #include "eckit/testing/Test.h"
24 
25 #include "oops/mpi/mpi.h"
26 #include "oops/runs/Test.h"
27 #include "oops/test/TestEnvironment.h"
28 #include "oops/util/DateTime.h"
29 #include "oops/util/FloatCompare.h"
30 #include "oops/util/Logger.h"
31 
32 #include "ioda/core/IodaUtils.h"
33 #include "ioda/distribution/DistributionFactory.h"
34 #include "ioda/io/ObsIo.h"
35 #include "ioda/io/ObsIoFactory.h"
36 #include "ioda/ObsGroup.h"
37 #include "ioda/ObsSpaceParameters.h"
39 
40 namespace ioda {
41 namespace test {
42 
43 // -----------------------------------------------------------------------------
44 // Helper Functions
45 // -----------------------------------------------------------------------------
46 
47 // -----------------------------------------------------------------------------
48 // Test Functions
49 // -----------------------------------------------------------------------------
50 
51 // -----------------------------------------------------------------------------
52 void testWrite() {
53  const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
54  std::vector<eckit::LocalConfiguration> confOspaces = conf.getSubConfigurations("observations");
55  util::DateTime bgn(::test::TestEnvironment::config().getString("window begin"));
56  util::DateTime end(::test::TestEnvironment::config().getString("window end"));
57 
58  for (std::size_t i = 0; i < confOspaces.size(); ++i) {
59  eckit::LocalConfiguration obsConfig;
60  eckit::LocalConfiguration testConfig;
61  confOspaces[i].get("obs space", obsConfig);
62  confOspaces[i].get("test data", testConfig);
63  oops::Log::trace() << "ObsIo testWrite obs space config: " << i << ": "
64  << obsConfig << std::endl;
65  oops::Log::trace() << "ObsIo testWrite test data config: " << i << ": "
66  << obsConfig << std::endl;
67 
68  ioda::ObsSpaceParameters obsParams(bgn, end, oops::mpi::world(), oops::mpi::myself());
69  obsParams.deserialize(obsConfig);
70 
71  if (obsParams.top_level_.obsOutFile.value() != boost::none) {
72  std::vector<eckit::LocalConfiguration> writeVarConfigs =
73  testConfig.getSubConfigurations("write variables");
74  std::vector<eckit::LocalConfiguration> writeDimConfigs =
75  testConfig.getSubConfigurations("write dimensions");
76 
77  // Output constructor
78  setOfileParamsFromTestConfig(testConfig, obsParams);
79  std::shared_ptr<ObsIo> obsIo =
81 
82  // Write the test variables
83  for (std::size_t j = 0; j < writeVarConfigs.size(); ++j) {
84  std::string varName = writeVarConfigs[j].getString("name");
85  std::string varType = writeVarConfigs[j].getString("type");
86  std::vector<std::string> varDimNames =
87  writeVarConfigs[j].getStringVector("dims");
88 
89  // Create the variable
90  ioda::Variable var;
91  std::vector<ioda::Variable> varDims;
92  for (std::size_t idim = 0; idim < varDimNames.size(); ++idim) {
93  varDims.push_back(obsIo->vars().open(varDimNames[idim]));
94  }
95 
97  params.chunk = true;
98  params.compressWithGZIP();
99  if (varType == "int") {
100  params.setFillValue<int>(-999);
101  var = obsIo->vars()
102  .createWithScales<int>(varName, varDims, params);
103  } else if (varType == "float") {
104  params.setFillValue<float>(-999);
105  var = obsIo->vars()
106  .createWithScales<float>(varName, varDims, params);
107  } else if (varType == "string") {
108  params.setFillValue<std::string>("fill");
109  var = obsIo->vars()
110  .createWithScales<std::string>(varName, varDims, params);
111  }
112 
113  // Write the variable data
114  if (varType == "int") {
115  std::vector<int> varValues =
116  writeVarConfigs[j].getIntVector("values");
117  var.write<int>(varValues);
118  } else if (varType == "float") {
119  std::vector<float> varValues =
120  writeVarConfigs[j].getFloatVector("values");
121  var.write<float>(varValues);
122  } else if (varType == "string") {
123  std::vector<std::string> varValues =
124  writeVarConfigs[j].getStringVector("values");
125  var.write<std::string>(varValues);
126  }
127  }
128 
129  // Update the variable lists in the ObsIo object
130  obsIo->updateVarDimInfo();
131 
132  // Check if all the variables got written into the file
133  // Dimension scale variables
134  std::vector<std::string> expectedDimList;
135  for (size_t i = 0; i < writeDimConfigs.size(); ++i) {
136  expectedDimList.push_back(writeDimConfigs[i].getString("name"));
137  }
138  std::sort(expectedDimList.begin(), expectedDimList.end());
139  VarNameObjectList dimList = obsIo->dimVarList();
140  std::sort(dimList.begin(), dimList.end(), [](auto & p1, auto & p2) {
141  return (p1.first < p2.first); });
142  for (size_t i = 0; i < dimList.size(); ++i) {
143  EXPECT_EQUAL(dimList[i].first, expectedDimList[i]);
144  }
145 
146  // Regular variables
147  std::vector<std::string> expectedVarList;
148  for (size_t i = 0; i < writeVarConfigs.size(); ++i) {
149  expectedVarList.push_back(writeVarConfigs[i].getString("name"));
150  }
151  std::sort(expectedVarList.begin(), expectedVarList.end());
152  VarNameObjectList varList = obsIo->varList();
153  std::sort(varList.begin(), varList.end(), [](auto & p1, auto & p2) {
154  return (p1.first < p2.first); });
155  for (size_t i = 0; i < dimList.size(); ++i) {
156  EXPECT_EQUAL(varList[i].first, expectedVarList[i]);
157  }
158 
159  // Check if the values of the variables got written correctly
160  for (std::size_t j = 0; j < writeVarConfigs.size(); ++j) {
161  std::string varName = writeVarConfigs[j].getString("name");
162  std::string varType = writeVarConfigs[j].getString("type");
163 
164  // Read the variable data from the file and compare with
165  // the values from the YAML configuration
166  Variable var = obsIo->vars().open(varName);
167  if (varType == "int") {
168  std::vector<int> expectedVarValues =
169  writeVarConfigs[j].getIntVector("values");
170  std::vector<int> varValues;
171  var.read<int>(varValues);
172  EXPECT_EQUAL(varValues, expectedVarValues);
173  } else if (varType == "float") {
174  std::vector<float> expectedVarValues =
175  writeVarConfigs[j].getFloatVector("values");
176  std::vector<float> varValues;
177  var.read<float>(varValues);
178  EXPECT_EQUAL(varValues, expectedVarValues);
179  } else if (varType == "string") {
180  std::vector<std::string> expectedVarValues =
181  writeVarConfigs[j].getStringVector("values");
182  std::vector<std::string> varValues;
183  var.read<std::string>(varValues);
184  EXPECT_EQUAL(varValues, expectedVarValues);
185  }
186  }
187  }
188  }
189 }
190 
191 // -----------------------------------------------------------------------------
192 
193 class ObsIoWrite : public oops::Test {
194  public:
196  virtual ~ObsIoWrite() {}
197  private:
198  std::string testid() const override {return "test::ObsIoWrite";}
199 
200  void register_tests() const override {
201  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
202 
203  ts.emplace_back(CASE("ioda/ObsIoWrite/testWrite")
204  { testWrite(); });
205  }
206 
207  void clear() const override {}
208 };
209 
210 // -----------------------------------------------------------------------------
211 
212 } // namespace test
213 } // namespace ioda
214 
215 #endif // TEST_IO_OBSIOWRITE_H_
Interfaces for ioda::ObsGroup and related classes.
Interfaces for ioda::Variable and related classes.
static std::shared_ptr< ObsIo > create(ObsIoModes mode, const ObsSpaceParameters &parameters)
Create and return a new instance of an ObsIo subclass.
Definition: ObsIoFactory.cc:24
void deserialize(const eckit::Configuration &config)
deserialize the parameter sub groups
ObsTopLevelParameters top_level_
sub groups of parameters
oops::OptionalParameter< ObsFileOutParameters > obsOutFile
output specification by writing to a file
Variables store data!
Definition: Variable.h:680
virtual Variable write(gsl::span< char > data, const Type &in_memory_dataType, const Selection &mem_selection=Selection::all, const Selection &file_selection=Selection::all)
The fundamental write function. Backends overload this function to implement all write operations.
Definition: Variable.cpp:317
void register_tests() const override
Definition: ObsIoWrite.h:200
void clear() const override
Definition: ObsIoWrite.h:207
std::string testid() const override
Definition: ObsIoWrite.h:198
CASE("Derived variable and unit conversion methods")
std::vector< std::pair< std::string, Variable > > VarNameObjectList
typedef for holding list of variable names with associated variable object
Definition: IodaUtils.h:30
void setOfileParamsFromTestConfig(const eckit::LocalConfiguration &obsConfig, ioda::ObsSpaceParameters &obsParams)
set params for output file construction from test YAML configuration
Definition: IodaUtils.cc:306
Used to specify Variable creation-time properties.
Definition: Has_Variables.h:57