IODA
Layout_ObsGroup_ODB.cpp
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2021 Met Office UK
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 /// \file Layout_ObsGroup_ODB.cpp
8 /// \brief Contains implementations for how ODB data are arranged in ioda internally.
9 
11 
13 
14 #include "ioda/Group.h"
15 #include "ioda/Layout.h"
16 #include "ioda/Misc/StringFuncs.h"
17 #include "ioda/defs.h"
18 
19 #include "boost/none_t.hpp"
20 #include "boost/optional.hpp"
21 #include "eckit/config/Configuration.h"
22 #include "eckit/config/LocalConfiguration.h"
23 #include "eckit/config/YAMLConfiguration.h"
24 #include "eckit/exception/Exceptions.h"
25 #include "eckit/filesystem/LocalPathName.h"
26 #include "eckit/filesystem/PathName.h"
27 #include "oops/util/parameters/Parameters.h"
28 
29 #include <exception>
30 #include <string>
31 #include <unordered_map>
32 #include <vector>
33 
34 namespace ioda {
35 namespace detail {
37 
39  : mappingParams_(new ODBLayoutParameters())
40 {
41 
42  parseMappingFile(fileMappingName);
43 }
44 
46  const std::string &method) {
47  if (method != "concat") {
48  throw eckit::MethodNotYetImplemented("Concatenation is the only supported merge method.");
49  }
51 }
52 
53 void DataLayoutPolicy_ObsGroup_ODB::parseMappingFile(const std::string &nameMapFile) {
54  eckit::PathName yamlPath = nameMapFile;
55  eckit::YAMLConfiguration conf(yamlPath);
56  eckit::LocalConfiguration ioda(conf, "ioda");
57  mappingParams_->validateAndDeserialize(ioda);
58  if (mappingParams_->variables.value() != boost::none)
60  if (mappingParams_->complementaryVariables.value() != boost::none)
62 }
63 
65 {
66  for (VariableParameters const& variable : *(mappingParams_->variables.value())) {
67  if (variable.unit.value())
68  Mapping[variable.source] = {variable.name, {true, *(variable.unit.value())}};
69  else
70  Mapping[variable.source] = {variable.name, {false, ""}};
71  //Mapping[variable.source] = {variable.name, variable.unit};
72  }
73 }
74 
76 {
77  for (ComplementaryVariablesParameters const& variable :
78  *(mappingParams_->complementaryVariables.value())) {
79  if (variable.outputVariableDataType.value() != "string") {
80  throw eckit::MethodNotYetImplemented("YAML mapping file: the output variable "
81  "data type for a derived variable is not "
82  "'string'");
83  }
84  MergeMethod mergeMethod = parseMergeMethod(variable.mergeMethod);
85  if (std::find(variable.inputNames.value().begin(), variable.inputNames.value().end(),
86  variable.outputName.value()) != variable.inputNames.value().end()) {
87  throw eckit::ReadError(std::string("YAML mapping file has a complementary variable name") +
88  std::string("matching a derived variable name."));
89  }
90  std::type_index outputTypeIndex = typeid(std::string);
91  //augustweinbren: outputTypeIndex will be defined using outputVariableDataType when other
92  //merge methods are available
93 
94  std::shared_ptr<ComplementaryVariableOutputMetadata> sharedOutputMetaData(
96  variable.outputName, outputTypeIndex, mergeMethod, 0});
97  size_t inputIndex = 0;
98  for (const std::string &input : variable.inputNames.value()) {
99  complementaryVariableDataMap[input] = std::make_pair(inputIndex, sharedOutputMetaData);
100  inputIndex++;
101  }
102  sharedOutputMetaData->inputVariableCount = inputIndex;
103  }
104 }
105 
107  // First, set an attribute to indicate that the data are managed
108  // by this data policy.
109  g.atts.add<std::string>("_ioda_layout", std::string("ObsGroup_ODB"));
110  g.atts.add<int32_t>("_ioda_layout_version", ObsGroup_ODB_Layout_Version);
111 
112  // Create the default containers - currently ignored as these are
113  // dynamically created.
114  /*
115  g.create("MetaData");
116  g.create("ObsBias");
117  g.create("ObsError");
118  g.create("ObsValue");
119  g.create("PreQC");
120  */
121 }
122 
123 std::string DataLayoutPolicy_ObsGroup_ODB::doMap(const std::string &str) const {
124  // If the string contains '@', then it needs to be broken into
125  // components and reversed. Additionally, if the string is a key in the mapping file,
126  // it is replaced with its value. All other strings are passed through untouched.
127  std::string mappedStr;
128  auto it = Mapping.find(str);
129  if (it != Mapping.end()) {
130  mappedStr = (it->second).iodaName;
131  } else {
132  mappedStr = str;
133  }
134 
135  mappedStr = convertV1PathToV2Path(mappedStr);
136  return mappedStr;
137 }
138 
139 bool DataLayoutPolicy_ObsGroup_ODB::isComplementary(const std::string &inputVariable) const
140 {
141  if (complementaryVariableDataMap.find(inputVariable) != complementaryVariableDataMap.end())
142  return true;
143  else
144  return false;
145 }
146 
147 bool DataLayoutPolicy_ObsGroup_ODB::isMapped(const std::string &input) const {
148  return (Mapping.find(input) != Mapping.end());
149 }
150 
151 size_t DataLayoutPolicy_ObsGroup_ODB::getComplementaryPosition(const std::string &input) const
152 {
153  if (!isComplementary(input))
154  throw eckit::ReadError(input + " was not found to be a complementary variable.");
155  return complementaryVariableDataMap.at(input).first;
156 }
157 
158 size_t DataLayoutPolicy_ObsGroup_ODB::getInputsNeeded(const std::string &input) const
159 {
160  if (!isComplementary(input))
161  throw eckit::ReadError(input + std::string(" was not found to be a complementary variable."));
162  return complementaryVariableDataMap.at(input).second->inputVariableCount;
163 }
164 
166  const std::string &input) const
167 {
168  if (!isComplementary(input))
169  throw eckit::ReadError(input + " was not found to be a complementary variable.");
170  return complementaryVariableDataMap.at(input).second->outputName;
171 }
172 
174  const std::string &input) const
175 {
176  if (!isComplementary(input))
177  throw eckit::ReadError(input + " was not found to be a complementary variable.");
178  return complementaryVariableDataMap.at(input).second->outputVariableDataType;
179 }
180 
182  const std::string &input) const
183 {
184  if (!isComplementary(input))
185  throw eckit::ReadError(input + " was not found to be a complementary variable.");
186  return complementaryVariableDataMap.at(input).second->mergeMethod;
187 }
188 
189 std::pair<bool, std::string> DataLayoutPolicy_ObsGroup_ODB::getUnit(
190  const std::string & input) const {
191  if (Mapping.find(input) == Mapping.end()) {
192  throw eckit::ReadError(input + " was not found to to be an ODB source variable.");
193  }
194  return (Mapping.at(input)).inputUnit;
195 }
196 
197 std::string DataLayoutPolicy_ObsGroup_ODB::name() const { return std::string{"ObsGroup ODB v1"}; }
198 
199 } // namespace detail
200 } // namespace ioda
Interfaces for ioda::Group and related classes.
Contains definitions for how data are arranged in ioda internally.
Contains definitions for how ODB data are arranged in ioda internally.
Defines all of the information which should be stored in the YAML mapping file.
DataLayoutPolicy::MergeMethod getMergeMethod(const std::string &) const override
std::string doMap(const std::string &) const override
Map a user-specified Variable path to the correct location.
std::unordered_map< std::string, variableStorageInformation > Mapping
Mapping with ODB equivalents as keys and IODA naming/unit pairs as values.
DataLayoutPolicy::MergeMethod parseMergeMethod(const std::string &)
size_t getInputsNeeded(const std::string &) const override
std::string getOutputNameFromComponent(const std::string &) const override
const int32_t ObsGroup_ODB_Layout_Version
Record versioning information for this layout in the ioda object. Provides forward compatability.
void initializeStructure(Group_Base &) const override
bool isComplementary(const std::string &) const override
Check if the named variable will be a part of a derived variable.
std::string name() const override
A descriptive name for the policy.
std::pair< bool, std::string > getUnit(const std::string &) const override
std::unordered_map< std::string, complementaryVariableMetaData > complementaryVariableDataMap
bool isMapped(const std::string &) const override
Check if the named variable is in the Variables section of the ODB mapping file.
size_t getComplementaryPosition(const std::string &) const override
std::shared_ptr< ODBLayoutParameters > mappingParams_
std::type_index getOutputVariableDataType(const std::string &) const override
@ Concat
Concatenate complementary variables entry-by-entry.
Hidden base class to prevent constructor confusion.
Definition: Group.h:42
Common preprocessor definitions used throughout IODA.
IODA_DL std::string convertV1PathToV2Path(const std::string &path)
Split path into substrings separated by @ characters, then concatenate them in reverse order,...
Definition: StringFuncs.cpp:85
Metadata for generating a variable in IODA from multiple component variables (same across components)...