OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
scan_cvt.c
Go to the documentation of this file.
1 #include "viirs_sim_sdr.h"
2 #include <math.h>
3 #include <stdlib.h>
4 
5 int scan_cvt(in_rec_struc *in_rec, out_rec_struc *out_rec)
6 /*-----------------------------------------------------------------------------
7  scan_cvt
8 
9  purpose: make proper output record from the input record
10  based on the scan formats for both
11 
12  Returns type: int - 0 if good
13 
14  Parameters (in calling order):
15  Type Name I/O Description
16  ---- ---- --- -----------
17  in_rec_struc * in_rec I/O controls for input record reading
18  out_rec_struc * out_rec I/O controls for output file writing
19 
20  Modification history:
21 
22  W. Robinson, SAIC 29 Apr 2010 Original development
23  W. Robinson, SAIC 18 Nov 2010 create the QF1_VIIRSMBANDSDR value in
24  out_rec array qual1_m from saturation and gain info in in_rec
25 
26 ----------------------------------------------------------------------------*/ {
27  static int cvt_mode = -1; /* conversion mode for this run: -1 not started,
28  0 - no conversion, 1 - make aggregated,
29  2 - make unaggregated */
30  static int npixin, npixout;
31  static float *cvt_lat, *cvt_lon, *cvt_senz, *cvt_sena, *cvt_solz, *cvt_sola,
32  *cvt_bnd_lt[MAX_BND];
33  int ibnd, ilin, olin, opix, nxfr, nxfrb, ipix_st, ag_rng, num, iag, ipix;
34  float theta1, theta2, theta, phi1, phi2, phi, sum;
35  static unsigned char *cvt_bnd_q[MAX_BND];
36  unsigned char uc_val, ua_gain_vals[] = {4, 0};
37  unsigned char ua_sat_vals[] = {0, 8};
38  int v_unsat, v_sat, ag_sat_vals[] = {8, 0, 8, 4};
39 
40  /*
41  * if in_rec->lat is null, this is signal to for end, so free local storage
42  */
43  if (in_rec->lat == NULL) {
44  free(cvt_lat);
45  free(cvt_lon);
46  free(cvt_senz);
47  free(cvt_sena);
48  free(cvt_solz);
49  free(cvt_sola);
50  for (ibnd = 0; ibnd < out_rec->nbnd; ibnd++) {
51  free(cvt_bnd_lt[ibnd]);
52  free(cvt_bnd_q[ibnd]);
53  }
54  return 0;
55  }
56  /*
57  * initialization phase
58  */
59  if (cvt_mode == -1) {
60  /*
61  * determine the conversion mode based on the input scan format and
62  * requested output scan format change
63  */
64  if ((in_rec->scn_fmt == 1) && (out_rec->scn_fmt == 0))
65  cvt_mode = 1;
66  else if ((in_rec->scn_fmt == 2) && (out_rec->scn_fmt == 0))
67  cvt_mode = 1;
68  else if ((in_rec->scn_fmt == 2) && (out_rec->scn_fmt == 1))
69  cvt_mode = 2;
70  else {
71  cvt_mode = 0;
72  }
73  if (cvt_mode != 0) {
74  /*
75  * A conversion is needed for all scans. allocate space for
76  * the converted data and re-assign it to the out_rec locations
77  * (from default done in init_sdr with in_rec)
78  */
79  npixin = in_rec->npix;
80  npixout = out_rec->npix;
81  if ((cvt_lat = (float *)
82  malloc(out_rec->npix * out_rec->ndet_scan * sizeof (float)))
83  == NULL) {
84  printf("%s, %d: Unable to allocate storage for lat conversion\n",
85  __FILE__, __LINE__);
86  return 1;
87  }
88  out_rec->lat = cvt_lat;
89  if ((cvt_lon = (float *)
90  malloc(out_rec->npix * out_rec->ndet_scan * sizeof (float)))
91  == NULL) {
92  printf("%s, %d: Unable to allocate storage for lon conversion\n",
93  __FILE__, __LINE__);
94  return 1;
95  }
96  out_rec->lon = cvt_lon;
97  if ((cvt_senz = (float *)
98  malloc(out_rec->npix * out_rec->ndet_scan * sizeof (float)))
99  == NULL) {
100  printf("%s, %d: Unable to allocate storage for senz conversion\n",
101  __FILE__, __LINE__);
102  return 1;
103  }
104  out_rec->senz = cvt_senz;
105  if ((cvt_sena = (float *)
106  malloc(out_rec->npix * out_rec->ndet_scan * sizeof (float)))
107  == NULL) {
108  printf("%s, %d: Unable to allocate storage for sena conversion\n",
109  __FILE__, __LINE__);
110  return 1;
111  }
112  out_rec->sena = cvt_sena;
113  if ((cvt_solz = (float *)
114  malloc(out_rec->npix * out_rec->ndet_scan * sizeof (float)))
115  == NULL) {
116  printf("%s, %d: Unable to allocate storage for solz conversion\n",
117  __FILE__, __LINE__);
118  return 1;
119  }
120  out_rec->solz = cvt_solz;
121  if ((cvt_sola = (float *)
122  malloc(out_rec->npix * out_rec->ndet_scan * sizeof (float)))
123  == NULL) {
124  printf("%s, %d: Unable to allocate storage for sola conversion\n",
125  __FILE__, __LINE__);
126  return 1;
127  }
128  out_rec->sola = cvt_sola;
129  for (ibnd = 0; ibnd < out_rec->nbnd; ibnd++) {
130  if ((cvt_bnd_lt[ibnd] = (float *)
131  malloc(out_rec->npix * out_rec->ndet_scan * sizeof (float)))
132  == NULL) {
133  printf(
134  "%s, %d: Unable to allocate storage for bnd_lt[%d] conversion\n",
135  __FILE__, __LINE__, ibnd);
136  return 1;
137  }
138  out_rec->bnd_lt[ibnd] = cvt_bnd_lt[ibnd];
139  /*
140  */
141  if ((cvt_bnd_q[ibnd] = (unsigned char *)
142  malloc(out_rec->npix * out_rec->ndet_scan *
143  sizeof (unsigned char))) == NULL) {
144  printf(
145  "%s, %d: Unable to allocate storage for bnd_q[%d] conversion\n",
146  __FILE__, __LINE__, ibnd);
147  return 1;
148  }
149  out_rec->bnd_q[ibnd] = cvt_bnd_q[ibnd];
150  }
151  }
152  }
153  /*
154  * work on different conversion modes
155  */
156  if (cvt_mode == 0) {
157  /*
158  * if the data is aggregated, set up qual1_m from the dn_sat * 4
159  * (most likely, dn_sat always 0 in this case, but if not, we'll
160  * assume the 3 state format for the standard saturation field)
161  */
162  if (out_rec->scn_fmt == 0) {
163  for (ibnd = 0; ibnd < in_rec->nbnd; ibnd++) {
164  for (ilin = 0; ilin < in_rec->ndet_scan; ilin++) {
165  for (ipix = 0; ipix < in_rec->npix; ipix++) {
166  *(out_rec->qual1_m[ibnd] + ipix + in_rec->npix * ilin) =
167  *(in_rec->dn_sat[ibnd] + ipix + in_rec->npix * ilin) * 4;
168  }
169  }
170  }
171  } /*
172  * if the data is un-aggregated, fold the gain and sat into qual1_m
173  * bit 2 = gain 0 hi, 1 lo, bit 3 = sat 0 not, 1 saturated
174  */
175  else {
176  for (ibnd = 0; ibnd < in_rec->nbnd; ibnd++) {
177  for (ilin = 0; ilin < in_rec->ndet_scan; ilin++) {
178  for (ipix = 0; ipix < in_rec->npix; ipix++) {
179  uc_val = ua_gain_vals[ *(in_rec->gain_bit[ibnd] + ipix +
180  in_rec->npix * ilin) ];
181  uc_val = uc_val | ua_sat_vals[ (int) *(in_rec->dn_sat[ibnd] + ipix +
182  in_rec->npix * ilin) ];
183  *(out_rec->qual1_m[ibnd] + ipix + in_rec->npix * ilin) = uc_val;
184  }
185  }
186  }
187  }
188  return 0;
189  } else if (cvt_mode == 2) {
190  /*
191  * mode 2 will go from margin to unaggregated, so move to proper storage
192  */
193  nxfr = npixout * sizeof (float);
194  nxfrb = npixout * sizeof (unsigned char);
195  for (olin = 0, ilin = in_rec->margin[0]; olin < NDET; olin++, ilin++) {
196  memcpy((void *) (cvt_lat + npixout * olin),
197  (void *) (in_rec->lat + npixin * ilin + in_rec->margin[1]), nxfr);
198  memcpy((void *) (cvt_lon + npixout * olin),
199  (void *) (in_rec->lon + npixin * ilin + in_rec->margin[1]), nxfr);
200  memcpy((void *) (cvt_sena + npixout * olin),
201  (void *) (in_rec->sena + npixin * ilin + in_rec->margin[1]), nxfr);
202  memcpy((void *) (cvt_senz + npixout * olin),
203  (void *) (in_rec->senz + npixin * ilin + in_rec->margin[1]), nxfr);
204  memcpy((void *) (cvt_sola + npixout * olin),
205  (void *) (in_rec->sola + npixin * ilin + in_rec->margin[1]), nxfr);
206  memcpy((void *) (cvt_solz + npixout * olin),
207  (void *) (in_rec->solz + npixin * ilin + in_rec->margin[1]), nxfr);
208  for (ibnd = 0; ibnd < out_rec->nbnd; ibnd++) {
209  memcpy((void *) (cvt_bnd_lt[ibnd] + npixout * olin),
210  (void *) (in_rec->bnd_lt[ibnd] + npixin * ilin + in_rec->margin[1]),
211  nxfr);
212  memcpy((void *) (cvt_bnd_q[ibnd] + npixout * olin),
213  (void *) (in_rec->bnd_q[ibnd] + npixin * ilin + in_rec->margin[1]),
214  nxfrb);
215  /*
216  * handle the conversion and transfer of saturation and gain
217  */
218  for (ipix = in_rec->margin[1], opix = 0;
219  ipix < in_rec->npix - in_rec->margin[1]; ipix++, opix++) {
220  uc_val = ua_gain_vals[ *(in_rec->gain_bit[ibnd] + ipix +
221  in_rec->npix * ilin) ];
222  uc_val = uc_val | ua_sat_vals[ (int) *(in_rec->dn_sat[ibnd] + ipix +
223  in_rec->npix * ilin) ];
224  *(out_rec->qual1_m[ibnd] + opix + npixout * olin) = uc_val;
225  }
226  }
227  }
228  } else if (cvt_mode == 1) {
229  /*
230  * mode 1 will involve aggregating and possibly trimming off the margins
231  * Method for aggregating depends on the agg zone:
232  * ZONE (scan location)
233  * PARM 1:1 agg (edge) 2:1 agg 3:1 agg (center)
234  * -------
235  * lat, lon, Just 'Angle Use center
236  * view angles Transfer Average' angle
237  *
238  * Lt data values Average Average
239  * 2 values 3 values
240  */
241  for (olin = 0, ilin = in_rec->margin[0]; olin < out_rec->ndet_scan;
242  olin++, ilin++) {
243  for (opix = 0; opix < npixout; opix++) {
244  if ((opix >= 0) && (opix <= 639)) {
245  ipix_st = opix + in_rec->margin[1];
246  ag_rng = 1;
247  } else if ((opix >= 640) && (opix <= 1007)) {
248  ipix_st = 640 + in_rec->margin[1] + (opix - 640) * 2;
249  ag_rng = 2;
250  } else if ((opix >= 1008) && (opix <= 2191)) {
251  ipix_st = 1376 + in_rec->margin[1] + (opix - 1008) * 3;
252  ag_rng = 3;
253  } else if ((opix >= 2192) && (opix <= 2559)) {
254  ipix_st = 4928 + in_rec->margin[1] + (opix - 2192) * 2;
255  ag_rng = 2;
256  } else if ((opix >= 2560) && (opix <= 3199)) {
257  ipix_st = 5664 + in_rec->margin[1] + opix - 2560;
258  ag_rng = 1;
259  }
260  /*
261  * Handle each agg range for the parameters
262  */
263  switch (ag_rng) {
264  case 1:
265  /*
266  * at 1:1 zones, just transfer (to proper locations)
267  */
268  *(cvt_lat + npixout * olin + opix) =
269  *(in_rec->lat + ipix_st + npixin * ilin);
270  *(cvt_lon + npixout * olin + opix) =
271  *(in_rec->lon + ipix_st + npixin * ilin);
272  *(cvt_senz + npixout * olin + opix) =
273  *(in_rec->senz + ipix_st + npixin * ilin);
274  *(cvt_sena + npixout * olin + opix) =
275  *(in_rec->sena + ipix_st + npixin * ilin);
276  *(cvt_solz + npixout * olin + opix) =
277  *(in_rec->solz + ipix_st + npixin * ilin);
278  *(cvt_sola + npixout * olin + opix) =
279  *(in_rec->sola + ipix_st + npixin * ilin);
280  for (ibnd = 0; ibnd < out_rec->nbnd; ibnd++) {
281  *(cvt_bnd_lt[ibnd] + npixout * olin + opix) =
282  *(in_rec->bnd_lt[ibnd] + ipix_st + npixin * ilin);
283  *(cvt_bnd_q[ibnd] + npixout * olin + opix) =
284  *(in_rec->bnd_q[ibnd] + ipix_st + npixin * ilin);
285  /*
286  * saturation aggregation - the unagg saturation is either 0 or 1
287  * it xlates to 0 or 2 (all sat) and at bit location it
288  * translates to 0 or 8 (x4)
289  */
290  *(out_rec->qual1_m[ibnd] + opix + npixout * olin) =
291  *(in_rec->dn_sat[ibnd] + ipix_st + npixin * ilin);
292  }
293  break;
294  case 2:
295  /*
296  * at 2:1 zones, average the radiances and treat lat, lon and
297  * view angles as vectors to find the average of
298  *
299  * Lt
300  */
301  for (ibnd = 0; ibnd < out_rec->nbnd; ibnd++) {
302  sum = 0.;
303  num = 0;
304  v_unsat = 0;
305  v_sat = 0;
306  for (iag = 0; iag < ag_rng; iag++) {
307  if (
308  (*(in_rec->bnd_lt[ibnd] + ilin * npixin + ipix_st + iag) > 0)
309  && (*(in_rec->bnd_q[ibnd] + ilin * npixin + ipix_st + iag) == 0)) {
310  sum +=
311  *(in_rec->bnd_lt[ibnd] + ilin * npixin + ipix_st + iag);
312  num++;
313  /*
314  * see if saturated or unsaturated or both - the v_unsat and
315  * v_sat work together with ag_sat_vals to set proper value
316  */
317  if (*(in_rec->dn_sat[ibnd] + ilin + npixin + ipix_st + iag)
318  == 0) v_unsat = 1;
319  if (*(in_rec->dn_sat[ibnd] + ilin + npixin + ipix_st + iag)
320  == 1) v_sat = 2;
321  }
322  }
323  if (num > 0) {
324  *(cvt_bnd_lt[ibnd] + npixout * olin + opix) = sum / num;
325  *(cvt_bnd_q[ibnd] + npixout * olin + opix) = 0;
326  } else {
327  *(cvt_bnd_lt[ibnd] + npixout * olin + opix) = -32767.;
328  *(cvt_bnd_q[ibnd] + npixout * olin + opix) = 2;
329  }
330  /* for saturation setting */
331  *(out_rec->qual1_m[ibnd] + npixout * olin + opix) =
332  ag_sat_vals[ v_sat + v_unsat ];
333  }
334  /*
335  * lat, lon, and view angles
336  */
337  theta1 = *(in_rec->lat + ilin * npixin + ipix_st);
338  theta2 = *(in_rec->lat + ilin * npixin + ipix_st + 1);
339  phi1 = *(in_rec->lon + ilin * npixin + ipix_st);
340  phi2 = *(in_rec->lon + ilin * npixin + ipix_st + 1);
341  ang_avg(theta1, phi1, theta2, phi2, &theta, &phi);
342  *(cvt_lat + npixout * olin + opix) = theta;
343  *(cvt_lon + npixout * olin + opix) = phi;
344 
345  theta1 = *(in_rec->senz + ilin * npixin + ipix_st);
346  theta2 = *(in_rec->senz + ilin * npixin + ipix_st + 1);
347  phi1 = *(in_rec->sena + ilin * npixin + ipix_st);
348  phi2 = *(in_rec->sena + ilin * npixin + ipix_st + 1);
349  ang_avg(theta1, phi1, theta2, phi2, &theta, &phi);
350  *(cvt_senz + npixout * olin + opix) = theta;
351  *(cvt_sena + npixout * olin + opix) = phi;
352 
353  theta1 = *(in_rec->solz + ilin * npixin + ipix_st);
354  theta2 = *(in_rec->solz + ilin * npixin + ipix_st + 1);
355  phi1 = *(in_rec->sola + ilin * npixin + ipix_st);
356  phi2 = *(in_rec->sola + ilin * npixin + ipix_st + 1);
357  ang_avg(theta1, phi1, theta2, phi2, &theta, &phi);
358  *(cvt_solz + npixout * olin + opix) = theta;
359  *(cvt_sola + npixout * olin + opix) = phi;
360  break;
361  case 3:
362  /*
363  * at 3:1 zones, average 3 lt and take center angle
364  */
365  for (ibnd = 0; ibnd < out_rec->nbnd; ibnd++) {
366  sum = 0.;
367  num = 0;
368  v_unsat = 0;
369  v_sat = 0;
370  for (iag = 0; iag < ag_rng; iag++) {
371  if (
372  (*(in_rec->bnd_lt[ibnd] + ilin * npixin + ipix_st + iag) > 0)
373  && (*(in_rec->bnd_q[ibnd] + ilin * npixin + ipix_st + iag) == 0)) {
374  sum +=
375  *(in_rec->bnd_lt[ibnd] + ilin * npixin + ipix_st + iag);
376  num++;
377  /*
378  * see if saturated or unsaturated or both - the v_unsat and
379  * v_sat work together with ag_sat_vals to set proper value
380  */
381  if (*(in_rec->dn_sat[ibnd] + ilin + npixin + ipix_st + iag)
382  == 0) v_unsat = 1;
383  if (*(in_rec->dn_sat[ibnd] + ilin + npixin + ipix_st + iag)
384  == 1) v_sat = 2;
385  }
386  }
387  if (num > 0) {
388  *(cvt_bnd_lt[ibnd] + npixout * olin + opix) = sum / num;
389  *(cvt_bnd_q[ibnd] + npixout * olin + opix) = 0;
390  } else {
391  *(cvt_bnd_lt[ibnd] + npixout * olin + opix) = -32767.;
392  *(cvt_bnd_q[ibnd] + npixout * olin + opix) = 2;
393  }
394  /* for saturation setting */
395  *(out_rec->qual1_m[ibnd] + npixout * olin + opix) =
396  ag_sat_vals[ v_sat + v_unsat ];
397  }
398 
399  *(cvt_lat + npixout * olin + opix) =
400  *(in_rec->lat + ilin * npixin + ipix_st + 1);
401  *(cvt_lon + npixout * olin + opix) =
402  *(in_rec->lon + ilin * npixin + ipix_st + 1);
403  *(cvt_senz + npixout * olin + opix) =
404  *(in_rec->senz + ilin * npixin + ipix_st + 1);
405  *(cvt_sena + npixout * olin + opix) =
406  *(in_rec->sena + ilin * npixin + ipix_st + 1);
407  *(cvt_solz + npixout * olin + opix) =
408  *(in_rec->solz + ilin * npixin + ipix_st + 1);
409  *(cvt_sola + npixout * olin + opix) =
410  *(in_rec->sola + ilin * npixin + ipix_st + 1);
411  break;
412  }
413  }
414  }
415  }
416  return 0;
417 }
418 
419 int ang_avg(float theta1, float phi1, float theta2, float phi2,
420  float *theta, float *phi)
421 /*-----------------------------------------------------------------------------
422  ang_avg
423 
424  purpose: get resultant vector that is the average of 2 vectors
425 
426  Returns type: int - 0 if good
427 
428  Parameters (in calling order):
429  Type Name I/O Description
430  ---- ---- --- -----------
431  float theta1 I first zenith or lat angle in
432  degrees
433  float phi1 I first azimuth or lon angle in
434  degrees
435  float theta2 I second zenith or lat angle in
436  degrees
437  float phi2 I second azimuth or lon angle in
438  degrees
439  float * theta O resultant zenith or lat angle in
440  degrees
441  float * phi O result azimuth or lon angle in
442  degrees
443 
444  Modification history:
445 
446  W. Robinson, SAIC 4 May 2010 Original development
447 
448 ----------------------------------------------------------------------------*/ {
449  float v1[2], v2[2], v[2];
450  float rad2deg = 180. / M_PI;
451  /*
452  * convert to just the x, y parts of a vector - this assumes all are
453  * unit length
454  *** don't know why but sinf, cosf... do not work, so use less compatible
455  with floats sin, cos (gcc?)
456  */
457  v1[0] = sin(theta1 / rad2deg) * cos(phi1 / rad2deg);
458  v1[1] = sin(theta1 / rad2deg) * sin(phi1 / rad2deg);
459 
460  v2[0] = sin(theta2 / rad2deg) * cos(phi2 / rad2deg);
461  v2[1] = sin(theta2 / rad2deg) * sin(phi2 / rad2deg);
462 
463  /* average the vectors and return to unit length */
464  v[0] = (v1[0] + v2[0]) / 2.;
465  v[1] = (v1[1] + v2[1]) / 2.;
466 
467  /* go back to angles */
468  *theta = asin(sqrt(v[0] * v[0] + v[1] * v[1])) * rad2deg;
469  *phi = atan2(v[1], v[0]) * rad2deg;
470 
471  return 0;
472 }
#define NULL
Definition: decode_rs.h:63
#define MAX_BND
Definition: viirs_sim_sdr.h:34
int ang_avg(float theta1, float phi1, float theta2, float phi2, float *theta, float *phi)
Definition: scan_cvt.c:419
#define M_PI
Definition: pml_iop.h:15
int scan_cvt(in_rec_struc *in_rec, out_rec_struc *out_rec)
Definition: scan_cvt.c:5
an array had not been initialized Several spelling and grammar corrections were which is read from the appropriate MCF the above metadata values were hard coded A problem calculating the average background DN for SWIR bands when the moon is in the space view port was corrected The new algorithm used to calculate the average background DN for all reflective bands when the moon is in the space view port is now the same as the algorithm employed by the thermal bands For non SWIR changes in the averages are typically less than Also for non SWIR the black body DNs remain a backup in case the SV DNs are not available For SWIR the changes in computed averages were larger because the old which used the black body suffered from contamination by the micron leak As a consequence of the if SV DNs are not available for the SWIR the EV pixels will not be the granule time is used to identify the appropriate tables within the set given for one LUT the first two or last two tables respectively will be used for the interpolation If there is only one LUT in the set of it will be treated as a constant LUT The manner in which Earth View data is checked for saturation was changed Previously the raw Earth View DNs and Space View DNs were checked against the lookup table values contained in the table dn_sat The change made is to check the raw Earth and Space View DNs to be sure they are less than the maximum saturation value and to check the Space View subtracted Earth View dns against a set of values contained in the new lookup table dn_sat_ev The metadata configuration and ASSOCIATEDINSTRUMENTSHORTNAME from the MOD02HKM product The same metatdata with extensions and were removed from the MOD021KM and MOD02OBC products ASSOCIATEDSENSORSHORTNAME was set to MODIS in all products These changes are reflected in new File Specification which users may consult for exact the pow functions were eliminated in Emissive_Cal and Emissive bands replaced by more efficient code Other calculations throughout the code were also made more efficient Aside from a few round off there was no difference to the product The CPU time decreased by about for a day case and for a night case A minor bug in calculating the uncertainty index for emissive bands was corrected The frame the required RAM for each execution is MB on the DEC ALPHA and MB on the SGI Octane v2
Definition: HISTORY.txt:728
#define NDET
Definition: polcor.c:13
const double rad2deg
int npix
Definition: get_cmp.c:27