OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
goci.c
Go to the documentation of this file.
1 
8 #include <time.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <inttypes.h>
13 #include <unistd.h>
14 #include <proj.h>
15 #include <math.h>
16 
17 #include "hdf5.h"
18 #include "hdf5_hl.h"
19 #include "goci.h"
20 
30 int
32  hid_t gid;
33  hid_t attr;
34  herr_t herr;
35  float centralLat;
36  float centralLon;
37  float equitorialRadius;
38  float polarRadius;
39  float llLat, llLon;
40  float urLat, urLon;
41  char projStr[1024];
42 
43  // read Map Projection attributes
44  gid = H5Gopen(l1b->fid, "/HDFEOS/POINTS/Map Projection", H5P_DEFAULT);
45  if (gid < 0) {
46  return -1;
47  }
48  attr = H5Aopen_name(gid, "Central Latitude (parallel)");
49  if (attr < 0) {
50  H5Gclose(gid);
51  return -1;
52  }
53  herr = H5Aread(attr, H5T_NATIVE_FLOAT, &centralLat);
54  H5Aclose(attr);
55  if (herr < 0) {
56  H5Gclose(gid);
57  return -4;
58  }
59 
60  attr = H5Aopen_name(gid, "Central Longitude (meridian)");
61  if (attr < 0) {
62  H5Gclose(gid);
63  return -1;
64  }
65  herr = H5Aread(attr, H5T_NATIVE_FLOAT, &centralLon);
66  H5Aclose(attr);
67  if (herr < 0) {
68  H5Gclose(gid);
69  return -4;
70  }
71 
72  attr = H5Aopen_name(gid, "Equitorial radius of Earth ellipsoid");
73  if (attr < 0) {
74  H5Gclose(gid);
75  return -1;
76  }
77  herr = H5Aread(attr, H5T_NATIVE_FLOAT, &equitorialRadius);
78  H5Aclose(attr);
79  if (herr < 0) {
80  H5Gclose(gid);
81  return -4;
82  }
83 
84  attr = H5Aopen_name(gid, "Polar radius of Earth ellipsoid");
85  if (attr < 0) {
86  H5Gclose(gid);
87  return -1;
88  }
89  herr = H5Aread(attr, H5T_NATIVE_FLOAT, &polarRadius);
90  H5Aclose(attr);
91  if (herr < 0) {
92  H5Gclose(gid);
93  return -4;
94  }
95 
96  herr = H5Gclose(gid);
97  if (herr < 0)
98  return -2;
99 
100 
101  // read Scene Header attributes
102  gid = H5Gopen(l1b->fid, "/HDFEOS/POINTS/Scene Header", H5P_DEFAULT);
103  if (gid < 0) {
104  return -1;
105  }
106  attr = H5Aopen_name(gid, "Scene lower-left latitude");
107  if (attr < 0) {
108  H5Gclose(gid);
109  return -1;
110  }
111  herr = H5Aread(attr, H5T_NATIVE_FLOAT, &llLat);
112  H5Aclose(attr);
113  if (herr < 0) {
114  H5Gclose(gid);
115  return -4;
116  }
117 
118  attr = H5Aopen_name(gid, "Scene lower-left longitude");
119  if (attr < 0) {
120  H5Gclose(gid);
121  return -1;
122  }
123  herr = H5Aread(attr, H5T_NATIVE_FLOAT, &llLon);
124  H5Aclose(attr);
125  if (herr < 0) {
126  H5Gclose(gid);
127  return -4;
128  }
129 
130  attr = H5Aopen_name(gid, "Scene upper-right latitude");
131  if (attr < 0) {
132  H5Gclose(gid);
133  return -1;
134  }
135  herr = H5Aread(attr, H5T_NATIVE_FLOAT, &urLat);
136  H5Aclose(attr);
137  if (herr < 0) {
138  H5Gclose(gid);
139  return -4;
140  }
141 
142  attr = H5Aopen_name(gid, "Scene upper-right longitude");
143  if (attr < 0) {
144  H5Gclose(gid);
145  return -1;
146  }
147  herr = H5Aread(attr, H5T_NATIVE_FLOAT, &urLon);
148  H5Aclose(attr);
149  if (herr < 0) {
150  H5Gclose(gid);
151  return -4;
152  }
153 
154  PJ *pj;
155  PJ_COORD c, c_ll, c_ur;
156 
157  // init the proj4 projections
158  sprintf(projStr, "+proj=ortho +ellps=WGS84 +datum=WGS84 +lon_0=%g +lat_0=%g +a=%g +b=%g",
159  centralLon, centralLat, equitorialRadius, polarRadius);
160  pj = proj_create_crs_to_crs(PJ_DEFAULT_CTX,
161  projStr,
162  "+proj=longlat +ellps=WGS84 +datum=WGS84",
163  NULL);
164  if(pj == NULL) {
165  printf("Error - GOCI first PROJ projection failed to init\n");
166  exit(1);
167  }
168  l1b->pj = proj_normalize_for_visualization(PJ_DEFAULT_CTX, pj);
169  if(l1b->pj == NULL) {
170  printf("Error - GOCI visualization PROJ projection failed to init\n");
171  exit(1);
172  }
173  proj_destroy(pj);
174 
175  // calculate start and delta for grid
176  // set default z and t
177  c.xyzt.z = 0.0;
178  c.xyzt.t = HUGE_VAL;
179 
180  c.xy.x = llLon;
181  c.xy.y = llLat;
182  c_ll = proj_trans(l1b->pj, PJ_INV, c);
183 
184  c.xy.x = urLon;
185  c.xy.y = urLat;
186  c_ur = proj_trans(l1b->pj, PJ_INV, c);
187 
188  l1b->startX = c_ll.xy.x;
189  l1b->startY = c_ur.xy.y;
190  l1b->deltaX = (c_ur.xy.x - c_ll.xy.x) / l1b->npixels;
191  l1b->deltaY = (c_ll.xy.y - c_ur.xy.y) / l1b->nscans;
192 
193  return 0;
194 
195 }
196 
204 void
206  proj_destroy(l1b->pj);
207 }
208 
225 int
226 goci_l1b_open(const char *src_path, goci_l1b_t **goci_l1b) {
227  goci_l1b_t *l1b = NULL;
228 
229  hsize_t dims[3];
230  herr_t herr;
231  htri_t exists;
232  hid_t fid, gid;
233  hid_t loc_id, dset_id[8];
234  hid_t space, dset;
235  float cpos[3], radius_in_xy;
236 
237 
238  char *fields[] = {"Band 1 Image Pixel Values",
239  "Band 2 Image Pixel Values",
240  "Band 3 Image Pixel Values",
241  "Band 4 Image Pixel Values",
242  "Band 5 Image Pixel Values",
243  "Band 6 Image Pixel Values",
244  "Band 7 Image Pixel Values",
245  "Band 8 Image Pixel Values"};
246  int i;
247  int32_t slot_nav_avail; // is the slot navigation good?
248  static float slot_rel_time[16]; // relative time of each slot to start
249  unsigned char *slot_asg; // array of slot numbers for scene pixels
250 
251  // open GOCI file
252 
253  fid = H5Fopen(src_path, H5F_ACC_RDONLY, H5P_DEFAULT);
254  if (fid < 0)
255  return -1;
256 
257  gid = H5Gopen(fid, "/", H5P_DEFAULT);
258  if (gid < 0) {
259  herr = H5Fclose(fid);
260  if (herr < 0)
261  return -2;
262  return -1;
263  }
264 
265  // open group that holds GRIDS fields;
266  loc_id = -1;
267  exists = H5Lexists(gid, "HDFEOS/GRIDS/Image Data/Data Fields", H5P_DEFAULT);
268  if (exists > 0)
269  loc_id = H5Gopen(gid, "HDFEOS/GRIDS/Image Data/Data Fields", H5P_DEFAULT);
270 
271  if (loc_id < 0)
272  goto grid_error;
273 
274  // open each data set in the group
275  for (i = 0; i < 8; i++) {
276 
277  dset = H5Dopen(loc_id, fields[i], H5P_DEFAULT);
278  if (dset < 0)
279  goto grid_error;
280 
281  dset_id[i] = dset;
282  }
283  H5Gclose(loc_id);
284 
285  // make object
286 
287  l1b = (goci_l1b_t *) malloc(sizeof (goci_l1b_t));
288  if (l1b == NULL) {
289  H5Gclose(gid);
290  H5Fclose(fid);
291  return -5;
292  }
293 
294  l1b->fid = fid;
295  l1b->gid = gid;
296  // l1b->loc_id = loc_id;
297  for (i = 0; i < 8; i++)
298  l1b->dset_id[i] = dset_id[i];
299 
300  // set file extents from first band
301 
302  space = H5Dget_space(dset_id[0]);
303  if (space < 0)
304  goto grid_error;
305  H5Sget_simple_extent_dims(space, dims, NULL);
306 
307  l1b->nbands = 8;
308  l1b->npixels = dims[1];
309  l1b->nscans = dims[0];
310 
311  l1b->pj = NULL;
312 
313  // get satellite position at scene center
314  herr = H5LTget_attribute_float(l1b->gid, "HDFEOS/POINTS/Ephemeris",
315  "Satellite position XYZ (ECEF) at scene center time", cpos);
316  if (herr < 0)
317  goto grid_error;
318 
319  // convert ( radius, sub-sat lon, sub-sat lat ) to position
320  // (note that lat, lon already in radians)
321  l1b->sat_pos[2] = cpos[0] * sin(cpos[2]) / 1000.; // z
322  radius_in_xy = cpos[0] * cos(cpos[2]) / 1000.;
323  l1b->sat_pos[1] = radius_in_xy * sin(cpos[1]); // y
324  l1b->sat_pos[0] = radius_in_xy * cos(cpos[1]); // x
325 
326  // set up goci slot navigation for time derivation
327  if ((slot_asg = (unsigned char *)
328  malloc(dims[0] * dims[1] * sizeof ( unsigned char))) == NULL) {
329  printf("%s,%d:E Unable to allocate space for slot_asg array\n",
330  __FILE__, __LINE__);
331  goto grid_error;
332  }
333  if (goci_slot_init(fid, dims, slot_rel_time, slot_asg, &slot_nav_avail)
334  != 0)
335  goto grid_error;
336  l1b->slot_nav_avail = slot_nav_avail;
337  l1b->slot_rel_time = slot_rel_time;
338  l1b->slot_asg = slot_asg;
339 
340  *goci_l1b = l1b;
341 
342  return 0;
343 
344  // We had an error reading the grid projection information
345 
346 grid_error:
347  if (l1b)
348  free(l1b);
349  herr = H5Gclose(gid);
350  if (herr < 0) {
351  H5Fclose(fid);
352  return -2;
353  }
354  herr = H5Fclose(fid);
355  if (herr < 0)
356  return -2;
357  return -3;
358 }
359 
369 int
371  herr_t herr;
372  int i;
373 
374  // close all data sets
375 
376  for (i = 0; i < 8; i++)
377  herr = H5Dclose(goci_l1b->dset_id[i]);
378  if (herr < 0)
379  return -2;
380 
381  // close GRIDS Fields group
382 
383  // herr = H5Gclose( goci_l1b->loc_id );
384  // if ( herr < 0 )
385  // return -2;
386 
387  // close file
388 
389  herr = H5Gclose(goci_l1b->gid);
390  if (herr < 0)
391  return -2;
392  herr = H5Fclose(goci_l1b->fid);
393  if (herr < 0)
394  return -2;
395 
396  free(goci_l1b);
397 
398  return 0;
399 }
400 
414 int
415 goci_l1b_get_date(goci_l1b_t *goci_l1b, char *tstr_name, int *year,
416  int *month, int *day) {
417 
418  struct tm time;
419  herr_t herr;
420 
421  char str[32];
422 
423  // For example, 12-APR-2011 02:15:38.398
424  herr = H5LTget_attribute_string(goci_l1b->gid, "HDFEOS/POINTS/Ephemeris",
425  tstr_name, str);
426  if (herr < 0)
427  return -3;
428 
429  strptime(str, "%d-%B-%Y %H:%M:%S.%f", &time);
430 
431  *year = time.tm_year + 1900;
432  *month = time.tm_mon + 1;
433  *day = time.tm_mday;
434 
435  return 0;
436 }
437 
451 int
452 goci_l1b_get_time(goci_l1b_t *goci_l1b, char *tstr_name, int *hour, int *min,
453  int *sec) {
454  struct tm time;
455  herr_t herr;
456 
457  char str[32];
458 
459  // For example, 12-APR-2011 02:15:38.398
460  herr = H5LTget_attribute_string(goci_l1b->gid, "HDFEOS/POINTS/Ephemeris", tstr_name, str);
461  if (herr < 0) {
462  fprintf(stderr, "H5Lt failed\n");
463  return -3;
464  }
465  strptime(str, "%d-%B-%Y %H:%M:%S.%f", &time);
466 
467  *hour = time.tm_hour;
468  *min = time.tm_min;
469  *sec = time.tm_sec;
470 
471  return 0;
472 }
473 
487 int
488 goci_l1b_get_band(goci_l1b_t *goci_l1b, int band, int line, uint32_t *buf) {
489  hsize_t start[2], count[2], dims[2];
490  herr_t herr;
491  hid_t space_file, space_mem;
492 
493  if (band < 0 || band > 7)
494  return -6;
495 
496  // get data space of file
497  space_file = H5Dget_space(goci_l1b->dset_id[band]);
498  if (space_file < 0)
499  return -4;
500  H5Sget_simple_extent_dims(space_file, dims, NULL);
501 
502  start[0] = line;
503  start[1] = 0;
504 
505  count[0] = 1;
506  count[1] = dims[1];
507 
508  // define a memory space
509 
510  space_mem = H5Screate_simple(2, count, NULL);
511  if (space_mem < 0)
512  return -4;
513  H5Sselect_all(space_mem);
514 
515  // define hyperslab
516 
517  herr = H5Sselect_hyperslab(space_file, H5S_SELECT_SET, start, NULL, count, NULL);
518  if (herr < 0) {
519  fprintf(stderr, "error reading %d\n", line);
520  return -4;
521  }
522 
523  // read line
524 
525  herr = H5Dread(goci_l1b->dset_id[band], H5T_STD_U32LE, space_mem, space_file, H5P_DEFAULT, buf);
526  if (herr < 0) {
527  fprintf(stderr, "error reading %d\n", line);
528  return -4;
529  }
530 
531  H5Sclose(space_mem);
532  return 0;
533 }
int32_t slot_nav_avail
Definition: goci.h:32
int goci_l1b_get_time(goci_l1b_t *goci_l1b, char *tstr_name, int *hour, int *min, int *sec)
read a time of GOCI data
Definition: goci.c:452
double startY
Definition: goci.h:22
double deltaY
Definition: goci.h:24
int32_t day
These are used to scale the SD before writing it to the HDF4 file The default is and which means the product is not scaled at all Since the product is usually stored as a float inside of this is a way to write the float out as a integer l2prod min
#define NULL
Definition: decode_rs.h:63
double deltaX
Definition: goci.h:23
PARAM_TYPE_NONE Default value No parameter is buried in the product name name_prefix is case insensitive string compared to the product name PARAM_TYPE_VIS_WAVE The visible wavelength bands from the sensor are buried in the product name The product name is compared by appending and name_suffix ie aph_412_giop where prod_ix will be set to PARAM_TYPE_IR_WAVE same search method as PARAM_TYPE_VIS_WAVE except only wavelength above are looped through but prod_ix is still based ie aph_2_giop for the second band
int goci_l1b_get_band(goci_l1b_t *goci_l1b, int band, int line, uint32_t *buf)
read specified band and line from GOCI file.
Definition: goci.c:488
float tm[MODELMAX]
void goci_proj4_close(goci_l1b_t *l1b)
free all memory related to proj4
Definition: goci.c:205
hid_t fid
Definition: goci.h:29
PJ * pj
Definition: goci.h:20
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 thereby resolving MODur00108 Changed header guard macro names to avoid reserved name space
Definition: HISTORY.txt:268
int goci_l1b_open(const char *src_path, goci_l1b_t **goci_l1b)
open GOCI bands
Definition: goci.c:226
float * slot_rel_time
Definition: goci.h:33
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 fields
Definition: HISTORY.txt:400
int nscans
Definition: goci.h:17
int32_t goci_slot_init(hid_t file_id, hsize_t *dims, float *slot_rel_time, unsigned char *slot_asg, int32_t *slot_nav_avail)
Definition: goci_slot.c:20
int goci_l1b_close(goci_l1b_t *goci_l1b)
close GOCI bands
Definition: goci.c:370
GOCI file format reader.
const char * str
Definition: l1c_msi.cpp:35
hid_t dset_id[8]
Definition: goci.h:31
double startX
Definition: goci.h:21
hid_t gid
Definition: goci.h:30
int goci_proj4_open(goci_l1b_t *l1b)
init proj4 for GOCI geolocation
Definition: goci.c:31
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
unsigned char * slot_asg
Definition: goci.h:34
int nbands
Definition: goci.h:18
int goci_l1b_get_date(goci_l1b_t *goci_l1b, char *tstr_name, int *year, int *month, int *day)
read a date of GOCI data
Definition: goci.c:415
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
float sat_pos[3]
Definition: goci.h:25
int i
Definition: decode_rs.h:71
int npixels
Definition: goci.h:16
int count
Definition: decode_rs.h:79