16 #include "Eigen/Dense"
22 #include "ioda/testconfig.h"
25 const std::string mappingFile =
"") {
39 std::vector<int> nLocs(locationsX2);
40 std::iota(nLocs.begin(), nLocs.end(), 0);
43 std::iota(nChans.begin(), nChans.end(), 1);
45 Eigen::ArrayXXf myDataExpected(locationsX2,
channels);
46 std::vector<float> myLonExpected(locationsX2);
47 std::vector<float> myLatExpected(locationsX2);
48 auto mid_loc =
static_cast<float>(
locations);
49 auto mid_chan =
static_cast<float>(
channels) / 2.0f;
50 for (std::size_t i = 0; i < locationsX2; ++i) {
51 myLonExpected[i] =
static_cast<float>(i % 8) * 3.0f;
52 myLatExpected[i] =
static_cast<float>(i / 8) * 3.0f;
53 for (std::size_t j = 0; j <
channels; ++j) {
54 float del_i =
static_cast<float>(i) - mid_loc;
55 float del_j =
static_cast<float>(j) - mid_chan;
56 myDataExpected(i, j) = sqrt(del_i * del_i + del_j * del_j);
66 std::vector<float> myLatExpected1(myLatExpected.begin(), myLatExpected.begin() +
locations);
67 std::vector<float> myLatExpected2(myLatExpected.begin() +
locations, myLatExpected.end());
68 std::vector<float> myLonExpected1(myLonExpected.begin(), myLonExpected.begin() +
locations);
69 std::vector<float> myLonExpected2(myLonExpected.begin() +
locations, myLonExpected.end());
70 std::vector<int> nLocs1(nLocs.begin(), nLocs.begin() +
locations);
71 std::vector<int> nLocs2(nLocs.begin() +
locations, nLocs.end());
76 if (backendType ==
"file" || backendType ==
"fileRemapped") {
82 }
else if (backendType ==
"memory") {
86 .
add(
"backendType", backendType);
92 if (backendType !=
"fileRemapped") {
98 }
else if (mappingFile ==
"") {
108 NewDimensionScale<int>(
110 NewDimensionScale<int>(
116 nlocs_var.
write(nLocs1);
119 nchans_var.
write(nChans);
123 float_params.
chunk =
true;
127 Variable obs_var =
og.vars.createWithScales<
float>(
"ObsValue/myObs", {nlocs_var, nchans_var}, float_params);
129 og.vars.createWithScales<
float>(
"MetaData/latitude", {nlocs_var}, float_params);
130 Variable lat_var =
og.vars.open(
"MetaData/latitude");
132 og.vars.createWithScales<
float>(
"MetaData/longitude", {nlocs_var}, float_params);
133 Variable lon_var =
og.vars[
"MetaData/longitude"];
136 obs_var.atts.add<std::string>(
"coordinates", {
"longitude latitude nchans"}, {1})
137 .add<std::string>(
"long_name", {
"obs I made up"}, {1})
138 .add<std::string>(
"units", {
"K"}, {1})
139 .add<float>(
"valid_range", {0.0, 50.0}, {2});
140 lat_var.atts.add<std::string>(
"long_name", {
"latitude"}, {1})
141 .add<std::string>(
"units", {
"degrees_north"}, {1})
142 .add<float>(
"valid_range", {-90.0, 90.0}, {2});
143 lon_var.atts.add<std::string>(
"long_name", {
"longitude"}, {1})
144 .add<std::string>(
"units", {
"degrees_east"}, {1})
145 .add<float>(
"valid_range", {-360.0, 360.0}, {2});
148 obs_var.writeWithEigenRegular(myDataExpected1);
149 lat_var.write(myLatExpected1);
150 lon_var.write(myLonExpected1);
154 og.resize({std::pair<ioda::Variable, ioda::Dimensions_t>(nlocs_var, locationsX2)});
157 std::vector<ioda::Dimensions_t> memStarts(1, 0);
158 std::vector<ioda::Dimensions_t> memCounts(1,
locations);
159 std::vector<ioda::Dimensions_t> fileStarts(1,
locations);
160 std::vector<ioda::Dimensions_t> fileCounts(1,
locations);
168 memStarts.push_back(0);
170 fileStarts.push_back(0);
179 nlocs_var.
write(nLocs2, memSelect1D, fileSelect1D);
181 lat_var.
write(myLatExpected2, memSelect1D, fileSelect1D);
182 lon_var.
write(myLonExpected2, memSelect1D, fileSelect1D);
185 Eigen::ArrayXXf myData(locationsX2,
channels);
186 obs_var.readWithEigenRegular(myData);
187 if (!myData.isApprox(myDataExpected)) {
191 std::vector<float> myLats(locationsX2, 0.0);
192 lat_var.read(myLats);
193 for (std::size_t i = 0; i < locationsX2; ++i) {
194 double check = fabs((myLats[i] / myLatExpected[i]) - 1.0);
195 if (check > 1.0e-3) {
198 .
add(
" myLatExpected[i]", myLatExpected[i])
199 .
add(
" myLats[i]", myLats[i]);
203 std::vector<float> myLons(locationsX2, 0.0);
204 lon_var.read(myLons);
205 for (std::size_t i = 0; i < locationsX2; ++i) {
206 double check = fabs((myLons[i] / myLonExpected[i]) - 1.0);
207 if (check > 1.0e-3) {
210 .
add(
" myLonExpected[i]", myLonExpected[i])
211 .
add(
" myLons[i]", myLons[i]);
216 Expects(
og.open(
"ObsValue").vars[
"myObs"].isDimensionScaleAttached(1,
og.vars[
"nchans"]));
219 int main(
int argc,
char** argv) {
221 std::cerr <<
"Need to specify backend type (file, memory)" << std::endl;
224 std::string backendType(argv[1]);
226 if (backendType ==
"file") {
227 std::cout <<
"Testing file backend" << std::endl;
229 }
else if (backendType ==
"memory") {
230 std::cout <<
"Testing memory backend" << std::endl;
232 }
else if (backendType ==
"fileRemapped") {
235 std::cout <<
"Testing ODB Data Layout Policy with explicit mapping file" << std::endl;
236 std::string mappingFile = std::string(IODA_ENGINES_TEST_SOURCE_DIR)
237 +
"/obsgroup/odb_default_name_map.yaml";
241 .
add(
"Backend type", backendType);
243 }
catch (
const std::exception& e) {
Definitions for setting up backends with file and memory I/O.
Contains definitions for how data are arranged in ioda internally.
Interfaces for ioda::ObsGroup and related classes.
The ioda exception class.
Exception & add(const std::string &key, const T value)
Add a key-value pair to the error message.
Groups are a new implementation of ObsSpaces.
An ObsGroup is a specialization of a ioda::Group. It provides convenience functions and guarantees th...
static ObsGroup generate(Group &emptyGroup, const NewDimensionScales_t &fundamentalDims, std::shared_ptr< const detail::DataLayoutPolicy > layout=nullptr)
Create an empty ObsGroup and populate it with the fundamental dimensions.
A Selection represents the bounds of the data, in ioda or in userspace, that you are reading or writi...
static std::shared_ptr< const DataLayoutPolicy > generate(const std::string &polid="")
Factory generator.
Variable_Implementation writeWithEigenRegular(const EigenClass &d, const Selection &mem_selection=Selection::all, const Selection &file_selection=Selection::all)
Write an Eigen object (a Matrix, an Array, a Block, a Map).
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.
BackendNames
Backend names.
IODA_DL Group constructBackend(BackendNames name, BackendCreationParameters ¶ms)
This is a simple factory style function that will instantiate a different backend based on a given na...
@ Create
Create a new file.
@ Hdf5File
HDF5 file access.
@ ObsStore
ObsStore in-memory.
@ Truncate_If_Exists
If the file already exists, overwrite it.
Selection & extent(const VecDimensions_t &sz)
Provide the dimensions of the object that you are selecting from.
Selection & select(const SingleSelection &s)
Append a new selection.
constexpr int Unlimited
Specifies that a dimension is resizable to infinity.
IODA_DL void unwind_exception_stack(const std::exception &e, std::ostream &out=std::cerr, int level=0)
Convenience function for unwinding an exception stack.
Used to specify backend creation-time properties.
BackendFileActions action
BackendCreateModes createMode
Used to specify Variable creation-time properties.
void compressWithGZIP(int level=6)
VariableCreationParameters & setFillValue(DataType fill)
bool chunk
Do we chunk this variable? Required for extendible / compressible Variables.
int main(int argc, char **argv)
void test_obsgroup_helper_funcs(std::string backendType, std::string fileName, const std::string mappingFile="")