IODA Bundle
Odb2NetCDF.cc
Go to the documentation of this file.
1 #include "Odb2NetCDF.h"
2 
3 #include <iostream>
4 #include <netcdfcpp.h>
5 #include <algorithm>
6 
7 #include <odb_api/Reader.h>
8 #include <odb_api/Select.h>
9 
10 #include "eckit/exception/Exceptions.h"
11 
12 /// @author Anne Fouilloux
13 
14 using namespace std;
15 using namespace eckit;
16 
17 /// Replaces all occurences of '@' with '_'
18 string patchName(const string& s)
19 {
20  string r (s);
21  // ODB-334
22  //replace(r.begin(), r.end(), '@', '_');
23  return r;
24 }
25 
26 Odb2NetCDF::Odb2NetCDF(const string & inputfile, const string & outputfile)
27 : inputfile_(inputfile), outputfile_(outputfile)
28 {}
29 
31 
32 Odb2NetCDF_1D::Odb2NetCDF_1D(const string & inputfile, const string & outputfile)
33 : Odb2NetCDF(inputfile,outputfile)
34 {
35  Log::info() << "The following files will be opened and read: " << endl;
36  Log::info() << "ODB filename = " << inputfile << endl;
37  Log::info() << "Output NetCDF filename = " << outputfile << endl;
38 }
39 
40 vector<NcVar*> Odb2NetCDF_1D::createVariables(NcFile& dataFile, const odc::MetaData& columns, NcDim* xDim)
41 {
42  vector<NcVar*> vars;
43  for (size_t i(0); i < columns.size(); ++i)
44  {
45  const odc::Column& column (*(columns[i]));
46  NcVar* v;
47  switch (column.type())
48  {
49  case odc::INTEGER:
50  case odc::BITFIELD:
51  v = dataFile.add_var(patchName(column.name()).c_str(), ncInt, xDim);
52  v->add_att(_FillValue, int (column.missingValue()));
53  break;
54  case odc::REAL:
55  v = dataFile.add_var(patchName(column.name()).c_str(), ncFloat, xDim);
56  v->add_att(_FillValue, float (column.missingValue()));
57  break;
58  case odc::DOUBLE:
59  v = dataFile.add_var(patchName(column.name()).c_str(), ncDouble, xDim);
60  v->add_att(_FillValue, double (column.missingValue()));
61  break;
62  case odc::STRING:
63  v = dataFile.add_var(patchName(column.name()).c_str(), ncChar, xDim);
64  //v->add_att(_FillValue, ""); // TODO: missing value for strings ????
65  break;
66  case odc::IGNORE:
67  default:
68  Log::error() << "Unknown column type: name=" << column.name() << ", type=" << column.type() << endl;
69  ASSERT("Unknown type" && false);
70  break;
71  }
72  vars.push_back(v);
73  }
74  return vars;
75 }
76 
78  // Create the file. The Replace parameter tells netCDF to overwrite
79  // this file, if it already exists.
80  NcFile dataFile(outputfile().c_str(), NcFile::Replace);
81 
82  // You should always check whether a netCDF file creation or open
83  // constructor succeeded.
84  if (! dataFile.is_valid())
85  throw UserError("Could not open file"); // TODO: find appropriate exception
86 
87  Log::info() << "Conversion to NetCDF 1D" << endl;
88 
89  ////////////////////////////// ODB from MARS //////////////////////////////
90  NcDim* xDim (dataFile.add_dim("hdrlen"));
91  dataFile.add_att("Conventions", "CF-1.6");
92 
93  odc::Reader odb(inputfile());
94  odc::Reader::iterator it (odb.begin());
95 
96  vector<NcVar*> vars (createVariables(dataFile, it->columns(), xDim));
97 
98  union { double n; char b[sizeof(double) + 1]; } buffer;
99  memset(&buffer, 0, sizeof(buffer));
100 
101  size_t nrows (0);
102  for(; it != odb.end(); ++it, ++nrows)
103  for (int i(0); i < it->columns().size(); ++i)
104  {
105  buffer.n = ((*it)[i]);
106  switch (it->columns()[i]->type())
107  {
108  case odc::STRING:
109  vars[i]->put_rec(buffer.b, nrows);
110  break;
111  default:
112  vars[i]->put_rec(&buffer.n, nrows);
113  break;
114  }
115  }
116  Log::info() << "Converted " << nrows << " row(s)." << endl;
117 }
118 
119 //----------------------------------------------------------------
120 Odb2NetCDF_2D::Odb2NetCDF_2D(const string & inputfile, const string & outputfile)
121  : Odb2NetCDF(inputfile,outputfile) {
122 
123  fileNameHdr_ = inputfile + "_hdr.odb";
124  fileNameBody_ = inputfile + "_body.odb";
125 
126  Log::info() << "The following files will be opened and read: " << endl;
127  Log::info() << "Header filename = " << fileNameHdr_ << endl;
128  Log::info() << "Body filename = " << fileNameBody_ << endl;
129  Log::info() << "Output filename = " << outputfile << endl;
130 }
131 
132 //----------------------------------------------------------------
134  // Create the file. The Replace parameter tells netCDF to overwrite
135  // this file, if it already exists.
136  NcFile dataFile(outputfile().c_str(), NcFile::Replace);
137 
138  // You should always check whether a netCDF file creation or open
139  // constructor succeeded.
140  if (! dataFile.is_valid())
141  throw UserError ("Couldn't open file!");
142 
143  Log::info() << "Conversion to NetCDF 2D" << endl;
144  // Check how many channel/bodylen
145  string sql = "select distinct vertco_reference_1 from \"" + fileNameBody_ + "\" order by vertco_reference_1;";
146  odc::Select odbs(sql);
147  int nmaxchannel = 0;
148  for (odc::Select::iterator its = odbs.begin(); its != odbs.end(); ++its, ++nmaxchannel);
149 
150  Log::info() << " There are = " << nmaxchannel << " channels" << endl;
151 
152  // When we create netCDF dimensions, we get back a pointer to an
153  // NcDim for each one.
154  NcDim* xDim = dataFile.add_dim("hdrlen");
155  NcDim* yDim = dataFile.add_dim("maxbodylen", nmaxchannel);
156 
157  NcVar *colChannel;
158 
159  int * channel = new int [nmaxchannel];
160  int i=0;
161 
162  odc::Select odbs2(sql);
163  for (odc::Select::iterator its = odbs2.begin(); its != odbs2.end(); ++its, ++i)
164  {
165  if (i==0)
166  colChannel = dataFile.add_var(its->columns()[0]->name().c_str(), ncInt, yDim);
167  channel[i] = ((*its)[0]);
168  }
169 
170  colChannel->put(channel, nmaxchannel);
171 
172  ////////////////////////////// HDR //////////////////////////////
173 
174  odc::Reader odb_hdr(fileNameHdr_);
175  odc::Reader::iterator it_hdr = odb_hdr.begin();
176  NcVar **colHdr;
177  colHdr = new NcVar * [it_hdr->columns().size()];
178 
179  for (int i=0;i<it_hdr->columns().size();++i) {
180  switch(it_hdr->columns()[i]->type())
181  {
182  case odc::INTEGER:
183  case odc::BITFIELD:
184  colHdr[i] = dataFile.add_var(it_hdr->columns()[i]->name().c_str(), ncInt, xDim);
185  colHdr[i]->add_att(_FillValue,(int)it_hdr->columns()[i]->missingValue());
186  break;
187  case odc::REAL:
188  colHdr[i] = dataFile.add_var(it_hdr->columns()[i]->name().c_str(), ncFloat, xDim);
189  colHdr[i]->add_att(_FillValue, (float)it_hdr->columns()[i]->missingValue());
190  break;
191  case odc::STRING:
192  // colHdr[i] = dataFile.add_var(it_hdr->columns()[i]->name().c_str(), ncInt, xDim);
193  // colHdr[i]->add_att();
194  break;
195  case odc::IGNORE:
196  default:
197  ASSERT("Unknown type" && false);
198  break;
199  }
200  }
201 
202  int nrows=0;
203  double nr;
204  for(; it_hdr != odb_hdr.end(); ++it_hdr)
205  {
206  ++nrows;
207  for (int i=0;i<it_hdr->columns().size();++i) {
208  nr = ((*it_hdr)[i]);
209  colHdr[i]->put(&nr, 1);
210  colHdr[i]->set_cur(nrows);
211  }
212  }
213 
214  ////////////////////////////// BODY //////////////////////////////
215 
216 
217  odc::Reader odb_body(fileNameBody_);
218  odc::Reader::iterator it_body = odb_body.begin();
219  NcVar **colBody;
220  colBody = new NcVar * [it_body->columns().size()];
221 
222  int index_channel=-1;
223  int index_seqno=-1;
224  for (int i=0;i<it_body->columns().size();++i) {
225  if (it_body->columns()[i]->name() == "vertco_reference_1" || it_body->columns()[i]->name() == "vertco_reference_1@body")
226  index_channel = i;
227  if (it_body->columns()[i]->name() == "seqno" || it_body->columns()[i]->name() == "seqno@hdr")
228  index_seqno = i;
229  }
230 
231  Log::info() << " index_vertco_reference_1 = " << index_channel << endl;
232  Log::info() << " index_seqno = " << index_seqno << endl;
233 
234  if (index_channel != -1 && index_seqno != -1) {
235  for (int i=0;i<it_body->columns().size();++i) {
236  if ((it_body->columns()[i]->name() != "seqno" && it_body->columns()[i]->name() != "vertco_reference_1") &&
237  (it_body->columns()[i]->name() != "seqno@hdr" && it_body->columns()[i]->name() != "vertco_reference_1@body")) {
238  switch(it_body->columns()[i]->type())
239  {
240  case odc::INTEGER:
241  case odc::BITFIELD:
242  colBody[i] = dataFile.add_var(it_body->columns()[i]->name().c_str(), ncInt, xDim, yDim);
243  colBody[i]->add_att(_FillValue,(int)it_body->columns()[i]->missingValue());
244  break;
245  case odc::REAL:
246  colBody[i] = dataFile.add_var(it_body->columns()[i]->name().c_str(), ncFloat, xDim, yDim);
247  colBody[i]->add_att(_FillValue,(float) it_body->columns()[i]->missingValue());
248  break;
249  case odc::STRING:
250  // colBody[i] = dataFile.add_var(it_body->columns()[i]->name().c_str(), ncInt, xDim, yDim);
251  break;
252  case odc::IGNORE:
253  default:
254  ASSERT("Unknown type" && false);
255  break;
256  }
257  }
258  }
259 
260  int nrows = 0;
261  int nchannel = 0;
262  double nd[it_body->columns().size()][nmaxchannel];
263  double lnd[nmaxchannel];
264  long icurrent_seqno=-1;
265  int icurrent_channel=-1;
266  for(; it_body != odb_body.end(); ++it_body)
267  {
268  if (((*it_body)[index_seqno]) != icurrent_seqno) {
269  if (nrows > 0) { // not the first time
270  for (int i=0;i<it_body->columns().size();++i) {
271  if ((it_body->columns()[i]->name() != "seqno" && it_body->columns()[i]->name() != "vertco_reference_1") &&
272  (it_body->columns()[i]->name() != "seqno@hdr" && it_body->columns()[i]->name() != "vertco_reference_1@body")) {
273  // copy to a local array (this specific ODB column) to write in netCDF
274  for (int j=0; j<nmaxchannel; ++j)
275  lnd[j] = nd[i][j];
276  colBody[i]->put_rec(&lnd[0], nrows-1); // nrows -1 because we start to write at line 0 and not 1
277  }
278  }
279  }
280  ++nrows;
281  icurrent_seqno = ((*it_body)[index_seqno]);
282  icurrent_channel = 0;
283  nchannel=0;
284  // initialize to missing value nd for all columns and all channel
285  for (int i=0;i<it_body->columns().size();++i) {
286  for (int j=0; j< nmaxchannel; ++j) {
287  nd[i][j] = it_body->columns()[i]->missingValue();
288  }
289  }
290  }
291  while (icurrent_channel < nmaxchannel && channel[icurrent_channel] < ((*it_body)[index_channel])) {
292  ++icurrent_channel;
293  ++nchannel;
294  }
295 
296  for (int i=0;i<it_body->columns().size();++i) {
297  if ((it_body->columns()[i]->name() != "seqno" && it_body->columns()[i]->name() != "vertco_reference_1") &&
298  (it_body->columns()[i]->name() != "seqno@hdr" && it_body->columns()[i]->name() != "vertco_reference_1@body")) {
299  nd[i][icurrent_channel] = ((*it_body)[i]);
300  }
301  }
302  ++nchannel;
303  ++icurrent_channel;
304  }
305  for (int i=0;i<it_body->columns().size();++i) {
306  if ((it_body->columns()[i]->name() != "seqno" && it_body->columns()[i]->name() != "vertco_reference_1") &&
307  (it_body->columns()[i]->name() != "seqno@hdr" && it_body->columns()[i]->name() != "vertco_reference_1@body")) {
308  for (int j=0; j<nmaxchannel; ++j)
309  lnd[j] = nd[i][j];
310  for (int j=0; j<nmaxchannel; ++j)
311  Log::info() << nrows << " lnd[" << j << "]=" << lnd[j] << " " ;
312  Log::info() << endl;
313  colBody[i]->put_rec(&lnd[0], nrows-1);
314  }
315  }
316 
317  }
318 }
string patchName(const string &s)
Replaces all occurences of '@' with '_'.
Definition: Odb2NetCDF.cc:18
std::vector< NcVar * > createVariables(NcFile &dataFile, const odc::MetaData &columns, NcDim *)
Definition: Odb2NetCDF.cc:40
Odb2NetCDF_1D(const std::string &inputfile, const std::string &outputfile)
Definition: Odb2NetCDF.cc:32
virtual void convert()
Definition: Odb2NetCDF.cc:77
std::string fileNameHdr_
Definition: Odb2NetCDF.h:39
std::string fileNameBody_
Definition: Odb2NetCDF.h:40
Odb2NetCDF_2D(const std::string &inputfile, const std::string &outputfile)
Definition: Odb2NetCDF.cc:120
virtual void convert()
Definition: Odb2NetCDF.cc:133
std::string & outputfile()
Definition: Odb2NetCDF.h:18
Odb2NetCDF(const std::string &inputfile, const std::string &outputfile)
Definition: Odb2NetCDF.cc:26
std::string & inputfile()
Definition: Odb2NetCDF.h:17
virtual ~Odb2NetCDF()
Definition: Odb2NetCDF.cc:30
const iterator end() const
Definition: Reader.cc:81
iterator begin()
Definition: Reader.cc:74
const core::MetaData & columns() const
Definition: IteratorProxy.h:94
const iterator end()
Definition: Select.cc:77
iterator begin()
Definition: Select.cc:81
@ BITFIELD
Definition: ColumnType.h:27
Definition: encode.cc:30