IODA Bundle
ODA2RequestTool.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 1996-2012 ECMWF.
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  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
11 #include <fstream>
12 
13 #include "eckit/config/Resource.h"
14 #include "eckit/filesystem/PathName.h"
15 #include "eckit/log/Log.h"
16 #include "eckit/utils/StringTools.h"
17 #include "eckit/utils/Tokenizer.h"
18 #include "odc/FastODA2Request.h"
19 #include "odc/GribCodes.h"
20 #include "odc/Select.h"
22 
23 using namespace std;
24 using namespace eckit;
25 
26 namespace odc {
27 namespace tool {
28 
29 char * static_argv[] = { const_cast<char *>("oda2request") };
30 
31 ODA2RequestTool::ODA2RequestTool(int argc, char **argv)
32 : Tool(argc, argv)
33 {
35  readConfig();
36 }
37 
39 : Tool(1, static_argv)
40 {
42  readConfig();
43 }
44 
46 
47 void ODA2RequestTool::help(std::ostream &o) { o << "Creates MARS ARCHIVE request for a given file"; }
48 
49 void ODA2RequestTool::usage(const std::string& name, std::ostream &o)
50 {
51  o << name << " [-c configFile] [-q] <input-file.odb> [<output-file>]";
52 }
53 
55 {
56  eckit::PathName inputFile;
57  string outputFile;
58 
59  switch (parameters().size())
60  {
61  case 3:
62  outputFile = parameters(2);
63  case 2:
64  inputFile = parameters(1);
65  break;
66  default:
67  Log::error() << "Usage: ";
69  Log::error() << std::endl;
70  return;// 1;
71  break;
72  }
73 
74  readConfig();
75 
76  string request = generateMarsRequest(inputFile, optionIsSet("-q"));
77 
78  if (outputFile.size() == 0)
79  std::cout << request << std::endl;
80  else
81  {
82  ofstream out(outputFile.c_str());
83  out << request << std::endl;
84  out.close();
85  }
86 
87  return;
88 }
89 
91 {
92  return optionArgument("-c", std::string("~odc/codes/ODA2RequestTool.cfg"));
93 }
94 
96 
97 void ODA2RequestTool::readConfig(const PathName& fileName)
98 {
99  Log::debug() << "ODA2RequestTool::readConfig: reading file '" << fileName << "'" << std::endl;
100  columnName2requestKey_.clear();
101 
102  string s = readFile(fileName);
103 
104  Log::debug() << "ODA2RequestTool::readConfig: parsing '" << s << "'" << std::endl;
105 
106  parseConfig(s);
107 }
108 
109 void ODA2RequestTool::parseConfig(const std::string& s)
110 {
111  Log::debug() << "ODA2RequestTool::parseConfig: '" << s << "'" << std::endl;
112 
113  vector<std::string> lines;
114  Tokenizer("\n")(s, lines);
115 
116  Tokenizer tokenizer(": \t");
117  for (size_t i = 0; i < lines.size(); ++i)
118  {
119  vector<std::string> words;
120  tokenizer(lines[i], words);
121 
122  if (words.size() == 0)
123  continue;
124 
125  ASSERT("Each line of config file should be like: 'MARS_KEYWORD : oda_column_name'" && words.size() == 2);
126  columnName2requestKey_[words[1]] = words[0];
127  }
128 }
129 
130 inline string int_as_double2string(double v)
131 {
132  stringstream s;
133  s.precision(0);
134  s << fixed << v;
135  return s.str();
136 }
137 
138 string ODA2RequestTool::gatherStatsFast(const PathName& inputFile)
139 {
140  FastODA2Request<ODA2RequestClientTraits> o;
141  o.parseConfig(readFile(config()));
142  o.scanFile(inputFile);
143  return o.genRequest();
144 }
145 
146 void ODA2RequestTool::gatherStats(const PathName& inputFile)
147 {
148  size_t n = columnName2requestKey_.size();
149  values_ = vector<Values>(n);
150 
151  string columnList;
152  for (std::map<string, string>::iterator it = columnName2requestKey_.begin();
153  it != columnName2requestKey_.end();
154  ++it)
155  {
156  if (it != columnName2requestKey_.begin())
157  columnList += ", ";
158  columnList += it->first;
159  }
160 
161  const string select = std::string("select ") + columnList + " from \"" + inputFile + "\";";
162  Log::info() << "Executing '" << select << "'" << std::endl;
163 
164  Translator<double, string> double2string;
165  odc::Select oda(select, inputFile);
166  odc::Select::iterator end = oda.end();
167  for (odc::Select::iterator row = oda.begin(); row != end; ++row)
168  for (size_t i = 0; i < n; ++i)
169  {
170  odc::api::ColumnType type = row->columns()[i]->type();
171  Value v = type == odc::api::STRING ? (*row).string(i)
173  : double2string((*row)[i]);
174  values_[i].insert(v);
175  }
176 }
177 
178 string ODA2RequestTool::generateMarsRequest(const PathName& inputFile, bool fast)
179 {
180  stringstream request;
181 
182  if (fast)
183  request << gatherStatsFast(inputFile);
184  else
185  {
186  gatherStats(inputFile);
187 
188  size_t i = 0;
189  std::map<string, string>::iterator end = columnName2requestKey_.end();
190  for (std::map<string, string>::iterator it = columnName2requestKey_.begin(); it != end; ++it)
191  {
192  if (request.str().size()) request << ",\n";
193 
194  const std::string& key = it->second;
195  const string k = StringTools::upper(key);
196 
197  string valuesList;
198  Values& vs = values_[i++];
199  for (Values::iterator vi = vs.begin(); vi != vs.end(); ++vi)
200  {
201  string v = *vi;
202  Log::debug() << "ODA2RequestTool::genRequest: v = '" << v << "', key = " << key << std::endl;
203  if (k == "TIME")
205  else
206  if (k == "CLASS" || k == "TYPE" || k == "STREAM")
207  {
208  Log::debug() << "ODA2RequestTool::genRequest: checking if '" << v << "' is numeric" << std::endl;
209  if (StringTool::check(v, isdigit))
210  {
211  v = StringTools::trim(v);
212  Log::debug() << "ODA2RequestTool::genRequest: replacing " << v << " with ";
213  v = GribCodes::alphanumeric(StringTools::lower(key), v);
214  Log::debug() << v << std::endl;
215  }
216  v = StringTools::upper(v);
217  }
218 
219  if (vi != vs.begin())
220  valuesList += "/";
221 
222  valuesList += v;
223  }
224  request << key << " = " << valuesList;
225  }
226  }
227 
228  stringstream str;
229  str << "ODB," << std::endl;
230  str << request.str();
231  return str.str();
232 }
233 
234 } // namespace tool
235 } // namespace odc
236 
void oda
static std::string readFile(const eckit::PathName fileName, bool logging=false)
Definition: StringTool.cc:40
static bool check(const std::string &, ctypeFun)
Definition: StringTool.cc:82
static std::string patchTimeForMars(const std::string &v)
Definition: StringTool.cc:182
static std::string int_as_double2string(double)
Definition: StringTool.cc:125
bool optionIsSet(const std::string &)
T optionArgument(const std::string &, T defaultValue)
void registerOptionWithArgument(const std::string &)
const std::vector< std::string > parameters()
void gatherStats(const eckit::PathName &inputFile)
std::string gatherStatsFast(const eckit::PathName &inputFile)
void parseConfig(const std::string &)
std::vector< Values > values_
static void usage(const std::string &name, std::ostream &o)
std::set< Value > Values
static void help(std::ostream &o)
std::map< std::string, std::string > columnName2requestKey_
std::string generateMarsRequest(const eckit::PathName &inputFile, bool fast=false)
std::string name()
Definition: Tool.h:34
std::string trim(const std::string &str)
char * static_argv[]
string int_as_double2string(double v)
Definition: ColumnInfo.h:23
Definition: encode.cc:30