OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
ice2hdf.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <time.h>
4 #include <string.h>
5 
6 #include <clo.h>
7 #include <hdf_utils.h>
8 #include <genutils.h>
9 
10 #define PROGRAM "ice2hdf"
11 #define VERSION "1.2"
12 #define FMT_L2HDF 2
13 
14 #define DATA_CITATION "Meier, W., F. Fetterer, K. Knowles, M. Savoie, M. J. Brodzik. 2006, updated quarterly. Sea ice concentrations from Nimbus-7 SMMR and DMSP SSM/I passive microwave data. Boulder, Colorado USA: National Snow and Ice Data Center. Digital media."
15 #define WEB_SITE "http://nsidc.org/data/docs/daac/nsidc0051_gsfc_seaice.gd.html"
16 #define FTP_SITE "ftp://sidads.colorado.edu/pub/DATASETS/seaice/polar-stereo/nasateam/near-real-time"
17 
18 #define HEADER_SIZE 300
19 
20 #define NORTH_ROWS 448
21 #define NORTH_COLS 304
22 #define SOUTH_ROWS 332
23 #define SOUTH_COLS 316
24 
25 #define MAX_DATA 250
26 #define POLAR_HOLE 251
27 #define MISSING_DATA 255
28 
29 // data file structure
30 
31 typedef struct data_file_t {
32  char* filename;
33  uint8 *dataPtr;
34  int32 numRows;
35  int32 numCols;
36  int hasHeader;
37  int32 year;
38  int32 doy;
39 } data_file_t;
40 
41 /* -------------------------------------------------------------------- */
42 /* allocateDataFile */
43 
44 /* -------------------------------------------------------------------- */
45 data_file_t* allocateDataFile(char* filename, int32 numRows, int32 numCols) {
46  data_file_t* dataFile = (data_file_t*) malloc(sizeof (data_file_t));
47 
48  dataFile->filename = strdup(filename);
49  dataFile->dataPtr = (uint8*) malloc(numRows * numCols);
50  dataFile->numRows = numRows;
51  dataFile->numCols = numCols;
52  dataFile->hasHeader = 0;
53  dataFile->year = 0;
54  dataFile->doy = 0;
55 
56  return dataFile;
57 }
58 
59 /* -------------------------------------------------------------------- */
60 /* readFile */
61 
62 /* -------------------------------------------------------------------- */
63 void readFile(data_file_t* dataFile) {
64  char header[HEADER_SIZE];
65  int result;
66  FILE *fin;
67 
68  fin = fopen(dataFile->filename, "rb");
69  if (fin == NULL) {
70  fprintf(stderr, "-E- %s line %d: Could not open file, \"%s\" .\n",
71  __FILE__, __LINE__, dataFile->filename);
72  exit(EXIT_FAILURE);
73  }
74 
75  if (dataFile->hasHeader) {
76  result = fread(header, 1, HEADER_SIZE, fin);
77  if (result != HEADER_SIZE) {
78  fprintf(stderr,
79  "-E- %s line %d: Error reading file header, \"%s\" .\n",
80  __FILE__, __LINE__, dataFile->filename);
81  exit(EXIT_FAILURE);
82  }
83 
84  //
85  // parse the header
86  //
87  int32 numRows = atoi(&header[12]);
88  int32 numCols = atoi(&header[6]);
89  dataFile->year = atoi(&header[102]);
90  dataFile->doy = atoi(&header[108]);
91 
92  if (numRows != dataFile->numRows) {
93  fprintf(stderr,
94  "-E- %s line %d: Bad number of rows(%d) in \"%s\" should be %d\n",
95  __FILE__, __LINE__, numRows, dataFile->filename,
96  dataFile->numRows);
97  exit(EXIT_FAILURE);
98  }
99 
100  if (numCols != dataFile->numCols) {
101  fprintf(stderr,
102  "-E- %s line %d: Bad number of columns(%d) in \"%s\" should be %d\n",
103  __FILE__, __LINE__, numCols, dataFile->filename,
104  dataFile->numCols);
105  exit(EXIT_FAILURE);
106  }
107 
108  }
109 
110  //
111  // read the data
112  //
113  result = fread(dataFile->dataPtr, 1, dataFile->numRows * dataFile->numCols,
114  fin);
115  if (result != dataFile->numRows * dataFile->numCols) {
116  fprintf(stderr, "-E- %s line %d: Error reading file data, \"%s\" \n",
117  __FILE__, __LINE__, dataFile->filename);
118  exit(EXIT_FAILURE);
119  }
120 
121 }
122 
123 /* -------------------------------------------------------------------- */
124 /* maskData */
125 /* Set the data to 255 anywhere the mask dataset is set to the */
126 /* given values. */
127 
128 /* -------------------------------------------------------------------- */
129 void maskData(data_file_t* dataFile, data_file_t* maskFile, int numVals,
130  int* vals) {
131  if (dataFile->numRows != maskFile->numRows) {
132  fprintf(stderr,
133  "-E- %s line %d: data file \"%s\" and mask file \"%s\" have different number of Rows\n",
134  __FILE__, __LINE__, dataFile->filename, maskFile->filename);
135  exit(EXIT_FAILURE);
136  }
137  if (dataFile->numCols != maskFile->numCols) {
138  fprintf(stderr,
139  "-E- %s line %d: data file \"%s\" and mask file \"%s\" have different number of Columns\n",
140  __FILE__, __LINE__, dataFile->filename, maskFile->filename);
141  exit(EXIT_FAILURE);
142  }
143 
144  int i, j;
145  for (i = 0; i < dataFile->numRows * dataFile->numCols; i++) {
146  for (j = 0; j < numVals; j++) {
147  if (maskFile->dataPtr[i] == vals[j]) {
148  dataFile->dataPtr[i] = MISSING_DATA;
149  }
150  }
151  }
152 }
153 
154 /* -------------------------------------------------------------------- */
155 /* fillHoles */
156 /* Fill the holes in the data by iterativly averaging the surrounding */
157 /* pixels. Assume anything over 250 is a hole. */
158 /* */
159 
160 /* -------------------------------------------------------------------- */
161 void fillHoles(data_file_t* dataFile) {
162  int delta = 1; // size of the box around the pixel
163 
164  uint8 * data2;
165  int holesFound = 1;
166  int row, col;
167  int r, c;
168  int r1, r2;
169  int c1, c2;
170  int count;
171  int sum;
172 
173  data2 = (uint8*) malloc(dataFile->numRows * dataFile->numCols);
174  if (data2 == NULL) {
175  fprintf(stderr, "-E- %s line %d: Could not malloc.\n", __FILE__,
176  __LINE__);
177  exit(EXIT_FAILURE);
178  }
179 
180  while (holesFound) {
181  holesFound = 0;
182 
183  // copy the data so we don't key off of newly filled values
184  memcpy(data2, dataFile->dataPtr, dataFile->numRows * dataFile->numCols);
185 
186  for (row = 0; row < dataFile->numRows; row++) {
187  for (col = 0; col < dataFile->numCols; col++) {
188 
189  if (data2[row * dataFile->numCols + col] > MAX_DATA) {
190  holesFound = 1;
191 
192  // calc limits of the box around the pixel
193  r1 = row - delta;
194  if (r1 < 0)
195  r1 = 0;
196  r2 = row + delta;
197  if (r2 >= dataFile->numRows)
198  r2 = dataFile->numRows - 1;
199 
200  c1 = col - delta;
201  if (c1 < 0)
202  c1 = 0;
203  c2 = col + delta;
204  if (c2 >= dataFile->numCols)
205  c2 = dataFile->numCols - 1;
206 
207  // intialize the average variables
208  count = 0;
209  sum = 0;
210 
211  // sum surrounding pixels
212  for (r = r1; r <= r2; r++) {
213  for (c = c1; c <= c2; c++) {
214  if (data2[r * dataFile->numCols + c] <= MAX_DATA) {
215  count++;
216  sum += data2[r * dataFile->numCols + c];
217  }
218  } // for c1 to c2
219  } // for r1 to r2
220 
221  if (count > 1) {
222  dataFile->dataPtr[row * dataFile->numCols + col] = sum
223  / count;
224  }
225 
226  } // pixel is a hole
227  } // for cols
228  } // for rows
229 
230  } // while holes
231 
232  free(data2);
233 }
234 
235 /* -------------------------------------------------------------------- */
236 /* main */
237 
238 /* -------------------------------------------------------------------- */
239 int main(int argc, char* argv[]) {
241  clo_option_t* option;
242 
243  char tmpStr[2048];
244  int initialNumOptions;
245  int numExtraOptions;
246 
247  data_file_t *northData;
248  data_file_t *southData;
249  int northNumRegions;
250  int* northRegionList;
251  data_file_t *northRegion;
252  int southNumRegions;
253  int* southRegionList;
254  data_file_t *southRegion;
255 
256  int32 hdfStat;
257  idDS ds_id;
258 
259  char northFilename[1024];
260  char southFilename[1024];
261  char outFilename[1024];
262  char northRegionFilename[1024];
263  char southRegionFilename[1024];
264 
265  sprintf(tmpStr, "ice2hdf %s (%s %s)", VERSION, __DATE__, __TIME__);
266  clo_setVersion(tmpStr);
267 
268  list = clo_createList();
269 
270  strcpy(tmpStr, "Usage: ice2hdf [options] northFile southFile outFile\n\n");
271  strcat(tmpStr,
272  "Program to convert the NSIDC ice data into an HDF file that l2gen can use.\n");
273  strcat(tmpStr, "Documentation - ");
274  strcat(tmpStr, WEB_SITE);
275  strcat(tmpStr, "\nData - ");
276  strcat(tmpStr, FTP_SITE);
277  strcat(tmpStr, "\n");
278  clo_setHelpStr(tmpStr);
279 
280  clo_addOption(list, "fill_pole", CLO_TYPE_BOOL, "true", "Fill the Arctic polar hole with 100% ice");
281  strcpy(tmpStr, "Mask the values in the given\n northern regions\n");
282  strcat(tmpStr, " 0: Lakes, extended coast\n");
283  strcat(tmpStr, " 1: Non-regional ocean\n");
284  strcat(tmpStr, " 2: Sea of Okhotsk and Japan\n");
285  strcat(tmpStr, " 3: Bering Sea\n");
286  strcat(tmpStr, " 4: Hudson Bay\n");
287  strcat(tmpStr, " 5: Baffin Bay/Davis Strait/Labrador Sea\n");
288  strcat(tmpStr, " 6: Greenland Sea\n");
289  strcat(tmpStr, " 7: Kara and Barents Seas\n");
290  strcat(tmpStr, " 8: Arctic Ocean\n");
291  strcat(tmpStr, " 9: Canadian Archipelago\n");
292  strcat(tmpStr, " 10: Gulf of St. Lawrence\n");
293  strcat(tmpStr, " 11: Land\n");
294  strcat(tmpStr, " 12: Coast");
295  clo_addOption(list, "region_mask_north", CLO_TYPE_INT, "[0,11,12]", tmpStr);
296  clo_addOption(list, "region_file_north", CLO_TYPE_IFILE,
297  "$OCDATAROOT/common/region_n.msk",
298  "\n Region mask file for the northern hemisphere");
299 
300  strcpy(tmpStr, "Mask the values in the given\n southern regions\n");
301  strcat(tmpStr, " 2: Weddell Sea\n");
302  strcat(tmpStr, " 3: Indian Ocean\n");
303  strcat(tmpStr, " 4: Pacific Ocean\n");
304  strcat(tmpStr, " 5: Ross Sea\n");
305  strcat(tmpStr, " 6: Bellingshausen Amundsen Sea\n");
306  strcat(tmpStr, " 11: Land\n");
307  strcat(tmpStr, " 12: Coast");
308  clo_addOption(list, "region_mask_south", CLO_TYPE_INT, "[11,12]", tmpStr);
309  clo_addOption(list, "region_file_south", CLO_TYPE_IFILE,
310  "$OCDATAROOT/common/region_s.msk",
311  "\n Region mask file for the southern hemisphere");
312 
313  initialNumOptions = clo_getNumOptions(list);
314  clo_readArgs(list, argc, argv);
315  numExtraOptions = clo_getNumOptions(list) - initialNumOptions;
316 
317  if (numExtraOptions != 3) {
318  printf("ERROR - wrong number of parameters given\n\n");
320  return 1;
321  }
322 
323  option = clo_getOption(list, initialNumOptions);
324  parse_file_name(option->key, northFilename);
325 
326  option = clo_getOption(list, initialNumOptions + 1);
327  parse_file_name(option->key, southFilename);
328 
329  option = clo_getOption(list, initialNumOptions + 2);
330  parse_file_name(option->key, outFilename);
331 
332  northRegionList = clo_getInts(list, "region_mask_north", &northNumRegions);
333  parse_file_name(clo_getString(list, "region_file_north"),
334  northRegionFilename);
335 
336  southRegionList = clo_getInts(list, "region_mask_south", &southNumRegions);
337  parse_file_name(clo_getString(list, "region_file_south"),
338  southRegionFilename);
339 
340  time_t currentTime = time(NULL);
341  char* currentTimeStr = strdup(asctime(gmtime(&currentTime)));
342  currentTimeStr[24] = '\0';
343 
344  //
345  // read the data files
346  //
347  northData = allocateDataFile(northFilename, NORTH_ROWS, NORTH_COLS);
348  northData->hasHeader = 1;
349  readFile(northData);
350 
351  if (clo_getBool(list, "fill_pole")) {
352  int i;
353  for (i = 0; i < NORTH_ROWS * NORTH_COLS; i++) {
354  if (northData->dataPtr[i] == POLAR_HOLE) {
355  northData->dataPtr[i] = MAX_DATA;
356  }
357  }
358  }
359 
360  southData = allocateDataFile(southFilename, SOUTH_ROWS, SOUTH_COLS);
361  southData->hasHeader = 1;
362  readFile(southData);
363 
364  if (northNumRegions > 0) {
365  northRegion = allocateDataFile(northRegionFilename, NORTH_ROWS,
366  NORTH_COLS);
367  northRegion->hasHeader = 1;
368  readFile(northRegion);
369  maskData(northData, northRegion, northNumRegions, northRegionList);
370  }
371 
372  if (southNumRegions > 0) {
373  southRegion = allocateDataFile(southRegionFilename, SOUTH_ROWS,
374  SOUTH_COLS);
375  southRegion->hasHeader = 1;
376  readFile(southRegion);
377  maskData(southData, southRegion, southNumRegions, southRegionList);
378  }
379 
380  fillHoles(northData);
381  fillHoles(southData);
382 
383  //
384  // open the HDF file
385  //
386  ds_id = startDS(outFilename, DS_HDF, DS_WRITE, 0);
387  if (ds_id.fid == FAIL) {
388  fprintf(stderr, "-E- %s line %d: Could not create HDF file, %s .\n",
389  __FILE__, __LINE__, outFilename);
390  return (HDF_FUNCTION_ERROR);
391  }
392 
393  /* */
394  /* Create the north and south data array SDSes */
395  /* ---------------------------------------------------------------- */
396  /* */
397  PTB(createDS(ds_id, /* file id */
398  "north", /* short name */
399  "North Pole Ice Fraction", /* long name */
400  NULL, /* standard name */
401  NULL, /* units */
402  0, 0, /* range */
403  0, 0, /* slope */
404  DFNT_INT8, /* HDF number type */
405  2, /* rank */
406  northData->numRows, northData->numCols, 0, /* dimension sizes */
407  "north_rows", "north_cols", NULL /* dimension names */
408  ));
409 
410  PTB(createDS(ds_id, /* file id */
411  "south", /* short name */
412  "South Pole Ice Fraction", /* long name */
413  NULL, /* standard name */
414  NULL, /* units */
415  0, 0, /* range */
416  0, 0, /* slope */
417  DFNT_INT8, /* HDF number type */
418  2, /* rank */
419  southData->numRows, southData->numCols, 0, /* dimension sizes */
420  "south_rows", "south_cols", NULL /* dimension names */
421  ));
422 
423  // Modify to use new HDF4/NCDF4 libhdfutils library JMG 09/28/12
424  PTB(SetChrGA(ds_id, "Title", "Sea Ice Concentration Daily"));
425  PTB(SetChrGA(ds_id, "Creation Date", currentTimeStr));
426  PTB(SetChrGA(ds_id, "Created By", "Don Shea, SAIC, from NSIDC NRT data (http://nsidc.org)"));
427  PTB(SetChrGA(ds_id, "Reference1", DATA_CITATION));
428  PTB(SetChrGA(ds_id, "Software Name", PROGRAM));
429  PTB(SetChrGA(ds_id, "Software Version", VERSION));
430  PTB(SetI32GA(ds_id, "year", northData->year));
431  PTB(SetI32GA(ds_id, "day_of_year", northData->doy));
432 
433  PTB(sd_writedata(ds_id.fid, "north", northData->dataPtr, 0, 0, 0, northData->numRows, northData->numCols, 0));
434  PTB(sd_writedata(ds_id.fid, "south", southData->dataPtr, 0, 0, 0, southData->numRows, southData->numCols, 0));
435 
436  //
437  // close the HDF file
438  //
439  hdfStat = endDS(ds_id);
440  if (hdfStat == FAIL) {
441  fprintf(stderr, "-E- %s line %d: Could not close HDF file, %s .\n",
442  __FILE__, __LINE__, outFilename);
443  return (HDF_FUNCTION_ERROR);
444  }
445 
446  return (LIFE_IS_GOOD);
447 }
clo_option_t * clo_addOption(clo_optionList_t *list, const char *key, enum clo_dataType_t dataType, const char *defaultVal, const char *desc)
Definition: clo.c:684
int r
Definition: decode_rs.h:73
int j
Definition: decode_rs.h:73
char * clo_getString(clo_optionList_t *list, const char *key)
Definition: clo.c:1357
int32 year
Definition: ice2hdf.c:37
void clo_readArgs(clo_optionList_t *list, int argc, char *argv[])
Definition: clo.c:2103
list(APPEND LIBS ${PGSTK_LIBRARIES}) add_executable(atteph_info_modis atteph_info_modis.c) target_link_libraries(atteph_info_modis $
Definition: CMakeLists.txt:7
#define MAX_DATA
Definition: ice2hdf.c:25
#define FAIL
Definition: ObpgReadGrid.h:18
int32 numCols
Definition: ice2hdf.c:35
#define NULL
Definition: decode_rs.h:63
int32 numRows
Definition: ice2hdf.c:34
#define MISSING_DATA
Definition: ice2hdf.c:27
char * key
Definition: clo.h:104
void fillHoles(data_file_t *dataFile)
Definition: ice2hdf.c:161
int32 doy
Definition: ice2hdf.c:38
int createDS(idDS ds_id, int sensorId, const char *sname, int32_t dm[3], const char dm_name[3][80])
Definition: wrapper.c:344
@ CLO_TYPE_BOOL
Definition: clo.h:78
#define VERSION
Definition: ice2hdf.c:11
int * clo_getInts(clo_optionList_t *list, const char *key, int *count)
Definition: clo.c:1515
#define LIFE_IS_GOOD
Definition: passthebuck.h:4
int main(int argc, char *argv[])
Definition: ice2hdf.c:239
uint8 * dataPtr
Definition: ice2hdf.c:33
clo_optionList_t * clo_createList()
Definition: clo.c:532
#define SOUTH_COLS
Definition: ice2hdf.c:23
void clo_setHelpStr(const char *str)
Definition: clo.c:487
#define NORTH_ROWS
Definition: ice2hdf.c:20
@ CLO_TYPE_INT
Definition: clo.h:79
char * strdup(const char *)
idDS startDS(const char *filename, ds_format_t format, ds_access_t accessmode, int32_t deflate)
Definition: wrapper.c:561
void clo_printUsage(clo_optionList_t *list)
Definition: clo.c:1988
const double delta
@ CLO_TYPE_IFILE
Definition: clo.h:84
char filename[FILENAME_MAX]
Definition: atrem_corl1.h:122
#define HEADER_SIZE
Definition: ice2hdf.c:18
clo_option_t * clo_getOption(clo_optionList_t *list, int i)
Definition: clo.c:908
#define PTB(function)
Definition: passthebuck.h:16
#define NORTH_COLS
Definition: ice2hdf.c:21
int clo_getNumOptions(clo_optionList_t *list)
Definition: clo.c:1017
void parse_file_name(const char *inpath, char *outpath)
int hasHeader
Definition: ice2hdf.c:36
int SetI32GA(idDS ds_id, const char *name, int32_t value)
Definition: wrapper.c:326
data_file_t * allocateDataFile(char *filename, int32 numRows, int32 numCols)
Definition: ice2hdf.c:45
#define SOUTH_ROWS
Definition: ice2hdf.c:22
#define WEB_SITE
Definition: ice2hdf.c:15
@ DS_WRITE
Definition: dfutils.h:25
int SetChrGA(idDS ds_id, const char *name, const char *value)
Definition: wrapper.c:236
void clo_setVersion(const char *str)
Definition: clo.c:448
this program makes no use of any feature of the SDP Toolkit that could generate such a then geolocation is calculated at that and then aggregated up to Resolved feature request Bug by adding three new int8 SDSs for each high resolution offsets between the high resolution geolocation and a bi linear interpolation extrapolation of the positions This can be used to reconstruct the high resolution geolocation Resolved Bug by delaying cumulation of gflags until after validation of derived products Resolved Bug by setting Latitude and Longitude to the correct fill resolving to support Near Real Time because they may be unnecessary if use of entrained ephemeris and attitude data is turned resolving bug report Corrected to filter out Aqua attitude records with missing status helping resolve bug MOD_PR03 will still correctly write scan and pixel data that does not depend upon the start time
Definition: HISTORY.txt:248
int32_t fid
Definition: dfutils.h:29
#define DATA_CITATION
Definition: ice2hdf.c:14
@ DS_HDF
Definition: dfutils.h:19
Definition: dfutils.h:28
int sd_writedata(int32_t sd_id, const char *name, const void *data, int32_t s0, int32_t s1, int32_t s2, int32_t e0, int32_t e1, int32_t e2)
Definition: hdf_utils.c:293
int clo_getBool(clo_optionList_t *list, const char *key)
Definition: clo.c:1375
void readFile(data_file_t *dataFile)
Definition: ice2hdf.c:63
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
#define PROGRAM
Definition: ice2hdf.c:10
int endDS(idDS ds_id)
Definition: wrapper.c:634
#define FTP_SITE
Definition: ice2hdf.c:16
int i
Definition: decode_rs.h:71
#define POLAR_HOLE
Definition: ice2hdf.c:26
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
char * filename
Definition: ice2hdf.c:32
#define HDF_FUNCTION_ERROR
Definition: passthebuck.h:7
void maskData(data_file_t *dataFile, data_file_t *maskFile, int numVals, int *vals)
Definition: ice2hdf.c:129
int count
Definition: decode_rs.h:79