OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
polcor.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /* module polcor.c - functions to read and apply polarization correction */
3 /* */
4 /* Written By: B. Franz, SAIC, November 2005. */
5 /* W. Robinson, SAIC, 29 May 2009 generalize for use with VIIRS */
6 /* ========================================================================== */
7 
8 #include "l12_proto.h"
9 #include "polcor_hawkeye.h"
10 #include <xcal.h>
11 
12 #define NMIR 2 /* always 2 mirror sides */
13 #define NDET 40 /* big enough for largest detector array */
14 #define NANG 15 /* big enough for largest set of table AOI or scan angles */
15 
16 void polcor(l1str *l1rec, int32_t ip) {
17  static int firstCall = 1;
18 
19  typedef float m_array[NMIR][NANG][NDET];
20  static m_array *m12, *m13;
21  static float *detfac;
22  static float maxpix;
23  static int32 nang;
24  static float *ang = NULL, margin_s;
25  static int32_t nir_s;
26  static int32_t nir_l;
27 
28  static double *dm12;
29  static double *dm13;
30  static int *have_xcal;
31 
32  static float *pxwt; /* weights for each pixel in the line and */
33  static char *pxangix; /* index of low angle storage */
34 
35  float *polcor = l1rec->polcor;
36  float *dpol = l1rec->dpol;
37 
38  int32_t pixnum = l1rec->pixnum[ip];
39  int32_t detnum = l1rec->detnum;
40  int32_t mside = l1rec->mside;
41  int32_t nbands = l1rec->l1file->nbands;
42 
43  int32_t sensorID = l1rec->l1file->sensorID;
44 
45  float m1 [NANG];
46  float alpha;
47  int32_t ib, ipb;
48  int32_t idet, iang;
49  float wt, zang;
50  float L_x, L_qp, L_up;
51 
52  int iagsm[] = {0, 640, 1376, 3152, 4928, 5664, 6304};
53  int iagpx[] = {0, 640, 1008, 1600, 2192, 2560, 3200};
54  int iseq, ix1, ix2, ipx, irng, step[] = {1, 2, 3, 3, 2, 1};
55  char ix, attrname[50];
56  double sind = 0.0003104;
57  float rad_2_deg = 180. / acos(-1);
58  int get_wt(float, float *, int, float *, char *);
59 
60  if (mside < 0) mside = 0;
61  if (mside > 1) mside = 1;
62 
63  for (ib = 0; ib < nbands; ib++) {
64  l1rec->polcor[ip * nbands + ib] = 1.0;
65  }
66 
67  if (input->pol_opt == 0 || input->pol_opt > 99)
68  return;
69 
70  if(sensorID == HAWKEYE) {
71  polcor_hawkeye(l1rec, ip);
72  return;
73  }
74 
75  if (firstCall) {
76 
77  char name [H4_MAX_NC_NAME] = "";
78  char sdsname[H4_MAX_NC_NAME] = "";
79  char file [FILENAME_MAX] = "";
80  int32 sd_id;
81  int32 sds_id;
82  int32 rank;
83  int32 nt;
84  int32 dims[H4_MAX_VAR_DIMS];
85  int32 nattrs;
86  int32 start[3] = {0, 0, 0};
87  int32 end [3] = {1, 1, 1};
88  int32 status;
89 
90  int32 ndets;
91  int32 nmside;
92  int32_t im, ia, id, ixb;
93 
94 
95  if ((detfac = (float *) calloc(l1rec->l1file->nbands, sizeof (float))) == NULL) {
96  printf("-E- : Error allocating memory to dray_for_i\n");
97  exit(FATAL_ERROR);
98  }
99 
100  if ((have_xcal = (int *) calloc(l1rec->l1file->nbands, sizeof (int))) == NULL) {
101  printf("-E- : Error allocating memory to dray_for_i\n");
102  exit(FATAL_ERROR);
103  }
104 
105  for (ixb = 0; ixb < l1_input->xcal_nwave; ixb++) {
106  if ((l1_input->xcal_opt[ixb] & XCALPOL) != 0) {
107  if ((ib = bindex_get(l1_input->xcal_wave[ixb])) < 0) {
108  printf("-E- %sline %d: xcal wavelength %f does not match sensor\n",
109  __FILE__, __LINE__, l1_input->xcal_wave[ixb]);
110  exit(1);
111  };
112  have_xcal[ib] = 1;
113  }
114  }
115 
116  if ((m12 = (m_array *) calloc(l1rec->l1file->nbands, sizeof (m_array))) == NULL) {
117  printf("-E- : Error allocating memory to dray_for_i\n");
118  exit(FATAL_ERROR);
119  }
120  if ((m13 = (m_array *) calloc(l1rec->l1file->nbands, sizeof (m_array))) == NULL) {
121  printf("-E- : Error allocating memory to dray_for_i\n");
122  exit(FATAL_ERROR);
123  }
124  /* load polfile for each sensor wavelength */
125  for (ib = 0; ib < nbands; ib++) {
126 
127  sprintf(file, "%s%s%d%s", input->polfile, "_", l1rec->l1file->iwave[ib], ".hdf");
128 
129  printf("Loading polarization file %s\n", file);
130 
131  /* Open the file */
132  sd_id = SDstart(file, DFACC_RDONLY);
133  if (sd_id == FAIL) {
134  fprintf(stderr, "-E- %s line %d: SDstart(%s, %d) failed.\n",
135  __FILE__, __LINE__, file, DFACC_RDONLY);
136  exit(1);
137  }
138 
139  status = SDreadattr(sd_id, SDfindattr(sd_id, "Number of Detectors"), &ndets);
140  if (status != 0) {
141  printf("-E- %s Line %d: Error reading global attribute %s from %s.\n",
142  __FILE__, __LINE__, "Number of Detectors", file);
143  exit(1);
144  }
145 
146  status = SDreadattr(sd_id, SDfindattr(sd_id, "Number of Mirror Sides"), &nmside);
147  if (status != 0) {
148  printf("-E- %s Line %d: Error reading global attribute %s from %s.\n",
149  __FILE__, __LINE__, "Number of Mirror Sides", file);
150  exit(1);
151  }
152 
153  if (ib == 0) {
154 
155  // decide on which angle information needs to be read
156 
157  if ((sensorID == VIIRSN) || (sensorID == VIIRSJ1)) {
158  strcpy(attrname, "Number of Scan angles");
159  strcpy(sdsname, "scanangle");
160  } else {
161  strcpy(attrname, "Number of AOIs");
162  strcpy(sdsname, "AOI");
163  }
164  status = SDreadattr(sd_id, SDfindattr(sd_id, attrname), &nang);
165  if (status != 0) {
166  printf(
167  "-E- %s Line %d: Error reading global attribute %s from %s.\n",
168  __FILE__, __LINE__, attrname, file);
169  exit(1);
170  }
171 
172  if ((ang = (float *) malloc(nang * sizeof (float))) == NULL) {
173  printf("-E- %s Line %d: Error allocating memory for ang.\n",
174  __FILE__, __LINE__);
175  exit(1);
176  }
177 
178  sds_id = SDselect(sd_id, SDnametoindex(sd_id, sdsname));
179  status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
180  status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) ang);
181  if (status != 0) {
182  printf("-E- %s Line %d: Error reading SDS %s from %s.\n",
183  __FILE__, __LINE__, sdsname, file);
184  exit(1);
185  } else {
186  status = SDendaccess(sds_id);
187  }
188  }
189 
190 
191  strcpy(sdsname, "m12");
192  sds_id = SDselect(sd_id, SDnametoindex(sd_id, sdsname));
193  for (im = 0; im < nmside; im++) for (ia = 0; ia < nang; ia++) for (id = 0; id < ndets; id++) {
194  start[0] = im;
195  start[1] = ia;
196  start[2] = id;
197  status = SDreaddata(sds_id, start, NULL, end, (VOIDP) & m12[ib][im][ia][id]);
198  if (status != 0) {
199  printf("-E- %s Line %d: Error reading SDS %s from %s.\n",
200  __FILE__, __LINE__, sdsname, file);
201  exit(1);
202  }
203  }
204 
205  status = SDendaccess(sds_id);
206 
207  strcpy(sdsname, "m13");
208  sds_id = SDselect(sd_id, SDnametoindex(sd_id, sdsname));
209  for (im = 0; im < nmside; im++) for (ia = 0; ia < nang; ia++) for (id = 0; id < ndets; id++) {
210  start[0] = im;
211  start[1] = ia;
212  start[2] = id;
213  status = SDreaddata(sds_id, start, NULL, end, (VOIDP) & m13[ib][im][ia][id]);
214  if (status != 0) {
215  printf("-E- %s Line %d: Error reading SDS %s from %s.\n",
216  __FILE__, __LINE__, sdsname, file);
217  exit(1);
218  }
219  }
220  status = SDendaccess(sds_id);
221  status = SDend(sd_id);
222 
223  /* we need to translate from actual detectors to replicated detectors or */
224  /* aggregated detectors, to handle the HMODIS resolution switching. Get */
225  /* the conversion factor by comparing sensor ndets to table ndets. */
226  if ((sensorID == VIIRSN) || (sensorID == VIIRSJ1))
227  detfac[ib] = 1.;
228  else
229  detfac[ib] = l1rec->l1file->ndets * 1.0 / ndets; /* 0.25 to 4 */
230  }
231 
232 
233  /* get the max # pixels */
234  if (sensorID == MODISA || sensorID == MODIST) {
235  switch (l1_input->resolution) {
236  case 250:
237  maxpix = 5416.0;
238  break;
239  case 500:
240  maxpix = 2708.0;
241  break;
242  default:
243  maxpix = 1354.0;
244  break;
245  }
246  } else if ((sensorID == VIIRSN) || (sensorID == VIIRSJ1)) {
247  margin_s = l1rec->margin_s;
248  if (l1rec->scn_fmt == 0)
249  maxpix = 3200.;
250  else
251  maxpix = 6304 + margin_s * 2;
252  } else {
253  printf("-E- %s line %d: Mirror geometry unknown for %s\n",
254  __FILE__, __LINE__, sensorId2SensorDir(sensorID));
255  exit(1);
256  }
257 
258  // precompute the weights and angle (AOI on mirror or scan angle)
259  // dimension index for each pixel in the scan
260 
261  if ((pxwt = (float *) malloc(maxpix * sizeof ( float))) == NULL) {
262  printf("-E- %s Line %d: Error allocating memory for weights.\n",
263  __FILE__, __LINE__);
264  exit(1);
265  }
266  if ((pxangix = (char *) malloc(maxpix * sizeof ( char))) == NULL) {
267  printf("-E- %s Line %d: Error allocating memory for angle index.\n",
268  __FILE__, __LINE__);
269  exit(1);
270  }
271 
272  // depending on instrument, get the angle and find the weight and index
273  // into pol table for all pixels
274 
275  if ((sensorID == VIIRSN) || (sensorID == VIIRSJ1)) {
276  if (l1rec->scn_fmt == 0) /* aggregated */ {
277  for (irng = 0; irng < 6; irng++) {
278  ix1 = irng;
279  ix2 = irng + 1;
280  for (ipx = iagpx[ix1]; ipx < iagpx[ix2]; ipx++) {
281  iseq = ipx - iagpx[ix1];
282  zang = iagsm[ix1] + ((2 * iseq + 1) * step[irng] - 1.) / 2.;
283  zang = (zang - 3151.5) * sind * rad_2_deg;
284 
285  // use zang in same way as below - I hate to repeat this though
286  get_wt(zang, ang, nang, &wt, &ix);
287  pxwt[ipx] = wt;
288  pxangix[ipx] = ix;
289  }
290  }
291  } else /* unaggregated */ {
292  for (ipx = 0; ipx < maxpix; ipx++) {
293  zang = ((float) ipx - 3151.5 - margin_s) * sind * rad_2_deg;
294  get_wt(zang, ang, nang, &wt, &ix);
295  pxwt[ipx] = wt;
296  pxangix[ipx] = ix;
297  }
298  }
299 
300  } else {
301 
302  for (ipx = 0; ipx < maxpix; ipx++) {
303  zang = 10.5 + ipx / maxpix * (65.5 - 10.5);
304  get_wt(zang, ang, nang, &wt, &ix);
305  pxwt[ipx] = wt;
306  pxangix[ipx] = ix;
307  }
308  }
309 
310  nir_s = bindex_get(input->aer_wave_short);
311  nir_l = bindex_get(input->aer_wave_long);
312 
313  firstCall = 0;
314  }
315 
316  /* apply sensitivites to radiances to get corrections */
317 
318  for (ib = 0; ib < nbands; ib++) {
319 
320  ipb = ip * nbands + ib;
321  idet = (int32_t) rint(detnum / detfac[ib]);
322  alpha = l1rec->alpha[ip] / RADEG;
323  L_x = l1rec->Lt[ipb] / l1rec->tg_sol[ipb] / l1rec->tg_sen[ipb];
324 
325  if (L_x > 0.0) {
326  L_qp = l1rec->L_q[ipb] * cos(2 * alpha) + l1rec->L_u[ipb] * sin(2 * alpha);
327  L_up = l1rec->L_u[ipb] * cos(2 * alpha) - l1rec->L_q[ipb] * sin(2 * alpha);
328  if (have_xcal[ib]) {
329  dm12 = get_xcal(l1rec, XM12, l1rec->l1file->iwave[ib]);
330  dm13 = get_xcal(l1rec, XM13, l1rec->l1file->iwave[ib]);
331  polcor[ipb] = 1.0 / (1.0 - dm12[ip] * L_qp / L_x - dm13[ip] * L_up / L_x);
332  } else {
333  for (iang = pxangix[pixnum]; iang <= (pxangix[pixnum] + 1); iang++) {
334  m1[iang] = 1.0 / (1.0
335  - m12[ib][mside][iang][idet] * L_qp / L_x
336  - m13[ib][mside][iang][idet] * L_up / L_x);
337  }
338  polcor[ipb] = m1[(int) pxangix[pixnum]] * (1. - pxwt[pixnum]) + m1[(int) pxangix[pixnum] + 1] * pxwt[pixnum];
339  }
340  dpol [ipb] = sqrt(pow(l1rec->L_q[ipb], 2.0) + pow(l1rec->L_u[ipb], 2.0)) / L_x;
341 
342  /* quick-fix to polcor of aerosol bands only */
343  if (input->pol_opt == 6 && ib != nir_l && ib != nir_s)
344  polcor[ipb] = 1.0;
345 
346  } else {
347  polcor[ipb] = 1.0;
348  dpol [ipb] = 0.0;
349  }
350  }
351 }
352 
353 int get_wt(float zang, float *ang, int nang, float *wt, char *ix)
354 /*******************************************************************
355 
356  get_wt
357 
358  purpose: derive a weight and index into angle array
359 
360  Returns type: int - 0 if all is OK
361 
362  Parameters: (in calling order)
363  Type Name I/O Description
364  ---- ---- --- -----------
365  float zang I angle to interpolate to
366  float * ang I array of angles in
367  interpolation table
368  int nang I # of angle tie points
369  float * wt O derived weight
370  char * ix O index of first angle to use in
371  weighting
372 
373  *******************************************************************/ {
374  int iang, ix2;
375 
376  if (zang <= ang[0])
377  *ix = 0;
378  else if (zang >= ang[nang - 1])
379  *ix = nang - 2;
380  else {
381  for (iang = 1; iang < nang; iang++) {
382  if (zang < ang[iang]) {
383  *ix = iang - 1;
384  break;
385  }
386  }
387  }
388  ix2 = *ix + 1;
389  *wt = (zang - ang[(int) *ix]) / (ang[ix2] - ang[(int) *ix]);
390  return 0;
391 }
const char * sensorId2SensorDir(int sensorId)
Definition: sensorInfo.c:240
#define XCALPOL
Definition: l1.h:86
int status
Definition: l1_czcs_hdf.c:32
void polcor(l1str *l1rec, int32_t ip)
Definition: polcor.c:16
#define NANG
Definition: polcor.c:14
#define FAIL
Definition: ObpgReadGrid.h:18
#define NULL
Definition: decode_rs.h:63
read l1rec
#define VIIRSN
Definition: sensorDefs.h:23
#define MODIST
Definition: sensorDefs.h:18
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 file
Definition: HISTORY.txt:413
int32_t im
Definition: atrem_corl1.h:161
#define XM13
Definition: xcal.h:12
instr * input
int get_wt(float zang, float *ang, int nang, float *wt, char *ix)
Definition: polcor.c:353
int bindex_get(int32_t wave)
Definition: windex.c:45
int32_t mside
#define HAWKEYE
Definition: sensorDefs.h:39
l1_input_t * l1_input
Definition: l1_options.c:9
#define FATAL_ERROR
Definition: swl0_parms.h:5
void polcor_hawkeye(l1str *l1rec, int32_t ip)
#define RADEG
Definition: czcs_ctl_pt.c:5
#define XM12
Definition: xcal.h:11
double * get_xcal(l1str *l1rec, int type, int wave)
Definition: xcal.c:33
int32_t nbands
Extra metadata that will be written to the HDF4 file l2prod rank
#define NMIR
Definition: polcor.c:12
#define NDET
Definition: polcor.c:13
double rint(double)
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int32_t sensorID[MAXNFILES]
Definition: l2bin.cpp:97
#define MODISA
Definition: sensorDefs.h:19
#define VIIRSJ1
Definition: sensorDefs.h:37