OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
niwa_iop.c
Go to the documentation of this file.
1 
2 /* ---------------------------------------------------------------------------
3  * niwa_iop.c - IOP algorithm: Gerald Moore, Sam Lavender, Matt Pinkerton
4  *
5  * Products:
6  * niwa_a: total absorption coefficient - water absorption
7  * niwa_bb: total backscatter coefficient - water backscatter
8  *
9  * Algorithm citation: Pinkerton et al., 2006. 'A method for estimating
10  * inherent optical properties of New Zealand continental shelf waters
11  * from satellite ocean colour measurements', New Zealand Journal of
12  * Marine and Freshwater Research 40, pp 227-247.
13  *
14  * Implementation of IOP only: J.N. Schwarz, Simon Wood, NIWA, Sept. 2008
15  *
16  * ---------------------------------------------------------------------------
17  */
18 
19 #include <stdio.h>
20 #include <math.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "l12_proto.h"
24 #include "l2prod.h"
25 
26 #include "niwa_iop.h"
27 
28 /* macros */
29 #define radians(degrees) ((degrees) * M_PI / 180.0)
30 #define degrees(radians) ((radians) * 180.0 / M_PI)
31 
32 /* constant sizes */
33 #define LBANDS 8 /* 8 bands in LUT */
34 #define VBANDS 6 /* results returned for 6 visible bands, regardless which sensor */
35 #define SEAWIFS_NBANDS 8
36 #define MODIS_NBANDS 9
37 
38 /* Look-up table dimensions */
39 #define TH_NS 10
40 #define DPHI_NS 19
41 #define AP_NS 16
42 #define BP_NS 16
43 #define ABSIND_NS 3891200 /* 8 bands (10.10.19.16.16) from 172800 */
44 
45 #define IOPF_NIWA_BADGEOM 0x0020 /* was SPARE2 */
46 
47 #define IOPmodel 1 /* uses only 490 and 510 bands */
48 
49 /* Switch on/off VERBose mode for error checking */
50 #define VERB 0
51 //#define VERB 1
52 
53 /* value to return when we cannot generate an IOP value for whatever reason
54  * -- make sure this matches 'l2prodstr.badData' */
55 const float NO_DATA = BAD_FLT;
56 
57 
58 /* LUT - IOP variables */
59 static int th_s_n, th_v_n, dphi_n;
60 static float th_s_lev[TH_NS], th_v_lev[TH_NS], dphi_lev[DPHI_NS];
61 static float th_s_ind[TH_NS], th_v_ind[TH_NS], dphi_ind[DPHI_NS];
62 static int ap_n, bp_n;
63 static float band_lev[LBANDS], ap_lev[AP_NS], bp_lev[BP_NS];
64 static float a_ind[AP_NS], b_ind[BP_NS];
65 
66 /* IOP base table variables */
67 static float abst[AP_NS][BP_NS][LBANDS];
68 static float *absen; /* the pointer for absen */
69 static int absind;
70 
71 /* mapping from our VBAND index to sensor's l2rec bands */
72 static const int seawifs_map[VBANDS] = {0, 1, 2, 3, 4, 5};
73 static const int modis_map[VBANDS] = {0, 1, 2, 3, 4, 5};
74 static int nbands;
75 static const int *band_map;
76 
77 /* sensor / band specific data values */
78 static float aw[VBANDS], bbw[VBANDS], lambda[VBANDS];
79 
80 /* structure for passing iop retrievals per pixel */
81 typedef struct abs_res_ {
82  float a[VBANDS];
83  float bb[VBANDS];
84 } abs_res_t;
85 
86 
87 /* --------------------------------------------------------------------------- */
88 
89 /* ---------------------------------------------------------------------------
90  * interpol()
91  * Converted from IDL interpol function, but now only does linear 1-D interpolation
92  *
93  * inputs:
94  * outputs:
95  * returns:
96  * ---------------------------------------------------------------------------
97  */
98 static float interpol(float *v, float *x, float u, int size) {
99  static const int rsize = 1;
100 
101  int s1, i, ix, m2;
102  float d, r;
103 
104  /* last subs in v and x */
105  m2 = size - 2;
106 
107  /* Incr or Decr X */
108  s1 = ((x[1] - x[0]) >= 0) ? 1 : -1;
109 
110  /* current point */
111  ix = 0;
112 
113  /* point loop */
114  for (i = 0; i <= rsize; i++) {
115  /* difference */
116  d = s1 * (u - x[ix]);
117  if (d == 0.0) {
118  r = v[ix];
119  } else {
120  if (d > 0.0) {
121  while ((s1 * (u - x[ix + 1]) > 0.0) && (ix < m2)) {
122  ix = ix + 1;
123  }
124  } else {
125  while ((s1 * (u - x[ix]) < 0.0) && (ix > 0)) {
126  ix = ix - 1;
127  }
128  }
129  r = v[ix] + (u - x[ix]) * (v[ix + 1] - v[ix]) / (x[ix + 1] - x[ix]);
130  }
131  }
132  return r;
133 }
134 
135 /* ---------------------------------------------------------------------------
136  * setgeom()
137  *
138  * inputs:
139  * outputs:
140  * returns: TRUE if viewing geometry within accepatble limits; FALSE otherwise
141  * ---------------------------------------------------------------------------
142  */
143 static int setgeom(float sun_theta, float sen_theta, float dphi) {
144  /* angles passed from niwa_iop() are in radians */
145  int tabind;
146  int x, y, i, pos;
147  float th_s_ent, th_v_ent, dphi_ent;
148 
149 #if (VERB)
150  printf("setgeom starting: [%f %f %f]\n", sun_theta * 180. / M_PI,
151  sen_theta * 180. / M_PI, dphi * 180. / M_PI);
152 #endif
153 
154  /* Page in IOP table */
155  /* check that the angle matches index */
156  th_s_ent = floor(interpol(th_s_ind, th_s_lev, sun_theta, TH_NS) + 0.5);
157  th_v_ent = floor(interpol(th_v_ind, th_v_lev, sen_theta, TH_NS) + 0.5);
158  if (dphi < 0.0)
159  dphi = dphi + M_PI * 2.0;
160  if (dphi > M_PI * 2.0)
161  dphi = dphi - M_PI * 2.0;
162  dphi_ent = floor(interpol(dphi_ind, dphi_lev, dphi, DPHI_NS) + 0.5);
163 
164  /* LUT index */
165  tabind = (int) (th_s_ent * TH_NS * DPHI_NS * AP_NS * BP_NS * LBANDS)
166  + (th_v_ent * DPHI_NS * AP_NS * BP_NS * LBANDS) + (dphi_ent * AP_NS * BP_NS * LBANDS);
167 
168 #if (VERB)
169  printf("[th_s_ent th_v_ent dphi_ent tabind]=[%f %f %f %d]\n",
170  th_s_ent, th_v_ent, dphi_ent, tabind);
171 #endif
172 
173  /* Check geometry within table limits */
174  if (tabind > ABSIND_NS) {
175  printf("\nWARNING: NIWA-IOP: Table limits exceeded.\n");
176  return FALSE;
177  }
178 
179  /* Load data */
180  for (i = 0; i < LBANDS; i++) {
181  for (y = 0; y < BP_NS; y++) {
182  pos = (int) tabind + (i * BP_NS * AP_NS) + (y * AP_NS);
183  for (x = 0; x < AP_NS; x++) {
184  abst[x][y][i] = absen[pos + x];
185  }
186  }
187  }
188 
189 #if (VERB)
190  printf("LUT loaded: abst=%d\n"), abst;
191  printf("Check: endpos %d endpos %d\n", pos + AP_NS, tabind + (AP_NS * BP_NS * LBANDS));
192 
193  printf("Bands first:");
194  for (x = 0; x < LBANDS; x++)
195  printf(" %f", abst[0][0][x]);
196  printf("\n");
197  printf("Bands last:");
198  for (x = 0; x < LBANDS; x++)
199  printf(" %f", abst[AP_NS - 1][BP_NS - 1][x]);
200  printf("\n");
201 #endif
202 
203  return TRUE;
204 }
205 
206 /* ---------------------------------------------------------------------------
207  * load_work_tab()
208  * Load the look-up tables from disk
209  *
210  * inputs: none
211  * outputs: global table data initialised from file values
212  * returns: size of 'absen' array
213  * ---------------------------------------------------------------------------
214  */
215 static int load_work_tab(void) {
216  char *tmp_str;
217  char lutdir[FILENAME_MAX];
218  char fname[FILENAME_MAX];
219  FILE *fp;
220  int i, lut_nbands;
221 
222  if ((tmp_str = getenv("OCDATAROOT")) == NULL) {
223  printf("\nERROR: NIWA-IOP: OCDATAROOT environment variable is not defined.\n");
224  exit(EXIT_FAILURE);
225  }
226 
227  strcpy(lutdir, tmp_str);
228  strcat(lutdir, "/common");
229 #if (VERB)
230  printf("LUT dir = %s\n", lutdir);
231 #endif
232 
233  /* Open header table */
234  sprintf(fname, "%s/niwa_iop_h.txt", lutdir);
235 
236  printf("NIWA-IOP: Reading LUT header file %s\n", fname);
237 
238  fp = fopen(fname, "r");
239  if (fp == NULL) {
240  printf("\nERROR: NIWA-IOP: Cannot open %s\n", fname);
241  exit(EXIT_FAILURE);
242  }
243 
244  fscanf(fp, "%d", &lut_nbands);
245  if (lut_nbands != LBANDS) {
246  printf("\nERROR: NIWA-IOP: Band mismatch opening %s\n", fname);
247  exit(EXIT_FAILURE);
248  }
249  for (i = 0; i < LBANDS; i++)
250  fscanf(fp, "%f", &band_lev[i]);
251 
252  fscanf(fp, "%d", &th_s_n);
253  for (i = 0; i < TH_NS; i++)
254  fscanf(fp, "%f", &th_s_lev[i]);
255  for (i = 0; i < TH_NS; i++)
256  th_s_ind[i] = i;
257 #if (VERB)
258  printf("th_s_n %d th_s_lev %f %f\n", th_s_n, th_s_lev[0], th_s_lev[1]);
259 #endif
260 
261  fscanf(fp, "%d", &th_v_n);
262  for (i = 0; i < TH_NS; i++)
263  fscanf(fp, "%f", &th_v_lev[i]);
264  for (i = 0; i < TH_NS; i++)
265  th_v_ind[i] = i;
266 #if (VERB)
267  printf("th_v_n %d th_v_lev %f %f\n", th_v_n, th_v_lev[0], th_v_lev[1]);
268 #endif
269 
270  fscanf(fp, "%d", &dphi_n);
271  for (i = 0; i < DPHI_NS; i++)
272  fscanf(fp, "%f", &dphi_lev[i]);
273  for (i = 0; i < DPHI_NS; i++)
274  dphi_ind[i] = i;
275 #if (VERB)
276  printf("dphi_n %d dphi_lev %f %f\n", dphi_n, dphi_lev[0], dphi_lev[1]);
277 #endif
278 
279  fscanf(fp, "%d", &ap_n);
280  for (i = 0; i < AP_NS; i++)
281  fscanf(fp, "%f", &ap_lev[i]);
282 #if (VERB)
283  printf("ap_n %d ap_lev %f %f\n", ap_n, ap_lev[0], ap_lev[1]);
284 #endif
285 
286  fscanf(fp, "%d", &bp_n);
287  for (i = 0; i < BP_NS; i++)
288  fscanf(fp, "%f", &bp_lev[i]);
289 #if (VERB)
290  printf("bp_n %d bp_lev %f %f\n", bp_n, bp_lev[0], bp_lev[1]);
291 #endif
292 
293  fclose(fp);
294 #if (VERB)
295  printf("NIWA-IOP: Loaded OK %s\n", fname);
296 #endif
297  /* ---End of header--- */
298 
299  /*--- Setup the table indexes ---*/
300  for (i = 0; i < BP_NS; i++)
301  b_ind[i] = i;
302  for (i = 0; i < AP_NS; i++)
303  a_ind[i] = i;
304 
305  /*--- Open data table ---*/
306  sprintf(fname, "%s/niwa_iop.dat", lutdir); /* LUT data file */
307  printf("NIWA-IOP: Loading LUT data from %s\n", fname);
308 
309  fp = fopen(fname, "r");
310  if (fp == NULL) {
311  printf("\nERROR: NIWA-IOP: Cannot open %s\n", fname);
312  exit(EXIT_FAILURE);
313  }
314 
315  /* Allocate memory for LUT array */
316  absind = th_s_n * th_v_n * dphi_n * ap_n * bp_n * LBANDS;
317 #if (VERB)
318  printf("S_F_T: absind= %d\n", absind);
319 #endif
320 
321  if ((absen = (float *) calloc((absind), sizeof (float))) == 0) {
322  printf("\nERROR: NIWA-IOP: memory allocation failure, absen\n");
323  exit(EXIT_FAILURE);
324  }
325 
326  fread(absen, sizeof (float), absind, fp);
327  fclose(fp);
328 
329 #if (VERB)
330  printf("NIWA-IOP: %s Loaded OK\n", fname);
331  printf("absen first %f %f %f %f %f %f %f %f\n", absen[0], absen[1], absen[2], absen[3],
332  absen[4], absen[5], absen[6], absen[7]);
333  printf("absen last %f %f %f %f %f %f %f %f\n", absen[absind - 8], absen[absind - 7],
334  absen[absind - 6], absen[absind - 5], absen[absind - 4], absen[absind - 3],
335  absen[absind - 2], absen[absind - 1]);
336 #endif
337 
338  return absind;
339 }
340 
341 /* ---------------------------------------------------------------------------
342  * mbcucof()
343  *
344  * inputs:
345  * outputs:
346  * returns: none
347  * ---------------------------------------------------------------------------
348  */
349 static void mbcucof(float y[], float y1[], float y2[], float y12[], float d1, float d2, float *cl) {
350  static const int wt[16][16] = {
351  {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
352  {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
353  {-3, 0, 0, 3, 0, 0, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0},
354  {2, 0, 0, -2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0},
355  {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
356  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
357  {0, 0, 0, 0, -3, 0, 0, 3, 0, 0, 0, 0, -2, 0, 0, -1},
358  {0, 0, 0, 0, 2, 0, 0, -2, 0, 0, 0, 0, 1, 0, 0, 1},
359  {-3, 3, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
360  {0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, -2, -1, 0, 0},
361  {9, -9, 9, -9, 6, 3, -3, -6, 6, -6, -3, 3, 4, 2, 1, 2},
362  {-6, 6, -6, 6, -4, -2, 2, 4, -3, 3, 3, -3, -2, -1, -1, -2},
363  {2, -2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
364  {0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 1, 1, 0, 0},
365  {-6, 6, -6, 6, -3, -3, 3, 3, -4, 4, 2, -2, -2, -2, -1, -1},
366  {4, -4, 4, -4, 2, 2, -2, -2, 2, -2, -2, 2, 1, 1, 1, 1}
367  };
368 
369  int k, i;
370  float xx, d1d2, x[16];
371 
372  d1d2 = d1 * d2;
373  for (i = 0; i < 4; i++) {
374  x[i] = y[i];
375  x[i + 4] = y1[i] * d1;
376  x[i + 8] = y2[i] * d2;
377  x[i + 12] = y12[i] * d1d2;
378  }
379  for (i = 0; i < 16; i++) {
380  xx = 0.0;
381  for (k = 0; k < 16; k++)
382  xx += wt[i][k] * x[k];
383  cl[i] = xx;
384  }
385 }
386 
387 /* ---------------------------------------------------------------------------
388  * f_abx()
389  *
390  * inputs:
391  * outputs:
392  * returns:
393  * ---------------------------------------------------------------------------
394  */
395 static float f_abx(float a, float b, int band) {
396  int x, y, i;
397  float ain, bin;
398  float res;
399  float tarr[AP_NS][BP_NS];
400  int al, bl, ah, bh, xl, xh, yl, yh;
401  float t, u, d1, d2, c[4][4], cl[16];
402  float yy[4], y1[4], y2[4], y12[4];
403 
404  /* don't accept bad a, b inputs */
405  if ((a < 0.0) || (b < 0.0))
406  return 0.0;
407 
408  /* Interpolate loaded LUT values to input a and b */
409  ain = interpol(a_ind, ap_lev, a, AP_NS);
410  bin = interpol(b_ind, bp_lev, b, BP_NS);
411 
412  /* set array indices */
413  for (y = 0; y < BP_NS; y++)
414  for (x = 0; x < AP_NS; x++)
415  tarr[x][y] = abst[x][y][band];
416 
417  /* set lower and upper range in table a, b */
418  al = (ain > 0) ? (int) floor(ain) : 0;
419  bl = (bin > 0) ? (int) floor(bin) : 0;
420 
421  bh = bl + 1;
422  ah = al + 1;
423 
424  /* catch inconsistent upper and lower table a,b values */
425  if ((bh > BP_NS - 1) || (ah > AP_NS - 1))
426  return 0.0;
427  if ((al == ah) || (bl == bh))
428  return 0.0;
429 
430  /* set indices for smoothed interpolation over 3x3 table coefficient array */
431  for (i = 0; i < 4; i++) {
432  x = (i == 0 || i == 3) ? al : ah;
433  y = (i < 2) ? bl : bh;
434  xl = (x == 0) ? x : x - 1;
435  xh = (x == AP_NS - 1) ? x : x + 1;
436  yl = (y == 0) ? y : y - 1;
437  yh = (y == BP_NS - 1) ? y : y + 1;
438 
439  yy[i] = tarr[x][y];
440  y1[i] = (tarr[xh][y] - tarr[xl][y]) / (ap_lev[xh] - ap_lev[xl]);
441  y2[i] = (tarr[x][yh] - tarr[x][yl]) / (bp_lev[yh] - bp_lev[yl]);
442  y12[i] = (tarr[xh][yh] - tarr[xh][yl] - tarr[xl][yh] + tarr[xl][yl])
443  / ((ap_lev[xh] - ap_lev[xl]) * (bp_lev[yh] - bp_lev[yl]));
444  }
445  d1 = ap_lev[ah] - ap_lev[al];
446  d2 = bp_lev[bh] - bp_lev[bl];
447 
448  /* call function to retrieve 3x3 interpolated table look-up value of F */
449  mbcucof(yy, y1, y2, y12, d1, d2, cl);
450  i = 0;
451  for (x = 0; x < 4; x++)
452  for (y = 0; y < 4; y++)
453  c[x][y] = cl[i++];
454  t = (a - ap_lev[al]) / d1;
455  u = (b - bp_lev[bl]) / d2;
456  res = 0.0;
457  for (i = 3; i >= 0; i--)
458  res = t * res + ((c[i][3] * u + c[i][2]) * u + c[i][1]) * u + c[i][0];
459 
460  return res;
461 }
462 
463 /* ---------------------------------------------------------------------------
464  * f_ab()
465  * Sensor specific version of f_abx() which corrects for MODIS vs SeaWIFs bands
466  *
467  * inputs:
468  * outputs:
469  * returns:
470  * ---------------------------------------------------------------------------
471  */
472 static float f_ab(float a, float b, int band, int sensor_id) {
473  float res, res1;
474 
475  res = f_abx(a, b, band);
476  if (band == 3 && sensor_id != SEAWIFS) {
477  if (sensor_id == MODIST || sensor_id == MODISA) {
478  res1 = f_abx(a, b, 4);
479  res += ((530 - 510) / (555 - 510)) * (res1 - res);
480  } else res = 0; /* probably better to assert here? */
481  }
482  return res;
483 }
484 
485 /* ---------------------------------------------------------------------------
486  * iop_model1() -- calculate a and bb values for one pixel
487  *
488  * inputs: input values for this pixel
489  * outputs: a and bb values (placed in caller's result struct)
490  * (all values will be NO_DATA if not success)
491  * returns: TRUE if success (ie some good data) else FALSE
492  *
493  * Note: currently only works for SeaWiFS
494  * ---------------------------------------------------------------------------
495  */
496 static int iop_model1(float Rrs[], int sensor_id, abs_res_t *result) {
497  static const float b_tilde = 0.01756; /* Mobley phase function */
498  static const float init_a[] = {0.05, 0.06, 0.05, 0.04, 0.02, 0.03};
499  static const int maxIts = 20; /* local limit on no. iterations for F, a and bb */
500  static const float tol = 0.001;
501 
502  float minEpsa, maxEpsa; /* limits on epsilon_a, Pinkerton et al., 2006 */
503  int iter, iw;
504  float new_err, old_err;
505  float b490, hib490, lob490, bstep, temp1; /* iteration parameters for bb */
506  float bestb[2], besta[2];
507  float F[VBANDS], a[VBANDS], temp[VBANDS]; /* local variables */
508  float b[VBANDS], bn[VBANDS], rho[VBANDS];
509  int success;
510 
511  /* set min max Epsa according to sensor */
512  if (sensor_id == SEAWIFS) {
513  minEpsa = 1.22;
514  maxEpsa = 1.42;
515  }
516  else if (sensor_id == MODIST || sensor_id == MODISA) {
517  //minEpsa = 1.80; /* NOMAD 20th percentile */
518  //maxEpsa = 2.34; /* NOMAD 80th percentile */
519  minEpsa = 1.65; /* NOMAD 5th percentile */
520  maxEpsa = 2.77; /* NOMAD 95th percentile */
521  }
522 
523  /* initialise */
524  iter = 0;
525  lob490 = 0.001;
526  hib490 = 60.0;
527  bestb[0] = -1.0;
528  bestb[1] = -1.0;
529  besta[0] = -1.0;
530  besta[1] = -1.0;
531 
532  /* convert Rrs to rho */
533  for (iw = 0; iw < VBANDS; iw++) {
534  rho[iw] = M_PI * Rrs[iw];
535  }
536 
537  /* initialise outputs */
538  success = FALSE; /* until we produce some good data */
539  for (iw = 0; iw < VBANDS; iw++) {
540  result->a[iw] = NO_DATA;
541  result->bb[iw] = NO_DATA;
542  if (rho[iw] < 0.0)
543  rho[iw] = 0.0;
544 
545  // b[iw] = 0.24 * ( pow (490.0 / lambda[iw], 2.22)); /* NOMAD data for eps_b spectral slope */
546  // b[iw] = (1.62517 - 0.00113 * lambda[iw])/1.00367; */
547  b[iw] = (lambda[iw] / lambda[2]) * (0.841 * (lambda[iw] / lambda[2]) - 2.806) + 2.965; /* EBoP */
548  a[iw] = init_a[iw];
549  }
550 
551  /* normalise to b to 489 nm, bn remains fixed from here on */
552  for (iw = 0; iw < VBANDS; iw++) {
553  bn[iw] = b[iw] / b[2];
554  }
555 
556 #if (VERB)
557  printf("--- START iop_model1 ---\n");
558  printf("rho=[%f %f %f %f %f %f]\n", rho[0], rho[1], rho[2], rho[3], rho[4], rho[5]);
559  printf("b=[%f %f %f %f %f %f]\n", b[0], b[1], b[2], b[3], b[4], b[5]);
560  printf("bn=[%f %f %f %f %f %f]\n", bn[0], bn[1], bn[2], bn[3], bn[4], bn[5]);
561 #endif
562 
563  /*** Begin calculations ***/
564  b[2] = 0.05; /* start search value of b(490) */
565  for (iw = 3; iw < 5; iw++)
566  b[iw] = b[2] * bn[iw]; /* start values of b(510) and b(555) */
567  for (iw = 2; iw < 5; iw++)
568  temp[iw] = b[iw]; /* initialise */
569  iter = 0;
570  old_err = 100.; /* high starting value */
571  new_err = old_err - 1;
572 
573  while ((old_err - new_err) > tol && iter < maxIts) { /* stop iterating */
574  old_err = new_err;
575  new_err = 0.0;
576  for (iw = 2; iw < 5; iw++) {
577  F[iw] = f_ab(0.0, b[iw], iw, sensor_id); /* 1st estimate of f(lambda, geom, iop) */
578  if (F[iw] > 0.0) {
579  temp[iw] = (rho[iw] * aw[iw] / F[iw] - bbw[iw]) / b_tilde; /* estimate better b(lambda) */
580 #if (VERB)
581  printf("b[%d]=%f\n", iw, temp[iw]);
582 #endif
583  if (temp[iw] < 0.0)
584  temp[iw] = 0.001; /* if negative, set to low value */
585  } else
586  temp[iw] = 0.001; /* catch negative F case */
587 
588  new_err += fabsf(temp[iw] - b[iw]) / b[iw]; /* calculate proportional change in b */
589  b[iw] = temp[iw];
590 
591  } /* end loop over 490:555 for this iteration */
592  temp1 = (b[2] + b[3] / bn[3] + b[4] / bn[4]) / 3.; /* average value of b2 */
593  for (iw = 2; iw < 5; iw++)
594  b[iw] = temp1 * bn[iw]; /* reset */
595 #if (VERB)
596  printf("%d getting bF [b2,F2] =[%f %f] -> %f\n", iter, b[2], F[2], new_err);
597 #endif
598  iter++;
599  }
600 
601  /* now we have a stable value for F */
602 #if (VERB)
603  printf("got a+F: iter=%d new_err=%f\n", iter, new_err);
604  printf("F=[%f %f %f]\n", F[2], F[3], F[4]);
605  printf("a=[%f %f %f]\n", a[2], a[3], a[4]);
606  printf("b=[%f %f %f]\n", b[2], b[3], b[4]);
607  printf("lob490=%f\n", lob490);
608 #endif
609 
610  /* select highest b-value calculated in 490:555 range for conservative limit in eps_a iterations */
611  /*for (iw=2; iw<5; iw++) if (b[iw]*bn[iw] > lob490) lob490=b[iw]*bn[iw]; */
612  lob490 = b[2];
613  for (iw = 3; iw < 5; iw++)
614  if (b[iw] / bn[iw] > lob490)
615  lob490 = b[iw] / bn[iw];
616 
617 #if (VERB)
618  printf("lob490=%f\n", lob490);
619  //printf("lob490=%f F[2]=%f\n",lob490,F[2]);
620 #endif
621 
622  /*** Take 15 steps in b490, seeking highest and lowest b490 which yield acceptable eps_a values ***/
623  /* calculate stepsize */
624  bstep = pow((hib490 / lob490), (1.0 / 15.0)) - 1.0;
625 #if (VERB)
626  printf("bstep=%f lob490\n", bstep, lob490);
627 #endif
628 
629  /* initialise starting values */
630  b490 = lob490;
631  do {
632  iter = 0; /* reset iteration counter for this step */
633 
634  for (iw = 2; iw < 4; iw++) { /* re-initialise a and b for this step */
635  b[iw] = b490 * bn[iw];
636  a[iw] = F[2] * (b[iw] * b_tilde + bbw[iw]) / rho[iw] - aw[iw]; /* use a F[2] to init a */
637  if (a[iw] < 0.0)
638  a[iw] = 0.001;
639  }
640 
641  /* Iterate for a and F */
642  old_err = 100.; /* reset error for this step */
643  new_err = old_err - 1;
644  while ((old_err - new_err) > tol && iter < maxIts) { /* end iteration for a at this b490 step */
645  old_err = new_err;
646  new_err = 0.0; /* reset error within loop */
647 
648  for (iw = 2; iw < 4; iw++) { /* loop through 490:510 */
649 
650  F[iw] = f_ab(a[iw], b[iw], iw, sensor_id); /* get next estimate of F */
651  if (F[iw] > 0.0)
652  temp1 = F[iw] * (b[iw] * b_tilde + bbw[iw]) / rho[iw] - aw[iw]; /* use new F to get better a */
653  else
654  temp1 = 0.001; /* if F unrealistic, set a=0.001 */
655  if (temp1 < 0.0)
656  temp1 = 0.001;
657  new_err += fabsf(temp1 - a[iw]) / a[iw]; /* calculate proportional change in estimate */
658  a[iw] = temp1;
659  }
660  iter++;
661 #if (VERB)
662  printf("%d 1getting aF [a2,F2] =[%f %f] -> %f\n", iter, a[2], F[2], new_err);
663  printf("%d 1getting aF [a3,F3] =[%f %f] -> %f\n", iter, a[3], F[3], new_err);
664 #endif
665  }
666 #if (VERB)
667  printf("finished iters\n");
668 #endif
669 
670  /* Check b and eps_a are still in range (negative values indicate first run) */
671  /* on first run through, set lower b limit to lob490 */
672  if (bestb[0] < 0.0 || a[2] / a[3] > maxEpsa) {
673  bestb[0] = b490;
674  besta[0] = a[2];
675  } /* If b and eps_a within range, store upper and lower limits of b and a */
676  /* on second run through, set upper b to lob490+bstep */
677  else {
678  if (bestb[1] < 0.0) {
679  bestb[1] = b490;
680  besta[1] = a[2];
681  //bestb[0]=b490;
682  //besta[0]=a[2];
683  } else if (a[2] / a[3] > minEpsa) {
684  bestb[1] = b490; /* store this upper b-value */
685  besta[1] = a[2]; /* store this upper a-value */
686  }
687  }
688 
689 #if (VERB)
690  printf("besta=[%f %f]\n", besta[0], besta[1]);
691  printf("bestb=[%f %f]\n", bestb[0], bestb[1]);
692 #endif
693 
694  b490 += b490 * bstep;
695 #if (VERB)
696  printf(" [a,b,epsa]=[%f %f %f]\n", a[2], b490, a[2] / a[3]);
697  printf("---finished while\n");
698 #endif
699 
700  } while (b490 < 1.1 * hib490 && a[2] / a[3] > minEpsa); /* end loop through 15 steps in b490 */
701 
702  /* Quality checks */
703  if (bestb[0] > 0.0 && bestb[1] > 0.0) {
704 
705  /* choose best value for b490 */
706  temp1 = pow(besta[0] * besta[1], 0.5);
707 
708  if (b490 > 1.1 * hib490)
709  b490 = bestb[0];
710  else if (bestb[1] / bestb[0] > 20.)
711  b490 = pow(bestb[0] * bestb[1], 0.5);
712  else if (temp1 > 1.0)
713  b490 = bestb[1];
714  else if (temp1 < 0.01)
715  b490 = bestb[0];
716  else
717  b490 = 0.5 * (bestb[0] + bestb[1]);
718 
719 #if (VERB)
720  printf("FINAL1 b490=%f\n", b490);
721 #endif
722 
723  /* keep b within range used for look-up tables */
724  if (b490 > hib490)
725  b490 = hib490;
726  else if (b490 < lob490)
727  b490 = lob490;
728 #if (VERB)
729  printf("FINAL2 b490=%f\n", b490);
730 #endif
731 
732  /* calculate full spectra for a and bb */
733  for (iw = 0; iw < VBANDS; iw++) {
734  /* final b is best b490 adjusted to required spectral shape */
735  b[iw] = b490 * bn[iw];
736 
737  /* initialise a using final best b */
738  a[iw] = 0.2 * (b[iw] * b_tilde + bbw[iw]) / rho[iw] - aw[iw];
739  if (a[iw] < 0.0)
740  a[iw] = 0.001;
741 
742  /* iterate for a and F */
743  iter = 0; /* reset iteration counter */
744  old_err = 100.;
745  new_err = new_err - 1.;
746  while ((old_err - new_err) > tol && iter < maxIts) {
747  old_err = new_err;
748  new_err = 0.0;
749  F[iw] = f_ab(a[iw], b[iw], iw, sensor_id);
750  if (F[iw] > 0.0)
751  temp1 = F[iw] * (b[iw] * b_tilde + bbw[iw]) / rho[iw] - aw[iw];
752  else
753  temp1 = 0.001; /* set a to 0.001 if F unrealistic */
754  if (temp1 < 0.0)
755  temp1 = 0.001; /* set a to 0.001 if derived a was unrealistic */
756  new_err += fabsf(temp1 - a[iw]) / a[iw];
757  a[iw] = temp1;
758  iter++;
759 #if (VERB)
760  printf("%d 2getting aF [a2,F2] =[%f %f] -> %f\n", iter, a[2], F[2], new_err);
761 #endif
762  }
763 #if (VERB)
764  printf("finished iters\n");
765 #endif
766 
767  /* transfer to main result */
768  result->bb[iw] = b[iw] * b_tilde; /* all 'bb' values considered good at this point */
769  if (a[iw] > 0.001001) {
770  result->a[iw] = a[iw];
771  success = TRUE; /* need just one good 'a' band to consider success initially */
772  }
773 #if (VERB)
774  printf("%d main.result1 [a,bb]=[%f %f]\n", iw, result->a[iw], result->bb[iw]);
775 #endif
776  } /* end wavelength loop for final a,bb */
777 
778  /* final quality checks -- both a_490 and a_510 must be good */
779  if (result->a[2] < 0.001 || result->a[3] < 0.001) {
780  success = FALSE;
781  }
782  } /* end if upper and lower b490 values were positive */
783 
784 #if (VERB)
785  printf("Returning\n");
786  (success) ? printf("success\n") : printf("fail\n");
787  printf("result a=%f %f %f %f %f %f\n", result->a[0], result->a[1], result->a[2],
788  result->a[3], result->a[4], result->a[5]);
789  printf("result bb=%f %f %f %f %f %f\n", result->bb[0], result->bb[1], result->bb[2],
790  result->bb[3], result->bb[4], result->bb[5]);
791 #endif
792 
793  return success;
794 }
795 
796 /* ---------------------------------------------------------------------------
797  * init()
798  * perform first time initialisations and load LUTs etc
799  *
800  * inputs: ptr to the l2 record structure (of first scan line)
801  * outputs: none
802  * returns: none
803  * ---------------------------------------------------------------------------
804  */
805 static void init(l2str *l2rec) {
806  int iw, ib;
807 
808  filehandle *l1file = l2rec->l1rec->l1file;
809 
810  printf("\nUsing NIWA / UoP / Moore IOP algorithm.\n");
811 
812  if (load_work_tab() != ABSIND_NS) {
813  printf("\nERROR: NIWA-IOP: failed to load look-up tables.\n");
814  exit(EXIT_FAILURE);
815  }
816 #if (VERB)
817  printf("loaded work table OK\n");
818 #endif
819 
820  switch (l1file->sensorID) {
821  case SEAWIFS:
823  band_map = seawifs_map;
824  break;
825  case MODIST:
826  case MODISA:
828  band_map = modis_map;
829  break;
830  default:
831  printf("\nERROR: NIWA-IOP: The NIWA IOP algorithm requires SeaWiFS or MODIS LAC input data.\n");
832  printf(" [sensor ID = %d]\n", l1file->sensorID);
833  exit(EXIT_FAILURE);
834  }
835 
836  /* make local copy of aw, bbw and lambda for bands we use */
837  for (iw = 0; iw < VBANDS; iw++) {
838  ib = band_map[iw];
839  aw[iw] = l1file->aw[ib];
840  bbw[iw] = l1file->bbw[ib];
841  lambda[iw] = l1file->fwave[ib];
842  }
843 
844  /* The look-up tables assume that no brdf correction has been applied
845  * we require either brdf_opt=0 or valid numbers in the brdf array so can reverse out correction */
846  if (input->brdf_opt > 0) {
847  printf("\nWARNING: NIWA-IOP: brdf correction detected, attempting to reverse (use brdf_opt=0 in future).\n\n");
848  }
849 }
850 
851 /* ---------------------------------------------------------------------------
852  * niwa_iop()
853  * this is the main iop function which must be called once for each scan line
854  *
855  * inputs: the L2 data structure for a single scan line
856  * outputs: a & bb values for VBANDS channels in supplied arrays, flags for each pixel
857  * (a & bb arrays expected size = NBANDS x npix)
858  * returns: none
859  * ---------------------------------------------------------------------------
860  */
861 void niwa_iop(l2str *l2rec, float niwa_a[], float niwa_bb[], int16 niwa_iopf[]) {
862  static int first_time = 1;
863 
864  int iw, ib, ip, ibp, badrrs;
865  float dphiRad, dphi, theta0Rad, thetaRad, brdf[VBANDS], Rrs[VBANDS];
866  abs_res_t result;
867 
868  l1str *l1rec = l2rec->l1rec;
869  filehandle *l1file = l1rec->l1file;
870 
871  /* do inits first time only */
872  if (first_time) {
873  init(l2rec);
874  first_time = 0;
875  }
876 
877  /* --- loop across scan --- */
878  for (ip = 0; ip < l1rec->npix; ip++) {
879 
880  /* start by writing 'no data' value to all output bands
881  * (note this includes bands we do not use) */
882  for (ib = 0; ib < nbands; ib++) {
883  ibp = ip * l1file->nbands + ib;
884  niwa_a[ibp] = NO_DATA;
885  niwa_bb[ibp] = NO_DATA;
886  }
887  niwa_iopf[ip] = 0;
888 
889  /* skip if this pixel already masked out */
890  if (l1rec->mask[ip]) {
891  niwa_iopf[ip] |= IOPF_ISMASKED;
892  continue;
893  }
894 
895  /* take copy of Rrs */
896  badrrs = FALSE;
897  for (iw = 0; iw < VBANDS; iw++) {
898 
899  /* get index to 1-d array l2rec variables */
900  ibp = ip * l1file->nbands + band_map[iw];
901 
902  /* make local copy of Rrs(lambda) at this pixel */
903  Rrs[iw] = l2rec->Rrs[ibp];
904 
905  /* if brdf has been applied, we need to back-correct */
906  if (input->brdf_opt > 0) {
907  brdf[iw] = l2rec->brdf[ibp];
908  Rrs[iw] = (brdf[iw] > 0) ? Rrs[iw] / brdf[iw] : -1;
909  }
910 
911  /* quality check -- all must be >= 0 to procede */
912  if (Rrs[iw] < 0)
913  badrrs = TRUE;
914  }
915  if (badrrs) {
916  niwa_iopf[ip] |= IOPF_BADRRS;
917  continue;
918  }
919  /* Rrs is now non-brdf-corrected */
920 
921  /* set geometry */
922  theta0Rad = radians(l1rec->solz[ip]);
923  thetaRad = radians(l1rec->senz[ip]);
924 
925  /* relative azimuth in 0 - 180.0 (BFranz) */
926  dphi = l1rec->sena[ip] - l1rec->sola[ip];
927  if (dphi > 180.0)
928  dphi -= 360.0;
929  if (dphi < -180.0)
930  dphi += 360.0;
931  dphiRad = radians(dphi);
932 
933  if (!setgeom(theta0Rad, thetaRad, dphiRad)) {
934  printf("WARNING: NIWA-IOP: Viewing geometry is out of look-up table bounds for NIWA IOP algorithm.\n");
935  niwa_iopf[ip] |= IOPF_NIWA_BADGEOM;
936  continue;
937  }
938 
939  /* all looks good -- solve for IOPs at this pixel */
940  if (iop_model1(Rrs, l1file->sensorID, &result)) {
941 
942  /* success -- copy data to output arrays */
943  for (iw = 0; iw < VBANDS; iw++) {
944  ibp = ip * l1file->nbands + band_map[iw];
945  niwa_a[ibp] = result.a[iw];
946  niwa_bb[ibp] = result.bb[iw];
947  }
948  } else {
949  /* record that we attempted to calculate IOPs but failed */
950  niwa_iopf[ip] |= IOPF_FAILED;
951 
952  //### debug for Matt
953  //printf("WARNING: NIWA-IOP: iop_model failed at line %d, pixel %d:\n", l2rec->iscan, ip);
954  //for (iw = 0; iw < VBANDS; ++iw) {
955  // printf("band %d: lambda = %f, Rrs = %f, aw = %f, bbw = %f, a = %f, bb = %f\n",
956  // iw, lambda[iw], Rrs[iw], aw[iw], bbw[iw], result.a[iw], result.bb[iw]);
957  //}
958  }
959  }
960  /* report fail for all pixels where any flags were set */
961  for (ip = 0; ip < l1rec->npix; ip++)
962  if (niwa_iopf[ip] != 0)
963  l1rec->flags[ip] |= PRODFAIL;
964 }
int32 l1file(int32 sdfid, int32 *nsamp, int32 *nscans, int16 *dtynum)
Definition: l1stat_chk.c:586
integer, parameter int16
Definition: cubeio.f90:3
int r
Definition: decode_rs.h:73
data_t t[NROOTS+1]
Definition: decode_rs.h:77
#define IOPF_ISMASKED
Definition: flags_iop.h:8
#define FALSE
Definition: rice.h:164
#define NULL
Definition: decode_rs.h:63
#define TH_NS
Definition: niwa_iop.c:39
read l1rec
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
float32 * pos
Definition: l1_czcs_hdf.c:35
#define TRUE
Definition: rice.h:165
#define MODIST
Definition: sensorDefs.h:18
#define PRODFAIL
Definition: l2_flags.h:41
data_t lambda[NROOTS+1]
Definition: decode_rs.h:75
void niwa_iop(l2str *l2rec, float niwa_a[], float niwa_bb[], int16 niwa_iopf[])
Definition: niwa_iop.c:861
instr * input
const double F
int init(int32_t ipr, int32_t jpr, char *efile, char *pfile)
Definition: proj_report.c:51
#define radians(degrees)
Definition: niwa_iop.c:29
#define BP_NS
Definition: niwa_iop.c:42
#define AP_NS
Definition: niwa_iop.c:41
float tol
const float NO_DATA
Definition: niwa_iop.c:55
#define M_PI
Definition: pml_iop.h:15
#define LBANDS
Definition: niwa_iop.c:33
#define SEAWIFS_NBANDS
Definition: niwa_iop.c:35
float bb[VBANDS]
Definition: niwa_iop.c:83
data_t b[NROOTS+1]
Definition: decode_rs.h:77
#define BAD_FLT
Definition: jplaeriallib.h:19
float a[VBANDS]
Definition: niwa_iop.c:82
int32_t nbands
data_t u
Definition: decode_rs.h:74
#define IOPF_NIWA_BADGEOM
Definition: niwa_iop.c:45
#define DPHI_NS
Definition: niwa_iop.c:40
#define IOPF_BADRRS
Definition: flags_iop.h:11
#define VBANDS
Definition: niwa_iop.c:34
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 IOPF_FAILED
Definition: flags_iop.h:9
#define SEAWIFS
Definition: sensorDefs.h:12
int i
Definition: decode_rs.h:71
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
PGE01 indicating that PGE02 PGE01 V6 for and PGE01 V2 for MOD03 were used to produce the granule By convention adopted in all MODIS Terra PGE02 code versions are The fourth digit of the PGE02 version denotes the LUT version used to produce the granule The source of the metadata environment variable ProcessingCenter was changed from a QA LUT value to the Process Configuration A sign used in error in the second order term was changed to a
Definition: HISTORY.txt:424
#define MODISA
Definition: sensorDefs.h:19
#define MODIS_NBANDS
Definition: niwa_iop.c:36
int k
Definition: decode_rs.h:73
#define ABSIND_NS
Definition: niwa_iop.c:43