OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
get_avw.c
Go to the documentation of this file.
1 /*
2  * get_avw.c
3  *
4  * This algorithm returns the weighted harmonic mean of the visible-range (400 – 700 nm) remote sensing reflectance (Rrs) wavelengths,
5  * outputting the Apparent Visible Wavelength (AVW) in units of nanometers.
6  * The AVW is an optical water classification index, representing a one-dimensional geophysical metric that is inherently correlated
7  * to Rrs spectral shape (Vandermeulen et al. 2020).
8  *
9  *
10  *Vandermeulen, R. A., Mannino, A., Craig, S.E., Werdell, P.J., 2020: “150 shades of green: Using the full spectrum of remote sensing reflectance
11  * to elucidate color shifts in the ocean,” Remote Sensing of Environment, 247, 111900, https://doi.org/10.1016/j.rse.2020.111900
12  *
13  * Created on: Sep 30, 2020
14  * Author: M. Zhang
15  */
16 
17 #include "l12_proto.h"
18 
19 
20 float avw_cal_hypspectral(float *Rrs, float *wave, int nwave){
21 
22  float avw=BAD_FLT;
23  int32_t ib;
24 
25  float dfirst=0,dlast=0;
26  float *Secondderiv=(float *)malloc(nwave*sizeof(float));
27 
28  int32_t nwave_out=700-400+1;
29  float *wave_out=(float *)malloc(nwave_out*sizeof(float));
30  float *Rrs_out =(float *)malloc(nwave_out*sizeof(float));
31  double nominator=0., denominator=0.;
32 
33  for(ib=0;ib<nwave_out;ib++)
34  wave_out[ib]=400+ib;
35 
36  dfirst=first_deriv(wave,Rrs,0);
37  dlast=first_deriv(wave,Rrs,nwave);
38 
39  spline(wave,Rrs,nwave,dfirst,dlast,Secondderiv);
40 
41  for(ib=0;ib<nwave_out;ib++)
42  splint(wave,Rrs,Secondderiv,nwave,wave_out[ib],&Rrs_out[ib]);
43 
44  for(ib=0;ib<nwave_out;ib++){
45  nominator+=Rrs_out[ib];
46  denominator+=(Rrs_out[ib]/wave_out[ib]);
47  }
48  avw=nominator/denominator;
49 
50  free(wave_out);free(Rrs_out);
51  free(Secondderiv);
52  return avw;
53 
54 }
55 
56 
57 float avw_cal_multispectral(float *Rrs, float *wave, int nwave){
58 
59  float avw=BAD_FLT;
60  int32_t ib;
61  float *avw_coef=input->avw_coef;
62 
63  double nominator=0., denominator=0.,temp=0.;
64 
65  for(ib=0;ib<nwave; ib++){
66  nominator+=Rrs[ib];
67  denominator+=(Rrs[ib]/wave[ib]);
68  }
69  avw=nominator/denominator;
70 
71  for(ib=0;ib<6;ib++)
72  temp+=avw_coef[ib]*pow(avw,ib);
73 
74  avw=temp;
75 
76  return avw;
77 
78 }
79 
80 void get_avw(l2str *l2rec, float avw[]){
81  filehandle* l1file = l2rec->l1rec->l1file;
82 
83  int32_t ip,ib;
84  int32_t ipb;
85 
86  int32_t sensorID = l1file->sensorID;
87  int32_t nbands = l1file->nbands;
88  int32_t npix = l2rec->l1rec->npix;
89  static float fsol;
90  float *wave = l1file->fwave;
91  float *Rrs;
92  static float *Rrs_avw, *wave_avw;
93  static int firstcall=1;
94  int32_t nwave_avw;
95  int32_t negative=0;
96  static int ifhyper=0;
97  static int ib400=0,ib700=0;
98 
99  if(firstcall){
100  firstcall=0;
101  Rrs_avw =(float *)malloc(nbands*sizeof(float));
102  wave_avw=(float *)malloc(nbands*sizeof(float));
103  switch (sensorID){
104  case HICO:
105  case PRISM:
106  ifhyper=1;
107  break;
108  }
109  if(ifhyper){
110  ib400=windex(400, wave,nbands);
111  ib700=windex(700, wave,nbands);
112 
113  if(ib400>0 && wave[ib400]>=400)
114  ib400--;
115  if(ib700<nbands-1 && wave[ib700]<700)
116  ib700++;
117  }
118  fsol=l2rec->l1rec->fsol;
119  }
120 
121  /* */
122  /* Compute desired products at each pixel */
123  /* */
124  for (ip = 0; ip < npix; ip++) {
125  avw[ip]=BAD_FLT;
126 
127  if(l2rec->l1rec->mask[ip] || l2rec->l1rec->solz[ip] >= SOLZNIGHT)
128  continue;
129 
130  ipb=ip*nbands;
131  Rrs=&l2rec->Rrs[ipb];
132 
133  nwave_avw=0;
134  negative=0;
135  if(ifhyper){
136  for(ib=ib400;ib<=ib700;ib++){
137  if(Rrs[ib]!=BAD_FLT){
138  Rrs_avw [nwave_avw]=Rrs[ib] * (l1file->Fonom[ib]*fsol/l2rec->l1rec->Fo[ib])/l2rec->outband_correction[ipb+ib];
139  wave_avw[nwave_avw]=wave[ib];
140  nwave_avw++;
141  }
142  else if(Rrs[ib]<0)
143  negative=1;
144  }
145  }
146  else{
147  for(ib=0;ib<nbands;ib++){
148  if(wave[ib]>=400 && wave[ib]<=700){
149  if(Rrs[ib]!=BAD_FLT){
150  Rrs_avw [nwave_avw]=Rrs[ib] * (l1file->Fonom[ib]*fsol/l2rec->l1rec->Fo[ib])/l2rec->outband_correction[ipb+ib];
151  wave_avw[nwave_avw]=wave[ib];
152  nwave_avw++;
153  }
154  else if(Rrs[ib]<0)
155  negative=1;
156  }
157  }
158  }
159 
160  if(negative)
161  l2rec->l1rec->flags[ip] |=PRODWARN;
162 
163  if(ifhyper)
164  avw[ip]=avw_cal_hypspectral(Rrs_avw,wave_avw,nwave_avw);
165  else
166  avw[ip]=avw_cal_multispectral(Rrs_avw,wave_avw,nwave_avw);
167 
168  }
169 }
170 void get_Rrs_brightness(l2str *l2rec, float Rrs_brightness[]){
171 
172  int32_t ip,ib;
173  int32_t ipb;
174 
175  int32_t nbands = l2rec->l1rec->l1file->nbands;
176  int32_t npix = l2rec->l1rec->npix;
177  float *wave=l2rec->l1rec->l1file->fwave;
178  float *Rrs;
179  static float *Rrs_avw, *wave_avw;
180  static int firstcall=1;
181  int32_t nwave_avw;
182  static int ib400=0,ib700=0;
183 
184  if(firstcall){
185  firstcall=0;
186  Rrs_avw =(float *)malloc(nbands*sizeof(float));
187  wave_avw=(float *)malloc(nbands*sizeof(float));
188 
189  ib400=windex(400, wave,nbands);
190  ib700=windex(700, wave,nbands);
191  }
192 
193  /* */
194  /* Compute desired products at each pixel */
195  /* */
196  for (ip = 0; ip < npix; ip++) {
197  Rrs_brightness[ip]=BAD_FLT;
198 
199  if(l2rec->l1rec->mask[ip] || l2rec->l1rec->solz[ip] >= SOLZNIGHT)
200  continue;
201 
202  ipb=ip*nbands;
203  Rrs=&l2rec->Rrs[ipb];
204  nwave_avw=0;
205 
206  for(ib=ib400;ib<=ib700;ib++){
207  if(Rrs[ib]!=BAD_FLT){
208  Rrs_avw [nwave_avw]=Rrs[ib];
209  wave_avw[nwave_avw]=wave[ib];
210  nwave_avw++;
211  }
212  else if (Rrs[ib]<0)
213  l2rec->l1rec->flags[ip]|=PRODWARN;
214  }
215 
216  if(nwave_avw<2)
217  continue;
218 
219  Rrs_brightness[ip]=0;
220  for(ib=0;ib<nwave_avw-1;ib++){
221  Rrs_brightness[ip]+=(Rrs_avw[ib]+Rrs_avw[ib+1])/2.0*(wave_avw[ib+1]-wave_avw[ib]);
222  }
223  }
224 }
225 
226 void get_lambda_max(l2str *l2rec, float lambda_max[]){
227 
228  int32_t ip,ib;
229  int32_t ipb;
230 
231  int32_t nbands = l2rec->l1rec->l1file->nbands;
232  int32_t npix = l2rec->l1rec->npix;
233  float *wave=l2rec->l1rec->l1file->fwave;
234  float *Rrs;
235  float Rrs_temp;
236  static int firstcall=1;
237  static int ib400, ib700;
238  int negative=0;
239 
240  if(firstcall){
241  ib400=windex(400, wave,nbands);
242  ib700=windex(700, wave,nbands);
243  firstcall=0;
244  }
245 
246  /* */
247  /* Compute desired products at each pixel */
248  /* */
249  for (ip = 0; ip < npix; ip++) {
250  negative=0;
251  lambda_max[ip]=BAD_FLT;
252 
253  if(l2rec->l1rec->mask[ip] || l2rec->l1rec->solz[ip] >= SOLZNIGHT)
254  continue;
255 
256  ipb=ip*nbands;
257  Rrs=&l2rec->Rrs[ipb];
258  Rrs_temp=Rrs[ib400];
259 
260  if(Rrs_temp>=0)
261  lambda_max[ip]=wave[ib400];
262  else
263  negative=1;
264 
265  for(ib=ib400+1;ib<=ib700;ib++){
266  if(Rrs[ib]<0)
267  negative=1;
268  if(Rrs[ib]>Rrs_temp){
269  Rrs_temp=Rrs[ib];
270  lambda_max[ip]=wave[ib];
271  }
272  }
273  if(negative)
274  l2rec->l1rec->flags[ip] |=PRODWARN;
275  }
276 }
int32 l1file(int32 sdfid, int32 *nsamp, int32 *nscans, int16 *dtynum)
Definition: l1stat_chk.c:586
float avw_cal_multispectral(float *Rrs, float *wave, int nwave)
Definition: get_avw.c:57
void get_lambda_max(l2str *l2rec, float lambda_max[])
Definition: get_avw.c:226
void get_avw(l2str *l2rec, float avw[])
Definition: get_avw.c:80
subroutine spline(s, x, y, n, in, t, il, iu, vl, vu, e, u)
Definition: phs.f:1348
@ PRODWARN
void get_Rrs_brightness(l2str *l2rec, float Rrs_brightness[])
Definition: get_avw.c:170
instr * input
float avw_cal_hypspectral(float *Rrs, float *wave, int nwave)
Definition: get_avw.c:20
#define PRISM
Definition: sensorDefs.h:31
#define SOLZNIGHT
Definition: l1.h:57
#define BAD_FLT
Definition: jplaeriallib.h:19
int32_t nbands
int windex(float wave, float twave[], int ntwave)
Definition: windex.c:73
subroutine splint(xa, ya, y2a, n, x, y)
float first_deriv(float x[], float y[], int n)
Definition: aerosol.c:246
#define HICO
Definition: sensorDefs.h:25
int32_t sensorID[MAXNFILES]
Definition: l2bin.cpp:97
int npix
Definition: get_cmp.c:27