NASA Logo
Ocean Color Science Software

ocssw V2022
convert_band.c
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <math.h>
3 #include "l12_proto.h"
4 
5 #define MINWVDIFF 10
6 #define REFWVL 443
7 
8 typedef struct _context {
9  float *wvl_i;
10  float *tar_rrs;
11  float *aw_i, *bbw_i, *aBric_i, *bBric_i;
12  float *aw_o, *bbw_o, *aBric_o, *bBric_o;
13  float *aphRef, *adgRef, *bbpRef;
15 } ccstr;
16 
17 float conv_rrs_to_555(float Rrs, float wave, float uRrs_in, float *uRrs_out ) {
18  float sw, a1, b1, a2, b2;
19  float temp_Rrs;
20 
21  if (fabs(wave - 555) > 2) {
22  if (fabs(wave - 547) <= 2) {
23  sw = 0.001723;
24  a1 = 0.986;
25  b1 = 0.081495;
26  a2 = 1.031;
27  b2 = 0.000216;
28  } else if (fabs(wave - 550) <= 2) {
29  sw = 0.001597;
30  a1 = 0.988;
31  b1 = 0.062195;
32  a2 = 1.014;
33  b2 = 0.000128;
34  } else if (fabs(wave - 560) <= 2) {
35  sw = 0.001148;
36  a1 = 1.023;
37  b1 = -0.103624;
38  a2 = 0.979;
39  b2 = -0.000121;
40  } else if (fabs(wave - 565) <= 2) {
41  sw = 0.000891;
42  a1 = 1.039;
43  b1 = -0.183044;
44  a2 = 0.971;
45  b2 = -0.000170;
46  } else {
47  printf("-E- %s line %d: Unable to convert Rrs at %f to 555nm.\n", __FILE__, __LINE__, wave);
48  exit(1);
49  }
50 
51  if (Rrs < sw){
52  temp_Rrs=Rrs;
53  Rrs = pow(10.0, a1 * log10(Rrs) - b1);
54  if(uRrs_out) {
55  *uRrs_out=Rrs*a1/temp_Rrs*uRrs_in;
56  }
57  } else{
58  Rrs = a2 * Rrs - b2;
59  if(uRrs_out) {
60  *uRrs_out=a2*uRrs_in;
61  }
62  }
63  }
64 
65  return (Rrs);
66 }
67 
68 /*
69 int windex(float wave, float twave[], int ntwave)
70 {
71  int iw, index;
72  float wdiff;
73  float wdiffmin = 99999.;
74 
75  for (iw=0; iw<ntwave; iw++) {
76 
77  // break on exact match
78  if (twave[iw] == wave) {
79  index = iw;
80  break;
81  }
82 
83  // look for closest
84  wdiff = fabs(twave[iw]-wave);
85  if (wdiff < wdiffmin) {
86  wdiffmin = wdiff;
87  index = iw;
88  }
89  }
90 
91  return(index);
92 }
93  */
94 void grabBricaud(float wvl[], int nwvl, float* a_bricaud, float* b_bricaud) {
95 
96  float bricaud_L_A_B[][17] ={
97  {410, 412, 413, 440, 443, 488, 490, 510, 530, 531, 547, 550, 555, 560, 665, 667, 670},
98  {0.0313, 0.0323, 0.032775, 0.0403, 0.0394, 0.0279, 0.0274, 0.018, 0.0117, 0.0115, 0.00845,
99  0.008, 0.007, 0.0062, 0.0152, 0.01685, 0.0189},
100  {0.283, 0.286, 0.28775, 0.332, 0.3435, 0.369, 0.361, 0.260, 0.139, 0.134, 0.0625,
101  0.052, 0.0315, 0.016, 0.134, 0.140, 0.149}
102  };
103 
104  int wvlToSrch = 17;
105  int kb = 0, ko = 0;
106  int srchCounter = 0;
107 
108  /* if (wvl[nwvl-1] > bricaud_L_A_B[0][wvlToSrch - 1]){
109  printf ("-E- %s line %d: Bricaud coefficient not available for band %f :(\n",
110  __FILE__,__LINE__,wvl[ko]);
111  exit(1);
112  }*/
113  while (ko < nwvl && srchCounter < wvlToSrch) {
114 
115  if (wvl[ko] == bricaud_L_A_B[0][kb]) {
116  a_bricaud[ko] = bricaud_L_A_B[1][kb];
117  b_bricaud[ko] = bricaud_L_A_B[2][kb];
118  ko++;
119  srchCounter = 0;
120  } else if (wvl[ko] < bricaud_L_A_B[0][kb]) {
121  kb--;
122  srchCounter += 1;
123  } else {
124  kb++;
125  srchCounter += 1;
126  }
127  }
128 }
129 
130 void grabAwBw(float wvl[], int nwvl, float aw[], float bw[]) {
131  int i;
132  for (i = 0; i < nwvl; i++) {
133  aw[i] = aw_spectra(wvl[i], 11);
134  bw[i] = bbw_spectra(wvl[i], 11);
135  }
136  // float pwLAwBw[][17] =
137  // {
138  // {410,412,413,440,443,488,490,510,530,531,547,550,555,560,665,667,670},
139  // {0.00473,0.00455056,0.00449607,0.00635,0.00706914,0.0145167,0.015,0.0325,0.0434,
140  // 0.0439153,0.0531686,0.0565,0.0596,0.0619,0.429,0.434888,0.439},
141  // {0.0059145,0.00579201,0.00573196,0.00437075,0.00424592,0.00281659,0.00276835,0.00233870,
142  // 0.00198953,0.00197385,0.00174280,0.00170333,0.00163999,0.00157958,0.000772104,
143  // 0.000762543,0.000748479}
144  // };
145  //
146  // int wvlToSrch = 17;
147  // int kb=0,ko=0;
148  // int srchCounter = 0;
149  //
150  // /*if (wvl[nwvl-1] > pwLAwBw[0][wvlToSrch-1]){
151  // printf ("-E-: purewater coefficient not found for band %f >:(\n",wvl[ko]);
152  // exit(1);
153  // }
154  // */
155  // while (ko<nwvl && srchCounter<wvlToSrch){
156  // if (wvl[ko] == pwLAwBw[0][kb]){
157  // aw[ko] = pwLAwBw[1][kb];
158  // bw[ko] = pwLAwBw[2][kb];
159  // ko++;
160  // srchCounter = 0;
161  // }
162  //
163  // else if (wvl[ko] < pwLAwBw[0][kb]){
164  // kb--;
165  // srchCounter+=1;
166  // }
167  // else{
168  // kb++;
169  // srchCounter+=1;
170  // }
171  // }
172 }
173 
174 void calcQAA443(float ab_surf_rrs[], float wvl[], int nwvl, ccstr *ctxt) {
175  int ib;
176  float *blw_surf_rrs, *u_ptr;
177  float c1 = 0.52, c2 = 1.7;
178  float g0 = 0.089, g1 = 0.125;
179  float a0, bbp0, bbp0_exp, a0_exp;
180  float ratio_aph, slope_adg, ratio_adg;
181  static int firstCall = 1;
182  static int rIdx = -1, gIdx = -1, bgIdx = -1, refIdx = -1, purIdx = -1;
183 
184  blw_surf_rrs = (float*) malloc(nwvl * sizeof (float));
185  u_ptr = (float*) malloc(nwvl * sizeof (float));
186 
187  // get some indices:
188  if (firstCall) {
189  rIdx = windex(670, wvl, nwvl); // red (~670) band, idx=5 in Melin's code
190  gIdx = windex(550, wvl, nwvl); // green (~555) , idx=4 ---------------
191  bgIdx = windex(490, wvl, nwvl); // blue-green (~490),idx=2 ---------------
192  refIdx = windex(REFWVL, wvl, nwvl); //ref (~443), idx=1 ---------------
193  purIdx = windex(412, wvl, nwvl); // purple (~412), idx=0 ---------------
194  firstCall = 0;
195  }
196  float bbp[refIdx + 1], a[refIdx + 1];
197  // BEG ----- red band correction
198  float up_667 = 20 * pow(ab_surf_rrs[gIdx], 1.5);
199  float lw_667 = 0.9 * pow(ab_surf_rrs[gIdx], 1.7);
200  if (ab_surf_rrs[rIdx] > up_667 || ab_surf_rrs[rIdx] < lw_667) {
201  ab_surf_rrs[rIdx] = 1.27 * pow(ab_surf_rrs[gIdx], 1.47) +
202  0.00018 * pow(ab_surf_rrs[gIdx] / (ab_surf_rrs[bgIdx]), -3.19);
203 
204  }
205  // END ----- red band correciton
206 
207  for (ib = 0; ib < nwvl; ib++) {
208 
209  *(blw_surf_rrs + ib) = ab_surf_rrs[ib] / (c1 + c2 * ab_surf_rrs[ib]);
210  *(u_ptr + ib) = (-g0 + pow(pow(g0, 2) + 4 * g1 *
211  *(blw_surf_rrs + ib), 0.5)) / (2 * g1);
212  }
213  a0_exp = log10(
214  (*(blw_surf_rrs + refIdx) + *(blw_surf_rrs + bgIdx)) /
215  (*(blw_surf_rrs + gIdx) + 5 * (*(blw_surf_rrs + rIdx) /
216  *(blw_surf_rrs + bgIdx)) *
217  *(blw_surf_rrs + rIdx))
218  );
219  a0 = *(ctxt->aw_i + gIdx) + pow(10.0, (-1.146 - (1.366 * a0_exp) -(0.469 * pow(a0_exp, 2))));
220  bbp0 = *(u_ptr + gIdx) * a0 / (1 - *(u_ptr + gIdx)) - *(ctxt->bbw_i + gIdx);
221  bbp0_exp = 2 * (1 - 1.2 * exp(-0.9 * *(blw_surf_rrs + refIdx) / *(blw_surf_rrs + gIdx)));
222  ratio_aph = 0.74 + (0.2 / (0.8 + *(blw_surf_rrs + refIdx) / *(blw_surf_rrs + gIdx)));
223  slope_adg = 0.015 + 0.002 / (0.6 + *(blw_surf_rrs + refIdx) / *(blw_surf_rrs + gIdx));
224  ratio_adg = exp(slope_adg * (wvl[refIdx] - wvl[purIdx]));
225  for (ib = 0; ib <= refIdx; ib++) {
226 
227  bbp[ib] = bbp0 * pow((wvl[gIdx] / wvl[ib]), bbp0_exp);
228  a[ib] = (1 - *(u_ptr + ib)) * (bbp[ib] + *(ctxt->bbw_i + ib)) / *(u_ptr + ib);
229  }
230  *(ctxt->adgRef) = ((a[purIdx] - ratio_aph * a[refIdx]) - (*(ctxt->aw_i + purIdx) - ratio_aph * *(ctxt->aw_i + refIdx))) /
231  (ratio_adg - ratio_aph);
232  *(ctxt->aphRef) = a[refIdx] - *(ctxt->aw_i + refIdx) - *(ctxt->adgRef);
233  *(ctxt->bbpRef) = bbp[refIdx];
234 }
235 
236 /*
237  *Interpolation for cases with more than 2 input bands used
238  */
239 
240 float invDistInterp(ccstr *ctxt, float xout) {
241  /*
242  float invDistInterp(float xin[],float yin[],int ninout,float xout){*/
243  float wt, interpOut;
244  float wtSum = 0.0;
245  float prodSum = 0.0;
246  int in;
247  for (in = 0; in<*ctxt->num_wvl_i; in++) {
248  wt = 1.0 / fabs(ctxt->wvl_i[in] - xout);
249  prodSum += wt * ctxt->tar_rrs[in];
250  wtSum += wt;
251 
252  }
253  interpOut = prodSum / wtSum;
254  return interpOut;
255 }
256 
257 /*
258  * Function to identify band or bands (at most 2) to be used
259  */
260 
261 void idInputBand(float inputWvl[], float targetWvl, ccstr *ctxt, int nin) {
262  /* Function to match the target Wvl with one or two input Wvl.
263  * Two wavelengths are deemed necessary if the target wvl and the closest input wvl
264  * are more than 10nm apart. If this is the case and the input wvl is smaller than the
265  * target wvl, then the next higher wvl is also recruited. Similarly, if the input wvl is greater
266  * than the target wvl, the next smaller wvl is also recruited for shifting.
267  */
268  int closeIdx, kb;
269  int nout = 2;
270  int idx[2];
271  closeIdx = windex(targetWvl, inputWvl, nin);
272  if (((inputWvl[closeIdx] - targetWvl) > MINWVDIFF) && (closeIdx > 0)) {
273  idx[0] = closeIdx - 1;
274  idx[1] = closeIdx;
275  } else if (((inputWvl[closeIdx] - targetWvl) < -MINWVDIFF) && (closeIdx < (nin - 1))) {
276  idx[0] = closeIdx;
277  idx[1] = closeIdx + 1;
278  } else {
279  nout = 1;
280  idx[0] = closeIdx;
281  }
282  ctxt->sh_strt_idx = (int*) malloc(nout * sizeof (int));
283  ctxt->wvl_i = (float*) malloc(nout * sizeof (float));
284  ctxt->num_wvl_i = (int*) malloc(sizeof (int));
285  *(ctxt->num_wvl_i) = nout;
286  //*startWvlIdx = (int*)malloc(*nout*sizeof(int));
287  for (kb = 0; kb < nout; kb++) {
288  *(ctxt->sh_strt_idx + kb) = idx[kb];
289  *(ctxt->wvl_i + kb) = inputWvl[idx[kb]];
290  }
291  //*(*(startWvlIdx)+kb) = idx[kb];
292 
293 }
294 
295 /*
296  * Actual band shifting function
297  */
298 
299 void shiftBand(float inputWvl[], float inputRrs[], float chla, int numBands, float tarWvl, ccstr* ctxt)
300  {
301  //float* wvlIn,*rrsIn;
302  float wvlIn, rrsIn, refwvl;
303  float s = 0.015, g0 = 0.089, g1 = 0.125, c1 = -0.52, c2 = 1.7;
304  static int gIdx = -1, refIdx = -1; //,firstCall=1;
305  float b2g, sdg, yy; //,chla;
306  float ll_i, aph_i, adg_i, bbp_i;
307  float a_tot_i, bb_tot_i, qaa_fwd_i, qaa_rrs_bbw_i, qaa_rrs_aw_i;
308  float ll_o, aph_o, adg_o, bbp_o;
309  float a_tot_o, bb_tot_o, qaa_fwd_o, qaa_rrs_bbw_o, qaa_rrs_aw_o, correc_factor;
310  int kb, nin, idx;
311 
312 
313  //if(firstCall){
314  gIdx = windex(550, inputWvl, numBands);
315  refIdx = windex(REFWVL, inputWvl, numBands);
316  //firstCall=0;
317  refwvl = inputWvl[refIdx];
318  //}
319  nin = *(ctxt->num_wvl_i);
320 
321  b2g = inputRrs[refIdx] / inputRrs[gIdx];
322  sdg = s + 0.002 / (0.6 + b2g);
323  yy = 2 * (1 - 1.2 * exp(-0.9 * b2g));
324 
325  // chla = pow((*(ctxt->aphRef) / *(ctxt->aBric_i+refIdx)),1/(1-*(ctxt->bBric_i+refIdx)));
326  for (kb = 0; kb < nin; kb++) {
327  idx = *(ctxt->sh_strt_idx + kb);
328  wvlIn = inputWvl[idx];
329  rrsIn = inputRrs[idx];
330 
331  ll_i = wvlIn - refwvl;
332  aph_i = aph_bricaud(wvlIn, chla); //pow( (*(ctxt->aBric_i+idx) * chla),*(ctxt->bBric_i+idx));
333  adg_i = *(ctxt->adgRef) * exp(-sdg * ll_i);
334  bbp_i = *(ctxt->bbpRef) * pow((443 / wvlIn), yy);
335  a_tot_i = aph_i + adg_i + *(ctxt->aw_i + idx);
336  bb_tot_i = bbp_i + *(ctxt->bbw_i + idx);
337  qaa_fwd_i = bb_tot_i / (a_tot_i + bb_tot_i);
338  qaa_rrs_bbw_i = (g0 + g1 * qaa_fwd_i) * qaa_fwd_i;
339  qaa_rrs_aw_i = (c1 * qaa_rrs_bbw_i) / ((c2 * qaa_rrs_bbw_i) - 1);
340 
341  ll_o = tarWvl - REFWVL;
342  aph_o = aph_bricaud(tarWvl, chla); //aph_o = pow( ( *(ctxt->aBric_o) * chla),*(ctxt->bBric_o));
343  adg_o = *(ctxt->adgRef) * exp(-sdg * ll_o);
344  bbp_o = *(ctxt->bbpRef) * pow((443 / tarWvl), yy);
345  a_tot_o = aph_o + adg_o + *(ctxt->aw_o);
346  bb_tot_o = bbp_o + *(ctxt->bbw_o);
347  qaa_fwd_o = bb_tot_o / (a_tot_o + bb_tot_o);
348  qaa_rrs_bbw_o = (g0 + g1 * qaa_fwd_o) * qaa_fwd_o;
349  qaa_rrs_aw_o = (c1 * qaa_rrs_bbw_o) / ((c2 * qaa_rrs_bbw_o) - 1);
350  correc_factor = qaa_rrs_aw_o / qaa_rrs_aw_i;
351  *(ctxt->tar_rrs + kb) = rrsIn * correc_factor;
352  }
353 
354 }
355 
356 void deMalloc(ccstr* ctxt) {
357  free(ctxt->aw_i);
358  free(ctxt->bbw_i);
359  free(ctxt->aBric_i);
360  free(ctxt->bBric_i);
361  free(ctxt->aw_o);
362  free(ctxt->bbw_o);
363  free(ctxt->aBric_o);
364  free(ctxt->bBric_o);
365  free(ctxt->aphRef);
366  free(ctxt->adgRef);
367  free(ctxt->bbpRef);
368  free(ctxt->tar_rrs);
369  free(ctxt->num_wvl_i);
370  free(ctxt->wvl_i);
371  free(ctxt->sh_strt_idx);
372 
373 }
374 
375 float bioBandShift(float wvl[], float rrs[], float chla, int nw, float tarWvl) {
376  ccstr sh_ctxt; //band-shifting context structure
377  float result;
378  idInputBand(wvl, tarWvl, &sh_ctxt, nw);
379  sh_ctxt.aw_i = (float*) malloc(nw * sizeof (float));
380  sh_ctxt.bbw_i = (float*) malloc(nw * sizeof (float));
381  sh_ctxt.aBric_i = (float*) malloc(nw * sizeof (float));
382  sh_ctxt.bBric_i = (float*) malloc(nw * sizeof (float));
383  sh_ctxt.aw_o = (float*) malloc(sizeof (float));
384  sh_ctxt.bbw_o = (float*) malloc(sizeof (float));
385  sh_ctxt.aBric_o = (float*) malloc(sizeof (float));
386  sh_ctxt.bBric_o = (float*) malloc(sizeof (float));
387  sh_ctxt.aphRef = (float*) malloc(sizeof (float));
388  sh_ctxt.adgRef = (float*) malloc(sizeof (float));
389  sh_ctxt.bbpRef = (float*) malloc(sizeof (float));
390  sh_ctxt.tar_rrs = (float*) malloc(sizeof (float));
391 
392  grabAwBw(wvl, nw, sh_ctxt.aw_i, sh_ctxt.bbw_i);
393  grabAwBw(&tarWvl, 1, sh_ctxt.aw_o, sh_ctxt.bbw_o);
394 
395  calcQAA443(rrs, wvl, nw, &sh_ctxt);
396  shiftBand(wvl, rrs, chla, nw, tarWvl, &sh_ctxt);
397  if (*sh_ctxt.num_wvl_i > 1)
398  result = invDistInterp(&sh_ctxt, tarWvl);
399 
400  else
401  result = *(sh_ctxt.tar_rrs);
402  deMalloc(&sh_ctxt);
403  return result;
404 }
float * bbw_o
float * tar_rrs
Definition: convert_band.c:10
float * adgRef
Definition: convert_band.c:13
void grabBricaud(float wvl[], int nwvl, float *a_bricaud, float *b_bricaud)
Definition: convert_band.c:94
float * bbpRef
Definition: convert_band.c:13
float * aphRef
Definition: convert_band.c:13
float * bBric_i
Definition: convert_band.c:11
void grabAwBw(float wvl[], int nwvl, float aw[], float bw[])
Definition: convert_band.c:130
float * wvl_i
float * aBric_o
Definition: convert_band.c:12
#define REFWVL
Definition: convert_band.c:6
void deMalloc(ccstr *ctxt)
Definition: convert_band.c:356
float * aw_o
float * bbw_i
float invDistInterp(ccstr *ctxt, float xout)
Definition: convert_band.c:240
float * aw_i
int * num_wvl_i
Definition: convert_band.c:14
void calcQAA443(float ab_surf_rrs[], float wvl[], int nwvl, ccstr *ctxt)
Definition: convert_band.c:174
int * sh_strt_idx
Definition: convert_band.c:14
float aw_spectra(int32_t wl, int32_t width)
float * bBric_o
Definition: convert_band.c:12
float bbw_spectra(int32_t wl, int32_t width)
float conv_rrs_to_555(float Rrs, float wave, float uRrs_in, float *uRrs_out)
Definition: convert_band.c:17
#define MINWVDIFF
Definition: convert_band.c:5
float * aBric_i
Definition: convert_band.c:11
instead the metadata field ProcessingEnvinronment is filled in from the output of a call to the POSIX compliant function uname from within the L1B code A small bug in L1B_Tables an incorrect comparison of RVS coefficients for TEBs to RVS coefficients for RSBs was being made This was replaced with a comparison between TEB coefficients This error never resulted in an incorrect RVS correction but did lead to recalculating the coefficients for each detector in a thermal band even if the coefficients were the same for all detectors To reduce to overall size of the reflective LUT HDF fill values were eliminated from all LUTs previously dimensioned where and where NUM_TIMES is the number of time dependent table pieces In Preprocess a small error where the trailing dropped scan counter was incremented when the leading dropped scan counter should have been was fixed This counter is internal only and is not yet used for any chiefly to casting of were added to make it LINUX compatible Output of code run on LINUX machines displays differences of at most scaled sector incalculable values of the Emissive calibration factor b1
Definition: HISTORY.txt:576
void shiftBand(float inputWvl[], float inputRrs[], float chla, int numBands, float tarWvl, ccstr *ctxt)
Definition: convert_band.c:299
#define fabs(a)
Definition: misc.h:93
int windex(float wave, float twave[], int ntwave)
Definition: windex.c:73
data_t s[NROOTS]
Definition: decode_rs.h:75
float bioBandShift(float wvl[], float rrs[], float chla, int nw, float tarWvl)
Definition: convert_band.c:375
int i
Definition: decode_rs.h:71
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
float aph_bricaud(float wave, float chl)
Definition: aph.c:181
void idInputBand(float inputWvl[], float targetWvl, ccstr *ctxt, int nin)
Definition: convert_band.c:261