OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
snpp_diary_to_llh.c
Go to the documentation of this file.
1 // procedure to read an SNPP S/C diary file and generate an LLH
2 // ephemeris file in the Aquarius CODS format.
3 
4 // Arguments
5 //
6 // Name Type I/O Description
7 // ---- ---- --- -----------
8 // sfile string I S/C diary packet file name
9 // ofile string O LLH output file name
10 
11 // Liang Hong, Jan 14, 2016, Ported from IDL
12 // V0.1, Feb 1, 2016
13 // V0.2, Dec 21, 2018, Liang Hong, added error catch when altitude is < 100 km
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <sys/stat.h>
19 #include <math.h>
20 #include <libgen.h>
21 #include <timeutils.h>
22 #include "snpp_diary_to_llh.h"
23 
24 #define VERSION "0.2"
25 #define MIN_ALT 100
26 #define FILL_VALUE -9999
27 
28 int main(int argc, char *argv[]) {
29  printf("snpp_diary_to_llh Version: %s (%s %s)\n", VERSION, __DATE__, __TIME__);
30  int c, i, j;
31  int nResampled1mn; // count only the packtes that are closest to 1 minute time tag
32  char *sfile = NULL;
33  char *ofile = NULL;
34 
35  int32_t jd0, iyr, iday;
36  int16_t mon, idm, iy, ih, mn, mm, dd;
37  double usec, secm;
38  double otime[MAX_RECORDS];
39  double orb[6 * MAX_RECORDS];
40  double atime[MAX_RECORDS];
41  double quat[4 * MAX_RECORDS];
42  double lon[MAX_RECORDS];
43  double lat[MAX_RECORDS];
44  double alt[MAX_RECORDS];
45  int32_t jd[MAX_RECORDS];
46  int result = 1;
47  int nErr_val_out_of_range = 0;
48 
49  while ((c = getopt(argc, argv, "s:o:")) != -1)
50  switch (c) {
51  case 's':
52  sfile = optarg;
53  break;
54  case 'o':
55  ofile = optarg;
56  break;
57  case '?':
58  if (optopt == 's')
59  fprintf(stderr, "Option -s requires an argument.\n");
60  else if (optopt == 'o')
61  fprintf(stderr, "Option -o requires an argument.\n");
62  else
63  fprintf(stderr,
64  "Unknown option character `\\x%x'.\n",
65  optopt);
66  return 1;
67  default:
68  abort();
69  }
70 
71  FILE *infile, *outfile;
72 
73  infile = fopen(sfile, "r");
74  if (infile == NULL) {
75  printf("Unable to open input S/C diary packet file.\n");
76  printf("usage: snpp_diary_to_llh -s S/C_diary_packet_file -o llh_output_file\n");
77  return 1;
78  }
79  printf("Opened S/C diary packet file %s\n", sfile);
80  struct stat st;
81  stat(sfile, &st);
82  int nscd = st.st_size / 71;
83  uint8_t scdpkts[71 * nscd];
84  fread(scdpkts, 1, 71 * nscd, infile);
85  fclose(infile);
86 
87 
88  // Get start year and day
89  //jd0 = swap_endian(fix(dstore(6:7,0),0)) + 2436205 ;Days since 1/1/1958
90  jd0 = (scdpkts[0 * 71 + 6] << 8) + (scdpkts[0 * 71 + 7]) + 2436205;
91  jdate(jd0, &iyr, &iday);
92 
93  // Unpack and convert diary data
94  result = convert_diary(nscd, scdpkts, otime, orb, atime, quat);
95  if (result != 0) {
96  printf("diary data conversion problem!\n");
97  return 1;
98  }
99 
100  // Find records closest to the minute from the right. e.g. use 01:02:02 in stead of 01:01:59
101  nResampled1mn = 0;
102  double new_otime[MAX_RECORDS], new_orb[6 * MAX_RECORDS], min_dotime, tmp_dotime, curr1m, omm;
103  min_dotime = 6000; // otime - round_otime_to_closest_1_minute, in seconds
104  curr1m = round(otime[0] / 60.0)*60.0;
105  new_otime[0] = otime[0];
106  for (j = 0; j < 6; j++) new_orb[j + 0 * 6] = orb[j + 0 * 6];
107 
108  for (i = 1; i < nscd; i++) {
109  // omm = round(otime[i]/60.0)*60.0;
110  // tmp_dotime = fabs(otime[i] - omm);
111  omm = floor(otime[i] / 60.0)*60.0;
112  tmp_dotime = otime[i] - omm;
113  if (omm > curr1m) {
114  curr1m = omm;
115  min_dotime = tmp_dotime;
116  nResampled1mn++;
117  new_otime[nResampled1mn] = otime[i];
118  for (j = 0; j < 6; j++) new_orb[j + nResampled1mn * 6] = orb[j + i * 6] / 1000.0;
119  } else {
120  if (tmp_dotime < min_dotime) {
121  new_otime[nResampled1mn] = otime[i];
122  for (j = 0; j < 6; j++) new_orb[j + nResampled1mn * 6] = orb[j + i * 6] / 1000.0;
123  min_dotime = tmp_dotime;
124  }
125  }
126  }
127 
128  result = orb2lla(nResampled1mn, new_orb, lon, lat, alt);
129  if (result != 0) {
130  printf("orbit to lon, lat and alt conversion problem!\n");
131  return 1;
132  }
133 
134  // Check for day rollover
135  for (i = 0; i < nResampled1mn; i++) {
136  jd[i] = jday(iyr, 1, iday);
137  jd[i] = jd[i] + (int32_t) (new_otime[i] / 86400.0);
138  new_otime[i] = new_otime[i] - floor(new_otime[i] / 86400.0)*86400.0;
139  }
140 
141  // Generate output file name
142  jdate(jd[nResampled1mn - 1], &iyr, &iday);
143  yd2md((int16_t) iyr, (int16_t) iday, &mon, &idm);
144  //sod2hms,sec,ih,mn,secm
145  usec = yds2unix((int16_t) iyr, (int16_t) iday, new_otime[nResampled1mn - 1]);
146  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &secm);
147  //sprintf(cfile,"GSFC_%4d%02d%02d_%02d%02d%02d_SNPP_ORBEPHEM_GEOD_LLH_O.TXT", iyr, mon, idm, ih, mn, (int)secm);
148  //printf("cfile=%s\n",cfile);
149 
150  // no valid packets in input file
151  if (nResampled1mn<1) {
152  printf("Corrupted input file, no valid packets!\n");
153  return 1;
154  }
155 
156  // open llh output file
157  outfile = fopen(ofile, "w");
158  if (outfile == NULL) {
159  printf("Unable to open output file.\n");
160  return 1;
161  }
162  fprintf(outfile, "basename=%s\n", basename(sfile));
163  //printf("basename = %s\n",basename(sfile));
164 
165  // Output header record
166  fprintf(outfile, "*HEADER SNPP %d LLH UTC WGS84 PRO 37849 11061A GSFC %d/%02d/%02d %02d:%02d:%02d\n", nscd, iyr, mon, idm, ih, mn, (int) secm);
167 
168  // Output data records
169  for (i = 0; i < nResampled1mn; i++) {
170  jdate(jd[i], &iyr, &iday);
171  yd2md((int16_t) iyr, (int16_t) iday, &mon, &idm);
172  usec = yds2unix(iyr, iday, new_otime[i]);
173  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &secm);
174  if (alt[i]<MIN_ALT) {
175  lat[i] = FILL_VALUE;
176  lon[i] = FILL_VALUE;
177  alt[i] = FILL_VALUE; // fill value for bogus altitude
178  nErr_val_out_of_range++;
179  }
180  fprintf(outfile, "%d/%02d/%02d %02d:%02d:%011.8f %15.5f %15.5f %15.3f\n", iyr, mon, idm, ih, mn, secm, lat[i], lon[i], alt[i]);
181  }
182  fclose(outfile);
183 
184  printf("Total LLH output: %d\n", nResampled1mn);
185  if (nErr_val_out_of_range>0) printf("Records with value out of range: %d\n", nErr_val_out_of_range);
186 
187  return 0;
188 }
#define MIN_ALT
int j
Definition: decode_rs.h:73
double yds2unix(int16_t year, int16_t day, double secs)
Definition: yds2unix.c:7
#define MAX_RECORDS
#define NULL
Definition: decode_rs.h:63
float * lat
int jdate(int32_t julian, int32_t *year, int32_t *doy)
Definition: jdate.c:5
int32_t jday(int16_t i, int16_t j, int16_t k)
Definition: jday.c:4
int main(int argc, char *argv[])
void yd2md(int16_t year, int16_t doy, int16_t *month, int16_t *dom)
Definition: yd2md.c:6
int convert_diary(int npkts, uint8_t dstore[], double otime[], double orb[], double atime[], double quat[])
Definition: convert_diary.c:20
int orb2lla(int nRecords, double orb[], double lon[], double lat[], double alt[])
Definition: orb2lla.c:21
Definition: jd.py:1
int32_t ih
Definition: atrem_corl1.h:161
#define basename(s)
Definition: l0chunk_modis.c:29
#define VERSION
float * lon
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
void unix2ymdhms(double usec, int16_t *year, int16_t *mon, int16_t *day, int16_t *hour, int16_t *min, double *sec)
Definition: unix2ymdhms.c:8
int i
Definition: decode_rs.h:71
int32_t iyr
Definition: atrem_corl1.h:161
#define FILL_VALUE