OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
raman.c
Go to the documentation of this file.
1 /* =================================================================== */
2 /* module raman.c - Raman scattering correction for Rrs */
3 /* */
4 /* This module contains the functions to correct sensor-observed */
5 /* above-water remote sensing reflectances, Rrs. for Raman Scattering */
6 /* effects. */
7 /* */
8 /* References: */
9 /* Lee et al (1994) Model for the interpretation of hyperspectral */
10 /* remote-sensing reflectance, Applied Optics, 33(24), 5721-5732 */
11 /* doi:10.1364/AO.33.005721 */
12 /* */
13 /* Lee et al (2013) Penetration of UV-visible solar radiation in the */
14 /* global oceans: Insights from ocean color remote sensing, Journal of */
15 /* Geophysical Research Oceans, 118, 4241-4255, doi:10.1002/jgrc.20308 */
16 /* */
17 /* McKinna et al. (2016) Implementation of an analytical Raman */
18 /* scattering correction for satellite ocean-color processing, */
19 /* Opt. Express, 24(14), A1123-A1137, doi: 10.1364/OE.24.0A1123 */
20 /* */
21 /* Mobley. C.D. (2010) Hydrolight Technical Note 10: Interpretation */
22 /* of Raman Scattering Computations, Sequoia Scientific. */
23 /* */
24 /* Sathyendranath and Platt (1998) Ocean-color model incorporating */
25 /* transspectral processes, Applied Optics, 37(12), 2216-2227, */
26 /* doi:10.1364/AO.37.002216 */
27 /* */
28 /* Walrafen (1967) Raman spectral studies of the effects of temperature*/
29 /* on water structure, Journal of Chemical Physics, 47, 118-121, */
30 /* doi:10.1063/1.711834 */
31 /* */
32 /* Westberry et al. (2013) Influence if Raman scattering on ocean color*/
33 /* inversion models, Applied Optics, 52(22), 5552-5561, */
34 /* doi:10.1364/AO.52.005552 */
35 /* */
36 /* */
37 /* Implementation: */
38 /* L. McKinna NASA/OBPG/SAIC, April 2015 */
39 /* */
40 /* Notes: */
41 /* Feb 2019: Downwelling irradiance model updated to be consistent */
42 /* with atmospheric correction model. Added support for OLCIA, OLCIB, */
43 /* SGLI, and VIIRS-J1. */
44 /* */
45 /* May 2021: replaced hard-coded coefficients with netCDF files. */
46 /* Added support for PACE OCI. */
47 /* =================================================================== */
48 
49 #define NORAMAN 0
50 #define LEE2013 1
51 #define WESTBERRY2013 2
52 #define LEE1994 3
53 #define WAVEMIN 380
54 #define WAVEMAX 700
55 
56 #include <stdio.h>
57 #include <math.h>
58 #include <netcdf.h>
59 #include <gsl/gsl_fit.h>
60 #include "l12_proto.h"
61 #include "sensorDefs.h"
62 
63 static int32_t nbandVis; //Number of visible bands
64 static float *lambda; //Sensor wavelengths
65 
66 //Wavelength indices
67 static int idx412;
68 static int idx443;
69 static int idx488;
70 static int idx550;
71 static int idx670;
72 static int bandNum550; //Number of bands shorter than 500 nm;
73 static int limitVisFlag;
74 
75 //static float angstEst; //Estimate Angstrom exponent (Taua power law slope)
76 
77 static float nWater = 1.344; //Refractive index of seawater
78 
79 //Bio-optical model parameters
80 static float *aw; //water absorption coefficient at sensor bands
81 static float *bbw; //water backscattering coefficient at sensor bands
82 static float *awR; //water absorption coeficient at Raman excitation bands
83 static float *bbwR; //water backscattering coefficient at Raman excitation bandss
84 static float *bbtot; //total backscattering modelled at sensor bands
85 static float *atot; //total absorption modelled at sensor bands
86 static float *atotR; //total absorption coefficient at Raman excitation bands
87 static float *bbtotR; //total backscattering coefficient at Raman excitation bands
88 static float *aphStar; //Normalised phytoplankton absorption spectral shape at sensor bands
89 static float *aphStarR; //Normalised phytoplankton absorption spectral shape at Raman bands
90 static float *kdSen; //Diffuse attenuation coefficient at sensor bands
91 static float *kdRam; //Diffuse attenuation coefficient at raman bands
92 static float *kappaSen;
93 static float *kappaRam;
94 // at sensor bands
95 static float aph443; //QAA-derived phytoplankton absorption at 443 nm
96 static float adg443; //QAA-derived Absorption of CDOM and colored detrital matter at 443 nm
97 static float bbp443; //QAA-derived backscattering coefficient at 443 nm
98 static float Ybbp; //Power exponent of bbp
99 static float Sdg; //Exponential slope of adg
100 
101 static float *aph1Sen; //Bricaud aph0 coefficient at sensor bands
102 static float *aph2Sen; //Bricaud aph1 coefficient at sensor bands
103 static float *aph1Ram; //Bricaud aph0 coefficient at Raman bands
104 static float *aph2Ram; //Bricaud aph1 coefficient at Raman bands
105 
106 
107 //Radtran atmospheric model parameters
108 static float *eDRam; //Down-welling irradiance at Raman excitation bands
109 static float *eDSen; //Down-welling irradiance at sensor bands
110 
111 static float *t_sol_ram; //Down-welling irradiance at Raman excitation bands
112 
113 //static float *tauaRam; //Aerosol optical thickness at Raman bands
114 
115 static float *ramLam; //Raman excitation wavelengths
116 static float *ramBandW; //Raman band widths
117 static float *bRex; //Raman scattering coefficient
118 
119 static float *f0BarRam; //TOA solar irradiance at Raman bands
120 static float *rayRam; //Rayleigh transmittance at Raman bands
121 static float *ozRam; //Ozone absorption at Raman bands
122 static float *wvRam; //Water vapor absorption at Raman bands
123 static float *oxyRam; //Oxygen absorption at Raman bands
124 static float *no2Ram; //Oxygen absorption at Raman bands
125 
126 static float *Rrs_ram; //Rrs due to Raman scattering
127 
128 //Lee et al. 2013 Raman correction 1 coefficients
129 //Pointers for interpolation/extrapolation
130 static float *alphaCor;
131 static float *betaCor0;
132 static float *betaCor1;
133 
134 //Lee et al 2013 Empirical coefficients
135 static float lamCor1[6] = {412.0, 443.0, 488.0, 531.0, 551.0, 667.0};
136 static float alpha[6] = {0.003, 0.004, 0.011, 0.015, 0.017, 0.018};
137 static float beta0[6] = {0.014, 0.015, 0.010, 0.010, 0.010, 0.010};
138 static float beta1[6] = {-0.022, -0.023, -0.051, -0.070, -0.080, -0.081};
139 
140 
141 /* ------------------------------------------------------------------- */
142 /* getRamanCoeffs() get spectral coefficients from netCDF file */
143 /* ------------------------------------------------------------------- */
144 
145 void getRamanCoeff(int grpid, char* varName, float* variable) {
146 
147  int varid;
148  int dimid;
149  size_t varLen;
150 
151  //get the variable id
152  if (nc_inq_varid(grpid, varName, &varid) != NC_NOERR) {
153  fprintf(stderr, "-E- %s line %d: could not find netCDF variable \"%s\" in netCDF File.\n",
154  __FILE__, __LINE__, varName);
155  exit(1);
156  }
157 
158  //get the dimension id for the variable
159  if (nc_inq_dimid(grpid,varName, &dimid) != NC_NOERR ) {
160  fprintf(stderr, "-E- %s line %d: could not find %s in netCDF File.\n",
161  __FILE__, __LINE__, varName);
162  }
163 
164  //get the dimension length of the variable
165  if (nc_inq_dimlen(grpid, dimid, &varLen) != NC_NOERR ) {
166  fprintf(stderr, "-E- %s line %d: could not find netCDF variable dimensions in netCDF File.\n",
167  __FILE__, __LINE__);
168  exit(1);
169  }
170 
171  //Check to see if the dimensions of the coefficient arrays are consistent with
172  //visible bands of the sensor
173  if (varLen != nbandVis && limitVisFlag!=1) {
174  fprintf(stderr, "-E- %s line %d: number of Raman coefficients %ld does not equal sensors visible"
175  " bands %d.\n",
176  __FILE__, __LINE__,varLen,nbandVis);
177  exit(1);
178  }
179 
180  //get the spectral coefficient from the file
181  if (nc_get_var_float (grpid, varid, variable) != NC_NOERR ) {
182  fprintf(stderr, "-E- %s line %d: could not read netCDF variable %s in netCDF File.\n",
183  __FILE__, __LINE__,varName);
184  exit(1);
185  }
186 
187 }
188 
189 /* ---------------------------------------------------------------------------*/
190 /* raman_pixel_alloc() Allocate pointer memory for Raman computations */
191 /* ---------------------------------------------------------------------------*/
192 void raman_pixel_alloc(l2str *l2rec) {
193 
194  //Allocate static pointer memory
195  lambda = (float*) allocateMemory(nbandVis * sizeof (float), "lambda");
196 
197  aw = (float*) allocateMemory(nbandVis * sizeof (float), "aw");
198  bbw = (float*) allocateMemory(nbandVis * sizeof (float), "bbw");
199  awR = (float*) allocateMemory(nbandVis * sizeof (float), "awR");
200  bbwR = (float*) allocateMemory(nbandVis * sizeof (float), "bbwR");
201  aphStar = (float*) allocateMemory(nbandVis * sizeof (float), "aphStar");
202  aphStarR = (float*) allocateMemory(nbandVis * sizeof (float), "aphStarR");
203  bbtot = (float*) allocateMemory(nbandVis * sizeof (float), "bbtot");
204  atot = (float*) allocateMemory(nbandVis * sizeof (float), "atot");
205  bbtotR = (float*) allocateMemory(nbandVis * sizeof (float), "bbtotR");
206  atotR = (float*) allocateMemory(nbandVis * sizeof (float), "atotR");
207 
208  kdSen = (float*) allocateMemory(nbandVis * sizeof (float), "kdSen");
209  kdRam = (float*) allocateMemory(nbandVis * sizeof (float), "kdRam");
210  kappaSen = (float*) allocateMemory(nbandVis * sizeof (float), "kappaSen");
211  kappaRam = (float*) allocateMemory(nbandVis * sizeof (float), "kappaRam");
212 
213  betaCor0 = (float*) allocateMemory(nbandVis * sizeof (float), "betaCor0");
214  betaCor1 = (float*) allocateMemory(nbandVis * sizeof (float), "betaCor1");
215  alphaCor = (float*) allocateMemory(nbandVis * sizeof (float), "alphaCor");
216 
217  eDRam = (float*) allocateMemory(nbandVis * sizeof (float), "eDRam");
218  eDSen = (float*) allocateMemory(nbandVis * sizeof (float), "eDSen");
219 
220  t_sol_ram = (float*) allocateMemory(nbandVis * sizeof (float), "t_sol_ram");
221 
222  Rrs_ram = (float*) allocateMemory(l2rec->l1rec->npix *
223  l2rec->l1rec->l1file->nbands * sizeof (float), "Rrs_ram");
224 
225  ramLam = (float*) allocateMemory(nbandVis * sizeof (float), "ramLam");
226  ramBandW = (float*) allocateMemory(nbandVis * sizeof (float), "ramBandW");
227  bRex = (float*) allocateMemory(nbandVis * sizeof (float), "bRex");
228  f0BarRam = (float*) allocateMemory(nbandVis * sizeof (float), "foBarRam");
229  rayRam = (float*) allocateMemory(nbandVis * sizeof (float), "rayRam");
230  ozRam = (float*) allocateMemory(nbandVis * sizeof (float), "ozRam");
231  wvRam = (float*) allocateMemory(nbandVis * sizeof (float), "wvRam");
232  oxyRam = (float*) allocateMemory(nbandVis * sizeof (float), "oxyRam");
233  no2Ram = (float*) allocateMemory(nbandVis * sizeof (float), "no2Ram");
234  aph1Ram = (float*) allocateMemory(nbandVis * sizeof (float), "aph1Ram");
235  aph2Ram = (float*) allocateMemory(nbandVis * sizeof (float), "aph2Ram");
236 
237  aph1Sen = (float*) allocateMemory(nbandVis * sizeof (float), "aph1Sen");
238  aph2Sen = (float*) allocateMemory(nbandVis * sizeof (float), "aph2Sen");
239 
240 }
241 
242 /* ---------------------------------------------------------------------------*/
243 /* get_raman_coeffs() Allocate pointer memory for Raman computations */
244 
245 /* ---------------------------------------------------------------------------*/
246 void get_raman_coeffs(l2str *l2rec) {
247 
248  char filename[FILENAME_MAX];
249  char *filedir;
250 
251  if ((filedir = getenv("OCDATAROOT")) == NULL) {
252  printf("-E- %s: OCDATAROOT env variable undefined.\n", __FILE__);
253  exit(1);
254  }
255 
256  filehandle *l1file = l2rec->l1rec->l1file;
257  strcpy(filename, filedir);
258  strcat(filename, "/");
259  strcat(filename, sensorId2SensorDir(l1file->sensorID));
260  if(l1file->subsensorID > SEAWIFS_LAC) { // ignore seawifs subsensor ID
261  strcat(filename, "/");
262  strcat(filename, subsensorId2SubsensorDir(l1file->subsensorID));
263  }
264  strcat(filename, "/raman.nc");
265 
266  if(l1file->sensorID == OCIS) {
267  limitVisFlag = 1;
268  } else {
269  limitVisFlag = 0;
270  }
271 
272  printf("Loading Raman coefficients from: %s.\n", filename);
273 
274  int ncid;
275  int grpid;
276  //Open netCDF file
277  if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
278  fprintf(stderr, "-E- %s line %d: could not open netCDF File \"%s\".\n",
279  __FILE__, __LINE__, filename);
280  exit(1);
281  }
282 
283  //get the group id for raman_coeffs
284  if (nc_inq_grp_ncid(ncid, "raman_coeffs", &grpid) != NC_NOERR) {
285  fprintf(stderr, "-E- %s line %d: could not find netCDF group \"raman_coeffs\".\n",
286  __FILE__, __LINE__);
287  exit(1);
288  }
289 
290  getRamanCoeff(grpid, "ramLam",ramLam);
291  getRamanCoeff(grpid, "ramBandW",ramBandW);
292  getRamanCoeff(grpid, "bRex",bRex);
293  getRamanCoeff(grpid, "f0BarRam",f0BarRam);
294  getRamanCoeff(grpid, "rayRam",rayRam);
295  getRamanCoeff(grpid, "ozRam",ozRam);
296  getRamanCoeff(grpid, "wvRam",wvRam);
297  getRamanCoeff(grpid, "oxyRam",oxyRam);
298  getRamanCoeff(grpid, "no2Ram",no2Ram);
299  getRamanCoeff(grpid, "aph1Ram",aph1Ram);
300  getRamanCoeff(grpid, "aph2Ram",aph2Ram);
301 
302  //get the group id for sensor_coeffs
303  if (nc_inq_grp_ncid(ncid, "sensor_coeffs", &grpid) != NC_NOERR) {
304  fprintf(stderr, "-E- %s line %d: could not find netCDF group \"sensor_coeffs\".\n",
305  __FILE__, __LINE__);
306  exit(1);
307  }
308 
309  getRamanCoeff(grpid, "aph1Sen",aph1Sen);
310  getRamanCoeff(grpid, "aph2Sen",aph2Sen);
311 
312  //close the netcdf
313  if (nc_close(ncid) != NC_NOERR){
314  fprintf(stderr, "-E- %s line %d: could not close netCDF \"%s\".\n",
315  __FILE__, __LINE__,filename);
316  exit(1);
317  }
318 
319 }
320 /* -----------------------------------------------------------------------*/
321 /* set_raman_aph_uv() - Extrapolates aph* into the UV (below 400 nm). */
322 /* This methods assumes that aph can be linearly */
323 /* extrapolated into the UV */
324 
325 /* -----------------------------------------------------------------------*/
326 void set_raman_aph_uv(l2str *l2rec, int ip) {
327 
328  int iw;
329  float aphM, aphC;
330  float aphStar443;
331 
332  //Calculate aphStar at 443 nm using Bricaud et al 1998
333  aphStar443 = aph1Sen[idx443] * pow(l2rec->chl[ip], (aph2Sen[idx443]));
334 
335  //Using sensor-specific coefficients, calculate aphstar at all bands and
336  //normalize to 1.0 at 443 nm
337  for (iw = 0; iw < nbandVis; iw++) {
338  aphStar[iw] = (aph1Sen[iw] * pow(l2rec->chl[ip], (aph2Sen[iw])))
339  / aphStar443;
340  aphStarR[iw] = (aph1Ram[iw] * pow(l2rec->chl[ip], (aph2Ram[iw])))
341  / aphStar443;
342 
343  }
344 
345  //Linear model of aph betweeen 412 and 443 nm
346  aphM = (aphStar[idx443] - aphStar[idx412]) / (lambda[idx443] - lambda[idx412]);
347  aphC = aphStar[idx443] - aphM * lambda[idx443];
348 
349  //If outside the Bricaud in UV, extrapolate as linear function.
350  for (iw = 0; iw < nbandVis; iw++) {
351  if (ramLam[iw] <= 400) {
352  aphStarR[iw] = (aphM * ramLam[iw] + aphC);
353  }
354  }
355 
356 }
357 
358 /* -----------------------------------------------------------------------*/
359 /* fit_raman_tsol() - Interpolates/extrapolates tramsittanc.e from sun to */
360 /* surface (t_sol) at Raman excitation bands. The */
361 /* assumption is that t_sol follows a power law. */
362 /* -----------------------------------------------------------------------*/
363 void fit_raman_tsol(l2str *l2rec, int ip) {
364 
365  int iw;
366 
367  double logTsol[nbandVis];
368  double waveRatio[nbandVis];
369 
370  double c0, c1, cov00, cov01, cov11, sumsq;
371  int nbands = l2rec->l1rec->l1file->nbands;
372 
373  //Log transform data so function has a linear form
374  for (iw = 0; iw < nbandVis; iw++) {
375  logTsol[iw] = log(l2rec->l1rec->t_sol[ip * nbands + iw] / l2rec->l1rec->t_sol[ip * nbands + idx488]);
376  waveRatio[iw] = log(lambda[iw] / lambda[idx488]);
377  }
378 
379  //Use a linear fit on long-transformed data to compute power law exponent (range 412-490 nm)
380  gsl_fit_linear(waveRatio, 1, logTsol, 1, nbandVis, &c0, &c1, &cov00, &cov01, &cov11, &sumsq);
381 
382 
383  //Extrapolate/interpolate using power law model
384  for (iw = 0; iw < nbandVis; iw++) {
385  t_sol_ram[iw] = l2rec->l1rec->t_sol[ip * nbands + idx488] * pow((ramLam[iw] / lambda[idx488]), c1);
386  }
387 
388 }
389 
390 /* -----------------------------------------------------------------------*/
391 /* raman_qaa() - computes a first order estimate of the constituent IOPs */
392 /* -----------------------------------------------------------------------*/
393 void raman_qaa(l2str *l2rec, int ip) {
394 
395  int iw, idxref;
396 
397  float aref, bbpref, numer, denom, rho;
398  float rat, zeta, xi, term1, term2;
399 
400  float rrs_a[nbandVis];
401  float rrs_s[nbandVis];
402  float u[nbandVis];
403  float at[nbandVis];
404  float bbt[nbandVis];
405 
406  float g0 = 0.08945;
407  float g1 = 0.1247;
408  float acoefs[3] = {-1.146, -1.366, -0.469};
409 
410  //Calculate the sub-surface remote sensing reflectance
411  for (iw = 0; iw < nbandVis; iw++) {
412  rrs_a[iw] = l2rec->Rrs[ip * l2rec->l1rec->l1file->nbands + iw];
413  rrs_s[iw] = rrs_a[iw] / (0.52 + 1.7 * rrs_a[iw]);
414  }
415 
416  /*pre-test of Rrs550*/
417  if (rrs_a[idx550] <= 0.0)
418  rrs_a[idx550] = 0.001;
419 
420  /* pre-test 670 */
421  if ((rrs_a[idx670] > 20.0 * pow(rrs_a[idx550], 1.5)) || (rrs_a[idx670] < 0.9 * pow(rrs_a[idx550], 1.7))) {
422  rrs_a[idx670] = 1.27 * pow(rrs_a[idx550], 1.47) + 0.00018 * pow(rrs_a[idx488] / rrs_a[idx550], -3.19);
423  }
424 
425  /*Quadratic formula to get the quantity u*/
426  for (iw = 0; iw < nbandVis; iw++) {
427  u[iw] = (sqrt(g0 * g0 + 4.0 * g1 * rrs_s[iw]) - g0) / (2.0 * g1);
428  }
429 
430  /*Determine whether to use 550 or 670 nm as reference then compute total*/
431  /*absorption at the reference wavelength, aref*/
432  if (rrs_s[idx670] >= 0.0015) {
433  aref = aw[idx670] + 0.07 * pow(rrs_a[idx670] / rrs_s[idx443], 1.1);
434  idxref = idx670;
435 
436  } else {
437  numer = rrs_a[idx443] + rrs_a[idx488];
438  denom = rrs_a[idx550] + 5 * rrs_a[idx670]*(rrs_a[idx670] / rrs_a[idx488]);
439  rho = log10(numer / denom);
440  rho = acoefs[0] + acoefs[1] * rho + acoefs[2] * rho*rho;
441  aref = aw[idx550] + pow(10.0, rho);
442  idxref = idx550;
443  }
444 
445  /*Calculate the backscattering coefficient at the reference wavelength*/
446  bbpref = ((u[idxref] * aref) / (1.0 - u[idxref])) - bbw[idxref];
447 
448  /*Steps to compute power exponent of bbp coefficient*/
449  rat = rrs_s[idx443] / rrs_s[idx550];
450  Ybbp = 2.0 * (1.0 - 1.2 * exp(-0.9 * rat));
451 
452  /*Compute backscattering coefficient at 443nm, this is needed later for */
453  /*calculating bbp at the Raman excitation bands.s */
454  bbp443 = bbpref * pow((lambda[idxref] / lambda[idx443]), Ybbp);
455 
456  /*Compute the total backscattering coefficient for sensor bands*/
457  for (iw = 0; iw < nbandVis; iw++) {
458  bbt[iw] = bbpref * pow((lambda[idxref] / lambda[iw]), Ybbp) + bbw[iw];
459  }
460 
461  /*Calculate the total absorption coefficient at sensor bands*/
462  for (iw = 0; iw < nbandVis; iw++) {
463  at[iw] = ((1.0 - u[iw]) * bbt[iw]) / u[iw];
464  }
465 
466  /*Calculate the exponential slope coefficient of absorption by colored */
467  /*dissolved and detrital matter */
468  Sdg = 0.015 + 0.002 / (0.6 + rrs_s[idx443] / rrs_s[idxref]);
469 
470  /*Compute the absorption coefficient of colored dissolved and detrital */
471  /*matter at 443 nm, adg443*/
472  zeta = 0.74 + 0.2 / (0.8 + rrs_s[idx443] / rrs_s[idxref]);
473  xi = exp(Sdg * (lambda[idx443] - lambda[idx412]));
474  term1 = (at[idx412] - zeta * at[idx443]) - (aw[idx412] - zeta * aw[idx443]);
475  term2 = xi - zeta;
476  adg443 = term1 / term2;
477 
478  /*Calculate the absorption of phytoplankton at 443 nm*/
479  aph443 = at[idx443] - adg443 - aw[idx443];
480 
481 }
482 
483 /* -----------------------------------------------------------------------*/
484 /* raman_iops() - computes IOPs at raman excitation bands using a */
485 /* -----------------------------------------------------------------------*/
487 
488  int iw;
489  float bbpR, adgR, aphR;
490  float bbp, adg, aph;
491 
492  /*loop over sensor and raman bands*/
493  for (iw = 0; iw < nbandVis; iw++) {
494 
495  /*Compute IOPs at Raman bands*/
496  bbpR = bbp443 * pow((lambda[idx443] / ramLam[iw]), Ybbp);
497  adgR = adg443 * exp(-Sdg * (ramLam[iw] - lambda[idx443]));
498  aphR = aph443 * aphStarR[iw];
499 
500  /*Compute IOPs at sensor bands*/
501  bbp = bbp443 * pow((lambda[idx443] / lambda[iw]), Ybbp);
502  adg = adg443 * exp(-Sdg * (lambda[iw] - lambda[idx443]));
503  aph = aph443 * aphStar[iw];
504 
505  /*total absorption and backscattering coefficients at Raman bands*/
506  atotR[iw] = awR[iw] + adgR + aphR;
507  bbtotR[iw] = bbwR[iw] + bbpR;
508 
509  /*total absorption and backscattering coefficients at sensor bands*/
510  atot[iw] = aw[iw] + adg + aph;
511  bbtot[iw] = bbw[iw] + bbp;
512  }
513 
514 }
515 
516 /* -----------------------------------------------------------------------*/
517 /* k_functions() - computes k functions from IOP bio-optical models */
518 /* -----------------------------------------------------------------------*/
519 void raman_k_func(l2str *l2rec, int ip) {
520 
521  int iw;
522  float solzRad, solzRadSw, muD, muU;
523 
524  //Convert solar and sensor zenith angles from degrees to radianss
525  solzRad = l2rec->l1rec->solz[ip]*(M_PI / 180.0);
526  solzRadSw = asin(sin(solzRad) / nWater); //subsurface solar zenith angle
527 
528  //Means cosines
529  muD = cos(solzRadSw);
530  muU = 0.5;
531 
532  for (iw = 0; iw < nbandVis; iw++) {
533 
534  //Diffuse attenuation coefficient
535  kdSen[iw] = (atot[iw] + bbtot[iw]) / muD;
536  kdRam[iw] = (atotR[iw] + bbtotR[iw]) / muD;
537 
538  kappaSen[iw] = (atot[iw] + bbtot[iw]) / muU;
539  kappaRam[iw] = (atotR[iw] + bbtotR[iw]) / muU;
540 
541  }
542 
543 }
544 
545 /* -----------------------------------------------------------------------*/
546 /* radtran_raman_ed() - calculate total downwelling irradiance */
547 /* -----------------------------------------------------------------------*/
548 void raman_radtran_ed(l2str *l2rec, int ip) {
549 
550  int32_t iw, ipb;
551 
552  l1str *l1rec = l2rec->l1rec;
553 
554  //Constants
555  float p0 = 29.92 * 33.8639; //standard pressure (convert mmHg -> HPa);
556  float radCon = M_PI / 180.0; //degrees -> radians conversion
557  float ws = l2rec->l1rec->ws[ip]; //wind speed
558  float nw2= pow(nWater,2.); //refractive index of water squared
559 
560  //Define model variables
561  float sin2Solz, rf0, a0,a1,a2,a3, rho_fres;
562  float solz, solzRad, cosSolz, mPres, mAtm, f0Ex;
563  float th2oEx, to2Ex, tno2Ex, to3Ex, tgEx;
564  float a_285R, a_225R,tau_to200R;
565  float no2_tr200R, eDRam_above;
566 
567  //Load per-pixel variables from L2 record
568  solz = l1rec->solz[ip]; //solar zenith
569 
570  //Estimate the transmittance from sun to surface at Raman excitation bands
571  fit_raman_tsol(l2rec, ip);
572 
573  //Convert solar zenith in degrees to radians
574  solzRad = l1rec->solz[ip]*radCon;
575 
576  //Calculate cosine of the solar zenith angle
577  cosSolz = cos(solzRad);
578 
579  //Claculate sin2(solz)
580  sin2Solz = pow(sin(solzRad),2.);
581 
582  //Compute Fresnel reflection coefficient for a wind-blown surface following
583  //Haltrin 2002
584  //Fresnel specular reflection coefficient
585  rf0 = 0.5*( pow( (cosSolz - pow(nw2 - sin2Solz ,0.5))/(cosSolz + pow(nw2 + sin2Solz ,0.5)) ,2.)
586  + pow( (nw2*cosSolz - pow(nw2 - sin2Solz ,0.5))/(nw2*cosSolz + pow(nw2 + sin2Solz ,0.5)) ,2.) );
587 
588  //Wind-specific coefficients
589  a0 = 0.001*(6.944831 - 1.912076*ws + 0.03654833*ws*ws);
590  a1 = 0.7431368 + 0.0679787*ws - 0.0007171*ws*ws;
591  a2 = 0.5650262 + 0.0061502*ws - 0.0239810*ws*ws + 0.0010695*ws*ws*ws;
592  a3 = -0.4128083 - 0.1271037*ws + 0.0283907*ws*ws - 0.0011706*ws*ws*ws;
593 
594  //Fresnel reflectance as a function of wind speed
595  rho_fres = a0 + rf0*(a1 + rf0*(a2 + a3*rf0));
596 
597 
598  //---------------------
599  //Calculate the atmospheric pathlengths
600  //Use the Kasten abd Young (1989) coefficients
601  // mAtm = 1.0 / ( cosSolz + 0.50572*(96.07995 - solz)**(-1.6364) );
602  mAtm = 1.0 / (cosSolz + 0.50572 * pow((86.07995 - solz), -1.6364));
603 
604  //Greg and Carder (1990) values **NOT USED**
605  //mAtm = 1.0 / ( np.cos(solzRad) + 0.15* pow((93.885 - solz),-1.253) );
606 
607  //Pathlength corrected for non-standard atmoshperic pressure
608  mPres = mAtm * (l1rec->pr[ip] / p0);
609 
610 
611  //compute no2 above 200m per get_trans.c
612  if (l2rec->l1rec->no2_tropo[ip] > 0.0)
613  //compute tropo no2 above 200m (Z.Ahmad)
614  no2_tr200R = l1rec->no2_frac[ip] *l1rec->no2_tropo[ip];
615  else
616  no2_tr200R = 0.0;
617 
618  //---------------------//
619  //Spectral calculations - loop over sensor
620  for (iw = 0; iw < nbandVis; iw++) {
621 
622  ipb = ip*l1rec->l1file->nbands + iw;
623 
624  //Correct for sun-earth distance
625  f0Ex = f0BarRam[iw] * l1rec->fsol; //TOA solar irradiance at sensor bands
626 
627  //Compute ozone transmittance
628  to3Ex = exp(-(ozRam[iw] * l1rec->oz[ip] / l1rec->csolz[ip]) );
629 
630  //compute no2 absorption transmittance
631  a_285R = no2Ram[iw] * (1.0 - 0.003 * (285.0 - 294.0));
632  a_225R = no2Ram[iw] * (1.0 - 0.003 * (225.0 - 294.0));
633  tau_to200R = a_285R * no2_tr200R + a_225R * l1rec->no2_strat[ip];
634  tno2Ex = exp(-(tau_to200R / l1rec->csolz[ip]) );
635 
636  //Compute water vapour transmittance
637  th2oEx = exp((-0.2385 * wvRam[iw] * l1rec->wv[ip] * mAtm) /
638  (pow((1.0 + 20.07 * wvRam[iw] * l1rec->wv[ip] * mAtm), 0.45)));
639 
640 
641  //Gas Transmittance due to oxygen/gases
642  to2Ex = exp((-1.41 * oxyRam[iw] * mPres) / (pow((1.0 + 118.3 * oxyRam[iw] * mPres), 0.45)));
643 
644  tgEx = to3Ex*tno2Ex*th2oEx*to2Ex;
645 
646  //
647  eDRam_above = f0Ex * tgEx * t_sol_ram[iw]* cos(solzRad) * 10.0;
648  eDSen[iw] = l1rec->Fo[iw] * l1rec->tg_sol[ipb] * l1rec->t_sol[ipb]* cos(solzRad) * 10.0;
649 
650  eDRam[iw] = 1.03*(1.0 - rho_fres)*eDRam_above;
651 
652  }
653 
654 }
655 
656 /* -------------------------------------------------------------------------*/
657 /* raman_cor_1() - computes the Rrs corrected for Raman scattering reported */
658 /* by Lee et al, 2013 */
659 /* -------------------------------------------------------------------------*/
660 void raman_cor_lee1(l2str *l2rec, int ip) {
661 
662  int iw;
663  float Rrs443, Rrs550;
664  float rFactor;
665  float rrs_a;
666  int nbands = l2rec->l1rec->l1file->nbands;
667  //If pixel is already masked, return and do not attempt the correction.
668  if (l2rec->l1rec->mask[ip]) {
669  return;
670  }
671 
672  //Get Rrs443 and Rrs550 from the L2 record
673  Rrs443 = l2rec->Rrs[ip * nbands + idx443];
674  Rrs550 = l2rec->Rrs[ip * nbands + idx550];
675 
676  //Loop over vis bands
677  for (iw = 0; iw < nbandVis; iw++) {
678 
679  if (lambda[iw] >= WAVEMIN && lambda[iw] <= WAVEMAX) {
680 
681  //Raman correction factor - Eq. 11 in Lee et al 2013
682  rFactor = alphaCor[iw] * Rrs443 / Rrs550 + betaCor0[iw] * pow(Rrs550, betaCor1[iw]);
683 
684  rrs_a = l2rec->Rrs[ip * nbands + iw];
685 
686  Rrs_ram[ip * nbands + iw] = rrs_a - rrs_a / (1.0 + rFactor);
687 
688  } else {
689  Rrs_ram[ip * nbands + iw] = 0.0;
690  }
691 
692  }
693 
694 }
695 
696 /* -----------------------------------------------------------------------*/
697 /* raman_cor_westberry() - computes the Rrs corrected for Raman scattering*/
698 /* following the method of Westberry et al 2013 */
699 /* */
700 /* Note: only the first-order scattering term is */
701 /* used as the higher order term often to */
702 /* resulted in: Rrs_raman > Rrs. */
703 /* -----------------------------------------------------------------------*/
704 void raman_cor_westberry(l2str *l2rec, int ip) {
705 
706  //We are only considering the first-order Raman scattering
707 
708  int iw;
709  int nbands = l2rec->l1rec->l1file->nbands;
710  float term0, term1, numer1, denom1;
711  float Rrs_rc;
712 
713 
714  //If pixel is already masked, return and do not attempt the correction.
715  if (l2rec->l1rec->mask[ip]) {
716  return;
717  }
718 
719  //Extrapolate aphStar into the UV Raman excitation bands
720  set_raman_aph_uv(l2rec, ip);
721 
722  //Run QAA to estimate IOP magnitudes and spectral slopes
723  raman_qaa(l2rec, ip);
724 
725  //Get total absorption and scattering coefficients at both sensor
726  //and Raman excitation bands.
728 
729  //Get the k-functions
730  raman_k_func(l2rec, ip);
731 
732  //Get the down-welling irradiances
733  raman_radtran_ed(l2rec, ip);
734 
735  //From Mobley 2010 - assume isotropic emission
736  term0 = 1.0 / (4.0 * M_PI * nWater * nWater);
737 
738 
739  //Loop over visible bands
740  for (iw = 0; iw < nbandVis; iw++) {
741 
742  //Only calculate correction for visible bands
743  if (lambda[iw] >= WAVEMIN && lambda[iw] <= WAVEMAX) {
744 
745  //First term in in Westberry et al. 2013, Eq 7.
746  numer1 = bRex[iw] * eDRam[iw];
747  denom1 = (kdRam[iw]+kappaSen[iw])*eDSen[iw];
748  term1 = numer1 / denom1;
749 
750  //Raman corrected Rrs (first order scattering term only)
751  Rrs_rc = term0 * term1;
752 
753  //Fill Rrs_raman array
754  Rrs_ram[ip * nbands + iw] = Rrs_rc;
755 
756  } else {
757  Rrs_ram[ip * nbands + iw] = 0.0;
758  }
759 
760  }
761 
762 }
763 
764 /* -----------------------------------------------------------------------*/
765 /* raman_cor_lee2() - computes the Rrs corrected for Raman scattering */
766 /* following the method of Lee et al. 1994 */
767 
768 /* -----------------------------------------------------------------------*/
769 void raman_cor_lee2(l2str *l2rec, int ip) {
770 
771  int iw;
772  int nbands = l2rec->l1rec->l1file->nbands;
773  float Rrs_rc;
774 
775  //If pixel is already masked, return and do not attempt the correction.
776  if (l2rec->l1rec->mask[ip]) {
777  return;
778  }
779 
780  //Extrapolate aphStar into the UV Raman excitation bands
781  set_raman_aph_uv(l2rec, ip);
782 
783  //Run QAA to estimate IOP magnitudes and spectral slopes
784  raman_qaa(l2rec, ip);
785 
786  //Get total absorption and scattering coefficients at both sensor
787  //and Raman excitation bands.
789 
790  //Get the down-welling irradiances
791  raman_radtran_ed(l2rec, ip);
792 
793  //Loop over vis bands
794  for (iw = 0; iw < nbandVis; iw++) {
795 
796  if (lambda[iw] >= WAVEMIN && lambda[iw] <= WAVEMAX) {
797  //Raman-corrected Rrs
798  Rrs_rc = 0.072 * (bRex[iw] * eDRam[iw]) / ((2.0 * atot[iw] + atotR[iw]) * eDSen[iw]);
799 
800  //Fill Rrs_raman array
801  Rrs_ram[ip * nbands + iw] = Rrs_rc;
802 
803  } else {
804  Rrs_ram[ip * nbands + iw] = 0.0;
805  }
806 
807  }
808 
809 }
810 
811 /* -----------------------------------------------------------------------*/
812 /* run_raman_cor() - run the Raman scattering correction algorithm */
813 
814 /* -----------------------------------------------------------------------*/
815 void run_raman_cor(l2str *l2rec, int ip) {
816 
817  int iw;
818  static int firstCall = 1;
819  static int sensorSupported;
820  //int32_t ocSensorID;
821 
822  //Number of visible bands
823  nbandVis = rdsensorinfo(l2rec->l1rec->l1file->sensorID, l1_input->evalmask, "NbandsVIS", NULL);
824 
825  //First call
826  if (firstCall) {
827 
828  //Supported sensors list
829  switch (l2rec->l1rec->l1file->sensorID){
830  case MODISA:
831  case MODIST:
832  case SEAWIFS:
833  case VIIRSN:
834  case VIIRSJ1:
835  case MERIS:
836  case OCTS:
837  case OLCIS3A:
838  case OLCIS3B:
839  case SGLI:
840  case OCIS:
841  sensorSupported = 1;
842  break;
843  default:
844  //Force l2gen input to raman_opt=0
845  input->raman_opt = NORAMAN;
846  //Set flag to 1 - supported sensor
847  sensorSupported = 0;
848  }
849 
850 
851  //No Raman correction selected
852  if (input->raman_opt == 0) {
853 
854  printf("\n");
855  if (!sensorSupported) {
856  printf("Raman correction unsupported for this sensor. \n");
857  }
858 
859  printf("No Raman scattering correction calculated for Rrs. \n");
860  printf("\n");
861 
862  //Raman correction selected
863  } else if (input->raman_opt > 0 && input->raman_opt <= 3) {
864 
865  printf("\n");
866  printf("Compute Raman scattering correction #%d. \n", input->raman_opt);
867  printf("\n");
868 
869  //Invalid Raman correction selected
870  } else {
871  printf("-E- %s line %d : '%d' is not a valid Raman correction option.\n",
872  __FILE__, __LINE__, input->raman_opt);
873  exit(1);
874  }
875 
876 
877  /*Allocate memory according to number of sensor bands*/
878  raman_pixel_alloc(l2rec);
879 
880  //If sensor is supported for Raman correction, coefficients are allocated
881  if (sensorSupported) {
882 
883  /*Get the sensor-specific coefficients*/
884  get_raman_coeffs(l2rec);
885 
886  /*Loop over visible bands*/
887  for (iw = 0; iw < nbandVis; iw++) {
888 
889  //Get the visible band centers
890  lambda[iw] = l2rec->l1rec->l1file->fwave[iw];
891 
892  //Interpolate the Lee et al. (2013) correction coefficients to sensor resolution
893  alphaCor[iw] = linterp(lamCor1, alpha, 6, lambda[iw]);
894  betaCor0[iw] = linterp(lamCor1, beta0, 6, lambda[iw]);
895  betaCor1[iw] = linterp(lamCor1, beta1, 6, lambda[iw]);
896 
897  //Populate the pure water absorption data//
898  awR[iw] = aw_spectra(ramLam[iw], ramBandW[iw]);
899  bbwR[iw] = bbw_spectra(ramLam[iw], ramBandW[iw]);
900  aw[iw] = l2rec->l1rec->l1file->aw[iw];
901  bbw[iw] = l2rec->l1rec->l1file->bbw[iw];
902 
903 
904  }
905 
906  //Find the sensor wavelength indices, do this once.
907  idx412 = windex(412.0, lambda, nbandVis);
908  idx443 = windex(443.0, lambda, nbandVis);
909  idx488 = windex(488.0, lambda, nbandVis);
910  idx550 = windex(547.0, lambda, nbandVis);
911  idx670 = windex(667.0, lambda, nbandVis);
912 
913 
914  //How many bands between 412 and 490?
915  for (iw = 0; iw < nbandVis; iw++) {
916  if (lambda[iw] > 550.0) {
917  bandNum550 = iw - 1;
918  break;
919  }
920  }
921 
922  }
923  firstCall = 0;
924  }
925 
926 
927  /*No raman correction is applied, raman_opt=0*/
928  if (input->raman_opt == NORAMAN) {
929  /*Fill Rrs_raman with zeros*/
930  for (iw = 0; iw < l2rec->l1rec->l1file->nbands; iw++) {
931  Rrs_ram[ip * l2rec->l1rec->l1file->nbands + iw] = 0.0;
932  }
933 
934  /*Apply the Lee et al 2013 correction, raman_opt=1*/
935  } else if (input->raman_opt == LEE2013) {
936  raman_cor_lee1(l2rec, ip);
937 
938  /*Apply the Westberry et al 2013 correction, raman_opt=2*/
939  } else if (input->raman_opt == WESTBERRY2013) {
940  raman_cor_westberry(l2rec, ip);
941 
942  /*Apply the Lee et al 1994 Raman correction, raman_opt=3*/
943  } else if (input->raman_opt == LEE1994) {
944  raman_cor_lee2(l2rec, ip);
945  }
946 
947 
948  l2rec->Rrs_raman = Rrs_ram;
949 
950 }
951 
952 /* ---------------------------------------------------------------------------*/
953 /* ---------------------------------------------------------------------------*/
int32 l1file(int32 sdfid, int32 *nsamp, int32 *nscans, int16 *dtynum)
Definition: l1stat_chk.c:586
const char * sensorId2SensorDir(int sensorId)
Definition: sensorInfo.c:240
#define OLCIS3A
Definition: sensorDefs.h:32
#define SGLI
Definition: sensorDefs.h:33
int16_t * denom[MAXNFILES]
Definition: l2bin.cpp:99
void * allocateMemory(size_t numBytes, const char *name)
Definition: allocateMemory.c:7
#define NULL
Definition: decode_rs.h:63
read l1rec
#define VIIRSN
Definition: sensorDefs.h:23
void raman_pixel_alloc(l2str *l2rec)
Definition: raman.c:192
unsigned long long sumsq(signed short *in, int cnt)
void set_raman_aph_uv(l2str *l2rec, int ip)
Definition: raman.c:326
#define MERIS
Definition: sensorDefs.h:22
void get_raman_coeffs(l2str *l2rec)
Definition: raman.c:246
#define MODIST
Definition: sensorDefs.h:18
data_t lambda[NROOTS+1]
Definition: decode_rs.h:75
instr * input
void raman_cor_lee2(l2str *l2rec, int ip)
Definition: raman.c:769
#define WAVEMAX
Definition: raman.c:54
void raman_cor_lee1(l2str *l2rec, int ip)
Definition: raman.c:660
#define WAVEMIN
Definition: raman.c:53
float linterp(float xin[], float yin[], int32_t nin, float xout)
Definition: lspline.c:59
#define WESTBERRY2013
Definition: raman.c:51
void run_raman_cor(l2str *l2rec, int ip)
Definition: raman.c:815
float aw_spectra(int32_t wl, int32_t width)
l1_input_t * l1_input
Definition: l1_options.c:9
#define OCIS
Definition: sensorDefs.h:43
void raman_cor_westberry(l2str *l2rec, int ip)
Definition: raman.c:704
float bbw_spectra(int32_t wl, int32_t width)
#define NORAMAN
Definition: raman.c:49
#define M_PI
Definition: pml_iop.h:15
char filename[FILENAME_MAX]
Definition: atrem_corl1.h:122
#define LEE1994
Definition: raman.c:52
#define OCTS
Definition: sensorDefs.h:14
void raman_k_func(l2str *l2rec, int ip)
Definition: raman.c:519
#define LEE2013
Definition: raman.c:50
void getRamanCoeff(int grpid, char *varName, float *variable)
Definition: raman.c:145
int16_t * numer[MAXNFILES]
Definition: l2bin.cpp:99
int32_t nbands
data_t u
Definition: decode_rs.h:74
int windex(float wave, float twave[], int ntwave)
Definition: windex.c:73
void raman_qaa(l2str *l2rec, int ip)
Definition: raman.c:393
int32_t rdsensorinfo(int32_t, int32_t, const char *, void **)
Definition: rdsensorinfo.c:69
const char * subsensorId2SubsensorDir(int subsensorId)
Definition: sensorInfo.c:254
#define OLCIS3B
Definition: sensorDefs.h:41
void raman_radtran_ed(l2str *l2rec, int ip)
Definition: raman.c:548
void fit_raman_tsol(l2str *l2rec, int ip)
Definition: raman.c:363
#define SEAWIFS
Definition: sensorDefs.h:12
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
#define MODISA
Definition: sensorDefs.h:19
#define VIIRSJ1
Definition: sensorDefs.h:37
#define SEAWIFS_LAC
Definition: sensorDefs.h:56
void raman_and_sensor_iops()
Definition: raman.c:486