OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
DtAlgLand.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * NAME: DtAlgLand.cpp
4  *
5  * DESCRIPTION: Object class that provides data structures and processes that
6  * compute processings for a given DtAlgLand object class.
7  *
8  * Created on: November 3, 2016
9  * Author: Sam Anderson, DT
10  *
11  * Modified:
12  *
13  *******************************************************************************/
14 
15 #include <boost/math/interpolators/barycentric_rational.hpp>
16 #include <fstream>
17 
18 #include <DDataset.hpp>
19 #include <DDProcess.h>
20 #include "darktarget/DtLutNetcdf.h"
21 #include "darktarget/DtMask.h"
22 #include "darktarget/DtAlgorithm.h"
23 
24 using namespace std;
25 
26 /*
27 * This program derives aerosol optical depth (AOD) at 10km x 10km
28 * from cloud and water screened 500 meter and 250 meter MODIS measured
29 * radiances over land. AOD are derived at 0.553 micron, by inverting
30 * radiance data at 0.466,0.644 and 2.113 micron channels. Dark pixels
31 * are identified by the 2.113 mid-shortwave-IR (SWIR) *hannel, and
32 * sorted so that the brightest (50%) and darkest (20%) pixels are discarded
33 * to reduce cloud and other contaminations. Surface reflectance in the
34 * the visible channels (0.466 and 0.644 micron) are estimated from
35 * the 2.113 channel, using relationships parameterized from vegetation
36 * indices in the mid-IR (MVI) channels of 1.24 and 2.113 microns), and
37 * also as a function of the solar/surface/satellite scattering angles.
38 * Note, that the 2.113 SWIR is not assumed transparent to aerosol, so that
39 * the inversion of the two visible and one SWIR channels results in
40 * three parameters: 1) spectral AOD normalized to 0.553 micron
41 * 2) The spectral fine mode AOD (AODfine = AOD * non-dust weighting)
42 * and 3) Surface reflectance at 2.113 micron.
43 *
44 * The aerosol models have been derived from the AERONET data base and
45 * are considered "dynamic" models of the optical depth.
46 * and are fixed as a function of location and season.
47 *
48 * The program assumes that the input data are in reflectance units
49 * of PI*L/(F0*cos(theta0)) for all visible and mid-IR channels.
50 * The input data are on MODIS spatial resolutions where the pixel size
51 * of the 0.66 micron is double the resolution of the 0.466, 1.24 and 2.11
52 * mi*ron *hannels
53 *
54 * Note: the program uses input cloud mask file (cloudy=0,clear=1),
55 * which is determined by the thresholds of visible reflectance and
56 * the visible reflectance ratios. It requires that for 0.47 micron
57 * channel 75% of the subpixels (250 m resolution) to be cloud free
58 * and 100% of the subpixels to be water free. For 0.66 micron channel
59 * it requires 100% subpixels to be cloud and water free. The selection
60 * of 20th to 50th percentile will eliminate the residual clouds.
61 * A valid retrieval needs at least 12 remaining pixels.
62 *
63 **INPUT PARAMETERS:
64 *
65 * HANDLE_LUTs Logical unit numbers to open multi-wavelength lookup tables
66 * IMONTH calendar month
67 * ISACN Scan number
68 * IDATA Index of 10x10 km box
69 * NUMSQ Total number of 10x10 km boxes
70 * solz_ Solar zenith angle
71 * senz_ viewing angle
72 * raa_ Relative azimuth angle
73 * LAT_CENTER center latitude of 10x10 km box
74 * LON_CENTER center longitude of 10x10 km box
75 * START_500 Starting index for 500 m resolution array
76 * END_500 Ending index for 500 m resolution array
77 * START_250 Starting index for 250 m resolution array
78 * END_250 Ending index for 250 m resolution array
79 * start_line Starting index for 1 km resolution array
80 * END_1KM Ending index for 1 km resolution array
81 * W488_SYN L1B data at 0.466 micron
82 * W2250_SYN L1B data at 2.113 micron
83 * W1240_SYN L1B data at 1.24 micron
84 * W1610_SYN L1B data at 1.64 micron
85 * W553_SYN L1B data at 0.553 micron
86 * W670_SYN L1B data at 0.644 micron
87 * W865_SYN L1B data at 0.865 micron
88 * CLDMSK_250 cloud mask in 250 m resolution
89 * SET_COUNTER_LAND counter of land
90 *
91 **OUTPUT PARAMETERS:
92 *
93 * QA_Flag_Land QA flag araay for aerosol over land
94 * Success_Ret_Land Number of successfully retrieved value
95 * Fail_Ret_Land Number of failed retrieved value
96 * SDSLAT HDF SDS array for latitude
97 * SDSLON HDF SDS array for longitude
98 * SDS_MTHET0 HDF SDS array for solar zenith angle
99 * SDS_MTHET HDF SDS array for viewing angle
100 * SDS_MPHI HDF SDS array for relative azimuth
101 * SDS_Aerosol_Type HDF SDS array for aerosol type
102 * SDS_SCAT_ANGLE_land HDF SDS array for scattering angle
103 * SDS_mass_conc_lan HDF SDS array for mass concentration
104 * SDS_angs_coeff_land HDF SDS array for angstrom coefficient
105 * SDS_CLDFRC_land HDF SDS array for number of cloudy pixels
106 * SDS_dust_weighting HDF SDS array for dust weighting factor
107 * SDS_est_uncer HDF SDS array for estimated uncertainties
108 * SDS_NUMPIXELS_land HDF SDS array for number of pixels used in retrieval
109 * SDSTAU_corrected HDF SDS array for corrected aerosol optical depth
110 * SDSTAU_small_land HDF SDS array for fine mode aerosol optical depth
111 * SDS_ref_land HDF SDS array for mean apparent reflectance
112 * SDS_ref_STD_land HDF SDS array for std of apparent reflectance
113 * SDS_QCONTROL_land HDF SDS array for quality control
114 *
115 **REVISION HISTORY:
116 * $Log: Process_land_V6.f,v $
117 * 02/15/2006 levy
118 * Initial revision
119 *
120 **TEAM-UNIQUE HEADER:
121 *
122 * Developed by MODIS Aerosol/Solar Water Vapor Retrieval Team
123 * GSFc, Greenbelt, MD
124 *
125 *
126 **DESIGN NOTES:
127 *
128 * The following ERROR cODE indicates no retrieval possibly done:
129 * Shanacc
130 * 1 Solar, satellite zenith angle and relative azimuth angles
131 * are out of bound of look-up tables
132 * 2 Threshold for 2.13 um is not met in the entire grid box
133 * 3 The thresold for number of cloudfree points is not met.
134 * (NUMcLDFREE see the parameter) or there is water.
135 * 4 The computed reflectance for 0.47 or 0.66 channels is out
136 * of bounds from look-up table
137 * 5 Threshold for 2.13 um is not met in option 2 and 3
138 * 6 Aerosol type can not be determined
139 *
140 * The values of aerosol optical thickness corresponding to error code
141 * Error code Value of aerosol optical thickness
142 *
143 * 1 -3.0
144 * 2 -4.0
145 * 3 -5.0
146 * 4 -6.0
147 * 5 -7.0
148 * 6 -8.0
149 *
150 * Aerosol types (FTABLE)
151 * 1 continental
152 * 2 Generic : SSA ~ 0.9
153 * 3 Smoke : SSA ~ 0.85
154 * 4 Urban : SSA ~ 0.95
155 * 5 Dust
156 *
157 * Procedure used in retrieving aerosol optical thickness:
158 *
159 * 0 = no dark targets possibly met by the following thresholds
160 * 1 = threshold used for wave 2.13 um 0.01 - 0.25
161 * 2 = threshold used for wave 2.13 um 0.25 - 0.40
162 *
163 * INTERNALS:
164 *
165 * Subroutines:
166 * RNLOOKUP - READS THE LOOK-UP TABLES
167 * ERROR - SETS THE ERROR cODES
168 * OUTPUT - WRITES THE OUTPUT TO HDF FILE
169 * AEROSOL_MAP - Reads map of aerosol model as function of season and place
170 * INTANGLE_NL_RAY - Interpolates LUT Rayleigh parameters to measured geometry
171 * Process_land_Rob - The main code for doing the radiance to aerosol inversion
172 * cOMPUTE_ScATTANGLE_LAND - computes scattering angle
173 * Statistics_land - Statistics for Path Radiance and critical Reflectance
174 * FILLVALUE_LAND - Inserts fill values for parameters if errors
175 *
176 *
177 * Variables:
178 * W488_SYN(2*IGRIDX,2*IGRIDY) Reflectance for wav=0.47um
179 * W550_SYN(2*IGRIDX,2*IGRIDY) Reflectance for wav=0.55um
180 * W2250_SYN(2*IGRIDX,2*IGRIDY) Reflectance for wav=2.13um
181 * W1240_SYN(2*IGRIDX,2*IGRIDY) Reflectance for wav=1.24um
182 * W1610_SYN(2*IGRIDX,2*IGRIDY) Reflectance for wav=1.64um
183 * W670_SYN(4*IGRIDX,4*IGRIDY) Reflectance for wav=0.66um
184 * W865_SYN(4*IGRIDX,4*IGRIDY) Reflectance for wav=0.86um
185 * cLDMSK_250(ISWATH_B,ILINE) cloud mask of 250 m resolution
186 * (0=cloudy,1=clear)
187 * solz_ solar zenith angle (degree)
188 * senz_ satellite viewangle angle (degree)
189 * raa_ relative azimuth in angle (degree)
190 * MHGHT Topographic altitude (km)
191 * yint644,yint466,slope466,slope644
192 * characteristics of VIS/IR surface reflectance relationship
193 *
194 * LAND SDS_ARRAYS.........
195 *
196 * SDS_QCONTROL_land Quality control SDS array
197 * SDS_Aerosol_Type Index of Aerosol type
198 * SDS_SCAT_ANGLE_land Scattering Angle
199 * SDS_angs_coeff_land Angstrom exponent for 0.47 and 0.67 micron
200 * SDS_CLDFRC_land cloud fraction (%)
201 * SDS_dust_weighting Dust aerosol weighting factor
202 * SDS_est_uncer Uncertainty of optical thickness at 0.47 and 0.66 micron
203 * SDS_NUMPIXELS_land Number of pixels with desired percentile
204 * SDSTAU_corrected corrected optical thickness at 0.47 0.55 and 0.66 micron
205 * SDS_ref_land Mean reflectance at five bands
206 * SDS_ref_STD_land Standard deviation of reflectance at five bands
207 * SDS_mass_conc_land Mass concentration
208 */
209 
210 
211 /**************************************************************************
212  * NAME: DtAlgLand()
213  *
214  * DESCRIPTION: Class Constructor
215  *
216  *************************************************************************/
217 
219 {
220  cm_= nullptr;
221  season_= 0;
222  scatter_angle_= 0;
223  memset(mtable_, 0, NLSIZE*sizeof(int));
224  memset(refl_ray_nl_, 0, NLWAV*sizeof(float));
225  memset(opth_nl_, 0, NLSIZE*NLWAV*NLTAU*sizeof(float));
226  memset(int_nl_, 0, NLSIZE*NLWAV*NLTAU*sizeof(float));
227  memset(fd_nl_, 0, NLSIZE*NLWAV*NLTAU*sizeof(float));
228  memset(t_nl_, 0, NLSIZE*NLWAV*NLTAU*sizeof(float));
229  memset(fdt_nl_, 0, NLSIZE*NLWAV*NLTAU*sizeof(float));
230  memset(sbar_nl_, 0, NLSIZE*NLWAV*NLTAU*sizeof(float));
231  memset(refl_inter_, 0, NLWAV*GRIDX*GRIDY*sizeof(float));
232  memset(refl_, 0, NLWAV*sizeof(float)); // mean reflectance
233  memset(sdev_, 0, NLWAV*sizeof(float)); // reflectance standard deviation
234  error_= 0;
235  memset(rho_star_, 0, NLSIZE*NLWAV*NLTAU*sizeof(float));
236  memset(rho_star_tot_, 0, NLWAV*NLTAU*sizeof(float));
237  memset(rho_S212_, 0, NLSIZE*NLTAU*sizeof(float));
238  memset(rho_S212_tot_, 0, NLTAU*sizeof(float));
239  memset(errwave_, 0, NLWAV*sizeof(float));
240  rho_S466_= 0;
241  yint_466_= 0;
242  slope_466_= 0;
243  rho_S644_= 0;
244  yint_644_= 0;
245  slope_644_= 0;
246  eta_flag_= 0;
247  memset(aot_d_, 0, NLWAV*sizeof(float)); // tau corrected
248  memset(aot_f_, 0, NLWAV*sizeof(float)); // tau fine (small)
249  memset(aot_c_, 0, NLWAV*sizeof(float)); // tau coarse (big)
250  memset(rho_sfc_, 0, NLWAV*sizeof(float)); // surface reflectance
251  eta_= 0; // dust weighting
252  err644_= 0; // fitting error
253  masscon_= 0; // mass concentration
254  angstrom_= 0; // angs coefficient
255  ndvi_= 0; // ndvi
256  iaer_= 0; // aerosol type
257  memset(good_pixels_, 0, NLWAV*sizeof(int)); // good pixels
258  num_pixels_used_= 0; // = good_pixels_[W659]
259  iproc_= 0;
260  ifinish_= 0;
261  thresh_min_= 0;
262  thresh_max_= 0;
263  return_quality_cirrus_= 0;
264  success_ret_= 0;
265  fail_ret_= 0;
266  memset(quality_flag_for_joint_, 0, 2*sizeof(short));
267  quality_flag_for_retr_= 0;
268  qcontrol_special_= 0;
269  memset(sds_qcontrol_, 0, QA_LAND*sizeof(short));
270  sds_aerosol_type_= 0;
271  sds_scat_angle_= 0;
272  sds_fitting_error_= 0;
273  sds_mass_conc_= 0;
274  sds_cloud_fraction_= 0;
275  sds_angs_coeff_= 0;
276  sds_dust_weighting_= 0;
277  sds_ndvi_= 0;
278  memset(sds_numpixels_, 0, NLWAV*sizeof(float));
279  memset(sds_tau_corrected_, 0, NLWAV*sizeof(float));
280  memset(sds_refl_, 0, NLWAV*sizeof(float));
281  memset(sds_refl_std_, 0, NLWAV*sizeof(float));
282  memset(sds_tau_small_, 0, NLWAV*sizeof(float));
283  memset(sds_tau_big_, 0, NLWAV*sizeof(float));
284  memset(sds_surface_reflectance_, 0, NLWAV*sizeof(float));
285 
286 }
287 
288 /**************************************************************************
289  * NAME: ~DtAlgLand()
290  *
291  * DESCRIPTION: Class Destructor
292  *
293  *************************************************************************/
294 
296 {
297  if (cm_ != 0) {
298  delete cm_;
299  }
300 }
301 
302 /**************************************************************************
303  * NAME: initialize()
304  *
305  * DESCRIPTION: Virtual function initializes data and object classes for
306  * processing operations.
307  *
308  *************************************************************************/
309 
310 int DtAlgLand::initialize( map<string, ddata*> imap )
311 {
312  int status = DTDB_SUCCESS;
313 
314  DtAlgorithm::initialize( imap );
315 
316  DtLutNetcdf* lutgen = new DtLutNetcdf();
317  status = lutgen->read_land_aerosol_lut( lut_ );
318  delete lutgen;
319 
320  cm_ = new DtCloudMaskLand(this);
321 
322  return status;
323 }
324 
325 /**************************************************************************
326  * NAME: process()
327  *
328  * DESCRIPTION: Dark Target land algorithm process.
329  *
330  *************************************************************************/
331 
332 map<string, ddata*> DtAlgLand::process(vector<size_t> start, vector<size_t> count,
333  map<string, ddata*> imap)
334 {
335  get_inputs(start, count, imap);
336 
337  l2_flags_ += (unsigned int) flags::LAND;
338 
339  if (rfl_[(size_t)rhot_band::W550]<0.0) {
340  l2_flags_ += (unsigned int) flags::BOWTIEDEL;
341  return set_fills();
342  }
343 
344  rfld_[D412] = rfl_[(size_t)rhot_band::W410];
345  rfld_[D488] = rfl_[(size_t)rhot_band::W490];
346  rfld_[D550] = rfl_[(size_t)rhot_band::W550];
347  rfld_[D670] = rfl_[(size_t)rhot_band::W670];
348  rfld_[D865] = rfl_[(size_t)rhot_band::W865];
349  rfld_[D1240] = rfl_[(size_t)rhot_band::W1240];
350  rfld_[D1610] = rfl_[(size_t)rhot_band::W1610];
351  rfld_[D2250] = rfl_[(size_t)rhot_band::W2250];
352 
353  if((solz_ >= MINMTHET0) && (solz_ <= MAXMTHET0) &&
354  (senz_ >= MINMTHET) && (senz_ <= MAXMTHET) &&
355  (raa_ >= MINMPHI) && (raa_ <= MAXMPHI) && rfld_[D488] > 0.0)
356  {
357  if (bgascorrect_) {
358  compute_gas_correction();
359  rfld_[D412] *= gasc_[D412];
360  rfld_[D488] *= gasc_[D488];
361  rfld_[D550] *= gasc_[D550];
362  rfld_[D670] *= gasc_[D670];
363  rfld_[D865] *= gasc_[D865];
364  rfld_[D1240] *= gasc_[D1240];
365  rfld_[D1610] *= gasc_[D1610];
366  rfld_[D2250] *= gasc_[D2250];
367  }
368 
369  if (cloud_mask_ == DFILL_UBYTE) {
370  cm_->compute(cmask_);
371  if (cmask_ != DFILL_UBYTE) {
372  cloud_mask_ = (cmask_+1)%2;
373  }
374  } else {
375  cmask_ = (cloud_mask_+1)%2;
376  };
377  if (!bcloudmask_) cmask_ = 1;
378  if (bcloudmask_ && cloud_mask_) {
379  l2_flags_ += (unsigned int) flags::CLDICE;
380  return set_fills();
381  }
382 
383  index_geometry(solz_, senz_, raa_);
384  compute_glint_angle();
385  compute_scatter_angle(scatter_angle_);
386  interpolate_rayleigh();
387 
388  iproc_ = 0;
389  ifinish_ = 0;
390  thresh_min_ = THR213MIN_1;
391  thresh_max_ = THR213MAX_1;
392 
393  if ((cmask_ > 0) &&
394  rfld_[D488]>0 && rfld_[D670]>0 && rfld_[D865]>0 && rfld_[D2250]>0) {
395 
396  ndvi_ = (rfld_[D865]-rfld_[D670])/(rfld_[D865]+rfld_[D670]);
397  int ilon = 180 + round(lon_ + DLON);
398  int ilat = 90 - round(lat_ + DLAT);
399 
400 // Select LUT corresponding to season and location
401 // Fine mode LUT (choice of tables #2, #3 or #4)
402 // Continental mode LUT = #1; Coarse mode LUT = #5
403 
404  mtable_[ISMALL] = lut_.AEROSOL_ALL[season_][ilat][ilon] + 1;
405  mtable_[IBIG] = DTABLE-1;
406 
407  index_geometry( solz_, senz_, raa_);
408  interpolate_angle();
409  interpolate_elevation();
410  simulate_toa();
411  eta_flag_ = 0;
412  retrieve_first();
413  if (aot_d_[DL670] > 0) {
414  angstrom_ = -1.0 * log(aot_d_[DL488]/aot_d_[DL670])/ log(0.466/0.644);
415  }
416  iproc_=1;
417  }
418  iaer_ = mtable_[ISMALL]+1;
419  } else {
420  fill_values();
421  }
422  assign_quality();
423  store_output();
424 
425  // write to generic outputs
426 
427  qual_flag_ = quality_flag_for_joint_[0];
428  aerosol_type_ = sds_aerosol_type_;
429  error_flag_ = quality_flag_for_joint_[1];
430 
431  scatter_ang_ = 180.0 - glint_angle_;
432  glint_ang_ = glint_angle_;
433  sse_ = sds_fitting_error_;
434  fmf_ = sds_dust_weighting_;
435  aot_550_ = sds_tau_corrected_[DL550];
436  ae1_ = sds_angs_coeff_;
437  ndv_ = sds_ndvi_;
438  ae2_ = DFILL_FLOAT;
439  chlor_ = DFILL_FLOAT;
440  for ( int iWav=0; iWav<NOWL; iWav++ ) {
441  aot_[iWav] = DFILL_FLOAT;
442  }
443  aot_[(size_t)aot_band::W490] = sds_tau_corrected_[DL488];
444  aot_[(size_t)aot_band::W550] = sds_tau_corrected_[DL550];
445  aot_[(size_t)aot_band::W670] = sds_tau_corrected_[DL670];
446  aot_[(size_t)aot_band::W2250] = sds_tau_corrected_[DL2250];
447 
448  sr_[(size_t)srf_band::W410] = DFILL_FLOAT;
449  ssa_[(size_t)srf_band::W410] = DFILL_FLOAT;
450  sr_[(size_t)srf_band::W490] = sds_surface_reflectance_[DL488];
451  ssa_[(size_t)srf_band::W490] = DFILL_FLOAT;
452  sr_[(size_t)srf_band::W670] = sds_surface_reflectance_[DL670];
453  ssa_[(size_t)srf_band::W670] = DFILL_FLOAT;
454  sr_[(size_t)srf_band::W2250] = sds_surface_reflectance_[DL2250];
455  ssa_[(size_t)srf_band::W2250] = DFILL_FLOAT;
456 
457  vector<float> tba = {490.0,550.0,670.0,2250.0};
458  vector<float> yba = {aot_[(size_t)aot_band::W490],aot_[(size_t)aot_band::W550],aot_[(size_t)aot_band::W670],aot_[(size_t)aot_band::W2250]};
459  using boost::math::barycentric_rational;
460  barycentric_rational<float> interp(move(tba), move(yba));
461  aot_[(size_t)aot_band::W865] = interp(865.0);
462  aot_[(size_t)aot_band::W1240] = interp(1240.0);
463  aot_[(size_t)aot_band::W1610] = interp(1610.0);
464 
465  return set_outputs();
466 }
467 
468 /**************************************************************************
469  * NAME: index_geometry()
470  *
471  * DESCRIPTION: Reset LUT indices based on measured geometry.
472  *
473  *************************************************************************/
474 
475 int DtAlgLand::index_geometry( float sza, float azim, float phi)
476 {
477  int status = DTDB_SUCCESS;
478 
479  for (int iTh0=0; iTh0< NLTHET0-1; iTh0++) {
480  if ((sza >= lut_.THET0_NL[iTh0]) && (sza <= lut_.THET0_NL[iTh0+1])) {
481  SZA_0_= iTh0;
482  SZA_1_= iTh0+1;
483  }
484  }
485  for (int iTh=0; iTh < NLTHE-1; iTh++) {
486  if ((azim >= lut_.THE_NL[iTh]) && (azim <= lut_.THE_NL[iTh+1])) {
487  THE_0_= iTh;
488  THE_1_= iTh+1;
489  }
490  }
491  for (int iPhi=0; iPhi < NLPHI-1; iPhi++) {
492  if ((phi >= lut_.PHI_NL[iPhi]) && (phi <= lut_.PHI_NL[iPhi+1])) {
493  PHI_0_=iPhi;
494  PHI_1_=iPhi+1;
495  }
496  }
497 
498  return status;
499 }
500 
501 /**************************************************************************
502  * NAME: average()
503  *
504  * DESCRIPTION: This subroutine processes 10*10 pixel box for cloud detection and
505  * finds the average reflectance for red and blue channels. Surface
506  * Reflectance from wavelength 2.13 . This surface Reflectance and
507  * average Reflectance for red and blue channel are send to lookup
508  * table and optical thickness is derived.
509  *
510  *************************************************************************/
511 
512 int DtAlgLand::compute_average(size_t iy, size_t ix)
513 {
514  int status = DTDB_SUCCESS;
515 
516  int numCldRed = 0;
517  int numCldBlue = 0;
518  ifinish_ = 0;
519  error_ = 4;
520 
521  compute_cloudmask_ndvi(iy, ix, numCldRed, numCldBlue);
522 
523  int aindex[GRIDX*GRIDY];
524  memset(aindex, 0, GRIDX*GRIDY*sizeof(int));
525  float array_interm[NLWAV][GRIDX*GRIDY];
526  memset(array_interm, 0, NLWAV*GRIDX*GRIDY*sizeof(float));
527 
528 // I213>0 and Icld>0 indicate that the threshold for 2.13 micron
529 // is met and the data set is cloud free as defined.
530 // index in ascending order and get the index for reflectances at 0.66 um
531 
532  sort_index(numCldBlue,refl_inter_[DL670],aindex);
533 
534  int N20 = (int) ((float)numCldBlue/5.0);
535  int N50 = (int) ((float)numCldBlue/2.0);
536 // if (N20 == 0) N20=1;
537  if ((N50 == 0) && (numCldBlue > 0)) N50=1;
538  int number_pixels = 1;
539 // Throw away dark & bright pixels
540 // At least 5% after pixels are thrown out
541  if((N50-N20) > number_pixels) {
542  ifinish_ = 1;
543  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
544  good_pixels_[iWav]=0;
545  for ( int ix=N20; ix<N50; ix++ ) {
546  float ril = refl_inter_[iWav][aindex[ix]];
547  if ((ril > 0.0) && (ril <= 1.0)) {
548  array_interm[iWav][good_pixels_[iWav]] = ril;
549  good_pixels_[iWav] += 1;
550  }
551  }
552  }
553 // Report valid pixels used for Blue channel at 500 meter resolution
554  num_pixels_used_ = good_pixels_[DL670];
555  for ( int iWav = 0; iWav < NLWAV; iWav++ ) {
556  if(good_pixels_[iWav] > 0) {
557  float refl_val = 0;
558  float sd_val = 0;
559 
560  mean_std(good_pixels_[iWav],
561  array_interm[iWav], refl_val, sd_val);
562 
563  refl_[iWav] = refl_val;
564  sdev_[iWav] = sd_val;
565  }
566  else {
567  refl_[iWav] = DFILL_FLOAT;
568  sdev_[iWav] = DFILL_FLOAT;
569  }
570  }
571 // Check if 3 wavelengths have valid range
572  if( !((refl_[DL488] > 0) &&
573  (refl_[DL670] > 0) &&
574  (refl_[DL2250] > 0))) {
575 
576  error_ = 2;
577  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
578  refl_[iWav] = DFILL_FLOAT;
579  sdev_[iWav] = DFILL_FLOAT;
580  }
581  }
582  }
583  else {
584  error_ = 3;
585  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
586  refl_[iWav] = DFILL_FLOAT;
587  sdev_[iWav] = DFILL_FLOAT;
588  good_pixels_[iWav] = DFILL_SHORT;
589  }
590  }
591 
592  return status;
593 }
594 
595 /**************************************************************************
596  * NAME: cloudmask_ndvi()
597  *
598  * DESCRIPTION: This subroutine finds the dark targets using a
599  * threshold in the 2.13 micron channel.it averages the
600  * cloud free pixels in red channel to the 0.5 km resolution.
601  * If too cloudy or too bright at 2.13 it leaves the value
602  * as zero.
603  *
604  *************************************************************************/
605 
606 int DtAlgLand::compute_cloudmask_ndvi(size_t iy, size_t ix,
607  int& numCldRed, int& numCldBlue)
608 {
609  int status = DTDB_SUCCESS;
610 
611  numCldBlue = 0;
612  numCldRed = 0;
613  for (int iWav=0; iWav < NLWAV; iWav++) {
614  for (int j=0; j<GRIDX*GRIDY; j++) {
615  refl_inter_[iWav][j] = 0;
616  }
617  }
618 // If snowy pixels set cloud mask to Zero
619  if(cm_->snowmask_ == 0) {
620  cmask_ = 0;
621  }
622  numCldRed = 0;
623  int noWater = 0;
624 // Check if threshold for 2.13 um is met
625 // (missing pixels or noisy detectors are ignored)
626  if ((rfld_[D2250] <= thresh_max_) &&
627  (rfld_[D2250] > thresh_min_) && (cmask_ == 1)) {
628  numCldRed++;
629  if ((rfld_[D865] > 0.0) && (rfld_[D670] > 0.0)) {
630 // NDVI test according to Eric Vermote
631  ndvi_ = (rfld_[D865]-rfld_[D670])/(rfld_[D865]+rfld_[D670]);
632  if (ndvi_ > 0.1) {
633  noWater++;
634  }
635  }
636  }
637 
638  return status;
639 }
640 
641 /**************************************************************************
642  * NAME: interpolate_rayleigh()
643  *
644  * DESCRIPTION: Subroutine INTANGLE_NL interpolates the lookup
645  * Rayleigh reflectances to the measured geometry.
646  *
647  *************************************************************************/
648 
650 {
651  int status = DTDB_SUCCESS;
652 
653 // Initialize
654  float x0[2] = {0.0,0.0};
655  float y0[2] = {0.0,0.0};
656  float x1[2] = {0.0,0.0};
657  float y1[2] = {0.0,0.0};
658  float x2[2] = {0.0,0.0};
659  float y2[2] = {0.0,0.0};
660 // Interpolate Rayleigh
661  int iTable = 0;
662  int iTau = 0;
663  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
664  int numWave=0;
665  for ( int iTh0=SZA_0_; iTh0<=SZA_1_; iTh0++ ) {
666  int numSza=0;
667  for ( int iTh=THE_0_; iTh<=THE_1_; iTh++ ) {
668  int numThe=0;
669  for ( int iPhi=PHI_0_; iPhi<=PHI_1_; iPhi++ ) {
670  x0[numThe]=lut_.PHI_NL[iPhi];
671  y0[numThe]=lut_.INT_NL0[iTable][iWav][iTau][iTh0][iTh][iPhi];
672  numThe++;
673  }
674  interp_extrap(numThe,raa_,x0,y0,y1[numSza]);
675  x1[numSza]=lut_.THE_NL[iTh];
676  numSza++;
677  }
678  interp_extrap(numSza,senz_,x1,y1,y2[numWave]);
679  x2[numWave]=lut_.THET0_NL[iTh0];
680  numWave++;
681  }
682  interp_extrap(numWave,solz_,x2,y2,refl_ray_nl_[iWav]);
683  }
684 
685  return status;
686 }
687 
688 /**************************************************************************
689  * NAME: interpolate_angle()
690  *
691  * DESCRIPTION: Subroutine interpolates the lookup reflectances to the
692  * measured geometry.
693  *
694  *************************************************************************/
695 
697 {
698  int status = DTDB_SUCCESS;
699 
700  float x0[2] = {0.0,0.0};
701  float y0[2] = {0.0,0.0};
702  float x1[2] = {0.0,0.0};
703  float y1[2] = {0.0,0.0};
704  float w1[2] = {0.0,0.0};
705  float x2[2] = {0.0,0.0};
706  float y2[2] = {0.0,0.0};
707  float w2[2] = {0.0,0.0};
708  float v2[2] = {0.0,0.0};
709  float u2[2] = {0.0,0.0};
710  for ( int iSize=0; iSize<NLSIZE; iSize++ ) {
711  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
712  for ( int iTau=0; iTau<NLTAU; iTau++ ) {
713  int nTau = 0;
714  for ( int iSza=SZA_0_; iSza<=SZA_1_; iSza++ ) {
715  int nTh = 0;
716  for ( int iTh=THE_0_; iTh<=THE_1_; iTh++ ) {
717  int nPhi = 0;
718  for ( int iPhi=PHI_0_; iPhi<=PHI_1_; iPhi++ ) {
719  x0[nPhi]=lut_.PHI_NL[iPhi];
720  y0[nPhi]=lut_.INT_NL0[mtable_[iSize]][iWav][iTau][iSza][iTh][iPhi];
721  nPhi++;
722  }
723  interp_extrap(nPhi,raa_,x0,y0,y1[nTh]);
724  x1[nTh]=lut_.THE_NL[iTh];
725  w1[nTh]=lut_.T_NL0[mtable_[iSize]][iWav][iTau][iSza][iTh];
726  nTh++;
727  }
728  interp_extrap(nTh,senz_,x1,y1,y2[nTau]);
729  interp_extrap(nTh,senz_,x1,w1,w2[nTau]);
730  x2[nTau]=lut_.THET0_NL[iSza];
731  v2[nTau]=lut_.Fd_NL0[mtable_[iSize]][iWav][iTau][iSza];
732  u2[nTau]=lut_.SBAR_NL0[mtable_[iSize]][iWav][iTau][iSza];
733  nTau++;
734  }
735  interp_extrap(nTau,solz_,x2,y2,int_nl_[iSize][iWav][iTau]);
736  interp_extrap(nTau,solz_,x2,w2,t_nl_[iSize][iWav][iTau]);
737  interp_extrap(nTau,solz_,x2,v2,fd_nl_[iSize][iWav][iTau]);
738  interp_extrap(nTau,solz_,x2,u2,sbar_nl_[iSize][iWav][iTau]);
739  fdt_nl_[iSize][iWav][iTau] =
740  t_nl_[iSize][iWav][iTau]*fd_nl_[iSize][iWav][iTau];
741  }
742  }
743  }
744 
745  return status;
746 }
747 
748 /**************************************************************************
749  * NAME: interpolate_elevation()
750  *
751  * DESCRIPTION: The subroutine interpolates the lookup
752  * reflectances to the target elevation.
753  * It interpolates between wavelengths to simulate
754  * elevation by a longer wavelength
755  *
756  *************************************************************************/
757 
759 {
760  int status = DTDB_SUCCESS;
761 
762  float rod_pres[NLWAV];
763  float eqwav_nl[NLWAV];
764  memset(rod_pres, 0, NLWAV*sizeof(float));
765  memset(eqwav_nl, 0, NLWAV*sizeof(float));
766 
767 // Estimate surface pressure (hyposometric EQ)
768  float pressure = PRESSURE_P0 * exp(-(height_/7.5));
769 // Estimate ROD at nominal wavelengths at p0 and at pres
770  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
771  float expfactor = -4.15 + (0.2 * lut_.WAV_NL[iWav]);
772  rod_pres[iWav] = 0.0088*(pressure/PRESSURE_P0) *
773  pow(lut_.WAV_NL[iWav],expfactor);
774 // Estimate equivalent wavelengths for ROD at pressure
775  float lambda0 = 0.0;
776  float lambda1 = 0.1;
777  float lambda2 = 4.0;
778  float diff0 = 99.0;
779  while (diff0 > 0.00001) {
780  lambda0 = (lambda1 + lambda2) / 2.0;
781  float fexp0 = -4.15 + 0.2*lambda0;
782  float fexp1 = -4.15 + 0.2*lambda1;
783  float fexp2 = -4.15 + 0.2*lambda2;
784  float ftau0 = 0.0088*pow(lambda0,fexp0);
785  float ftau1 = 0.0088*pow(lambda1,fexp1);
786  float ftau2 = 0.0088*pow(lambda2,fexp2);
787  if ((ftau1 > rod_pres[iWav]) && (ftau2 < rod_pres[iWav])) {
788  if (ftau0 > rod_pres[iWav]) {
789  lambda1 = (lambda1 + lambda2)/2.0;
790  }
791  else {
792  lambda2 = (lambda1 + lambda2)/2.0;
793  }
794  }
795  diff0 = fabs(ftau0 - rod_pres[iWav]);
796  }
797  eqwav_nl[iWav] = log(lambda0);
798  }
799 // Apply slight modification to optical depth lut -SSA
800  for (int iTab=0; iTab<DTABLE; iTab++) {
801  for (int iWav=0; iWav<NLUTWAV; iWav++) {
802  lut_.OPTH_NL0[iTab][iWav][0] =
803  0.75*lut_.OPTH_NL0[iTab][iWav][1];
804  }
805  }
806 // Interpolate lookup tables to equiv Waves (let's start only with
807 // 1st two wavelengths until we derive 0.86 table)
808  for ( int iSize=0; iSize<NLSIZE; iSize++ ) {
809  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
810 
811  for ( int iTau=0; iTau<NLTAU; iTau++ ) {
812  float yout = 0.0;
813  float x[2] = {0.0,0.0};
814  float y[2] = {0.0,0.0};
815  float w[2] = {0.0,0.0};
816  float v[2] = {0.0,0.0};
817  float u[2] = {0.0,0.0};
818  float t[2] = {0.0,0.0};
819  float z[2] = {0.0,0.0};
820  int iWav1 = (iWav == 3) ? iWav-1 : iWav;
821  int iWav2 = (iWav == 3) ? iWav : iWav+1;
822  int numWav=0;
823  for ( int jWav=iWav1; jWav<=iWav2; jWav++ ) {
824  // Interpolate on log log scale
825  x[numWav]=log(lut_.WAV_NL[jWav]);
826  y[numWav]=log(int_nl_[iSize][jWav][iTau]);
827  w[numWav]=log(fdt_nl_[iSize][jWav][iTau]);
828  u[numWav]=log(fd_nl_[iSize][jWav][iTau]);
829  t[numWav]=log(t_nl_[iSize][jWav][iTau]);
830  z[numWav]=log(sbar_nl_[iSize][jWav][iTau]);
831  v[numWav]=lut_.OPTH_NL0[mtable_[iSize]][jWav][iTau];
832  if (lut_.OPTH_NL0[mtable_[iSize]][jWav][iTau] > 0.) {
833  v[numWav]=log(lut_.OPTH_NL0[mtable_[iSize]][jWav][iTau]);
834  }
835  numWav++;
836  }
837  interp_extrap(numWav,eqwav_nl[iWav],x,y,yout);
838  int_nl_[iSize][iWav][iTau] = exp(yout);
839  interp_extrap(numWav,eqwav_nl[iWav],x,w,yout);
840  fdt_nl_[iSize][iWav][iTau] = exp(yout);
841  interp_extrap(numWav,eqwav_nl[iWav],x,u,yout);
842  fd_nl_[iSize][iWav][iTau] = exp(yout);
843  interp_extrap(numWav,eqwav_nl[iWav],x,t,yout);
844  t_nl_[iSize][iWav][iTau] = exp(yout);
845  interp_extrap(numWav,eqwav_nl[iWav],x,z,yout);
846  sbar_nl_[iSize][iWav][iTau] = exp(yout);
847  interp_extrap(numWav,eqwav_nl[iWav],x,v,yout);
848  if (yout == 0.0) {
849  opth_nl_[iSize][iWav][iTau] = yout;
850  } else {
851  opth_nl_[iSize][iWav][iTau] = exp(yout);
852  }
853  }
854  refl_ray_nl_[iWav] = int_nl_[iSize][iWav][0];
855  }
856  }
857 
858  return status;
859 }
860 
861 /**************************************************************************
862  * NAME: retrieve_first()
863  *
864  * DESCRIPTION: This subroutine retrieves optical thickness, surface
865  * reflectance and error parameters by comparing observations and LUT data
866  *
867  * INPUTS
868  * REFW466L,REFW644L,REFW212L reflectance
869  * OPTH_NL LUT based optical thickness
870  * MASSCOEF_NL LUT based mass concentration coeficients
871  * EXTNORM_NL LUT based normalized extinction coeficients
872  * RHO_S212 simulated surface reflectance
873  * RHOSTAR simulated TOA reflectance
874  * yint644,yint466,slope466,slope644
875  * characteristics of VIS/IR surface reflectance relationship
876  * OUTPUTS
877  * ERR644 retrieval fitting errors
878  * AOD retrieved Optical depths
879  * AODF/C Fine and coarse mode optical depth
880  * RHOSFC retrieved surface reflectance
881  * ETA retrieved fine mode weighting
882  * MASSCON retrieved mass concentration coefficient
883  * ETA_FLAG 0 if eta within 0.0 - 1.0
884  *
885  *************************************************************************/
886 
888 {
889  int status = DTDB_SUCCESS;
890 
891 // Initialize
892  float yout=0;
893  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
894  rho_sfc_[iWav] = DFILL_FLOAT;
895  aot_d_[iWav] = DFILL_FLOAT;
896  }
897 // Now loop through ETA values (kind of like ocean)
898  float aot553_temp[NLETA];
899  float rhosfc212_temp[NLETA];
900  float err644_temp[NLETA];
901  float rho_star_temp[NLETA][NLWAV];
902  memset(aot553_temp, 0, NLETA*sizeof(float));
903  memset(rhosfc212_temp, 0, NLETA*sizeof(float));
904  memset(err644_temp, 0, NLETA*sizeof(float));
905  memset(rho_star_temp, 0, NLETA*NLWAV*sizeof(float));
906 
907  for ( int iEta=0; iEta<NLETA; iEta++ ) {
908 // Average, best, QCONTROL, FILLVALUE, OUTPUT, etc
909  float eta_temp = -0.2 + (iEta+1) * 0.1;
910 // Compute total apparent reflectance
911  for ( int iTau=0; iTau<NLTAU; iTau++ ) {
912  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
913  rho_star_tot_[iWav][iTau] = eta_temp *
914  rho_star_[ISMALL][iWav][iTau] +
915  ((1-eta_temp) * rho_star_[IBIG][iWav][iTau]);
916  }
917 // Compute total surface reflectance
918  rho_S212_tot_[iTau] = eta_temp * rho_S212_[ISMALL][iTau] +
919  ((1-eta_temp) * rho_S212_[IBIG][iTau]);
920  }
921 // Interpolate everything based on measured reflectance at 466.
922 
923  interp_extrap(NLTAU,rfld_[D488],rho_star_tot_[DL488],
924  opth_nl_[ISMALL][DL550],aot553_temp[iEta]);
925  aot553_temp[iEta] = (aot553_temp[iEta]<0) ? 0.0 : aot553_temp[iEta];
926  // Compute apparent reflectance for all wavelengths
927  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
928 
929  interp_extrap(NLTAU,aot553_temp[iEta],
930  opth_nl_[ISMALL][DL550],
931  rho_star_tot_[iWav],rho_star_temp[iEta][iWav]);
932  }
933 // COMPUTE Surface Reflectance at 2.1
934 
935  interp_extrap(NLTAU,aot553_temp[iEta],
936  opth_nl_[ISMALL][DL550],
937  rho_S212_tot_,rhosfc212_temp[iEta]);
938 
939 // Errors
940  errwave_[DL488] =
941  fabs(rfld_[D488]-rho_star_temp[iEta][DL488]) / rfld_[D488];
942  errwave_[DL670] =
943  fabs(rfld_[D670]-rho_star_temp[iEta][DL670]) / rfld_[D670];
944  errwave_[DL2250] =
945  fabs(rfld_[D2250]-rho_star_temp[iEta][DL2250]) / rfld_[D2250];
946 // Determine error at 644nm
947  err644_temp[iEta] = errwave_[DL670];
948  }
949 // Sort results in ascending error order
950  int nleta_index[NLETA];
951 
952  sort_index(NLETA, err644_temp, nleta_index);
953 
954 // Best solution
955  eta_ = -0.2 + (nleta_index[0]+1) * 0.1;
956  err644_ = err644_temp[nleta_index[0]];
957  rho_sfc_[DL2250] = rhosfc212_temp[nleta_index[0]];
958  rho_sfc_[DL670] = yint_644_ + slope_644_* rho_sfc_[DL2250];
959  rho_sfc_[DL488] = yint_466_ + slope_466_*rho_sfc_[DL670];
960 // set out of bounds Eta to 0 or 1
961  if( eta_ < 0) {
962  eta_= 0.0;
963  eta_flag_ = -1;
964  }
965  if( eta_ > 1) {
966  eta_= 1.0;
967  eta_flag_ = -1;
968  }
969 // Compute fine and coarse AOD for mass concentration
970  float aot_F553 = aot553_temp[nleta_index[0]] * eta_;
971  float aot_C553 = aot553_temp[nleta_index[0]] * (1.-eta_);
972 // COMPUTE Mass Concentration
973 // Fine
974 
975  interp_extrap(NLTAU,aot_F553,opth_nl_[ISMALL][DL550],
976  lut_.MASSCOEF_NL0[mtable_[ISMALL]][DL550],yout);
977 
978  float massconf = yout*aot_F553;
979 // Coarse
980 
981  interp_extrap(NLTAU,aot_C553,opth_nl_[IBIG][DL550],
982  lut_.MASSCOEF_NL0[mtable_[IBIG]][DL550],yout);
983 
984  float massconc = yout*aot_C553;
985  masscon_ = massconf + massconc;
986 // Compute AOD for fine mode at all wavelengths
987  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
988  interp_extrap(NLTAU,aot_F553,opth_nl_[ISMALL][DL550],
989  lut_.EXTNORM_NL0[mtable_[ISMALL]][iWav],yout);
990 
991  aot_f_[iWav] = aot_F553 * yout;
992  }
993 // Compute AOD for coarse mode at all wavelengths
994 // Compute total AOD at all wavelengths
995  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
996  interp_extrap(NLTAU,aot_C553,opth_nl_[IBIG][DL550],
997  lut_.EXTNORM_NL0[mtable_[IBIG]][iWav],yout);
998 
999  aot_c_[iWav] = aot_C553 * yout;
1000  aot_d_[iWav] = aot_f_[iWav] + aot_c_[iWav];
1001  }
1002 
1003  return status;
1004 }
1005 
1006 /**************************************************************************
1007  * NAME: retrieve_second()
1008  *
1009  * DESCRIPTION: This subroutine retrieves optical thickness, surface
1010  * reflectance and error parameters by comparing
1011  * observations and LUT data
1012  *
1013  * INPUTS: REFW466L, REFW644L, REFW212L reflectance
1014  * OPTH array of LUT optical thickness
1015  * RHO_S212 simulated surface reflectance
1016  * RHOSTAR simulated TOA reflectance
1017  * yint644, yint466, slope466, slope644
1018  * characteristics of VIS/IR surface reflectance relationship
1019  * OUTPUTS:
1020  * ERR644 retrieval fitting errors
1021  * AOD retrieved optical depths
1022  * RHOSFC retrieved surface reflectance
1023  * ETA retrieved fine mode weighting
1024  *
1025  *************************************************************************/
1026 
1028 {
1029  int status = DTDB_SUCCESS;
1030 
1031 // Initialize
1032  float rho_star_temp[NLWAV];
1033  memset(rho_star_temp, 0, NLWAV*sizeof(float));
1034  float yout=0;
1035 
1036  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
1037  rho_sfc_[iWav] = DFILL_FLOAT;
1038  aot_d_[iWav] = DFILL_FLOAT;
1039  }
1040 // Now loop through ETA values (kind of like ocean)
1041 // Average, best, QCONTROL, FILLVALUE, OUTPUT, etc
1042 // Compute total apparent reflectance
1043  for ( int iTau=0; iTau<NLTAU; iTau++ ) {
1044  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
1045  rho_star_tot_[iWav][iTau] = rho_star_[ISMALL][iWav][iTau];
1046  }
1047 // Compute total surface reflectance
1048  rho_S212_tot_[iTau] = rho_S212_[ISMALL][iTau];
1049  }
1050 // Interpolate everything based on measured reflectance at 466.
1051 // Compute tau using radiance of 0.455 um and tau wav553
1052  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
1053 
1054  interp_extrap(NLTAU,rfld_[D488],
1055  rho_star_tot_[DL488],
1056  opth_nl_[ISMALL][iWav], aot_d_[iWav]);
1057  }
1058 // Compute apparent reflectance for all wavelengths
1059  for ( int iWav=0; iWav<NLWAV; iWav++ ) {
1060 
1061  interp_extrap(NLTAU,aot_d_[DL550],
1062  opth_nl_[ISMALL][DL550],
1063  rho_star_tot_[iWav], rho_star_temp[iWav]);
1064  }
1065 // Compute surface reflectance at 2.1
1066 
1067  interp_extrap(NLTAU,aot_d_[DL550],
1068  opth_nl_[ISMALL][DL550],
1069  rho_S212_tot_, rho_sfc_[DL2250]);
1070 
1071 // Errors
1072  errwave_[DL488] =
1073  fabs(rfld_[D488] - rho_star_temp[DL488]) / rfld_[D488];
1074  errwave_[DL670] =
1075  fabs(rfld_[D670] - rho_star_temp[DL670]) / rfld_[D670];
1076  errwave_[DL2250] =
1077  fabs(rfld_[D2250] - rho_star_temp[DL2250]) / rfld_[D2250];
1078  err644_ = errwave_[DL670];
1079 
1080  rho_sfc_[DL550] = DFILL_FLOAT;
1081  rho_sfc_[DL670] = yint_644_ + slope_644_*rho_sfc_[DL2250];
1082  rho_sfc_[DL488] = yint_466_ + slope_466_*rho_sfc_[DL670];
1083 // Compute Mass Concentration
1084 // Continental only
1085  interp_extrap(NLTAU,aot_d_[DL550],
1086  opth_nl_[ISMALL][DL550],
1087  lut_.MASSCOEF_NL0[mtable_[ISMALL]][DL550],yout);
1088  masscon_ = yout*aot_d_[DL550];
1089 
1090  return status;
1091 }
1092 
1093 /**************************************************************************
1094  * NAME: simulate_toa()
1095  *
1096  * DESCRIPTION: This subroutine simulates TOA reflectance
1097  *
1098  *************************************************************************/
1099 
1101 {
1102  int status = DTDB_SUCCESS;
1103 
1104 // At each tau index, calculate surface reflectance at 2.1 and
1105 // apparent reflectance at all wavelengths
1106  for ( int iSize=0; iSize<NLSIZE; iSize++ ) {
1107  for ( int iTau=0; iTau<NLTAU; iTau++ ) {
1108  rho_S212_[iSize][iTau] =
1109  (int_nl_[iSize][DL2250][iTau]-rfld_[D2250]) /
1110  (sbar_nl_[iSize][DL2250][iTau] *
1111  (int_nl_[iSize][DL2250][iTau]-rfld_[D2250]) -
1112  fdt_nl_[iSize][DL2250][iTau]);
1113  if (rho_S212_[iSize][iTau] > 1.0) {
1114  rho_S212_[iSize][iTau] = DFILL_FLOAT;
1115  }
1116 // Estimate surface reflectance
1117 // Use Red/IR and Blue/Red surface correlations
1118 // For simple ratios, overwrite (or comment out all lines above)
1119 // Current VIIRS slope_466 = ratio of M3(.48) / M5(0.67)
1120 // slope_644 =ratio of M5(0.67) / M11 (2.25)
1121  const float slpc = 1.0;
1122  slope_644_ = 0.559*slpc;
1123  yint_644_ = 0.0;
1124  slope_466_ = 0.645/slpc;
1125  yint_466_ = 0.0;
1126  rho_S644_ = slope_644_*rho_S212_[iSize][iTau] + yint_644_;
1127  rho_S466_ = slope_466_*rho_S644_ + yint_466_;
1128 // Compute model differentiated apparent reflectance
1129  rho_star_[iSize][DL488][iTau] =
1130  int_nl_[iSize][DL488][iTau] +
1131  fdt_nl_[iSize][DL488][iTau] * rho_S466_ /
1132  (1 - sbar_nl_[iSize][DL488][iTau] * rho_S466_);
1133 
1134  rho_star_[iSize][DL550][iTau] = 0.0;
1135  rho_star_[iSize][DL670][iTau] =
1136  int_nl_[iSize][DL670][iTau] +
1137  fdt_nl_[iSize][DL670][iTau] * rho_S644_ /
1138  (1 - sbar_nl_[iSize][DL670][iTau] * rho_S644_);
1139 
1140  rho_star_[iSize][DL2250][iTau] =
1141  int_nl_[iSize][DL2250][iTau] +
1142  fdt_nl_[iSize][DL2250][iTau] *
1143  rho_S212_[iSize][iTau] /
1144  (1 - sbar_nl_[iSize][DL2250][iTau] * rho_S212_[iSize][iTau]);
1145  }
1146  }
1147 
1148  return status;
1149 }
1150 
1151 /**************************************************************************
1152  * NAME: assign_quality()
1153  *
1154  * DESCRIPTION: This subroutine assigns quality variable to be
1155  * written to output file.
1156  *
1157  *************************************************************************/
1158 
1160 {
1161  int status = DTDB_SUCCESS;
1162 
1163  short quality_land = 0;
1164  short qa_flag[19];
1165  memset( qa_flag, 0, sizeof(qa_flag));
1166 
1167  quality_flag_for_joint_[0] = 0;
1168  quality_flag_for_joint_[1] = 0;
1169  if (aot_d_[DL550] < -0.10) {
1170  error_= 5;
1171  }
1172  if (aot_d_[DL550] > 5.00) {
1173  error_= 6;
1174  }
1175  if (iproc_== 0) {
1176  error_= 4;
1177  }
1178  if (error_ > 0) {
1179  quality_flag_for_retr_ = 11;
1180  fail_ret_+= 1;
1181  qa_flag[6] = 0;
1182  qa_flag[7] = 0;
1183  qa_flag[8] = 0;
1184  qa_flag[9] = 0;
1185 // set it to 12 to indicate No retrievals
1186  qa_flag[10] = quality_flag_for_retr_;
1187  qa_flag[11] = error_;
1188  qa_flag[14] = 0;
1189  qcontrol_special_ = 0;
1190  quality_flag_for_joint_[0] = qa_flag[7];
1191 // adding 10 to set Non ret. flag so that can tell them apart from Ret. Flag
1192  quality_flag_for_joint_[1] = error_+20;
1193 // fill values
1194  fill_values();
1195  }
1196  else if (error_== 0) {
1197 // Intilize the quality_flag_for_retr =0 to indicate good quality
1198  quality_flag_for_retr_ = 0;
1199 // Store SDS arrays for population to HDF file
1200  success_ret_ += 1;
1201  qa_flag[6] = 1;
1202  qa_flag[7] = 3;
1203 // quality_land ==0 is if there is one single pixel of water
1204  if (quality_land == 0){
1205  qa_flag[7] = 0;
1206  quality_flag_for_retr_ = 2;
1207  }
1208 // If Fitting error is greater than = 0.25 quality is bad
1209  if (err644_> 0.25) {
1210  qa_flag[7] = 0;
1211  quality_flag_for_retr_ = 4;
1212  }
1213 // Set Mass concentration & Fine optical depth to zero if tau is -ve.
1214  if (aot_d_[DL550] < 0.0) {
1215  qcontrol_special_ = 2;
1216  quality_flag_for_retr_ = 5;
1217  }
1218 // If optical depth negative then set angs_coeff_land to fill value
1219 // do not set the flag to zero
1220  if (!((angstrom_> -1.00) && (angstrom_<= 5.0))) {
1221  qa_flag[7] = 0;
1222  quality_flag_for_retr_ = 9;
1223  }
1224 
1225  float number_pixels = 1;
1226  int num_Q_pixel1 = (int)(number_pixels *.03);
1227  int num_Q_pixel2 = (int)(number_pixels *.05);
1228  int num_Q_pixel3 = (int)(number_pixels *.08);
1229  int num_Q_pixel4 = (int)(number_pixels *.12);
1230 // set quality for the number of pixels
1231 // 10%
1232 // if( num_pixels_used_ >= 12 && num_pixels_used_ <=20){
1233  if((num_pixels_used_ > num_Q_pixel1) && (num_pixels_used_ <= num_Q_pixel2)) {
1234  qa_flag[7]=0;
1235  quality_flag_for_retr_=6;
1236  }
1237 // 10-15%
1238 // if( num_pixels_used_ >= 21 && num_pixels_used_ <=30) {
1239  if((num_pixels_used_ > num_Q_pixel2) && (num_pixels_used_ <= num_Q_pixel3)) {
1240  qa_flag[7]=1;
1241  quality_flag_for_retr_=7;
1242  }
1243 // 15-25%
1244 // if( num_pixels_used_ >=31 && num_pixels_used_ <=50){
1245  if((num_pixels_used_ > num_Q_pixel3) &&
1246  (num_pixels_used_ <= num_Q_pixel4)) {
1247  qa_flag[7]=2;
1248  quality_flag_for_retr_=8;
1249  }
1250 // Above 25%
1251 // if( num_pixels_used_ >=51)qa_flag[8]=3
1252  if( num_pixels_used_ > num_Q_pixel4) {
1253  qa_flag[7]=3;
1254  }
1255  if (return_quality_cirrus_ == 0){
1256  quality_flag_for_retr_=3;
1257  qa_flag[7]=0;
1258  }
1259 
1260 //If Procedure is 2 set quality to report optical depths at 0.47 & 55 only
1261  if (iproc_>1) {
1262  qcontrol_special_ = 1;
1263  quality_flag_for_retr_ = 1;
1264 // If Procedure is 2 Quality is zero
1265  qa_flag[7] = 0;
1266  }
1267 // set quality flag 9 & 10 so that Level 3 uses the qulity flag to average
1268  qa_flag[8] = qa_flag[6];
1269  qa_flag[9] = qa_flag[7];
1270 // report eta only when optical depth is < 0.2
1271  if (aot_d_[DL550] < 0.2) {
1272  quality_flag_for_retr_ = 10;
1273 // sds_dust_weighting_ = DFILL_FLOAT;
1274  }
1275  qa_flag[10] = quality_flag_for_retr_;
1276  qa_flag[9] = error_;
1277  quality_flag_for_joint_[0] = qa_flag[7];
1278  quality_flag_for_joint_[1] = quality_flag_for_retr_;
1279 
1280 // Store QA flags into Quality_Assurance_Land array according to the order
1281 // of bits in MODIS atmosphere QA plan
1282  short qa_temp = 0;
1283  set_byte(qa_flag[6], 0, qa_temp);
1284  set_byte(qa_flag[7], 1, qa_temp);
1285  set_byte(qa_flag[8], 4, qa_temp);
1286  set_byte(qa_flag[9], 5, qa_temp);
1287  sds_qcontrol_[0] = qa_temp;
1288  qa_temp=0;
1289  qa_flag[12] = 0;
1290  qa_flag[13] = 0;
1291  set_byte(qa_flag[10], 0, qa_temp);
1292  set_byte(qa_flag[11], 4, qa_temp);
1293  sds_qcontrol_[1] = qa_temp;
1294  qa_temp = 0;
1295  qa_flag[16] = 3;
1296  qa_flag[17] = 3;
1297  set_byte(qa_flag[14], 0, qa_temp);
1298  set_byte(qa_flag[15], 2, qa_temp);
1299  set_byte(qa_flag[16], 4, qa_temp);
1300  set_byte(qa_flag[17], 6, qa_temp);
1301  sds_qcontrol_[2] = qa_temp;
1302  qa_temp=0;
1303  qa_flag[18] = 1;
1304  set_byte(qa_flag[18], 0, qa_temp);
1305  sds_qcontrol_[3] = qa_temp;
1306  sds_qcontrol_[4] = 0;
1307  // Re-initialized working variables
1308  for (int i=0; i<19; i++) {
1309  qa_flag[i]=0;
1310  }
1311  }
1312 
1313  return status;
1314 }
1315 
1316 
1317 /**************************************************************************
1318  * NAME: store_output()
1319  *
1320  * DESCRIPTION: This subroutine stores all the output variables to be
1321  * written to output file.
1322  *
1323  *************************************************************************/
1324 
1326 {
1327  int status = DTDB_SUCCESS;
1328 
1329  // Set Mass concentration & Fine optical depth to zero if tau is -ve.
1330  if (aot_d_[DL550] < 0.0) {
1331  masscon_= 0.0;
1332  for (int iWav=0; iWav<NLWAV; iWav++) {
1333  aot_f_[iWav] = 0.00;
1334  aot_c_[iWav] = 0.00;
1335  }
1336  }
1337 // If -0.10 <= aot <= -0.05 then set aot_d_[all waves] = -0.05 and Quality = zero
1338  if ((aot_d_[DL550] >= -0.10) && (aot_d_[DL550] <= -0.05)) {
1339  if (iproc_ > 1) {
1340  aot_d_[DL550] = -0.05;
1341  aot_d_[DL488] = -0.05;
1342  }
1343  else {
1344 // Set aot to -0.05, aotFine to 0.00
1345  for (int iWav=0; iWav<NLWAV; iWav++) {
1346  aot_d_[iWav] = -0.05;
1347  }
1348  }
1349  }
1350 // If optical depth negative then set angs_coeff_land to fill value
1351 // do not set the flag to zero
1352  if(qcontrol_special_ == 2){
1353  sds_angs_coeff_ = DFILL_FLOAT;
1354  }
1355  else {
1356  if ((angstrom_> -1.00) && (angstrom_<= 5.0)) {
1357  sds_angs_coeff_ = angstrom_;
1358  }
1359  else {
1360  sds_angs_coeff_ = DFILL_FLOAT;
1361  }
1362  }
1363  if (iaer_ >= 0) {
1364  sds_aerosol_type_ = iaer_;
1365  }
1366  if ((scatter_angle_ >= -180) && (scatter_angle_ <= 180)) {
1367  sds_scat_angle_ = scatter_angle_;
1368  }
1369  float aotmax = 5.0;
1370  if ((aot_d_[DL488] >= -0.1) && (aot_d_[DL488] <= aotmax)) {
1371  sds_tau_corrected_[DL488] = aot_d_[DL488];
1372  }
1373  if ((aot_d_[DL550] >= -0.1) && (aot_d_[DL550] <= aotmax)) {
1374  sds_tau_corrected_[DL550] = aot_d_[DL550];
1375  }
1376  if ((aot_d_[DL670] >= -0.1) && (aot_d_[DL670] <= aotmax)) {
1377  sds_tau_corrected_[DL670] = aot_d_[DL670];
1378  }
1379  if ((aot_d_[DL2250] >= -0.1) && (aot_d_[DL2250] <= aotmax)) {
1380  sds_tau_corrected_[DL2250] = aot_d_[DL2250];
1381  }
1382  sds_tau_small_[DL488] = aot_f_[DL488];
1383  sds_tau_small_[DL550] = aot_f_[DL550];
1384  sds_tau_small_[DL670] = aot_f_[DL670];
1385  sds_tau_small_[DL2250] = aot_f_[DL2250];
1386  sds_tau_big_[DL488] = aot_c_[DL488];
1387  sds_tau_big_[DL550] = aot_c_[DL550];
1388  sds_tau_big_[DL670] = aot_c_[DL670];
1389  sds_tau_big_[DL2250] = aot_c_[DL2250];
1390  sds_fitting_error_ = err644_;
1391  if (cloud_fraction_ >= 0) {
1392  sds_cloud_fraction_ = cloud_fraction_;
1393  }
1394  if (eta_ >= 0) {
1395  sds_dust_weighting_ = eta_;
1396  }
1397  for (int iWav=0; iWav<NLWAV; iWav++) {
1398  if (good_pixels_[iWav] >= 0) {
1399  sds_numpixels_[iWav] = good_pixels_[iWav];
1400  }
1401  }
1402  if (masscon_ >= 0) {
1403  sds_mass_conc_ = masscon_;
1404  }
1405  if (ndvi_ >= -1.0 && ndvi_ <= 1.0) {
1406  sds_ndvi_ = ndvi_;
1407  }
1408  if ((rfld_[D488] >= 0.0) && (rfld_[D488] <= 1.2)) {
1409  sds_refl_[DL488] = rfld_[D488];
1410  sds_refl_std_[DL488] = sdev_[DL488];
1411  sds_surface_reflectance_[DL488] = rho_sfc_[DL488];
1412  }
1413  if ((rfld_[D550] >= 0.0) && (rfld_[D550] <= 1.2)) {
1414  sds_refl_[DL550] = rfld_[D550];
1415  sds_refl_std_[DL550] = sdev_[DL550];
1416  }
1417  if ((rfld_[D670] >= 0.0) && (rfld_[D670] <= 1.2)) {
1418  sds_refl_[DL670] = rfld_[D670];
1419  sds_refl_std_[DL670] = sdev_[DL670];
1420  sds_surface_reflectance_[DL670] = rho_sfc_[DL670];
1421  }
1422  if ((rfld_[D865] >= 0.0) && (rfld_[D865] <= 1.2)) {
1423  sds_refl_[D865] = rfld_[D865];
1424  sds_refl_std_[D865] = sdev_[D865];
1425  }
1426  if ((rfld_[D1240] >= 0.0) && (rfld_[D1240] <= 1.2)) {
1427  sds_refl_[D1240] = rfld_[D1240];
1428  sds_refl_std_[D1240] = sdev_[D1240];
1429  }
1430  if ((rfld_[D1610] >= 0.0) && (rfld_[D1610] <= 1.2)) {
1431  sds_refl_[D1610] = rfld_[D1610];
1432  sds_refl_std_[D1610] = sdev_[D1610];
1433  }
1434  if ((rfld_[D2250] >= 0.0) && (rfld_[D2250] <= 1.2)) {
1435  sds_refl_[DL2250] = rfld_[D2250];
1436  sds_refl_std_[DL2250] = sdev_[DL2250];
1437  sds_surface_reflectance_[DL2250] = rho_sfc_[DL2250];
1438  }
1439 
1440  iaer_=DFILL_SHORT;
1441  iproc_=DFILL_SHORT;
1442  error_=DFILL_SHORT;
1443  eta_ = DFILL_FLOAT;
1444  err644_ = DFILL_FLOAT;
1445  masscon_ = DFILL_FLOAT;
1446  angstrom_ = DFILL_FLOAT;
1447  ndvi_ = DFILL_FLOAT;
1448  for (int iWav=0; iWav<NLWAV; iWav++) {
1449  aot_d_[iWav] = DFILL_FLOAT;
1450  aot_f_[iWav] = DFILL_FLOAT;
1451  aot_c_[iWav] = DFILL_FLOAT;
1452  rho_sfc_[iWav] = DFILL_FLOAT;
1453  }
1454  for (int iWav=0; iWav<NLWAV; iWav++) {
1455  rfld_[iWav] = DFILL_FLOAT;
1456  sdev_[iWav] = DFILL_FLOAT;
1457  }
1458 
1459  return status;
1460 }
1461 
1469 {
1470  int status = DTDB_SUCCESS;
1471 
1472  sds_aerosol_type_=8;
1473  sds_scat_angle_= DFILL_FLOAT;
1474  sds_cloud_fraction_= cloud_fraction_;
1475  sds_dust_weighting_ = DFILL_FLOAT;
1476  sds_fitting_error_= DFILL_FLOAT;
1477  sds_mass_conc_ = DFILL_FLOAT;
1478  sds_angs_coeff_ = DFILL_FLOAT;
1479  for (int iWav=0; iWav<NLWAV; iWav++) {
1480  sds_tau_corrected_[iWav]= DFILL_FLOAT;
1481  sds_tau_small_[iWav]= DFILL_FLOAT;
1482  sds_tau_big_[iWav]= DFILL_FLOAT;
1483  sds_surface_reflectance_[iWav] = DFILL_FLOAT;
1484  sds_numpixels_[iWav]=DFILL_SHORT;
1485  sds_refl_[iWav] = DFILL_FLOAT;
1486  sds_refl_std_[iWav] = DFILL_FLOAT;
1487  }
1488 
1489  return status;
1490 }
1491 
1492 
1493 
1494 
1495 
@ D412
Definition: DtAlgorithm.h:24
void interp(double *ephemPtr, int startLoc, double *inTime, int numCoefs, int numCom, int numSets, int velFlag, double *posvel)
int store_output()
Definition: DtAlgLand.cpp:1325
int compute_average(size_t iy, size_t ix)
Definition: DtAlgLand.cpp:512
int retrieve_first()
Definition: DtAlgLand.cpp:887
data_t t[NROOTS+1]
Definition: decode_rs.h:77
@ D865
Definition: DtAlgorithm.h:20
int index_geometry(float sza, float azim, float phi)
Definition: DtAlgLand.cpp:475
int j
Definition: decode_rs.h:73
int status
Definition: l1_czcs_hdf.c:32
constexpr unsigned char DFILL_UBYTE
Definition: DDataset.hpp:28
@ D2250
Definition: DtAlgorithm.h:23
int fill_values()
Definition: DtAlgLand.cpp:1468
int IBIG
Definition: dtland.py:33
@ BOWTIEDEL
float PRESSURE_P0
Definition: dtland.py:45
int ISMALL
Definition: dtland.py:32
int interpolate_angle()
Definition: DtAlgLand.cpp:696
@ D550
Definition: DtAlgorithm.h:18
@ DL670
Definition: DtAlgorithm.h:33
@ D670
Definition: DtAlgorithm.h:19
int retrieve_second()
Definition: DtAlgLand.cpp:1027
int assign_quality()
Definition: DtAlgLand.cpp:1159
int read_land_aerosol_lut(dtLandAerosolLUT &la_lut)
@ DL2250
Definition: DtAlgorithm.h:34
@ D488
Definition: DtAlgorithm.h:17
int interpolate_rayleigh()
Definition: DtAlgLand.cpp:649
constexpr float DFILL_FLOAT
Definition: DDataset.hpp:25
subroutine pressure(uw, uo3, xps)
Definition: 6sm1.f:6248
an array had not been initialized Several spelling and grammar corrections were which is read from the appropriate MCF the above metadata values were hard coded A problem calculating the average background DN for SWIR bands when the moon is in the space view port was corrected The new algorithm used to calculate the average background DN for all reflective bands when the moon is in the space view port is now the same as the algorithm employed by the thermal bands For non SWIR changes in the averages are typically less than Also for non SWIR the black body DNs remain a backup in case the SV DNs are not available For SWIR the changes in computed averages were larger because the old which used the black body suffered from contamination by the micron leak As a consequence of the if SV DNs are not available for the SWIR the EV pixels will not be the granule time is used to identify the appropriate tables within the set given for one LUT the first two or last two tables respectively will be used for the interpolation If there is only one LUT in the set of it will be treated as a constant LUT The manner in which Earth View data is checked for saturation was changed Previously the raw Earth View DNs and Space View DNs were checked against the lookup table values contained in the table dn_sat The change made is to check the raw Earth and Space View DNs to be sure they are less than the maximum saturation value and to check the Space View subtracted Earth View dns against a set of values contained in the new lookup table dn_sat_ev The metadata configuration and ASSOCIATEDINSTRUMENTSHORTNAME from the MOD02HKM product The same metatdata with extensions and were removed from the MOD021KM and MOD02OBC products ASSOCIATEDSENSORSHORTNAME was set to MODIS in all products These changes are reflected in new File Specification which users may consult for exact the pow functions were eliminated in Emissive_Cal and Emissive bands replaced by more efficient code Other calculations throughout the code were also made more efficient Aside from a few round off there was no difference to the product The CPU time decreased by about for a day case and for a night case A minor bug in calculating the uncertainty index for emissive bands was corrected The frame the required RAM for each execution is MB on the DEC ALPHA and MB on the SGI Octane v2
Definition: HISTORY.txt:728
data_t u
Definition: decode_rs.h:74
#define fabs(a)
Definition: misc.h:93
@ D1610
Definition: DtAlgorithm.h:22
int initialize(map< string, ddata * > imap)
Definition: DtAlgLand.cpp:310
def set_outputs(output_keys)
Definition: utils.py:164
@ DL488
Definition: DtAlgorithm.h:31
int simulate_toa()
Definition: DtAlgLand.cpp:1100
@ D1240
Definition: DtAlgorithm.h:21
int i
Definition: decode_rs.h:71
virtual int initialize(map< string, ddata * > imap)
Definition: DtAlgorithm.cpp:76
map< string, ddata * > process(vector< size_t > start, vector< size_t > count, map< string, ddata * > imap)
Definition: DtAlgLand.cpp:332
constexpr short DFILL_SHORT
Definition: DDataset.hpp:27
int compute_cloudmask_ndvi(size_t iy, size_t ix, int &iCldRed, int &iCldBlue)
Definition: DtAlgLand.cpp:606
int interpolate_elevation()
Definition: DtAlgLand.cpp:758
@ DL550
Definition: DtAlgorithm.h:32
int count
Definition: decode_rs.h:79