IODA
NetcdfIO.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2017-2019 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 #include "ioda/io/NetcdfIO.h"
9 
10 #include <algorithm>
11 #include <cmath>
12 #include <functional>
13 #include <iostream>
14 #include <memory>
15 #include <numeric>
16 #include <typeinfo>
17 
18 #include <boost/math/special_functions/fpclassify.hpp>
19 
20 #include "netcdf.h"
21 
22 #include "oops/mpi/mpi.h"
23 #include "oops/util/abor1_cpp.h"
24 #include "oops/util/Duration.h"
25 #include "oops/util/Logger.h"
26 #include "oops/util/missingValues.h"
27 
28 #include "ioda/core/IodaUtils.h"
29 
30 ////////////////////////////////////////////////////////////////////////
31 // Implementation of IodaIO for netcdf.
32 ////////////////////////////////////////////////////////////////////////
33 
34 namespace ioda {
35 
36 // -----------------------------------------------------------------------------
37 /*!
38  * \details This constructor will open the netcdf file. If opening in read
39  * mode, the parameters nlocs and nvars will be set
40  * by querying the size of dimensions of the same names in the input
41  * file. If opening in write mode, the parameters will be set from the
42  * same named arguements to this constructor.
43  *
44  * \param[in] FileName Path to the netcdf file
45  * \param[in] FileMode "r" for read, "w" for overwrite to an existing file
46  * and "W" for create and write to a new file.
47  */
48 
49 NetcdfIO::NetcdfIO(const std::string & FileName, const std::string & FileMode,
50  const std::size_t MaxFrameSize) :
51  IodaIO(FileName, FileMode, MaxFrameSize), have_offset_time_(false),
52  have_date_time_(false) {
53  oops::Log::trace() << __func__ << " fname_: " << fname_ << " fmode_: " << fmode_ << std::endl;
54 
55  // Open the file. The fmode_ values that are recognized are:
56  // "r" - read
57  // "w" - write, disallow overriting an existing file
58  // "W" - write, allow overwriting an existing file
59  std::string ErrorMsg = "NetcdfIO::NetcdfIO: Unable to open file: '" + fname_ +
60  "' in mode: " + fmode_;
61  if (fmode_ == "r") {
62  CheckNcCall(nc_open(fname_.c_str(), NC_NOWRITE, &ncid_), ErrorMsg);
63  } else if (fmode_ == "w") {
64  CheckNcCall(nc_create(fname_.c_str(), NC_NOCLOBBER|NC_NETCDF4, &ncid_), ErrorMsg);
65  } else if (fmode_ == "W") {
66  CheckNcCall(nc_create(fname_.c_str(), NC_CLOBBER|NC_NETCDF4, &ncid_), ErrorMsg);
67  } else {
68  oops::Log::error() << "NetcdfIO::NetcdfIO: Unrecognized FileMode: " << fmode_ << std::endl;
69  oops::Log::error() << "NetcdfIO::NetcdfIO: Must use one of: 'r', 'w', 'W'" << std::endl;
70  ABORT("Unrecognized file mode for NetcdfIO constructor");
71  }
72 
73  // When in read mode, the constructor is responsible for setting
74  // the data members nlocs_, nvars_ and grp_var_info_.
75  //
76  // The files have nlocs, nvars.
77  //
78  // The way to collect the VALID variable names is controlled by developers.
79  //
80 
81  if (fmode_ == "r") {
82  // Find counts of objects in the file
83  int NcNdims;
84  int NcNvars;
85  int NcNatts;
86  ErrorMsg = "NetcdfIO::NetcdfIO: Unable to read file object counts";
87  CheckNcCall(nc_inq(ncid_, &NcNdims, &NcNvars, &NcNatts, NULL), ErrorMsg);
88 
89  // Record the dimension ids and sizes in the dim_info_ container.
90  // Save nlocs, nvars in data members.
91  for (std::size_t i = 0; i < NcNdims; i++) {
92  char NcName[NC_MAX_NAME+1];
93  std::size_t NcSize;
94  ErrorMsg = "NetcdfIO::NetcdfIO: Unable to read dimension number: " + std::to_string(i);
95  CheckNcCall(nc_inq_dim(ncid_, i, NcName, &NcSize), ErrorMsg);
96  dim_info_[NcName].size = NcSize;
97  dim_info_[NcName].id = i;
98 
99  if (strcmp(NcName, "nlocs") == 0) {
100  nlocs_ = NcSize;
101  } else if (strcmp(NcName, "nvars") == 0) {
102  nvars_ = NcSize;
103  }
104  }
105 
106  // Walk through the variables and record the group and variable information. For
107  // now, want to support both datetime strings and ref, offset time so that
108  // we can incrementally update the files to datetime strings. Accomplish this
109  // by making sure that only the datetime variable appears in the grp_var_info_
110  // map.
111  //
112  // offset time is variable "time@MetaData"
113  // datetime string is variable "datetime@MetaData"
114  //
115  // offset time datetime grp_var_info_ read action
116  // in the file in the file entry
117  //
118  // N N nothing nothing
119  // N Y datetime read directly into var
120  // Y N datetime convert ref, offset
121  // to datetime string
122  // Y Y datetime read directly into var
123 
124  int NcVarId;
125  have_date_time_ = (nc_inq_varid(ncid_, "datetime@MetaData", &NcVarId) == NC_NOERR);
126  have_offset_time_ = (nc_inq_varid(ncid_, "time@MetaData", &NcVarId) == NC_NOERR);
127 
128  std::size_t MaxVarSize = 0;
129  for (std::size_t ivar=0; ivar < NcNvars; ++ivar) {
130  // nc variable dimension and type information
131  char NcVname[NC_MAX_NAME+1];
132  nc_type NcDtype;
133  int NcNdims;
134  int NcDimIds[NC_MAX_VAR_DIMS];
135  ErrorMsg = "NetcdfIO::NetcdfIO: Unable to read information for variable number: " +
136  std::to_string(ivar);
137  CheckNcCall(nc_inq_var(ncid_, ivar, NcVname, &NcDtype, &NcNdims, NcDimIds, 0), ErrorMsg);
138 
139  // nc type name
140  char NcDtypeName[NC_MAX_NAME+1];
141  std::size_t NcDtypeSize;
142  ErrorMsg = "NetcdfIO::NetcdfIO: Unable to look up type name";
143  CheckNcCall(nc_inq_type(ncid_, NcDtype, NcDtypeName, &NcDtypeSize), ErrorMsg);
144  if (strcmp(NcDtypeName, "char") == 0) {
145  strncpy(NcDtypeName, "string", NC_MAX_NAME);
146  }
147  std::string VarType(NcDtypeName);
148 
149  if (((VarType != "string") && (NcNdims == 1)) ||
150  ((VarType == "string") && (NcNdims == 2))) {
151  // Collect the sizes for dimensions from the dim_info_ container.
152  std::vector<std::size_t> NcDimSizes;
153  for (std::size_t j = 0; j < NcNdims; j++) {
154  NcDimSizes.push_back(dim_id_size(NcDimIds[j]));
155  }
156  // Copy shape from NcDims to VarShape. If we have a string data type, then
157  // copy only the first dimension size to VarShape since the internal variable
158  // is a vector of strings, and the file variable is a 2D character array.
159  std::vector<std::size_t> VarShape(1, NcDimSizes[0]);
160 
161  // Record the maximum variable size for the frame construction below.
162  MaxVarSize = std::max(MaxVarSize, VarShape[0]);
163 
164  // Record the variable info in the grp_var_info_ container.
165  std::string VarName;
166  std::string GroupName;
167  ExtractGrpVarName(NcVname, GroupName, VarName);
168 
169  // If the file type is double, change to float and increment the unexpected
170  // data type counter.
171  if (strcmp(NcDtypeName, "double") == 0) {
172  VarType = "float";
174  }
175 
176  // If the group name is "PreQC" and the file type is not integer, change to
177  // integer and increment the unexpected data type counter.
178  if ((GroupName == "PreQC") && (strcmp(NcDtypeName, "int") != 0)) {
179  VarType = "int";
181  }
182 
183  // If offset time exists, substitute the datetime specs for the offset time specs.
184  if (VarName.compare("time") == 0) {
185  // If we have datetime in the file, just let those specs get entered when
186  // datetime is encountered. Otherwise, replace the offset time specs
187  // with the expected datetime specs. The reader later on will do the
188  // conversion.
189  if (!have_date_time_) {
190  // Replace offset time with datetime specs. We want the offset time
191  // variable id, but with the character array specs for after the
192  // conversion.
193  // datetime strings are 20 character long
194  grp_var_insert(GroupName, "datetime", "string", VarShape, NcVname, NcDtypeName, 20);
195  }
196  } else {
197  // enter var specs into grp_var_info_ map
198  if (strcmp(NcDtypeName, "string") == 0) {
199  grp_var_insert(GroupName, VarName, VarType, VarShape, NcVname, NcDtypeName,
200  NcDimSizes[1]);
201  } else {
202  grp_var_insert(GroupName, VarName, VarType, VarShape, NcVname, NcDtypeName);
203  }
204  }
205  } else {
207  }
208  }
209 
210  // Set up the frames based on the largest variable size (first dimension of each
211  // variable). The netcdf file doesn't really have frames per se, but we want to
212  // emulate frames to make access to files generic.
213  frame_info_init(MaxVarSize);
214  }
215 }
216 
217 // -----------------------------------------------------------------------------
218 
220  oops::Log::trace() << __func__ << " fname_: " << fname_ << std::endl;
221 
222  nc_close(ncid_);
223  }
224 
225 // -----------------------------------------------------------------------------
226 /*!
227  * \brief Read data from netcdf file to memory
228  *
229  * \details The four NcReadVar methods are the same with the exception of the
230  * datatype that is being read (integer, float, double, string).
231  *
232  * \param[in] GroupName Name of ObsSpace group (ObsValue, ObsError, MetaData, etc.)
233  * \param[in] VarName Name of ObsSpace variable
234  * \param[in] Starts Starting indices in file
235  * \param[in] Counts Size of slices to read from file
236  * \param[out] FillValue Netcdf fill value associated with this variable
237  * \param[out] VarData Vector that will receive the file data
238  */
239 void NetcdfIO::NcReadVar(const std::string & GroupName, const std::string & VarName,
240  const std::vector<std::size_t> & Starts,
241  const std::vector<std::size_t> & Counts,
242  int & FillValue, std::vector<int> & VarData) {
243  // Get the netcdf variable id
244  int NcVarId = var_id(GroupName, VarName);
245 
246  // Get the variable name
247  std::array<char, NC_MAX_NAME> NcVarName;
248  std::string ErrorMsg =
249  "NetcdfIO::ReadVar: Unable to get netcdf variable name: " + std::to_string(NcVarId);
250  CheckNcCall(nc_inq_varname(ncid_, NcVarId, NcVarName.data()), ErrorMsg);
251 
252  // Read variable, and get the fill value.
253  VarData.assign(Counts[0], 0); // allocate space for the netcdf read
254  ErrorMsg = "NetcdfIO::ReadVar: Unable to read netcdf variable: ";
255  ErrorMsg += NcVarName.data();
256  CheckNcCall(nc_get_vara_int(ncid_, NcVarId, Starts.data(), Counts.data(),
257  VarData.data()), ErrorMsg);
258 
259  if (NcAttrExists(NcVarId, "_FillValue")) {
260  ErrorMsg = "NetcdfIO::ReadVar: cannot read _FillValue attribute for variable: ";
261  ErrorMsg += NcVarName.data();
262  CheckNcCall(nc_get_att_int(ncid_, NcVarId, "_FillValue", &FillValue), ErrorMsg);
263  } else {
264  FillValue = NC_FILL_INT;
265  }
266 }
267 
268 void NetcdfIO::NcReadVar(const std::string & GroupName, const std::string & VarName,
269  const std::vector<std::size_t> & Starts,
270  const std::vector<std::size_t> & Counts,
271  float & FillValue, std::vector<float> & VarData) {
272  // Get the netcdf variable id
273  int NcVarId = var_id(GroupName, VarName);
274 
275  // Get the variable name
276  std::array<char, NC_MAX_NAME> NcVarName;
277  std::string ErrorMsg =
278  "NetcdfIO::ReadVar: Unable to get netcdf variable name: " + std::to_string(NcVarId);
279  CheckNcCall(nc_inq_varname(ncid_, NcVarId, NcVarName.data()), ErrorMsg);
280 
281  // Read variable, and get the fill value.
282  VarData.assign(Counts[0], 0.0); // allocate space for the netcdf read
283  ErrorMsg = "NetcdfIO::ReadVar: Unable to read netcdf variable: ";
284  ErrorMsg += NcVarName.data();
285  CheckNcCall(nc_get_vara_float(ncid_, NcVarId, Starts.data(), Counts.data(),
286  VarData.data()), ErrorMsg);
287 
288  if (NcAttrExists(NcVarId, "_FillValue")) {
289  ErrorMsg = "NetcdfIO::ReadVar: cannot read _FillValue attribute for variable: ";
290  ErrorMsg += NcVarName.data();
291  CheckNcCall(nc_get_att_float(ncid_, NcVarId, "_FillValue", &FillValue), ErrorMsg);
292  } else {
293  FillValue = NC_FILL_FLOAT;
294  }
295 }
296 
297 void NetcdfIO::NcReadVar(const std::string & GroupName, const std::string & VarName,
298  const std::vector<std::size_t> & Starts,
299  const std::vector<std::size_t> & Counts,
300  double & FillValue, std::vector<double> & VarData) {
301  // Get the netcdf variable id
302  int NcVarId = var_id(GroupName, VarName);
303 
304  // Get the variable name
305  std::array<char, NC_MAX_NAME> NcVarName;
306  std::string ErrorMsg =
307  "NetcdfIO::ReadVar: Unable to get netcdf variable name: " + std::to_string(NcVarId);
308  CheckNcCall(nc_inq_varname(ncid_, NcVarId, NcVarName.data()), ErrorMsg);
309 
310  // Read variable, and get the fill value.
311  VarData.assign(Counts[0], 0.0); // allocate space for the netcdf read
312  ErrorMsg = "NetcdfIO::ReadVar: Unable to read netcdf variable: ";
313  ErrorMsg += NcVarName.data();
314  CheckNcCall(nc_get_vara_double(ncid_, NcVarId, Starts.data(), Counts.data(),
315  VarData.data()), ErrorMsg);
316 
317  if (NcAttrExists(NcVarId, "_FillValue")) {
318  ErrorMsg = "NetcdfIO::ReadVar: cannot read _FillValue attribute for variable: ";
319  ErrorMsg += NcVarName.data();
320  CheckNcCall(nc_get_att_double(ncid_, NcVarId, "_FillValue", &FillValue), ErrorMsg);
321  } else {
322  FillValue = NC_FILL_DOUBLE;
323  }
324 }
325 
326 void NetcdfIO::NcReadVar(const std::string & GroupName, const std::string & VarName,
327  const std::vector<std::size_t> & Starts,
328  const std::vector<std::size_t> & Counts,
329  char & FillValue, std::vector<std::string> & VarData) {
330  // Get the netcdf variable id
331  int NcVarId = var_id(GroupName, VarName);
332 
333  // Get the variable name and second dimension size.
334  std::array<char, NC_MAX_NAME> NcVarName;
335  std::string ErrorMsg =
336  "NetcdfIO::ReadVar: Unable to get netcdf variable info: " + std::to_string(NcVarId);
337  CheckNcCall(nc_inq_varname(ncid_, NcVarId, NcVarName.data()), ErrorMsg);
338 
339  ErrorMsg = "NetcdfIO::ReadVar: Unable to read netcdf variable: ";
340  ErrorMsg += NcVarName.data();
341  if (VarName == "datetime") {
342  if (have_date_time_) {
343  // datetime exists in the file, simply read it it. Counts holds the shape of the array
344  std::unique_ptr<char[]> CharData(new char[Counts[0] * Counts[1]]);
345  CheckNcCall(nc_get_vara_text(ncid_, NcVarId, Starts.data(), Counts.data(),
346  CharData.get()), ErrorMsg);
347  VarData = CharArrayToStringVector(CharData.get(), Counts);
348  } else {
349  // datetime does not exist in the file, read in offset time and convert to
350  // datetime strings.
351  ReadConvertDateTime(GroupName, VarName, Starts, Counts, VarData);
352  }
353  } else {
354  // All other variables beside datetime. Counts holds the shape of the array
355  std::unique_ptr<char[]> CharData(new char[Counts[0] * Counts[1]]);
356  CheckNcCall(nc_get_vara_text(ncid_, NcVarId, Starts.data(), Counts.data(),
357  CharData.get()), ErrorMsg);
358  VarData = CharArrayToStringVector(CharData.get(), Counts);
359  }
360 
361  if (NcAttrExists(NcVarId, "_FillValue")) {
362  ErrorMsg = "NetcdfIO::ReadVar: cannot read _FillValue attribute for variable: ";
363  ErrorMsg += NcVarName.data();
364  CheckNcCall(nc_get_att_text(ncid_, NcVarId, "_FillValue", &FillValue), ErrorMsg);
365  } else {
366  FillValue = NC_FILL_CHAR;
367  }
368 }
369 
370 // -----------------------------------------------------------------------------
371 /*!
372  * \brief Replace netcdf fill values with JEDI missing values
373  *
374  * \details This method replaces elements of VarData that match the netcdf
375  * fill value with the corresponding JEDI missing value.
376  *
377  * \param[inout] VarData Vector holding data to be converted
378  * \param[in] NcFillValue Netcdf fill value associated with this variable
379  */
380 
381 template <typename DataType>
382 void NetcdfIO::ReplaceFillWithMissing(std::vector<DataType> & VarData, DataType NcFillValue) {
383  const DataType missing_value = util::missingValue(missing_value);
384  for (std::size_t i = 0; i < VarData.size(); i++) {
385  if (VarData[i] == NcFillValue || boost::math::isinf(VarData[i])
386  || boost::math::isnan(VarData[i])) {
387  VarData[i] = missing_value;
388  }
389  }
390 }
391 
392 // -----------------------------------------------------------------------------
393 /*!
394  * \brief Write data from memory to netcdf file
395  *
396  * \details The three NcWriteVar methods are the same with the exception of the
397  * datatype that is being written (integer, float, char).
398  *
399  * \param[in] GroupName Name of ObsSpace group (ObsValue, ObsError, MetaData, etc.)
400  * \param[in] VarName Name of ObsSpace variable
401  * \param[in] Starts Starting indices in file
402  * \param[in] Counts Size of slices to read from file
403  * \param[in] VarData Vector that will be written into the file
404  */
405 
406 void NetcdfIO::NcWriteVar(const std::string & GroupName, const std::string & VarName,
407  const std::vector<std::size_t> & Starts,
408  const std::vector<std::size_t> & Counts,
409  const std::vector<int> & VarData) {
410  int MissVal = util::missingValue(MissVal);
411  int NcFillVal = NC_FILL_INT;
412 
413  // Replace missing values with fill value, then write into the file.
414  std::vector<int> FileData = VarData;
415  for (std::size_t i = 0; i < FileData.size(); i++) {
416  if (FileData[i] == MissVal) {
417  FileData[i] = NcFillVal;
418  }
419  }
420 
421  int NcVarId = var_id(GroupName, VarName);
422  std::string NcVarName = FormNcVarName(GroupName, VarName);
423  std::string ErrorMsg = "NetcdfIO::WriteVar: Unable to write dataset: " + NcVarName;
424  CheckNcCall(nc_put_vara_int(ncid_, NcVarId, Starts.data(), Counts.data(),
425  FileData.data()), ErrorMsg);
426 }
427 
428 void NetcdfIO::NcWriteVar(const std::string & GroupName, const std::string & VarName,
429  const std::vector<std::size_t> & Starts,
430  const std::vector<std::size_t> & Counts,
431  const std::vector<float> & VarData) {
432  float MissVal = util::missingValue(MissVal);
433  float NcFillVal = NC_FILL_FLOAT;
434 
435  // Replace missing values with fill value, then write into the file.
436  std::vector<float> FileData = VarData;
437  for (std::size_t i = 0; i < FileData.size(); i++) {
438  if (FileData[i] == MissVal) {
439  FileData[i] = NcFillVal;
440  }
441  }
442 
443  int NcVarId = var_id(GroupName, VarName);
444  std::string NcVarName = FormNcVarName(GroupName, VarName);
445  std::string ErrorMsg = "NetcdfIO::WriteVar: Unable to write dataset: " + NcVarName;
446  CheckNcCall(nc_put_vara_float(ncid_, NcVarId, Starts.data(), Counts.data(),
447  FileData.data()), ErrorMsg);
448 }
449 
450 void NetcdfIO::NcWriteVar(const std::string & GroupName, const std::string & VarName,
451  const std::vector<std::size_t> & Starts,
452  const std::vector<std::size_t> & Counts,
453  const std::vector<std::string> & VarData) {
454  std::unique_ptr<char[]> CharData(new char[Counts[0] * Counts[1]]);
455  StringVectorToCharArray(VarData, Counts, CharData.get());
456 
457  int NcVarId = var_id(GroupName, VarName);
458  std::string NcVarName = FormNcVarName(GroupName, VarName);
459  std::string ErrorMsg = "NetcdfIO::WriteVar: Unable to write dataset: " + NcVarName;
460  CheckNcCall(nc_put_vara_text(ncid_, NcVarId, Starts.data(), Counts.data(),
461  CharData.get()), ErrorMsg);
462 }
463 
464 // -----------------------------------------------------------------------------
465 /*!
466  * \brief Get the max string size in a vector of strings
467  *
468  * \details This method will return the size of the longest string in a vector
469  * of strings.
470  */
471 std::size_t NetcdfIO::GetMaxStringSize(const std::vector<std::string> & Strings) {
472  std::size_t MaxSize = 0;
473  for (std::size_t i = 0; i < Strings.size(); ++i) {
474  if (Strings[i].size() > MaxSize) {
475  MaxSize = Strings[i].size();
476  }
477  }
478  return MaxSize;
479 }
480 // -----------------------------------------------------------------------------
481 /*!
482  * \brief Get the netcdf dimension ids
483  *
484  * \details This method will determine the netcdf dimension ids associated with
485  * the current group name.
486  */
487 std::vector<int> NetcdfIO::GetNcDimIds(const std::string & GroupName,
488  const std::vector<std::size_t> & VarShape) {
489  // For now and in order to keep the IodaIO class file type agnostic, infer the
490  // dimensions from GroupName and VarShape. This is not a great way to
491  // do this, so we may need to remove the IodaIO class and expose the Netcdf
492  // and other classes.
493  //
494  // GroupName 1st dimension
495  //
496  // MetaData nlocs
497  // VarMetaData nvars
498  // RecMetaData nrecs
499  // all others nlocs
500  //
501  // If DataType is char, then assume you have a 2D character array where the
502  // second dimension is the string lengths.
503  //
504  // Assume only vectors for now meaning that int and float are just 1D arrays.
505 
506  // Form the dimension id list.
507  std::vector<int> NcDimIds;
508  if (GroupName.compare("MetaData") == 0) {
509  if (!dim_exists("nlocs")) {
510  dim_insert("nlocs", VarShape[0]);
511  }
512  NcDimIds.push_back(dim_name_id("nlocs"));
513  } else if (GroupName.compare("VarMetaData") == 0) {
514  if (!dim_exists("nvars")) {
515  dim_insert("nvars", VarShape[0]);
516  }
517  NcDimIds.push_back(dim_name_id("nvars"));
518  } else if (GroupName.compare("RecMetaData") == 0) {
519  if (!dim_exists("nrecs")) {
520  dim_insert("nrecs", VarShape[0]);
521  }
522  NcDimIds.push_back(dim_name_id("nrecs"));
523  } else {
524  if (!dim_exists("nlocs")) {
525  dim_insert("nlocs", VarShape[0]);
526  }
527  NcDimIds.push_back(dim_name_id("nlocs"));
528  }
529 
530  return NcDimIds;
531 }
532 
533 // -----------------------------------------------------------------------------
534 /*!
535  * \brief create a dimension in the netcdf file
536  *
537  * \details This method will create a dimension in the output netcdf file using
538  * the name given by DimName and the size given by DimSize. This method
539  * also records the dimension name and size for downstream use in the
540  * WriteVar methods.
541  *
542  * \param[in] Name Name of netcdf dimension
543  * \param[in] Size Size of netcdf dimension
544  */
545 
546 void NetcdfIO::DimInsert(const std::string & Name, const std::size_t Size) {
547  int NcDimId;
548  std::string ErrorMsg = "NetcdfIO::NetcdfIO: Unable to create dimension: " + Name;
549  CheckNcCall(nc_def_dim(ncid_, Name.c_str(), Size, &NcDimId), ErrorMsg);
550  dim_info_[Name].size = Size;
551  dim_info_[Name].id = NcDimId;
552 }
553 
554 // -----------------------------------------------------------------------------
555 /*!
556  * \brief Read data from the file into the frame containers
557  *
558  */
560  // Grab the specs for the current frame
561  std::size_t FrameStart = frame_start(iframe);
562  std::size_t FrameSize = frame_size(iframe);
563 
564  // Create new containers and read data from the file into them.
565  frame_data_init();
566 
567  for (IodaIO::GroupIter igrp = group_begin(); igrp != group_end(); ++igrp) {
568  std::string GroupName = group_name(igrp);
569  for (IodaIO::VarIter ivar = var_begin(igrp); ivar != var_end(igrp); ++ivar) {
570  // Since there are variables of different lengths in a netcdf file, check to
571  // see if the frame has gone past the end of the variable, and if so skip
572  // that variable.
573  std::vector<std::size_t> VarShape = var_shape(ivar);
574  if (VarShape[0] > FrameStart) {
575  // Grab the var specs, and calculate the start and count in the file.
576  // Make sure the count doesn't go past the end of the variable in the file.
577  // The start and count only apply to the first dimension, the remaining
578  // dimensions, if any are always read in full.
579  std::string VarName = var_name(ivar);
580  std::string VarType = var_dtype(ivar);
581  std::string FileType = file_type(ivar);
582  std::vector<std::size_t> VarStarts(1, FrameStart);
583 
584  std::vector<std::size_t> VarCounts;
585  if (FrameStart + FrameSize > VarShape[0]) {
586  VarCounts.push_back(VarShape[0] - FrameStart);
587  } else {
588  VarCounts.push_back(FrameSize);
589  }
590 
591  // Compare the variable type for memory (VarType) with the variable type
592  // from the file (FileType). Do conversions for cases that have come up with
593  // various netcdf obs files. The idea is to get all obs files with the expected
594  // data types so that these conversions will be unnecessary. Once we are there
595  // with the files, then make any unexpected data type in the file an error so that
596  // it will get corrected immediately.
597  if (VarType == "int") {
598  if (FileType == "int") {
599  std::vector<int> FileData;
600  int NcFillValue;
601  NcReadVar(GroupName, VarName, VarStarts, VarCounts, NcFillValue, FileData);
602  ReplaceFillWithMissing<int>(FileData, NcFillValue);
603  int_frame_data_->put_data(GroupName, VarName, FileData);
604  } else if (FileType == "float") {
605  std::vector<float> FileData;
606  float NcFillValue;
607  NcReadVar(GroupName, VarName, VarStarts, VarCounts, NcFillValue, FileData);
608  ReplaceFillWithMissing<float>(FileData, NcFillValue);
609 
610  std::vector<int> FrameData(FileData.size(), 0);
611  ConvertVarType<float, int>(FileData, FrameData);
612  int_frame_data_->put_data(GroupName, VarName, FrameData);
613  } else if (FileType == "double") {
614  std::vector<double> FileData;
615  double NcFillValue;
616  NcReadVar(GroupName, VarName, VarStarts, VarCounts, NcFillValue, FileData);
617  ReplaceFillWithMissing<double>(FileData, NcFillValue);
618 
619  std::vector<int> FrameData(FileData.size(), 0);
620  ConvertVarType<double, int>(FileData, FrameData);
621  int_frame_data_->put_data(GroupName, VarName, FrameData);
622  } else {
623  std::string ErrorMsg =
624  "NetcdfIO::ReadFrame: Conflicting data types for conversion to int: ";
625  ErrorMsg += "File variable: " + file_name(ivar) + ", File type: " + FileType;
626  ABORT(ErrorMsg);
627  }
628  } else if (VarType == "float") {
629  if (FileType == "float") {
630  std::vector<float> FileData;
631  float NcFillValue;
632  NcReadVar(GroupName, VarName, VarStarts, VarCounts, NcFillValue, FileData);
633  ReplaceFillWithMissing<float>(FileData, NcFillValue);
634  float_frame_data_->put_data(GroupName, VarName, FileData);
635  } else if (FileType == "double") {
636  std::vector<double> FileData;
637  double NcFillValue;
638  NcReadVar(GroupName, VarName, VarStarts, VarCounts, NcFillValue, FileData);
639  ReplaceFillWithMissing<double>(FileData, NcFillValue);
640 
641  std::vector<float> FrameData(FileData.size(), 0.0);
642  ConvertVarType<double, float>(FileData, FrameData);
643  float_frame_data_->put_data(GroupName, VarName, FrameData);
644  } else {
645  std::string ErrorMsg =
646  "NetcdfIO::ReadFrame: Conflicting data types for conversion to float: ";
647  ErrorMsg += "File variable: " + file_name(ivar) + ", File type: " + FileType;
648  ABORT(ErrorMsg);
649  }
650  } else if (VarType == "string") {
651  // Need to expand Starts, Counts with remaining dimensions.
652  std::vector<std::size_t> VarFileShape = file_shape(ivar);
653  for (std::size_t i = 1; i < VarFileShape.size(); ++i) {
654  VarStarts.push_back(0);
655  VarCounts.push_back(VarFileShape[i]);
656  }
657  std::vector<std::string> FileData;
658  char NcFillValue;
659  NcReadVar(GroupName, VarName, VarStarts, VarCounts, NcFillValue, FileData);
660  string_frame_data_->put_data(GroupName, VarName, FileData);
661  }
662  }
663  }
664  }
665 }
666 
667 // -----------------------------------------------------------------------------
668 /*!
669  * \brief Write data from the frame containers into the file
670  *
671  */
672 
674  // Grab the specs for the current frame
675  std::size_t FrameStart = frame_start(iframe);
676 
677  std::vector<std::size_t> Starts(1, FrameStart);
678  std::vector<std::size_t> Counts;
679 
680  std::string GroupName;
681  std::string VarName;
682  std::vector<std::size_t> VarShape;
683 
684  // Walk through the int, float, and string frame containers and dump
685  // their contents into the output file.
686  for (IodaIO::FrameIntIter iframe = frame_int_begin();
687  iframe != frame_int_end(); ++iframe) {
688  GroupName = frame_int_get_gname(iframe);
689  VarName = frame_int_get_vname(iframe);
690  std::vector<int> FrameData = frame_int_get_data(iframe);
691  Counts.assign(1, FrameData.size());
692  NcWriteVar(GroupName, VarName, Starts, Counts, FrameData);
693  }
694 
696  iframe != frame_float_end(); ++iframe) {
697  GroupName = frame_float_get_gname(iframe);
698  VarName = frame_float_get_vname(iframe);
699  std::vector<float> FrameData = frame_float_get_data(iframe);
700  Counts.assign(1, FrameData.size());
701  NcWriteVar(GroupName, VarName, Starts, Counts, FrameData);
702  }
703 
705  iframe != frame_string_end(); ++iframe) {
706  GroupName = frame_string_get_gname(iframe);
707  VarName = frame_string_get_vname(iframe);
708  std::vector<std::string> FrameData = frame_string_get_data(iframe);
709  std::vector<std::size_t> FileShape = file_shape(GroupName, VarName);
710  std::vector<std::size_t> CharStarts{ Starts[0], 0 };
711  std::vector<std::size_t> CharCounts{ FrameData.size(), FileShape[1] };
712  NcWriteVar(GroupName, VarName, CharStarts, CharCounts, FrameData);
713  }
714 }
715 
716 // -----------------------------------------------------------------------------
717 /*!
718  * \brief Add entry to the group, variable info container
719  *
720  */
721 
722 void NetcdfIO::GrpVarInsert(const std::string & GroupName, const std::string & VarName,
723  const std::string & VarType, const std::vector<std::size_t> & VarShape,
724  const std::string & FileVarName, const std::string & FileType,
725  const std::size_t MaxStringSize) {
726  int NcVarId;
727  std::string ErrorMsg;
728 
729  // If string type, append the MaxStringSize to the FileShape since a vector of strings
730  // is stored as a 2D character array in netcdf.
731  std::vector<std::size_t> FileShape = VarShape;
732  if (VarType == "string") {
733  FileShape.push_back(MaxStringSize);
734  }
735 
736  if (fmode_ == "r") {
737  ErrorMsg = "NetcdfIO::GrpVarInsert: Unable to get netcdf id for variable: " + FileVarName;
738  CheckNcCall(nc_inq_varid(ncid_, FileVarName.c_str(), &NcVarId), ErrorMsg);
739 
740  grp_var_info_[GroupName][VarName].var_id = NcVarId;
741  grp_var_info_[GroupName][VarName].dtype = VarType;
742  grp_var_info_[GroupName][VarName].file_shape = FileShape;
743  grp_var_info_[GroupName][VarName].file_name = FileVarName;
744  grp_var_info_[GroupName][VarName].file_type = FileType;
745  grp_var_info_[GroupName][VarName].shape = VarShape;
746  } else {
747  // Write mode, create the netcdf variable and insert data into
748  // group, variable info container
749  nc_type NcVarType = NC_NAT;
750  if (VarType == "int") {
751  NcVarType = NC_INT;
752  } else if (VarType == "float") {
753  NcVarType = NC_FLOAT;
754  } else if (VarType == "string") {
755  NcVarType = NC_CHAR;
756  } else {
757  ErrorMsg = "NetcdfIO::GrpVarInsert: Unrecognized variable type: " + VarType +
758  ", must use one of: int, float, string";
759  ABORT(ErrorMsg);
760  }
761 
762  std::vector<int> NcDimIds = GetNcDimIds(GroupName, FileShape);
763  if (VarType == "string") {
764  NcDimIds.push_back(GetStringDimBySize(FileShape[1]));
765  }
766  ErrorMsg = "NetcdfIO::WriteVar: Unable to create variable dataset: " + FileVarName;
767  CheckNcCall(nc_def_var(ncid_, FileVarName.c_str(), NcVarType, NcDimIds.size(),
768  NcDimIds.data(), &NcVarId), ErrorMsg);
769 
770  grp_var_info_[GroupName][VarName].var_id = NcVarId;
771  grp_var_info_[GroupName][VarName].dtype = VarType;
772  grp_var_info_[GroupName][VarName].file_shape = FileShape;
773  grp_var_info_[GroupName][VarName].file_name = FileVarName;
774  grp_var_info_[GroupName][VarName].file_type = FileType;
775  grp_var_info_[GroupName][VarName].shape = VarShape;
776  }
777 }
778 
779 
780 // -----------------------------------------------------------------------------
781 /*!
782  * \brief print method for stream output
783  *
784  * \details This method is supplied for the Printable base class. It defines
785  * how to print an object of this class in an output stream.
786  */
787 
788 void NetcdfIO::print(std::ostream & os) const {
789  os << "Netcdf: In " << __FILE__ << " @ " << __LINE__ << std::endl;
790  }
791 
792 // -----------------------------------------------------------------------------
793 /*!
794  * \brief check results of netcdf call
795  *
796  * \details This method will check the return code from a netcdf API call.
797  * Successful completion of the call is indicated by the return
798  * code being equal to NC_NOERR. If the call was not successful,
799  * then the error message is written to the OOPS log, and is also
800  * sent to the OOPS ABORT call (execution is aborted).
801  *
802  * \param[in] RetCode Return code from netcdf call
803  * \param[in] ErrorMsg Message for the OOPS error logger
804  */
805 
806 void NetcdfIO::CheckNcCall(int RetCode, std::string & ErrorMsg) {
807  if (RetCode != NC_NOERR) {
808  oops::Log::error() << ErrorMsg << " [NetCDF message: '"
809  << nc_strerror(RetCode) << "']" << std::endl;
810  ABORT(ErrorMsg);
811  }
812 }
813 
814 // -----------------------------------------------------------------------------
815 /*!
816  * \brief Check existence of netcdf attribute.
817  *
818  * \details This method will check to see if a netcdf exists in the
819  * input netcdf file. This can be used to check for existence
820  * of group and variable attributes.
821  *
822  * \param[in] AttrOwnerId Id number of owner of the attribute
823  * \param[in] AttrName Name attribute
824  */
825 
826 bool NetcdfIO::NcAttrExists(const int & AttrOwnerId, const std::string & AttrName) {
827  nc_type AttrType;
828  std::size_t AttrLen;
829  return (nc_inq_att(ncid_, AttrOwnerId, AttrName.c_str() , &AttrType, &AttrLen) == NC_NOERR);
830 }
831 
832 // -----------------------------------------------------------------------------
833 /*!
834  * \brief form the netcdf variable name
835  *
836  * \details This method will construct the name of the variable in the netcdf
837  * file from the given GroupName and VarName arguments. The netcdf
838  * variable name is "VarName@GroupName".
839  *
840  * \param[in] GroupName Name of group in ObsSpace database
841  * \param[in] VarName Name of variable in ObsSpace database
842  */
843 
844 std::string NetcdfIO::FormNcVarName(const std::string & GroupName, const std::string & VarName) {
845  std::string NcVarName = VarName + "@" + GroupName;
846  return NcVarName;
847 }
848 
849 // -----------------------------------------------------------------------------
850 /*!
851  * \brief allocate a dimension for writing a character array
852  *
853  * \details This method is used for setting up dimensions for a writing a
854  * character array in the output netcdf file. A character array is
855  * how a vector of strings is represented in netcdf. In order to
856  * minimize storage, this method is part of a scheme to always create
857  * the smallest character array necessary (the first dimension matches
858  * the size of the string vector, the second dimension matches the
859  * maximum string size in that vector). First, the existing dimensions
860  * that have already been allocated for character arrays are checked
861  * and if a match occurs that dimension id is returned. Otherwise, a
862  * new dimension of the size DimSize is created in the output netcdf file
863  * and that new dimension id is returned. New dimensions are named
864  * "nstringN" where N is set to DimSize.
865  *
866  * \param[in] DimSize Size of netcdf dimension
867  */
868 
869 int NetcdfIO::GetStringDimBySize(const std::size_t DimSize) {
870  // Form the name of the dimension by appending DimSize on the end of
871  // the string "nstring".
872  std::string DimName = "nstring" + std::to_string(DimSize);
873 
874  // If the dimenision exists simply return the id, otherwise create the dimension
875  // and return the new dimension's id.
876  int DimId;
877  if (dim_exists(DimName)) {
878  // Found so simply return the id
879  DimId = dim_name_id(DimName);
880  } else {
881  // Not found so create the dimension and get the id
882  std::string ErrorMsg = "NetcdfIO::NetcdfIO: Unable to create dimension: " + DimName;
883  CheckNcCall(nc_def_dim(ncid_, DimName.c_str(), DimSize, &DimId), ErrorMsg);
884  dim_info_[DimName].id = DimId;
885  dim_info_[DimName].size = DimSize;
886  }
887 
888  return DimId;
889 }
890 
891 // -----------------------------------------------------------------------------
892 /*!
893  * \brief read date and time information from the input netcdf file
894  *
895  * \details This method will read date and time information from the input netcdf
896  * file and convert that information to absolute date time strings in the
897  * ISO 8601 format. The date and time information in the input file is
898  * represented as an attribute called "date_time" that contains a reference
899  * date and time, and a float variable called "time@MetaData" that contains
900  * offset time values relative to the date_time attribute. The date_time attribute
901  * is an integer or string in the format, YYYYMMDDHH (year, month, day, hour).
902  * The time variable is the offest in units of hours. This is a placeholder
903  * function that will be removed once all input files have been converted to
904  * store absolute date time information in ISO 8601 strings.
905  *
906  * \param[in] GroupName Name of group in ObsSpace database
907  * \param[in] VarName Name of variable in ObsSpace database
908  * \param[out] VarData Character array where ISO 8601 date time strings will be placed
909  */
910 void NetcdfIO::ReadConvertDateTime(const std::string & GroupName, const std::string & VarName,
911  const std::vector<std::size_t> & Starts,
912  const std::vector<std::size_t> & Counts,
913  std::vector<std::string> & VarData) {
914  // Read in the reference date from the date_time attribute and the offset
915  // time from the time variable and convert to date_time strings.
916  int NcVarId = var_id(GroupName, VarName);
917 
918  // Read in the date_time attribute and convert to a DateTime object.
919  int RefDateAttr;
920  std::string ErrorMsg;
921  ErrorMsg = "NetcdfIO::ReadDateTime: Unable to read attribute: date_time";
922  CheckNcCall(nc_get_att_int(ncid_, NC_GLOBAL, "date_time", &RefDateAttr), ErrorMsg);
923 
924  int Year = RefDateAttr / 1000000;
925  int TempInt = RefDateAttr % 1000000;
926  int Month = TempInt / 10000;
927  TempInt = TempInt % 10000;
928  int Day = TempInt / 100;
929  int Hour = TempInt % 100;
930  util::DateTime RefDate(Year, Month, Day, Hour, 0, 0);
931 
932  // Read in the time variable.
933  std::vector<float> OffsetTime(Counts[0], 0.0);
934  ErrorMsg = "NetcdfIO::ReadDateTime: Unable to read variable: time@" + GroupName;
935  CheckNcCall(nc_get_vara_float(ncid_, NcVarId, Starts.data(), Counts.data(),
936  OffsetTime.data()), ErrorMsg);
937 
938  // Convert offset time to a Duration and add to RefDate. Then use DateTime to
939  // output an ISO 8601 datetime string, and place that string into VarData.
940  util::DateTime ObsDateTime;
941  VarData.assign(Counts[0], ""); // allocate space for the conversion
942  for (std::size_t i = 0; i < Counts[0]; ++i) {
943  ObsDateTime = RefDate + util::Duration(round(OffsetTime[i] * 3600));
944  VarData[i] = ObsDateTime.toString();
945  }
946 }
947 
948 } // namespace ioda
ioda::IodaIO::frame_int_get_data
std::vector< int > frame_int_get_data(FrameIntIter &iframe)
Definition: src/io/IodaIO.h:297
ioda::IodaIO::VarIter
VarInfoMap::const_iterator VarIter
group-variable map, variable iterator
Definition: src/io/IodaIO.h:230
ioda::IodaIO::grp_var_insert
void grp_var_insert(const std::string &GroupName, const std::string &VarName, const std::string &VarType, const std::vector< std::size_t > &VarShape, const std::string &FileVarName, const std::string &FileType, const std::size_t MaxStringSize=0)
Definition: IodaIO.cc:394
ioda::IodaIO::num_unexpect_dtypes_
std::size_t num_unexpect_dtypes_
count of unexpected data types
Definition: src/io/IodaIO.h:400
ioda::IodaIO::dim_insert
void dim_insert(const std::string &, const std::size_t)
Definition: IodaIO.cc:551
ioda::NetcdfIO::NcWriteVar
void NcWriteVar(const std::string &GroupName, const std::string &VarName, const std::vector< std::size_t > &Starts, const std::vector< std::size_t > &Counts, const std::vector< int > &VarData)
Write data from memory to netcdf file.
Definition: NetcdfIO.cc:406
ioda::IodaIO::dim_exists
bool dim_exists(const std::string &)
Definition: IodaIO.cc:410
ioda::IodaIO::FrameIntIter
FrameDataMap< int >::FrameStoreIter FrameIntIter
Definition: src/io/IodaIO.h:291
ioda::IodaIO::GroupIter
GroupVarInfoMap::const_iterator GroupIter
group-variable map, group iterator
Definition: src/io/IodaIO.h:218
ioda::NetcdfIO::NcAttrExists
bool NcAttrExists(const int &AttrOwnerId, const std::string &AttrName)
Check existence of netcdf attribute.
Definition: NetcdfIO.cc:826
ioda::IodaIO::group_end
GroupIter group_end()
Definition: IodaIO.cc:99
ioda::IodaIO::frame_string_get_vname
std::string frame_string_get_vname(FrameStringIter &iframe)
Definition: src/io/IodaIO.h:353
ioda::IodaIO::frame_string_end
FrameStringIter frame_string_end()
Definition: src/io/IodaIO.h:343
ioda::NetcdfIO::GetNcDimIds
std::vector< int > GetNcDimIds(const std::string &GroupName, const std::vector< std::size_t > &VarShape)
Get the netcdf dimension ids.
Definition: NetcdfIO.cc:487
ioda::NetcdfIO::have_offset_time_
bool have_offset_time_
offset time flag
Definition: NetcdfIO.h:136
ioda::NetcdfIO::DimInsert
void DimInsert(const std::string &Name, const std::size_t Size)
create a dimension in the netcdf file
Definition: NetcdfIO.cc:546
ioda::NetcdfIO::ReplaceFillWithMissing
void ReplaceFillWithMissing(std::vector< DataType > &VarData, DataType NcFillValue)
Replace netcdf fill values with JEDI missing values.
Definition: NetcdfIO.cc:382
ioda::IodaIO::FrameIter
FrameInfo::const_iterator FrameIter
Definition: src/io/IodaIO.h:275
ioda::IodaIO::fmode_
std::string fmode_
file mode
Definition: src/io/IodaIO.h:391
ioda::IodaIO::int_frame_data_
std::unique_ptr< FrameDataMap< int > > int_frame_data_
Containers for file frame.
Definition: src/io/IodaIO.h:418
ioda::IodaIO::frame_int_get_gname
std::string frame_int_get_gname(FrameIntIter &iframe)
Definition: src/io/IodaIO.h:300
ioda::IodaIO::frame_int_begin
FrameIntIter frame_int_begin()
Definition: src/io/IodaIO.h:292
ioda::IodaIO::frame_start
std::size_t frame_start(FrameIter &)
start value of current frame
Definition: IodaIO.cc:595
ioda::IodaIO::dim_info_
DimInfoMap dim_info_
dimension information map
Definition: src/io/IodaIO.h:409
ioda::NetcdfIO::NetcdfIO
NetcdfIO(const std::string &FileName, const std::string &FileMode, const std::size_t MaxFrameSize)
Definition: NetcdfIO.cc:49
ioda::IodaIO::var_name
std::string var_name(VarIter)
Definition: IodaIO.cc:147
ioda::IodaIO::frame_int_end
FrameIntIter frame_int_end()
Definition: src/io/IodaIO.h:293
ioda::IodaIO::var_id
std::size_t var_id(VarIter)
Definition: IodaIO.cc:360
ioda
Definition: IodaUtils.cc:13
ioda::IodaIO::float_frame_data_
std::unique_ptr< FrameDataMap< float > > float_frame_data_
Definition: src/io/IodaIO.h:419
ioda::IodaIO::var_end
VarIter var_end(GroupIter)
Definition: IodaIO.cc:135
ioda::IodaIO::dim_name_id
int dim_name_id(const std::string &)
Definition: IodaIO.cc:536
ioda::NetcdfIO::have_date_time_
bool have_date_time_
date time flag
Definition: NetcdfIO.h:144
ioda::IodaIO::num_excess_dims_
std::size_t num_excess_dims_
count of too many dimensions
Definition: src/io/IodaIO.h:403
ioda::IodaIO::frame_float_begin
FrameFloatIter frame_float_begin()
Definition: src/io/IodaIO.h:317
ioda::NetcdfIO::CheckNcCall
void CheckNcCall(int RetCode, std::string &ErrorMsg)
check results of netcdf call
Definition: NetcdfIO.cc:806
ioda::NetcdfIO::GrpVarInsert
void GrpVarInsert(const std::string &GroupName, const std::string &VarName, const std::string &VarType, const std::vector< std::size_t > &VarShape, const std::string &FileVarName, const std::string &FileType, const std::size_t MaxStringSize)
Add entry to the group, variable info container.
Definition: NetcdfIO.cc:722
ioda::IodaIO::nvars_
std::size_t nvars_
number of unique variables
Definition: src/io/IodaIO.h:397
ioda::IodaIO::frame_data_init
void frame_data_init()
initialize the frame data container
Definition: IodaIO.cc:644
ioda::IodaIO::frame_int_get_vname
std::string frame_int_get_vname(FrameIntIter &iframe)
Definition: src/io/IodaIO.h:303
ioda::IodaIO::frame_float_get_vname
std::string frame_float_get_vname(FrameFloatIter &iframe)
Definition: src/io/IodaIO.h:328
ioda::IodaIO::file_name
std::string file_name(VarIter)
Definition: IodaIO.cc:294
ioda::IodaIO::frame_info_init
void frame_info_init(std::size_t MaxVarSize)
initialize the frame info container
Definition: IodaIO.cc:613
ioda::IodaIO::file_type
std::string file_type(VarIter)
Definition: IodaIO.cc:327
ioda::IodaIO::dim_id_size
std::size_t dim_id_size(const int &)
Definition: IodaIO.cc:472
ioda::IodaIO::frame_string_get_data
std::vector< std::string > frame_string_get_data(FrameStringIter &iframe)
Definition: src/io/IodaIO.h:347
ioda::IodaIO::grp_var_info_
GroupVarInfoMap grp_var_info_
group-variable information map
Definition: src/io/IodaIO.h:406
ioda::IodaIO::frame_float_get_gname
std::string frame_float_get_gname(FrameFloatIter &iframe)
Definition: src/io/IodaIO.h:325
ioda::NetcdfIO::NcReadVar
void NcReadVar(const std::string &GroupName, const std::string &VarName, const std::vector< std::size_t > &Starts, const std::vector< std::size_t > &Counts, int &FillValue, std::vector< int > &VarData)
Read data from netcdf file to memory.
Definition: NetcdfIO.cc:239
ioda::IodaIO::frame_float_end
FrameFloatIter frame_float_end()
Definition: src/io/IodaIO.h:318
ioda::NetcdfIO::print
void print(std::ostream &os) const
print method for stream output
Definition: NetcdfIO.cc:788
ioda::IodaIO::frame_float_get_data
std::vector< float > frame_float_get_data(FrameFloatIter &iframe)
Definition: src/io/IodaIO.h:322
ioda::StringVectorToCharArray
void StringVectorToCharArray(const std::vector< std::string > &StringVector, const std::vector< std::size_t > &CharShape, char *CharData)
Definition: IodaUtils.cc:67
ioda::IodaIO::frame_size
std::size_t frame_size(FrameIter &)
size value of current frame
Definition: IodaIO.cc:604
ioda::NetcdfIO::ncid_
int ncid_
netcdf file id
Definition: NetcdfIO.h:128
ioda::IodaIO::FrameStringIter
FrameDataMap< std::string >::FrameStoreIter FrameStringIter
Definition: src/io/IodaIO.h:341
ioda::NetcdfIO::~NetcdfIO
~NetcdfIO()
Definition: NetcdfIO.cc:219
ioda::IodaIO::var_begin
VarIter var_begin(GroupIter)
Definition: IodaIO.cc:123
ioda::IodaIO::FrameFloatIter
FrameDataMap< float >::FrameStoreIter FrameFloatIter
Definition: src/io/IodaIO.h:316
ioda::IodaIO::group_begin
GroupIter group_begin()
Definition: IodaIO.cc:89
ioda::IodaIO::var_dtype
std::string var_dtype(VarIter)
Definition: IodaIO.cc:159
ioda::IodaIO::fname_
std::string fname_
file name
Definition: src/io/IodaIO.h:383
ioda::NetcdfIO::ReadConvertDateTime
void ReadConvertDateTime(const std::string &GroupName, const std::string &VarName, const std::vector< std::size_t > &Starts, const std::vector< std::size_t > &Counts, std::vector< std::string > &VarData)
read date and time information from the input netcdf file
Definition: NetcdfIO.cc:910
ioda::NetcdfIO::WriteFrame
void WriteFrame(IodaIO::FrameIter &iframe)
Write data from the frame containers into the file.
Definition: NetcdfIO.cc:673
ioda::NetcdfIO::GetStringDimBySize
int GetStringDimBySize(const std::size_t DimSize)
allocate a dimension for writing a character array
Definition: NetcdfIO.cc:869
ioda::IodaIO::var_shape
std::vector< std::size_t > var_shape(VarIter)
Definition: IodaIO.cc:226
ioda::IodaIO::frame_string_get_gname
std::string frame_string_get_gname(FrameStringIter &iframe)
Definition: src/io/IodaIO.h:350
ioda::NetcdfIO::ReadFrame
void ReadFrame(IodaIO::FrameIter &iframe)
Read data from the file into the frame containers.
Definition: NetcdfIO.cc:559
ioda::IodaIO::frame_string_begin
FrameStringIter frame_string_begin()
Definition: src/io/IodaIO.h:342
ioda::IodaIO::string_frame_data_
std::unique_ptr< FrameDataMap< std::string > > string_frame_data_
Definition: src/io/IodaIO.h:420
ioda::IodaIO
File access class for IODA.
Definition: src/io/IodaIO.h:116
ioda::IodaIO::ExtractGrpVarName
static void ExtractGrpVarName(const std::string &Name, std::string &GroupName, std::string &VarName)
Definition: IodaIO.cc:678
ioda::IodaIO::group_name
std::string group_name(GroupIter)
Definition: IodaIO.cc:111
ioda::NetcdfIO::GetMaxStringSize
std::size_t GetMaxStringSize(const std::vector< std::string > &Strings)
Get the max string size in a vector of strings.
Definition: NetcdfIO.cc:471
ioda::CharArrayToStringVector
std::vector< std::string > CharArrayToStringVector(const char *CharData, const std::vector< std::size_t > &CharShape)
Definition: IodaUtils.cc:33
ioda::IodaIO::nlocs_
std::size_t nlocs_
number of unique locations
Definition: src/io/IodaIO.h:394
ioda::NetcdfIO::FormNcVarName
std::string FormNcVarName(const std::string &GroupName, const std::string &VarName)
form the netcdf variable name
Definition: NetcdfIO.cc:844
ioda::IodaIO::file_shape
std::vector< std::size_t > file_shape(VarIter)
Definition: IodaIO.cc:260