UFO
ParameterTraitsVariable.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2020 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 
9 
10 #include <list>
11 #include <string>
12 #include <vector>
13 
14 #include "eckit/exception/Exceptions.h"
15 #include "eckit/utils/StringTools.h"
16 #include "oops/util/CompositePath.h"
17 #include "oops/util/LocalEnvironment.h"
18 #include "oops/util/parameters/ParameterTraits.h"
19 #include "oops/util/stringFunctions.h"
20 #include "ufo/filters/Variable.h"
21 
22 namespace oops {
23 
24 boost::optional<ufo::Variable> ParameterTraits<ufo::Variable>::get(
25  util::CompositePath &path, const eckit::Configuration &config, const std::string& name) {
26  if (config.has(name)) {
27  std::list<std::string> messages;
28 
29  {
30  // Within this block, set the ECKIT_EXCEPTION_IS_SILENT environment variable to 1
31  // to prevent eckit exceptions (which will be caught) from printing unnerving messages
32  // to the error log.
33  util::LocalEnvironment localEnv;
34  localEnv.set("ECKIT_EXCEPTION_IS_SILENT", "1");
35 
36  // Handle the following YAML structure:
37  //
38  // <name>:
39  // name: somevar@SomeGroup
40  // channels: ... # optional
41  // options: # optional
42  // ...
43  try {
44  eckit::LocalConfiguration varConf(config, name);
45  return ufo::Variable(varConf);
46  } catch (eckit::Exception &e) {
47  // The YAML doesn't have this structure.
48  messages.emplace_back(e.what());
49  }
50 
51  // Handle the following YAML structure:
52  //
53  // <name>: somevar@SomeGroup
54 
55  try {
56  std::string varAndGroup = config.getString(name);
57  return ufo::Variable(varAndGroup);
58  } catch (eckit::Exception &e) {
59  // The YAML doesn't have this structure.
60  messages.emplace_back(e.what());
61  }
62 
63  // ECKIT_EXCEPTION_IS_SILENT will be unset or restored to its previous value
64  // when localEnv goes of of scope at the end of this block.
65  }
66 
67  messages.push_front("The key '" + name +
68  "' is set to neither a string nor a map with the correct keys.");
69  throw eckit::Exception(eckit::StringTools::join("\n", messages.begin(), messages.end()),
70  Here());
71  } else {
72  return boost::none;
73  }
74 }
75 
76 void ParameterTraits<ufo::Variable>::set(eckit::LocalConfiguration &config,
77  const std::string &name,
78  const ufo::Variable &value) {
79  eckit::LocalConfiguration subConfig;
80  subConfig.set("name", value.variable() + "@" + value.group());
81  const std::vector<int> &channels = value.channels();
82  if (!channels.empty()) {
83  const std::string channelsAsString = util::stringfunctions::join(
84  ",", channels.begin(), channels.end(), [](int n) { return std::to_string(n); });
85  subConfig.set("channels", channelsAsString);
86  }
87  if (!value.options().keys().empty())
88  subConfig.set("options", value.options());
89  config.set(name, subConfig);
90 }
91 
92 ObjectJsonSchema ParameterTraits<ufo::Variable>::jsonSchema(const std::string &name) {
93  std::stringstream oneOf;
94  {
95  eckit::Channel ch;
96  ch.setStream(oneOf);
97  ch << "[\n";
98  {
99  eckit::AutoIndent indent(ch);
100  ObjectJsonSchema simpleSchema = ParameterTraits<std::string>::jsonSchema("");
101  ObjectJsonSchema completeSchema({{"name", {{"type", "\"string\""}}},
102  {"options", {{"type", "\"object\""}}},
103  {"channels", {{"type", "[\"string\", \"integer\"]"}}}});
104  ch << toString(simpleSchema.properties().at("")) << ",\n";
105  ch << completeSchema.toString() << '\n';
106  }
107  ch << "]";
108  }
109 
110  return ObjectJsonSchema({{name, {{"oneOf", oneOf.str()}}}});
111 }
112 
113 } // namespace oops
const std::string & variable() const
Definition: Variable.cc:99
const std::string & group() const
Definition: Variable.cc:116
const eckit::LocalConfiguration & options() const
Definition: Variable.h:47
const std::vector< int > & channels() const
Definition: Variable.cc:122
static boost::optional< ufo::Variable > get(util::CompositePath &path, const eckit::Configuration &config, const std::string &name)
static void set(eckit::LocalConfiguration &config, const std::string &name, const ufo::Variable &value)
static ObjectJsonSchema jsonSchema(const std::string &name)