OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
hawkeyeUtil.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <limits.h>
7 
8 #include <iostream>
9 #include <fstream>
10 #include <sstream>
11 #include <string>
12 #include <iomanip>
13 
14 #include "hawkeyeUtil.h"
15 
16 
17 // Modification history:
18 // Programmer Organization Date Ver Description of change
19 // ---------- ------------ ---- --- ---------------------
20 // Joel Gales FutureTech 05/21/18 0.10 Original development
21 // Joel Gales FutureTech 09/20/18 0.11 Exit if EOF when searching
22 // for 2052/2053 packet
23 // Joel Gales SAIC 11/01/18 Define ifct as uint8_t
24 // and compute uint8_t byte_diff
25 // = frame[2]-ifct to fix prob
26 // with dropped frames
27 // Joel Gales SAIC 11/16/18 Fixed corrupted code in
28 // get_packet_from_frame() that
29 // broke l0gen_hawkeye
30 // Liang Hong SAIC 07/13/21 Update in handling EOI packet
31 // crossing frames
32 // Liang Hong SAIC 01/12/22 0.20 added scale and offset attributes
33 
34 using namespace std;
35 
36 /*----------------------------------------------------------------- */
37 /* Create an Generic NETCDF4 file */
38 /* ---------------------------------------------------------------- */
39 int createFile( const char* filename, const char* cdlfile,
40  size_t sdim, int *ncid, int *gid) {
41 
42  int status;
43 
44  status = nc_create( filename, NC_NETCDF4, ncid);
45  check_err(status,__LINE__,__FILE__);
46 
47  ifstream hawkeye_data_structure;
48  string line;
49  string dataStructureFile;
50 
51  dataStructureFile.assign( cdlfile);
52  expandEnvVar( &dataStructureFile);
53 
54  hawkeye_data_structure.open( dataStructureFile.c_str(), ifstream::in);
55  if ( hawkeye_data_structure.fail() == true) {
56  cout << "\"" << dataStructureFile.c_str() << "\" not found" << endl;
57  exit(1);
58  }
59 
60  // Find "dimensions" section of CDL file
61  while(1) {
62  getline( hawkeye_data_structure, line);
63  size_t pos = line.find("dimensions:");
64  if ( pos == 0) break;
65  }
66 
67  // Define dimensions from "dimensions" section of CDL file
68  int ndims = 0;
69  int dimid[1000];
70  while(1) {
71  getline( hawkeye_data_structure, line);
72  size_t pos = line.find(" = ");
73  if ( pos == string::npos) break;
74 
75  uint32_t dimSize;
76  istringstream iss(line.substr(pos+2, string::npos));
77  iss >> dimSize;
78 
79  iss.clear();
80  iss.str( line);
81  iss >> skipws >> line;
82 
83  cout << "Dimension Name: " << line.c_str() << " Dimension Size: "
84  << dimSize << endl;
85 
86  if (line.compare("number_of_scans") == 0) {
87  dimSize = sdim;
88  }
89 
90  status = nc_def_dim( *ncid, line.c_str(), dimSize, &dimid[ndims++]);
91  check_err(status,__LINE__,__FILE__);
92 
93  } // while loop
94 
95  // Read global attributes (string attributes only)
96  while(1) {
97  getline( hawkeye_data_structure, line);
98  size_t pos = line.find("// global attributes");
99  if ( pos == 0) break;
100  }
101 
102  while(1) {
103  getline( hawkeye_data_structure, line);
104  size_t pos = line.find(" = ");
105  if ( pos == string::npos) break;
106 
107  //size_t slen = line.length();
108 
109  string attValue;
110 
111  // Remove leading and trailing quotes
112  attValue.assign(line.substr(pos+4));
113  size_t posQuote = attValue.find("\"");
114  attValue.assign(attValue.substr(0, posQuote));
115 
116  istringstream iss(line.substr(pos+2));
117  iss.clear();
118  iss.str( line);
119  iss >> skipws >> line;
120 
121  // Skip commented out attributes
122  if (line.compare("//") == 0) continue;
123 
124  string attName;
125  attName.assign(line.substr(1).c_str());
126 
127  // Skip non-string attributes
128  if (attName.compare("orbit_number") == 0) continue;
129  if (attName.compare("history") == 0) continue;
130  if (attName.compare("format_version") == 0) continue;
131  if (attName.compare("instrument_number") == 0) continue;
132  if (attName.compare("pixel_offset") == 0) continue;
133  if (attName.compare("number_of_filled_scans") == 0) continue;
134 
135  // cout << attName.c_str() << " " << attValue.c_str() << endl;
136 
137  status = nc_put_att_text( *ncid, NC_GLOBAL, attName.c_str(),
138  strlen(attValue.c_str()), attValue.c_str());
139  check_err(status,__LINE__,__FILE__);
140 
141  } // while(1)
142 
143 
144  int ngrps = 0;
145  // Loop through groups
146  while(1) {
147  getline( hawkeye_data_structure, line);
148 
149  // Check if end of CDL file
150  // If so then close CDL file and return
151  if (line.substr(0,1).compare("}") == 0) {
152  hawkeye_data_structure.close();
153  return 0;
154  }
155 
156  // Check for beginning of new group
157  size_t pos = line.find("group:");
158 
159  // If found then create new group and variables
160  if ( pos == 0) {
161 
162  // Parse group name
163  istringstream iss(line.substr(6, string::npos));
164  iss >> skipws >> line;
165 
166  // Create NCDF4 group
167  status = nc_def_grp( *ncid, line.c_str(), &gid[ngrps]);
168  check_err(status,__LINE__,__FILE__);
169 
170  ngrps++;
171 
172  int numDims=0;
173  int varDims[NC_MAX_DIMS];
174  size_t dimSize[NC_MAX_DIMS];
175  char dimName[NC_MAX_NAME+1];
176  string sname;
177  string lname;
178  string standard_name;
179  string units;
180  string flag_values;
181  string flag_meanings;
182  double valid_min=0.0;
183  double valid_max=0.0;
184  double fill_value=0.0;
185  float scale_factor=1.0;
186  float add_offset=0.0;
187 
188  int ntype=0;
189 
190  // Loop through datasets in group
191  getline( hawkeye_data_structure, line); // skip "variables:"
192  while(1) {
193  getline( hawkeye_data_structure, line);
194 
195  if (line.length() == 0) continue;
196  if (line.substr(0,1).compare("\r") == 0) continue;
197  if (line.substr(0,1).compare("\n") == 0) continue;
198 
199  size_t pos = line.find(":");
200 
201  // No ":" found, new dataset or empty line or end-of-group
202  if ( pos == string::npos) {
203 
204  if ( numDims > 0) {
205  // Create previous dataset
206  createNCDF( gid[ngrps-1],
207  sname.c_str(), lname.c_str(),
208  standard_name.c_str(), units.c_str(),
209  (void *) &fill_value,
210  flag_values.c_str(), flag_meanings.c_str(),
211  valid_min, valid_max, scale_factor, add_offset, ntype, numDims, varDims);
212 
213  flag_values.assign("");
214  flag_meanings.assign("");
215  units.assign("");
216  }
217 
218  valid_min=0.0;
219  valid_max=0.0;
220  fill_value=0.0;
221  scale_factor=1.0;
222  add_offset=0.0;
223 
224  if (line.substr(0,10).compare("} // group") == 0) break;
225 
226  // Parse variable type
227  string varType;
228  istringstream iss(line);
229  iss >> skipws >> varType;
230 
231  // Get corresponding NC variable type
232  if ( varType.compare("char") == 0) ntype = NC_CHAR;
233  else if ( varType.compare("byte") == 0) ntype = NC_BYTE;
234  else if ( varType.compare("short") == 0) ntype = NC_SHORT;
235  else if ( varType.compare("int") == 0) ntype = NC_INT;
236  else if ( varType.compare("long") == 0) ntype = NC_INT;
237  else if ( varType.compare("float") == 0) ntype = NC_FLOAT;
238  else if ( varType.compare("real") == 0) ntype = NC_FLOAT;
239  else if ( varType.compare("double") == 0) ntype = NC_DOUBLE;
240  else if ( varType.compare("ubyte") == 0) ntype = NC_UBYTE;
241  else if ( varType.compare("ushort") == 0) ntype = NC_USHORT;
242  else if ( varType.compare("uint") == 0) ntype = NC_UINT;
243  else if ( varType.compare("int64") == 0) ntype = NC_INT64;
244  else if ( varType.compare("uint64") == 0) ntype = NC_UINT64;
245 
246  // Parse short name (sname)
247  pos = line.find("(");
248  size_t posSname = line.substr(0, pos).rfind(" ");
249  sname.assign(line.substr(posSname+1, pos-posSname-1));
250  cout << "sname: " << sname.c_str() << endl;
251 
252  // Parse variable dimension info
253  parseDims( *ncid, ndims, line.substr(pos+1, string::npos),
254  &numDims, dimid, varDims);
255  for (int i=0; i<numDims; i++) {
256  nc_inq_dim( *ncid, varDims[i], dimName, &dimSize[i]);
257  cout << line.c_str() << " " << i << " " << dimName
258  << " " << dimSize[i] << endl;
259  }
260 
261  } else {
262  // Parse variable attributes
263  size_t posEql = line.find("=");
264  size_t pos1qte = line.find("\"");
265  size_t pos2qte = line.substr(pos1qte+1, string::npos).find("\"");
266  // cout << line.substr(pos+1, posEql-pos-2).c_str() << endl;
267 
268  string attrName = line.substr(pos+1, posEql-pos-2);
269 
270  // Get long_name
271  if ( attrName.compare("long_name") == 0) {
272  lname.assign(line.substr(pos1qte+1, pos2qte));
273  // cout << "lname: " << lname.c_str() << endl;
274  }
275 
276  // Get units
277  else if ( attrName.compare("units") == 0) {
278  units.assign(line.substr(pos1qte+1, pos2qte));
279  // cout << "units: " << units.c_str() << endl;
280  }
281 
282  // Get _FillValue
283  else if ( attrName.compare("_FillValue") == 0) {
284  iss.clear();
285  iss.str( line.substr(posEql+1, string::npos));
286  iss >> fill_value;
287  // cout << "_FillValue: " << fill_value << endl;
288  }
289 
290  // Get flag_values
291  else if ( attrName.compare("flag_values") == 0) {
292  flag_values.assign(line.substr(pos1qte+1, pos2qte));
293  }
294 
295  // Get flag_meanings
296  else if ( attrName.compare("flag_meanings") == 0) {
297  flag_meanings.assign(line.substr(pos1qte+1, pos2qte));
298  }
299 
300  // Get valid_min
301  else if ( attrName.compare("valid_min") == 0) {
302  iss.clear();
303  iss.str( line.substr(posEql+1, string::npos));
304  iss >> valid_min;
305  // cout << "valid_min: " << valid_min << endl;
306  }
307 
308  // Get valid_max
309  else if ( attrName.compare("valid_max") == 0) {
310  iss.clear();
311  iss.str( line.substr(posEql+1, string::npos));
312  iss >> valid_max;
313  // cout << "valid_max: " << valid_max << endl;
314  }
315 
316  // Get scale_factor
317  else if ( attrName.compare("scale_factor") == 0) {
318  iss.clear();
319  iss.str( line.substr(posEql+1, string::npos));
320  iss >> scale_factor;
321  }
322 
323  // Get add_offset
324  else if ( attrName.compare("add_offset") == 0) {
325  iss.clear();
326  iss.str( line.substr(posEql+1, string::npos));
327  iss >> add_offset;
328  }
329 
330  } // if ( pos == string::npos)
331  } // datasets in group loop
332  } // New Group loop
333  } // Main Group loop
334 
335  return 0;
336 }
337 
338 
339 int parseDims( int ncid, int ndims, string dimString,
340  int *numDims, int *dimid, int *varDims) {
341 
342  size_t dimSize, curPos=0;
343  char dimName[NC_MAX_NAME+1];
344 
345  *numDims = 0;
346 
347  while(1) {
348  size_t pos = dimString.find(",", curPos);
349  if ( pos == string::npos)
350  pos = dimString.find(")");
351 
352  string varDimName;
353  istringstream iss(dimString.substr(curPos, pos-curPos));
354  iss >> skipws >> varDimName;
355 
356  for (int i=0; i<ndims; i++) {
357  int status = nc_inq_dim( ncid, dimid[i], dimName, &dimSize);
358  check_err(status,__LINE__,__FILE__);
359  if ( varDimName.compare(dimName) == 0) {
360  varDims[(*numDims)++] = dimid[i];
361  break;
362  }
363  }
364  if ( dimString.substr(pos, 1).compare(")") == 0) break;
365 
366  curPos = pos + 1;
367  }
368 
369  return 0;
370 }
371 
372 
373 
374 int createNCDF( int ncid, const char *sname, const char *lname,
375  const char *standard_name, const char *units,
376  void *fill_value,
377  const char *flag_values, const char *flag_meanings,
378  double low, double high,
379  float scale_factor, float add_offset,
380  int nt, int rank, int *dimids) {
381 
382  int32_t varid;
383  int status;
384  size_t dimlength;
385  size_t chunksize[3];
386 
387  /* Create the NCDF dataset */
388  status = nc_def_var(ncid, sname, nt, rank, dimids, &varid);
389  if( status != NC_NOERR) {
390  printf("-E- %s %d: %s for %s\n",
391  __FILE__, __LINE__, nc_strerror(status), sname);
392  exit(1);
393  }
394 
395  // Set fill value
396  double fill_value_dbl;
397  memcpy( &fill_value_dbl, fill_value, sizeof(double));
398 
399  int8_t i8;
400  uint8_t ui8;
401  int16_t i16;
402  uint16_t ui16;
403  int32_t i32;
404  int32_t ui32;
405  float f32;
406 
407  // if ( (low < high) && (low != fill_value_dbl)) {
408  if ( low != fill_value_dbl) {
409  if ( nt == NC_BYTE) {
410  i8 = fill_value_dbl;
411  status = nc_def_var_fill( ncid, varid, 0, (void *) &i8);
412  } else if ( nt == NC_UBYTE) {
413  ui8 = fill_value_dbl;
414  status = nc_def_var_fill( ncid, varid, 0, (void *) &ui8);
415  } else if ( nt == NC_SHORT) {
416  i16 = fill_value_dbl;
417  status = nc_def_var_fill( ncid, varid, 0, (void *) &i16);
418  } else if ( nt == NC_USHORT) {
419  ui16 = fill_value_dbl;
420  status = nc_def_var_fill( ncid, varid, 0, (void *) &ui16);
421  } else if ( nt == NC_INT) {
422  i32 = fill_value_dbl;
423  status = nc_def_var_fill( ncid, varid, 0, (void *) &i32);
424  } else if ( nt == NC_UINT) {
425  ui32 = fill_value_dbl;
426  status = nc_def_var_fill( ncid, varid, 0, (void *) &ui32);
427  } else if ( nt == NC_FLOAT) {
428  f32 = fill_value_dbl;
429  status = nc_def_var_fill( ncid, varid, 0, (void *) &f32);
430  } else {
431  status = nc_def_var_fill( ncid, varid, 0, (void *) &fill_value_dbl);
432  }
433  check_err(status,__LINE__,__FILE__);
434  }
435 
436  /* vary chunck size based on dimensions */
437  int do_deflate = 0;
438  if ( rank == 3 && (strncmp(sname, "EV_", 3) == 0)) {
439  status = nc_inq_dimlen(ncid, dimids[2], &dimlength);
440  chunksize[0] = 1;
441  chunksize[1] = 16;
442  chunksize[2] = dimlength/10;
443  do_deflate = 1;
444  }
445 
446  /* Set compression */
447  if ( do_deflate) {
448  /* First set chunking */
449  status = nc_def_var_chunking(ncid, varid, NC_CHUNKED, chunksize);
450  if (status != NC_NOERR) {
451  printf("-E- %s %d: %s for %s\n", __FILE__, __LINE__,
452  nc_strerror(status), sname);
453  exit(1);
454  }
455 
456  /* Now we can set compression */
457  // status = nc_def_var_deflate(ncid, varid, NC_NOSHUFFLE, 1, 5);
458  status = nc_def_var_deflate(ncid, varid, NC_SHUFFLE, 1, 5);
459  if (status != NC_NOERR) {
460  printf("-E- %s %d: %s for %s\n", __FILE__, __LINE__,
461  nc_strerror(status), sname);
462  exit(1);
463  }
464  }
465 
466 
467  /* Add a "long_name" attribute */
468  status = nc_put_att_text(ncid, varid, "long_name", strlen(lname), lname);
469  if( status != NC_NOERR) {
470  printf("-E- %s %d: %s for %s\n",
471  __FILE__, __LINE__, nc_strerror(status), "long_name");
472  exit(1);
473  }
474 
475  /* Add a "flag_values" attribute if specified*/
476  // Parse string and save as signed bytes
477  if ( strcmp( flag_values, "") != 0) {
478 
479  size_t curPos=0;
480 
481  string fv;
482  fv.assign( flag_values);
483  size_t pos = fv.find("=", curPos);
484  fv = fv.substr(pos+1);
485 
486  size_t semicln = fv.find(";");
487  pos = 0;
488 
489  int8_t vec[1024];
490  int n = 0;
491  while(pos != semicln) {
492  pos = fv.find(",", curPos);
493  if ( pos == string::npos)
494  pos = semicln;
495 
496  string flag_value;
497  istringstream iss(fv.substr(curPos, pos-curPos));
498  iss >> skipws >> flag_value;
499  vec[n++] = atoi( flag_value.c_str());
500  curPos = pos + 1;
501  }
502 
503  status = nc_put_att_schar(ncid, varid, "flag_values", NC_BYTE, n, vec);
504  if( status != NC_NOERR) {
505  printf("-E- %s %d: %s for %s\n",
506  __FILE__, __LINE__, nc_strerror(status), "flag_values");
507  exit(1);
508  }
509  }
510 
511  /* Add a "flag_meanings" attribute if specified*/
512  if ( strcmp( flag_meanings, "") != 0) {
513  status = nc_put_att_text(ncid, varid, "flag_meanings",
514  strlen(flag_meanings), flag_meanings);
515  if( status != NC_NOERR) {
516  printf("-E- %s %d: %s for %s\n",
517  __FILE__, __LINE__, nc_strerror(status), "flag_meanings");
518  exit(1);
519  }
520  }
521 
522  /* Add scale_factor and add_offset*/
523  if ((scale_factor!=1) || (add_offset!=0) ) {
524  status = nc_put_att_float(ncid, varid,"scale_factor",NC_FLOAT,1,&scale_factor);
525  if( status != NC_NOERR) {
526  printf("-E- %s %d: %s for %s\n",
527  __FILE__, __LINE__, nc_strerror(status), "scale_factor");
528  exit(1);
529  }
530  status = nc_put_att_float(ncid, varid,"add_offset",NC_FLOAT,1,&add_offset);
531  if( status != NC_NOERR) {
532  printf("-E- %s %d: %s for %s\n",
533  __FILE__, __LINE__, nc_strerror(status), "add_offset");
534  exit(1);
535  }
536  }
537 
538  /* Add "valid_min/max" attributes if specified */
539  if (low < high) {
540  switch(nt) { /* Use the appropriate number type */
541  case NC_BYTE:
542  {
543  uint8_t vr[2];
544  vr[0] = (uint8_t)low;
545  vr[1] = (uint8_t)high;
546  status = nc_put_att_uchar(ncid, varid,"valid_min",NC_BYTE,1,&vr[0]);
547  if( status != NC_NOERR) {
548  printf("-E- %s %d: %s for %s\n",
549  __FILE__, __LINE__, nc_strerror(status), "valid_min");
550  exit(1);
551  }
552  status = nc_put_att_uchar(ncid, varid,"valid_max",NC_BYTE,1,&vr[1]);
553  if( status != NC_NOERR) {
554  printf("-E- %s %d: %s for %s\n",
555  __FILE__, __LINE__, nc_strerror(status), "valid_max");
556  exit(1);
557  }
558  }
559  break;
560  case NC_UBYTE:
561  {
562  uint8_t vr[2];
563  vr[0] = (uint8_t)low;
564  vr[1] = (uint8_t)high;
565  status = nc_put_att_uchar(ncid, varid,"valid_min",NC_UBYTE,1,&vr[0]);
566  if( status != NC_NOERR) {
567  printf("-E- %s %d: %s for %s\n",
568  __FILE__, __LINE__, nc_strerror(status), "valid_min");
569  exit(1);
570  }
571  status = nc_put_att_uchar(ncid, varid,"valid_max",NC_UBYTE,1,&vr[1]);
572  if( status != NC_NOERR) {
573  printf("-E- %s %d: %s for %s\n",
574  __FILE__, __LINE__, nc_strerror(status), "valid_max");
575  exit(1);
576  }
577  }
578  break;
579  case NC_SHORT:
580  {
581  int16_t vr[2];
582  vr[0] = (int16_t)low;
583  vr[1] = (int16_t)high;
584  status = nc_put_att_short(ncid, varid,"valid_min",NC_SHORT,1,&vr[0]);
585  if( status != NC_NOERR) {
586  printf("-E- %s %d: %s for %s\n",
587  __FILE__, __LINE__, nc_strerror(status), "valid_min");
588  exit(1);
589  }
590  status = nc_put_att_short(ncid, varid,"valid_max",NC_SHORT,1,&vr[1]);
591  if( status != NC_NOERR) {
592  printf("-E- %s %d: %s for %s\n",
593  __FILE__, __LINE__, nc_strerror(status), "valid_max");
594  exit(1);
595  }
596  }
597  break;
598  case NC_USHORT:
599  {
600  uint16_t vr[2];
601  vr[0] = (uint16_t)low;
602  vr[1] = (uint16_t)high;
603  status = nc_put_att_ushort(ncid, varid,"valid_min",NC_USHORT,1,&vr[0]);
604  if( status != NC_NOERR) {
605  printf("-E- %s %d: %s for %s\n",
606  __FILE__, __LINE__, nc_strerror(status), "valid_min");
607  exit(1);
608  }
609  status = nc_put_att_ushort(ncid, varid,"valid_max",NC_USHORT,1,&vr[1]);
610  if( status != NC_NOERR) {
611  printf("-E- %s %d: %s for %s\n",
612  __FILE__, __LINE__, nc_strerror(status), "valid_max");
613  exit(1);
614  }
615  }
616  break;
617  case NC_INT:
618  {
619  int32_t vr[2];
620  vr[0] = (int32_t)low;
621  vr[1] = (int32_t)high;
622  status = nc_put_att_int(ncid, varid,"valid_min",NC_INT,1,&vr[0]);
623  if( status != NC_NOERR) {
624  printf("-E- %s %d: %s for %s\n",
625  __FILE__, __LINE__, nc_strerror(status), "valid_min");
626  exit(1);
627  }
628  status = nc_put_att_int(ncid, varid,"valid_max",NC_INT,1,&vr[1]);
629  if( status != NC_NOERR) {
630  printf("-E- %s %d: %s for %s\n",
631  __FILE__, __LINE__, nc_strerror(status), "valid_max");
632  exit(1);
633  }
634  }
635  break;
636  case NC_UINT:
637  {
638  uint32_t vr[2];
639  vr[0] = (uint32_t)low;
640  vr[1] = (uint32_t)high;
641  status = nc_put_att_uint(ncid, varid,"valid_min",NC_UINT,1,&vr[0]);
642  if( status != NC_NOERR) {
643  printf("-E- %s %d: %s for %s\n",
644  __FILE__, __LINE__, nc_strerror(status), "valid_min");
645  exit(1);
646  }
647  status = nc_put_att_uint(ncid, varid,"valid_max",NC_UINT,1,&vr[1]);
648  if( status != NC_NOERR) {
649  printf("-E- %s %d: %s for %s\n",
650  __FILE__, __LINE__, nc_strerror(status), "valid_max");
651  exit(1);
652  }
653  }
654  break;
655  case NC_FLOAT:
656  {
657  float vr[2];
658  vr[0] = (float)low;
659  vr[1] = (float)high;
660  status = nc_put_att_float(ncid, varid,"valid_min",NC_FLOAT,1,&vr[0]);
661  if( status != NC_NOERR) {
662  printf("-E- %s %d: %s for %s\n",
663  __FILE__, __LINE__, nc_strerror(status), "valid_min");
664  exit(1);
665  }
666  status = nc_put_att_float(ncid, varid,"valid_max",NC_FLOAT,1,&vr[1]);
667  if( status != NC_NOERR) {
668  printf("-E- %s %d: %s for %s\n",
669  __FILE__, __LINE__, nc_strerror(status), "valid_max");
670  exit(1);
671  }
672  }
673  break;
674  case NC_DOUBLE:
675  {
676  double vr[2];
677  vr[0] = low;
678  vr[1] = high;
679  status = nc_put_att_double(ncid, varid,"valid_min",NC_DOUBLE,1,&vr[0]);
680  if( status != NC_NOERR) {
681  printf("-E- %s %d: %s for %s\n",
682  __FILE__, __LINE__, nc_strerror(status), "valid_min");
683  exit(1);
684  }
685  status = nc_put_att_double(ncid, varid,"valid_max",NC_DOUBLE,1,&vr[1]);
686  if( status != NC_NOERR) {
687  printf("-E- %s %d: %s for %s\n",
688  __FILE__, __LINE__, nc_strerror(status), "valid_max");
689  exit(1);
690  }
691  }
692  break;
693  default:
694  fprintf(stderr,"-E- %s line %d: ",__FILE__,__LINE__);
695  fprintf(stderr,"Got unsupported number type (%d) ",nt);
696  fprintf(stderr,"while trying to create NCDF variable, \"%s\", ",sname);
697  return(1);
698  }
699  }
700 
701  /* Add a "units" attribute if one is specified */
702  if(units != NULL && *units != 0) {
703  status = nc_put_att_text(ncid, varid, "units", strlen(units), units);
704  if( status != NC_NOERR) {
705  printf("-E- %s %d: %s for %s\n",
706  __FILE__, __LINE__, nc_strerror(status), "units");
707  exit(1);
708  }
709  }
710 
711  /* Add a "standard_name" attribute if one is specified */
712  if(standard_name != NULL && *standard_name != 0) {
713  status = nc_put_att_text(ncid, varid, "standard_name",
714  strlen(standard_name), standard_name);
715  if( status != NC_NOERR) {
716  printf("-E- %s %d: %s for %s\n",
717  __FILE__, __LINE__, nc_strerror(status), "standard_name");
718  exit(1);
719  }
720  }
721 
722  return 0;
723 }
724 
725 int tepoch2yds( double tepoch, int32_t *iyr, int32_t *idy, double *sec) {
726 
727  // Program to convert Hawkeye epoch time to year, day, seconds
728 
729  // Correct for leap seconds
730  int leap = 0;
731 
732  if (tepoch >= 15638401) leap = leap + 1; // Leapsecond on 1 July 2015
733  if (tepoch >= 63158402) leap = leap + 1; // Leapsecond on 1 January 2016
734 
735  double tlocal = tepoch - leap;
736 
737  // Convert epoch time to Julian day
738  int32_t jd = (long) (tlocal/86400) + 2457024; // Julian day of 1/1/2015
739  jdate( jd, iyr, idy);
740 
741  // Extract seconds of day
742  *sec = tlocal - (int) (tlocal / 86400) * 86400;
743 
744  return 0;
745 }
746 
747 /*
748 int get_packet_from_frame( ifstream *framefile, uint8_t **packet,
749  uint32_t &packet_length, int first) {
750 
751  int LFRM = 892;
752  int nbytep, iptr, pptr, nptr, nbytes, apid, len;
753  uint8_t phead[6], ifct;
754 
755  static int fptr;
756  static uint8_t frame[892];
757 
758  // Check if need to read first frame
759  if (first) {
760  //cout << "In first 1: " << framefile->tellg() << endl;
761  framefile->read( (char *) frame, sizeof(frame));
762  fptr = (frame[4] % 8)*256 + frame[5] + 6;
763  //cout << "fptr1: " << fptr << endl;
764  //cout << "In first 2: " << framefile->tellg() << endl;
765  } // first
766 
767 
768  // Check for non-continuation frame
769  while (fptr == 2052 || fptr == 2053) {
770  framefile->read( (char *) frame, sizeof(frame));
771  if (framefile->eof()) {
772  cout << "EOF before 2052/2053 frame found" << endl;
773  exit(110);
774  }
775  fptr = (frame[4] % 8)*256 + frame[5] + 6;
776  }
777 
778  //cout << "fptr2: " << fptr << endl;
779 
780  // Check for packet header split across frames
781  // Populate 6-byte packet header
782  if (fptr > (LFRM-6)) {
783  nbytep = LFRM - fptr;
784  memcpy( phead, &frame[fptr], nbytep);
785  framefile->read( (char *) frame, sizeof(frame));
786  fptr = (frame[4] % 8)*256 + frame[5] + 6;
787  iptr = 12 - nbytep;
788  memcpy( &phead[nbytep], &frame[6], 6-nbytep);
789  } else {
790  memcpy( phead, &frame[fptr], 6);
791  iptr = fptr+ 6;
792  //cout << "iptr: " << iptr << endl;
793  nbytep = 0;
794  }
795 
796  // Check for end-of-file (exposure) packet header
797  apid = (phead[0] % 8)*256 + phead[1];
798  //cout << "apdi: " << apid << endl;
799  if (apid == 2047) {
800  cout << "End of exposure" << endl;
801  return 1;
802  }
803 
804  // Get length from packet header
805  len = phead[4]*256 + phead[5] + 7;
806  packet_length = len;
807  //cout << "packet length: " << len << endl;
808 
809  // Allocate packet and copy header
810  *packet = new uint8_t[len];
811  memcpy( &(*packet)[0], phead, 6);
812  pptr = 6;
813 
814  // Check if entire packet is within current frame
815  nptr = iptr + len - 6;
816  //cout << "nptr: " << nptr << endl;
817  if (nptr < LFRM) {
818  memcpy( &(*packet)[6], &frame[iptr], nptr-iptr);
819  fptr = nptr;
820  // cout << "Entire packet within frame" << endl;
821  //cout << "fptr3: " << fptr << endl << endl;
822  return 0;
823  }
824 
825  // Otherwise get frames to complete packet
826  nbytes = LFRM - iptr;
827  if (nbytes > 0) memcpy( &(*packet)[pptr], &frame[iptr], nbytes);
828 
829  while (nptr >= LFRM) {
830  pptr = pptr + nbytes;
831  nptr = nptr - LFRM + 6;
832  ifct = frame[2];
833  framefile->read( (char *) frame, sizeof(frame));
834  fptr = (frame[4] % 8)*256 + frame[5] + 6;
835  nbytes = len - pptr;
836  if (nbytes > (LFRM-6)) nbytes = LFRM-6;
837 
838  // Check for dropped frames
839 
840  // Must define diff as byte, c++ defaults to int 11/01/18
841  uint8_t byte_diff = frame[2]-ifct;
842 
843  if (byte_diff == 1) {
844  if (nbytes > 0) memcpy( &(*packet)[pptr], &frame[6], nbytes);
845  } else {
846  // If continuation frame
847  while (fptr == 2053 && !framefile->eof()) {
848  //cout << "continuation frame: " << framefile->tellg() << endl;
849  framefile->read( (char *) frame, sizeof(frame));
850  fptr = (frame[4] % 8)*256 + frame[5] + 6;
851  }
852  if (framefile->eof())
853  return 1;
854  // cout << framefile->eof() << endl;
855  nptr = fptr;
856  }
857  }
858 
859  if (fptr > LFRM) {
860  cout << "Bad " << fptr << endl;
861  exit(110);
862  }
863 
864  return 0;
865 }
866 */
867 
868 int readFrame ( ifstream *framefile, uint8_t frame[892], int& prevFrameCnt,
869  int ierror[2]) {
870 
871  ierror[0] = 0;
872 
873  if (!framefile->eof()) {
874  framefile->read( (char *) frame, 892);
875 
876  // get frameCnt
877  int frameCnt = (int) frame[2];
878 
879  // Determine the change in frame count
880  // If not next mod 256 then frame drop
881  int deltaCnt = frameCnt - prevFrameCnt;
882  //long long int pos = framefile->tellg(); // V0.81
883 
884  if (deltaCnt != 1 && deltaCnt != -255) {
885 
886  // cout << "Frame Drop: " << prevFrameCnt << " " << frameCnt << " " <<
887  // pos << endl; // V0.82
888 
889  // Find first good packet
890  int framePtr = 2046;
891  int first2bytes = 20*256 + 160;
892  while ((framePtr == 2046 || framePtr == 2047 || first2bytes != 5280) && \
893  !framefile->eof()) {
894  framefile->read( (char *) frame, 892);
895  framePtr = (frame[4] % 8)*256 + frame[5];
896  first2bytes = frame[0]*256 + frame[1];
897  }
898  framePtr += 6;
899 
900  frameCnt = (int) frame[2];
901  ierror[0] = 1;
902  ierror[1] = framePtr; //i % 886 + 6;
903  }
904 
905  prevFrameCnt = frameCnt;
906  }
907 
908  return 0;
909 }
910 
911 
912 int getSHpacket( ifstream *framefile, uint8_t frame[892], int& framePtr,
913  uint8_t **packet, int& packetLength, int& prevFrameCnt,
914  int& frameDrop) {
915 
916  // Note: At normal end of this routine the framePtr is at the byte
917  // just after the data section.
918 
919  // Note: secondHdr[4]*256+secondHdr[5] includes last 2 bytes of PUS header
920 
921  int ierror[2];
922  uint8_t secondHdr[6];
923  uint8_t pusHdr[3];
924 
925  int bytesWritten;
926  int prevFramePtr;
927  int toWrite2nd;
928  int toWritePUS;
929  int dataLeftToWrite;
930  int packetPtr;
931 
932  int apid;
933  int dataLen;
934 
935  // If framePtr just past current frame then read new frame
936  if (framePtr == 892) {
937  // Read new frame
938  readFrame( framefile, frame, prevFrameCnt, ierror);
939 
940  // Frame drop
941  if (ierror[0] == 1) {
942  frameDrop = 1;
943  framePtr = ierror[1];
944  return 0;
945  }
946  framePtr = PHDRLEN;
947  }
948 
949  if (framePtr > (892-6)) {
950 
954 
955  // S E C O N D P U S
956  // 887 891
957  // 888 891
958  // 889 891
959  // 890 891
960  // 891
961 
962  if (framePtr > 892) {
963  long long int pos = framefile->tellg(); // V0.81
964  cout << "Bad frame pointer: " << framePtr << " " << pos << endl;
965 
966  // Force read of next frame
967  framePtr = 892;
968  frameDrop = -1;
969  return 0;
970  }
971 
972  // Write partial 2nd header
973  memcpy( secondHdr, &frame[framePtr], 892-framePtr);
974 
975  // Read new frame
976  readFrame( framefile, frame, prevFrameCnt, ierror);
977 
978  // Frame drop
979  if (ierror[0] == 1) {
980  frameDrop = 1;
981  framePtr = ierror[1];
982  return 0;
983  }
984 
985  // Set prevFramePtr at start of 2nd header in previous frame
986  // Set framePtr at byte after primary header in new frame
987  prevFramePtr = framePtr;
988  framePtr = PHDRLEN;
989 
990  // 2nd header bytes written & 2nd header bytes left to write
991  bytesWritten = 892 - prevFramePtr;
992  toWrite2nd = SHDRLEN - bytesWritten;
993 
994  // Write remaining part of 2nd header
995  memcpy( &secondHdr[bytesWritten], &frame[framePtr], toWrite2nd);
996 
997  // Set framePtr at byte after remainder of 2nd header
998  framePtr += toWrite2nd;
999 
1000  // Write PUS header
1001  memcpy( pusHdr, &frame[framePtr], PUSLEN);
1002 
1003  // V0.82
1004  if (secondHdr[0]==7) {
1005  // an End of Exposure packet
1006  cout<<"EOI packet detected type1"<<endl;
1007  return 1;
1008  }
1009 
1010  // Get length of data
1011  dataLen = secondHdr[4]*256 + secondHdr[5] - 2;
1012  if (dataLen < 0) {
1013  long long int pos = framefile->tellg(); // V0.81
1014  cout << "Bad dataLen type1: " << dataLen << " " << pos << endl;
1015 
1016  // Force read of next frame
1017  framePtr = 892;
1018  frameDrop = -1;
1019  return 0;
1020  }
1021 
1022  // Write 2nd/PUS headers to packet
1023  *packet = new uint8_t[SHDRLEN+PUSLEN+dataLen];
1024 
1025  memcpy( &(*packet)[0], secondHdr, SHDRLEN);
1026  memcpy( &(*packet)[SHDRLEN], pusHdr, PUSLEN);
1027  packetPtr = SHDRLEN+PUSLEN;
1028 
1029  apid = ((*packet)[0] % 8) * 256 + (*packet)[1];
1030  if (((*packet)[7] < 253 || (*packet)[7] > 255) && apid != 2047) {
1031  long long int pos = framefile->tellg(); // V0.81
1032  cout << "Bad PUS type1: " << (int) (*packet)[7] << " " << pos << endl;
1033 
1034  // Force read of next frame
1035  framePtr = 892;
1036  frameDrop = -1;
1037  return 0;
1038  }
1039 
1040  // Set prevFramePtr at byte after PUS header (start of data)
1041  prevFramePtr = framePtr + PUSLEN;
1042 
1043  // Set framePtr to byte after end of data
1044  framePtr = prevFramePtr + dataLen;
1045 
1046  // If data is within current frame then
1047  // fill remainder of packet and return
1048  if (framePtr <= 892) {
1049  memcpy( &(*packet)[packetPtr], &frame[prevFramePtr], dataLen);
1050  packetLength = SHDRLEN + PUSLEN + dataLen;
1051  return 0;
1052  }
1053 
1054  } else if (framePtr == (892-6)) {
1055 
1059 
1060  // S E C O N D P U S
1061  // 886 891
1062 
1063  // Write 2nd header
1064  memcpy( secondHdr, &frame[framePtr], SHDRLEN);
1065 
1066  // Read new frame
1067  readFrame( framefile, frame, prevFrameCnt, ierror);
1068 
1069  // Frame drop
1070  if (ierror[0] == 1) {
1071  frameDrop = 1;
1072  framePtr = ierror[1];
1073  return 0;
1074  }
1075 
1076  // Write PUS header
1077  memcpy( pusHdr, &frame[PHDRLEN], PUSLEN);
1078 
1079  // Get length of data
1080  dataLen = secondHdr[4]*256 + secondHdr[5] - 2;
1081  if (dataLen < 0) {
1082  long long int pos = framefile->tellg(); // V0.81
1083  cout << "Bad dataLen type2: " << dataLen << " " << pos << endl;
1084 
1085  // Force read of next frame
1086  framePtr = 892;
1087  frameDrop = -1;
1088  return 0;
1089  }
1090 
1091  // Write 2nd/PUS headers to packet
1092  *packet = new uint8_t[SHDRLEN+PUSLEN+dataLen];
1093 
1094  memcpy( &(*packet)[0], secondHdr, SHDRLEN);
1095  memcpy( &(*packet)[SHDRLEN], pusHdr, PUSLEN);
1096  packetPtr = SHDRLEN + PUSLEN;
1097 
1098  apid = ((*packet)[0] % 8) * 256 + (*packet)[1];
1099  if (((*packet)[7] < 253 || (*packet)[7] > 255) && apid != 2047) {
1100  long long int pos = framefile->tellg(); // V0.81
1101  cout << "Bad PUS type2: " << (int) (*packet)[7] << " " << pos << endl;
1102 
1103  // Force read of next frame
1104  framePtr = 892;
1105  frameDrop = -1;
1106  return 0;
1107  }
1108 
1109  // Set prevFramePtr at byte after PUS header (start of data)
1110  prevFramePtr = PHDRLEN + PUSLEN;
1111 
1112  // Set framePtr to byte after end of data
1113  framePtr = prevFramePtr + dataLen;
1114 
1115  // If data is within current frame then
1116  // fill remainder of packet and return
1117  if (framePtr <= 892) {
1118  memcpy( &(*packet)[packetPtr], &frame[prevFramePtr], dataLen);
1119  packetLength = SHDRLEN + PUSLEN + dataLen;
1120  return 0;
1121  }
1122 
1123  } else if (framePtr > (892-9)) {
1124 
1128 
1129  // S E C O N D P U S
1130  // 884 891
1131  // 885 891
1132 
1133  // Write 2nd header
1134  memcpy( secondHdr, &frame[framePtr], SHDRLEN);
1135 
1136  // Write partial PUS header
1137  memcpy( pusHdr, &frame[framePtr+SHDRLEN], 892-(framePtr+SHDRLEN));
1138 
1139  // Read new frame
1140  readFrame( framefile, frame, prevFrameCnt, ierror);
1141 
1142  // Frame drop
1143  if (ierror[0] == 1) {
1144  frameDrop = 1;
1145  framePtr = ierror[1];
1146  return 0;
1147  }
1148 
1149  // Set prevFramePtr at start of PUS header in previous frame
1150  // Set framePtr at byte after primary header in new frame
1151  prevFramePtr = framePtr + SHDRLEN;
1152  framePtr = PHDRLEN;
1153 
1154  // PUS header bytes written & PUS header bytes left to write
1155  bytesWritten = 892 - prevFramePtr;
1156  toWritePUS = PUSLEN - bytesWritten;
1157 
1158  // Write remaining part of PUS header
1159  memcpy( &pusHdr[bytesWritten], &frame[framePtr], toWritePUS);
1160 
1161  // Get length of data
1162  dataLen = secondHdr[4]*256 + secondHdr[5] - 2;
1163  if (dataLen < 0) {
1164  long long int pos = framefile->tellg(); // V0.81
1165  cout << "Bad dataLen type3: " << dataLen << " " << pos << endl;
1166 
1167  // Force read of next frame
1168  framePtr = 892;
1169  frameDrop = -1;
1170  return 0;
1171  }
1172 
1173  // Write 2nd/PUS headers to packet
1174  *packet = new uint8_t[SHDRLEN+PUSLEN+dataLen];
1175 
1176  memcpy( &(*packet)[0], secondHdr, SHDRLEN);
1177  memcpy( &(*packet)[SHDRLEN], pusHdr, PUSLEN);
1178  packetPtr = SHDRLEN+PUSLEN;
1179 
1180  apid = ((*packet)[0] % 8) * 256 + (*packet)[1];
1181  if (((*packet)[7] < 253 || (*packet)[7] > 255) && apid != 2047) {
1182  long long int pos = framefile->tellg(); // V0.81
1183  cout << "Bad PUS type3: " << (int) (*packet)[7] << " " << pos << endl;
1184 
1185  // Force read of next frame
1186  framePtr = 892;
1187  frameDrop = -1;
1188  return 0;
1189  }
1190 
1191  // Set prevFramePtr at byte after PUS header (start of data)
1192  prevFramePtr = framePtr + toWritePUS;
1193 
1194  // Set framePtr to byte after end of data
1195  framePtr = prevFramePtr + dataLen;
1196 
1197  // If data is within current frame then
1198  // fill remainder of packet and return
1199  if (framePtr <= 892) {
1200  memcpy( &(*packet)[packetPtr], &frame[prevFramePtr], dataLen);
1201  packetLength = SHDRLEN + PUSLEN + dataLen;
1202  return 0;
1203  }
1204 
1205  } else {
1206 
1210 
1211  // S E C O N D P U S
1212  // 883 891
1213  // 882 883 891
1214  // 881 882 883 891
1215 
1216  // Write 2nd/PUS headers
1217  memcpy( secondHdr, &frame[framePtr], SHDRLEN);
1218  memcpy( pusHdr, &frame[framePtr+SHDRLEN], PUSLEN);
1219 
1220  /*
1221  // V0.84
1222  if (secondHdr[0]==7) {
1223  // an End of Exposure packet
1224  cout<<"EOI packet detected type4"<<endl;
1225  return 1;
1226  }
1227  */
1228 
1229  // Get length of data
1230  dataLen = secondHdr[4]*256 + secondHdr[5] - 2;
1231  if (dataLen < 0) {
1232  long long int pos = framefile->tellg(); // V0.81
1233  cout << "Bad dataLen type4: " << dataLen << " " << pos << endl;
1234 
1235  // Force read of next frame
1236  framePtr = 892;
1237  frameDrop = -1;
1238  return 0;
1239  }
1240 
1241  // Write 2nd/PUS headers to packet
1242  *packet = new uint8_t[SHDRLEN+PUSLEN+dataLen];
1243 
1244  memcpy( &(*packet)[0], secondHdr, SHDRLEN);
1245  memcpy( &(*packet)[SHDRLEN], pusHdr, PUSLEN);
1246  packetPtr = SHDRLEN+PUSLEN;
1247 
1248  apid = ((*packet)[0] % 8) * 256 + (*packet)[1];
1249  if (((*packet)[7] < 253 || (*packet)[7] > 255) && apid != 2047) {
1250  long long int pos = framefile->tellg(); // V0.81
1251  cout << "Bad PUS type4: " << (int) (*packet)[7] << " " << pos << endl;
1252 
1253  // Force read of next frame
1254  framePtr = 892;
1255  frameDrop = -1;
1256  return 0;
1257  }
1258 
1259  // Set prevFramePtr at byte after PUS header (start of data)
1260  prevFramePtr = framePtr + SHDRLEN + PUSLEN;
1261 
1262  // Set framePtr to byte after end of data
1263  framePtr = prevFramePtr + dataLen;
1264 
1265  // If data is within current frame then
1266  // fill remainder of packet and return
1267  if (framePtr <= 892) {
1268  memcpy( &(*packet)[packetPtr], &frame[prevFramePtr], dataLen);
1269  packetLength = SHDRLEN + PUSLEN + dataLen;
1270  return 0;
1271  }
1272  }
1273 
1277 
1278  // Write data remaining in current frame
1279  // Note: If complete 2nd/PUS headers at end of frame then no data to write
1280  if (prevFramePtr < 892) {
1281  memcpy( &(*packet)[packetPtr], &frame[prevFramePtr], 892-prevFramePtr);
1282  packetPtr += 892-prevFramePtr;
1283  }
1284 
1285  // Determine number of bytes left to write
1286  dataLeftToWrite = dataLen - (892 - prevFramePtr);
1287 
1288  while (dataLeftToWrite > 0) {
1289 
1290  // If data to write then read new frame
1291  readFrame( framefile, frame, prevFrameCnt, ierror);
1292 
1293  // Frame drop
1294  if (ierror[0] == 1) {
1295  frameDrop = 1;
1296  framePtr = ierror[1];
1297  return 0;
1298  }
1299 
1300  // Set previous frame to start of data (after primary header)
1301  prevFramePtr = PHDRLEN;
1302 
1303  // Set frame pointer to minimum of frame length or pointer to byte
1304  // following end of data in current frame
1305  if (892 < prevFramePtr+dataLeftToWrite)
1306  framePtr = 892;
1307  else
1308  framePtr = prevFramePtr + dataLeftToWrite;
1309 
1310  int dataToWrite = framePtr - prevFramePtr;
1311 
1312  // Write data to packet
1313  memcpy( &(*packet)[packetPtr], &frame[prevFramePtr], dataToWrite);
1314  packetPtr += dataToWrite;
1315 
1316  // Compute remaining data to write
1317  dataLeftToWrite -= framePtr - prevFramePtr;
1318  }
1319 
1320  packetLength = SHDRLEN + PUSLEN + dataLen;
1321 
1322  return 0;
1323 }
1324 
1325 
int readFrame(ifstream *framefile, uint8_t frame[892], int &prevFrameCnt, int ierror[2])
int status
Definition: l1_czcs_hdf.c:32
void check_err(const int stat, const int line, const char *file)
Definition: nc4utils.c:35
#define NULL
Definition: decode_rs.h:63
int createFile(const char *filename, const char *cdlfile, size_t sdim, int *ncid, int *gid)
Definition: hawkeyeUtil.cpp:39
const int PHDRLEN
Definition: hawkeyeUtil.h:5
float32 * pos
Definition: l1_czcs_hdf.c:35
int jdate(int32_t julian, int32_t *year, int32_t *doy)
Definition: jdate.c:5
const int PUSLEN
Definition: hawkeyeUtil.h:7
int tepoch2yds(double tepoch, int32_t *iyr, int32_t *idy, double *sec)
const int SHDRLEN
Definition: hawkeyeUtil.h:6
int expandEnvVar(string *sValue)
Definition: hawkeyeUtil.h:41
Definition: jd.py:1
char filename[FILENAME_MAX]
Definition: atrem_corl1.h:122
int parseDims(int ncid, int ndims, string dimString, int *numDims, int *dimid, int *varDims)
int createNCDF(int ncid, const char *sname, const char *lname, const char *standard_name, const char *units, void *fill_value, const char *flag_values, const char *flag_meanings, double low, double high, float scale_factor, float add_offset, int nt, int rank, int *dimids)
Extra metadata that will be written to the HDF4 file l2prod rank
int getSHpacket(ifstream *framefile, uint8_t frame[892], int &framePtr, uint8_t **packet, int &packetLength, int &prevFrameCnt, int &frameDrop)
logical function leap(YEAR)
Definition: leap.f:10
int32_t idy
Definition: atrem_corl1.h:161
These two strings are used for the product XML output If product_id is not set then prefix is used If the last char of the name_prefix is _ then it is removed If algorithm_id is not set then name_suffix is used If the first char is _ then it is removed l2prod standard_name[0]
int i
Definition: decode_rs.h:71
int32_t iyr
Definition: atrem_corl1.h:161
float32 f32
Definition: l2bin.cpp:104