OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
cdom_morel.c
Go to the documentation of this file.
1 #include "l12_proto.h"
2 
3 #define NTAB 100
4 #define MAXLINE 1024
5 
6 static float badval = BAD_FLT;
7 static int32_t LastRecNum = -1;
8 static float adg_s = 0.018;
9 static float *chl;
10 static float *idx;
11 
12 
13 /* ---------------------------------------------------------------------------- */
14 /* run_cdom_morel - computes A. Morel's CDOM index and associated prodsucts. */
15 /* */
16 /* Reference: */
17 /* */
18 /* A. Morel, G. Gentili, A simple band ratio technique to quantify the colored */
19 /* disolved and detrital organic material from ocean color remotely sensed data.*/
20 /* Rem. Sens. Env., 2009. */
21 /* */
22 /* Implementation: */
23 /* */
24 /* B. Franz, NASA/OBPG, April 2009. */
25 /* */
26 
27 /* ---------------------------------------------------------------------------- */
28 void run_cdom_morel(l2str *l2rec) {
29  static int firstCall = 1;
30  static float idxtab [NTAB][NTAB]; // CDOM index
31  static float chltab [NTAB][NTAB]; // Chlorophyll
32  static float xtab [NTAB]; // R412:R443 ratio
33  static float ytab [NTAB]; // R490:R555 ratio
34  static int nx;
35  static int ny;
36  static int ib412 = -1;
37  static int ib443 = -1;
38  static int ib490 = -1;
39  static int ib555 = -1;
40 
41  float *Q0;
42  float R412;
43  float R443;
44  float R490;
45  float R555;
46  float xrat, yrat;
47  float t, u, w[4], wt;
48  int i, j, ip, ipb;
49 
50  l1str *l1rec = l2rec->l1rec;
51  filehandle *l1file = l1rec->l1file;
52 
53  if (firstCall) {
54 
55  char filename[FILENAME_MAX];
56  char *delim = ";";
57  FILE *fp;
58  char *tmp_str, *path;
59  char line [MAXLINE];
60  char buff [MAXLINE];
61 
62  if ((path = getenv("OCDATAROOT")) == NULL) {
63  printf("OCDATAROOT environment variable is not defined.\n");
64  exit(1);
65  }
66 
67  // number of visible bands and specific band indices
68 
69  ib412 = bindex_get(412);
70  ib443 = bindex_get(443);
71  ib490 = bindex_get(490);
72  ib555 = bindex_get(551);
73  ib555 = bindex_get(545);
74  if (ib555 < 0) ib555 = bindex_get(550);
75  if (ib555 < 0) ib555 = bindex_get(555);
76  if (ib555 < 0) ib555 = bindex_get(560);
77  if (ib412 < 0 || ib443 < 0 || ib490 < 0 || ib555 < 0) {
78  printf("cdom_morel: incompatible sensor wavelengths for this algorithm\n");
79  exit(1);
80  }
81 
82  // read look-up table for band ratio to chl
83 
85  strcat(filename, "/common/morel_chl_R490_R555.dat");
86  fp = fopen(filename, "r");
87  if (!fp) {
88  printf("-E- %s line %d: error opening (%s) file", __FILE__, __LINE__, filename);
89  exit(1);
90  }
91 
92  printf("\nLoading Morel CDOM table from file %s\n", filename);
93 
94  j = 0;
95  while (fgets(line, MAXLINE, fp) != NULL) {
96  strcpy(buff, line);
97  tmp_str = strtok(buff, delim);
98  if (strcmp(tmp_str, "R412/R443") == 0) {
99  i = 0;
100  while ((tmp_str = strtok(NULL, delim)) != NULL) {
101  xtab[i] = atof(tmp_str);
102  i++;
103  }
104  nx = i;
105  } else if (strcmp(tmp_str, "R490/R555") == 0) {
106  ;
107  } else {
108  ytab[j] = atof(tmp_str);
109  i = 0;
110  while ((tmp_str = strtok(NULL, delim)) != NULL) {
111  if (strcmp(tmp_str, "NA") != 0)
112  chltab[i][j] = atof(tmp_str);
113  else
114  chltab[i][j] = -999;
115  i++;
116  }
117  if (i != nx) {
118  printf("-E- %s line %d: error reading (%s) file", __FILE__, __LINE__, filename);
119  exit(1);
120  }
121  j++;
122  }
123  }
124  ny = j;
125 
126  printf("Read %d x %d entries.\n", nx, ny);
127 
128  // read look-up table for band ratio to CDOM index
129 
130  strcpy(filename, path);
131  strcat(filename, "/common/morel_cdm_index.dat");
132  fp = fopen(filename, "r");
133  if (!fp) {
134  printf("-E- %s line %d: error opening (%s) file", __FILE__, __LINE__, filename);
135  exit(1);
136  }
137 
138  printf("\nLoading Morel CDOM table from file %s\n", filename);
139 
140  j = 0;
141  while (fgets(line, MAXLINE, fp) != NULL) {
142  strcpy(buff, line);
143  tmp_str = strtok(buff, delim);
144  if (strcmp(tmp_str, "R412/R443") == 0) {
145  i = 0;
146  while ((tmp_str = strtok(NULL, delim)) != NULL) {
147  xtab[i] = atof(tmp_str);
148  i++;
149  }
150  nx = i;
151  } else if (strcmp(tmp_str, "R490/R555") == 0) {
152  ;
153  } else {
154  ytab[j] = atof(tmp_str);
155  i = 0;
156  while ((tmp_str = strtok(NULL, delim)) != NULL) {
157  if (strcmp(tmp_str, "NA") != 0)
158  idxtab[i][j] = atof(tmp_str);
159  else
160  idxtab[i][j] = -999;
161  i++;
162  }
163  if (i != nx) {
164  printf("-E- %s line %d: error reading (%s) filename", __FILE__, __LINE__, filename);
165  exit(1);
166  }
167  j++;
168  }
169  }
170  ny = j;
171 
172  printf("Read %d x %d entries.\n", nx, ny);
173 
174  // allocate space for static arrays
175 
176  if ((chl = calloc(l1rec->npix, sizeof (float))) == NULL) {
177  printf("-E- %s line %d : error allocating memory for Morel CDOM.\n",
178  __FILE__, __LINE__);
179  exit(1);
180  }
181 
182  if ((idx = calloc(l1rec->npix, sizeof (float))) == NULL) {
183  printf("-E- %s line %d : error allocating memory for Morel CDOM.\n",
184  __FILE__, __LINE__);
185  exit(1);
186  }
187 
188  firstCall = 0;
189  }
190 
191  if ((Q0 = calloc(l1file->nbands, sizeof (float))) == NULL) {
192  printf("-E- %s line %d : error allocating memory for Q0 Morel CDOM.\n",
193  __FILE__, __LINE__);
194  exit(1);
195  }
196 
197  // table look-up and interpolation for CDOM index and chl
198 
199  for (ip = 0; ip < l1rec->npix; ip++) {
200  ipb = ip * l1file->nbands;
201  idx[ip] = badval;
202  chl[ip] = badval;
203  if (l2rec->chl[ip] > 0.0) {
204  // get Rrs and convert to irradiance reflectance
205  qint_morel(l1file->fwave, l1file->nbands, 0.0, l2rec->chl[ip], Q0);
206  R412 = l2rec->Rrs[ipb + ib412] * Q0[ib412];
207  R443 = l2rec->Rrs[ipb + ib443] * Q0[ib443];
208  R490 = l2rec->Rrs[ipb + ib490] * Q0[ib490];
209  R555 = conv_rrs_to_555(l2rec->Rrs[ipb + ib555], l1file->fwave[ib555]) * Q0[ib555];
210  if (R443 > 0.0 && R555 > 0.0) {
211  // compute ratios and locate bounding table entries
212  xrat = MAX(MIN(R412 / R443, xtab[nx - 1]), xtab[0]);
213  yrat = MAX(MIN(R490 / R555, ytab[ny - 1]), ytab[0]);
214  for (i = 0; i < nx - 2; i++)
215  if (xtab[i] > xrat)
216  break;
217  for (j = 0; j < ny - 2; j++)
218  if (ytab[j] > yrat)
219  break;
220  // bilinearly interpolate, weigh missing table values to zero
221  t = (xrat - xtab[i]) / (xtab[i + 1] - xtab[i]);
222  u = (yrat - ytab[j]) / (ytab[j + 1] - ytab[j]);
223 
224  w[0] = (idxtab[i ][j ] > -1) * (1 - t)*(1 - u);
225  w[1] = (idxtab[i ][j + 1] > -1) * t * (1 - u);
226  w[2] = (idxtab[i + 1][j + 1] > -1) * t*u;
227  w[3] = (idxtab[i + 1][j ] > -1) * (1 - t) * u;
228 
229  wt = w[0] + w[1] + w[2] + w[3];
230 
231  if (wt > 0.0) {
232  idx[ip] = (idxtab[i ][j ] * w[0]
233  + idxtab[i ][j + 1] * w[1]
234  + idxtab[i + 1][j + 1] * w[2]
235  + idxtab[i + 1][j ] * w[3]) / wt;
236  chl[ip] = (chltab[i ][j ] * w[0]
237  + chltab[i ][j + 1] * w[1]
238  + chltab[i + 1][j + 1] * w[2]
239  + chltab[i + 1][j ] * w[3]) / wt;
240  } else {
241  l1rec->flags[ip] |= PRODFAIL; // missing table values
242  }
243  } else {
244  l1rec->flags[ip] |= PRODFAIL; // bad input Rrs
245  }
246  } else {
247  l1rec->flags[ip] |= PRODFAIL; // bad input chl
248  }
249  }
250 
251  LastRecNum = l1rec->iscan;
252  free(Q0);
253 }
254 
255 
256 /* ------------------------------------------------------------------- */
257 /* test if this line has been processed */
258 
259 /* ------------------------------------------------------------------- */
261  if (recnum == LastRecNum)
262  return 1;
263  else
264  return 0;
265 }
266 
267 
268 /* ------------------------------------------------------------------- */
269 /* compute absorption (adg) for given chl and CDOM index */
270 
271 /* ------------------------------------------------------------------- */
272 float adg_morel(float chl, float idx, float wave) {
273  if (chl > 0.0 && idx > badval + 1)
274  return (idx * 0.065 * pow(chl, 0.63) * exp(-adg_s * (wave - 400)));
275  else
276  return (badval);
277 }
278 
279 
280 /* ------------------------------------------------------------------- */
281 /* compute percent CDOM for given chl and CDOM index */
282 
283 /* ------------------------------------------------------------------- */
284 float pcdom_morel(float chl, float idx) {
285  float adg;
286  float aph;
287 
288  if (chl > 0.0 && idx > badval + 1) {
289  aph = 0.03782 * pow(chl, 0.635);
290  adg = adg_morel(chl, idx, 440.0);
291  return (100 * adg / (adg + aph));
292  } else
293  return (badval);
294 }
295 
296 
297 /* ------------------------------------------------------------------- */
298 /* compute cdom-corrected chlorophyll */
299 
300 /* ------------------------------------------------------------------- */
301 float chl_cdomcorr_morel(float chl, float idx) {
302  float A[] = {-73.65, -35.92, 15.3, 14.8};
303  float X, Y;
304 
305  if (chl > 0.0 && idx > 0.0) {
306  idx = MIN(MAX(idx, 0.1), 10.0);
307  X = log10(idx);
308  Y = X * (A[0] + X * (A[1] + X * (A[2] + X * A[3])));
309  return (chl * (1 + Y / 100));
310  } else
311  return (badval);
312 }
313 
314 
315 /* ------------------------------------------------------------------- */
316 /* interface to convl12() */
317 
318 /* ------------------------------------------------------------------- */
319 void get_cdom_morel(l2str *l2rec, l2prodstr *p, float prod[]) {
320  int prodID = p->cat_ix;
321  int ib = p->prod_ix;
322 
323  int32_t ip;
324 
325  if (!cdom_morel_ran(l2rec->l1rec->iscan))
326  run_cdom_morel(l2rec);
327 
328  for (ip = 0; ip < l2rec->l1rec->npix; ip++) {
329 
330  switch (prodID) {
331 
332  case CAT_iCDOM_morel:
333  prod[ip] = (float) idx[ip];
334  break;
335 
336  case CAT_chl_morel:
337  prod[ip] = (float) chl[ip];
338  break;
339 
340  case CAT_adg_morel:
341  prod[ip] = adg_morel(chl[ip], idx[ip], l2rec->l1rec->l1file->fwave[ib]);
342  break;
343 
344  case CAT_pCDOM_morel:
345  prod[ip] = pcdom_morel(chl[ip], idx[ip]);
346  break;
347 
349  prod[ip] = chl_cdomcorr_morel(l2rec->chl[ip], idx[ip]);
350  break;
351 
352  default:
353  printf("-E- %s line %d : erroneous product ID %d passed to CDOM morel.\n",
354  __FILE__, __LINE__, prodID);
355  exit(1);
356  }
357  }
358 
359  return;
360 }
361 
362 
#define CAT_chl_morel
Definition: l2prod.h:231
int32 l1file(int32 sdfid, int32 *nsamp, int32 *nscans, int16 *dtynum)
Definition: l1stat_chk.c:586
#define MAX(A, B)
Definition: swl0_utils.h:26
#define MIN(x, y)
Definition: rice.h:169
data_t t[NROOTS+1]
Definition: decode_rs.h:77
void run_cdom_morel(l2str *l2rec)
Definition: cdom_morel.c:28
int j
Definition: decode_rs.h:73
#define NULL
Definition: decode_rs.h:63
read l1rec
float pcdom_morel(float chl, float idx)
Definition: cdom_morel.c:284
float adg_morel(float chl, float idx, float wave)
Definition: cdom_morel.c:272
void get_cdom_morel(l2str *l2rec, l2prodstr *p, float prod[])
Definition: cdom_morel.c:319
#define PRODFAIL
Definition: l2_flags.h:41
float chl_cdomcorr_morel(float chl, float idx)
Definition: cdom_morel.c:301
#define NTAB
Definition: cdom_morel.c:3
int cdom_morel_ran(int recnum)
Definition: cdom_morel.c:260
int bindex_get(int32_t wave)
Definition: windex.c:45
#define CAT_chl_cdomcorr_morel
Definition: l2prod.h:249
read recnum
string path
Definition: color_dtdb.py:221
#define CAT_iCDOM_morel
Definition: l2prod.h:229
char filename[FILENAME_MAX]
Definition: atrem_corl1.h:122
#define CAT_adg_morel
Definition: l2prod.h:232
#define BAD_FLT
Definition: jplaeriallib.h:19
data_t u
Definition: decode_rs.h:74
void qint_morel(float wave[], int32_t nwave, float solz, float chl, float Qn[])
Definition: brdf.c:672
#define MAXLINE
Definition: cdom_morel.c:4
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")
float p[MODELMAX]
Definition: atrem_corl1.h:131
#define CAT_pCDOM_morel
Definition: l2prod.h:230
float conv_rrs_to_555(float Rrs, float wave)
Definition: convert_band.c:17