NASA Logo
Ocean Color Science Software

ocssw V2022
aerosol.c
Go to the documentation of this file.
1 /* ======================================================================================== */
2 /* module aerosol.c - functions to facilitate aerosol model selection and application */
3 /* */
4 /* Description: */
5 /* */
6 /* This code replaces the original set of fortran subroutines developed by M.Wang, H.Gordon,*/
7 /* and others (e.g., rho_a_sub_quad, linear_abc, funct_eps, load_aer, load_ss11) as well as */
8 /* the original get_aerosol() developed for MSl12. */
9 /* */
10 /* The functions herein read and interpolate the aerosol model tables, which are now stored */
11 /* as individual HDF files per model. Whfere sensor wavelengths differ from tabulated model */
12 /* wavelengths, interpolation is performed. Efficiencies are gained by remembering and */
13 /* reusing computational results when applicable. */
14 /* */
15 /* Primary Function: */
16 /* ---------------- */
17 /* aerosol() - compute aerosol reflectance using specified algorithm (main interface) */
18 /* */
19 /* Secondary Functions: */
20 /* ------------------- */
21 /* wangaer() - compute aerosol reflectance using Gordon & Wang 1994 algorithm */
22 /* fixedaot() - compute aerosol reflectance for fixed aot(lambda) */
23 /* fixedaer() - compute aerosol reflectance for fixed aerosol model */
24 /* get_angstrom() - compute angstrom coefficient (interface to l2_hdf_generic) */
25 /* diff_tran() - compute Rayleigh-aerosol diffuse trans for selected model pair, both paths */
26 /* */
27 /* Supporting Functions: */
28 /* -------------------- */
29 /* load_aermod() - loads the entire aerosol model table for the specified model list */
30 /* ss_to_ms_coef() - for one model, return coefficients of function relating single */
31 /* scattering to multiple scattering at the input geometry. */
32 /* rhoas_to_rhoa() - SS aerosol reflectance to MS aerosol reflectance */
33 /* rhoa_to_rhoas() - MS aerosol reflectance to SS aerosol reflectance */
34 /* model_select_wang() - M. Wang aerosol model selection process . */
35 /* model_select_angst() - Select model pair based on input Angstrom coefficient */
36 /* model_phase() - return phase function at model wavelengths at the input geometry. */
37 /* model_epsilon() - return model epsilon at input wavelengths for input geometry. */
38 /* model_transmittance() - compute path Rayleigh-aerosol diffuse trans for specified model */
39 /* model_taua() - compute AOT at input wavelengths using specified model */
40 /* aeroob - out-of-band water-vapor correction */
41 /* */
42 /* */
43 /* Written By: B. Franz, SAIC, NASA/GSFC Ocean Biology Processing Group, Summer 2004. */
44 /* W. Robinson, SAIC, 24 MAr 2017, modularized and enhanced for band-dependent */
45 /* geometry */
46 /* */
47 /* ======================================================================================== */
48 
49 #include <float.h>
50 
51 #include "l12_proto.h"
52 
53 #include <allocate2d.h>
54 #include <allocate3d.h>
55 #include <allocate5d.h>
56 
57 #define MAXMODEL MAXAERMOD
58 //#define MAXSOLZ 33
59 //#define MAXSENZ 35
60 //#define MAXPHI 19
61 //#define MAXSCATT 75
62 //#define DTNTHETA 33
63 
64 static int32_t first_solz;
65 static int32_t first_senz;
66 static int32_t first_phi;
67 static int32_t first_scatt;
68 static int32_t first_dtnwave;
69 static int32_t first_dtntheta;
70 static int32_t first_npc;
71 static int32_t first_ntau_870;
72 
73 static float pi = PI;
74 static double radeg = RADEG;
75 static float p0 = STDPR;
76 
77 static int have_ms = 0;
78 static int have_rh = 0;
79 static int have_sd = 0;
80 static int use_rh = 0;
81 static int use_netcdf = 0;
82 static int use_pca_lut = 0;
83 
84 static int32_t Nbands;
85 static int32_t Maxband; /* must be >= NBANDS */
86 
87 float *noise_global;
88 
89 typedef struct aermod_struct {
90  char name[32];
91  float rh;
92  int sd;
93 
94  /* angstrom exponent (nbands+1)*/
95  float *angstrom;
96 
97  /* single-scattering albedo(nbands+1), extinction coefficient(nbands+1), phase function */
98  float *albedo;
99  float *extc;
100  float **phase;
101 
102  /* quadratic coefficients for SS to MS relationship */
103  float *acost;
104  float *bcost;
105  float *ccost;
106 
107  /* cubic coefficients for ms_epsilon atmospheric correction ..ZA */
108  float *ams_all;
109  float *bms_all;
110  float *cms_all;
111  float *dms_all;
112  float *ems_all;
113 
114 
115  /* Rayleigh-aerosol diffuse transmittance coeffs */
116  float **dtran_a;
117  float **dtran_b;
118 
119  /* derived quantities */
120  float **lnphase;
121  float **d2phase;
122 
123  /* PCA table variables */
124  float *****pc_rhoa; // pc_rhoa(tau_870, solz, phi, senz, pc)
125  float **pc_components_rhoa; // pc_components_rhoa(pc, wave)
126  float *pc_mean_rhoa; // pc_mean_rhoa(wave)
127  float ***pc_td; // pc_td(tau_870, solz, pc)
128  float **pc_components_td; // pc_components_td(pc, wave)
129  float *pc_mean_td; // pc_mean_td(wave)
130  float *tau_870; // tau_870(tau_870)
131  float *pc; // pc(pc)
132 
133 } aermodstr;
134 
135 // sorting in ascending way elements of chi-squared -- will need clean-up
136 struct str { float value;int index;};
137 
138 static int cmp(const void *a,const void *b) {
139  struct str *a1 = (struct str *)a;
140  struct str *a2 = (struct str*)b;
141  if((*a1).value<(*a2).value)return -1;
142  else if((*a1).value>(*a2).value)return 1;
143  else return 0;
144 }
145 
146 aermodstr* alloc_aermodstr(int nbands, int nscatt, int nphi, int nsolz, int nsenz, int ntheta, int npc, int ntau_870) {
147  aermodstr *model;
148 
149  // make sure model starts out all zeros/null
150  model = (aermodstr *) calloc(1, sizeof(aermodstr));
151  model->angstrom = (float*) malloc(nbands * sizeof (float));
152  model->extc = (float*) malloc(nbands * sizeof (float));
153  if(use_pca_lut) {
154  // pc_rhoa(tau_870, solz, phi, senz, pc)
155  model->pc_rhoa = allocate5d_float(ntau_870, nsolz, nphi, nsenz, npc);
156 
157  // pc_components_rhoa(pc, wave)
158  model->pc_components_rhoa = allocate2d_float(npc, nbands);
159 
160  // pc_mean_rhoa(wave)
161  model->pc_mean_rhoa = (float*) malloc(nbands * sizeof(float));
162 
163  // pc_td(tau_870, solz, pc)
164  model->pc_td = allocate3d_float(ntau_870,nsenz , npc);//nsolz
165 
166  // pc_components_td(pc, wave)
167  model->pc_components_td = allocate2d_float(npc, nbands);
168 
169  // pc_mean_td(wave)
170  model->pc_mean_td = (float*) malloc(nbands * sizeof(float));
171 
172  // tau_870(tau_870)
173  model->tau_870 = (float*) malloc(ntau_870 * sizeof(float));
174 
175  // pc(pc)
176  model->pc = (float*) malloc(npc * sizeof(float));
177  } else {
178  if(nscatt > 0) {
179  model->albedo = (float*) malloc(nbands * sizeof (float));
180  model->phase = allocate2d_float(nbands, nscatt);
181  model->lnphase = allocate2d_float(nbands, nscatt);
182  model->d2phase = allocate2d_float(nbands, nscatt);
183  model->acost = (float*) malloc(nbands * nsolz * nphi * nsenz * sizeof (float));
184  model->bcost = (float*) malloc(nbands * nsolz * nphi * nsenz * sizeof (float));
185  model->ccost = (float*) malloc(nbands * nsolz * nphi * nsenz * sizeof (float));
186  }
187  model->dtran_a = allocate2d_float(nbands, ntheta);
188  model->dtran_b = allocate2d_float(nbands, ntheta);
189  model->ams_all = (float*) malloc(nbands * nsolz * nphi * nsenz * sizeof (float));
190  model->bms_all = (float*) malloc(nbands * nsolz * nphi * nsenz * sizeof (float));
191  model->cms_all = (float*) malloc(nbands * nsolz * nphi * nsenz * sizeof (float));
192  model->dms_all = (float*) malloc(nbands * nsolz * nphi * nsenz * sizeof (float));
193  model->ems_all = (float*) malloc(nbands * nsolz * nphi * nsenz * sizeof (float));
194  }
195  return model;
196 }
197 
198 typedef struct aermodtab_struct {
199  int32_t sensorID;
200 
201  /* table dimensions */
202  int32_t nwave;
203  int32_t nmodel;
204  int32_t nsolz;
205  int32_t nsenz;
206  int32_t nphi;
207  int32_t nscatt;
208  int32_t dtran_nwave;
209  int32_t dtran_ntheta;
210  int32_t npc;
211  int32_t ntau_870;
212 
213  /* table spectral bands and angles */
214  float *wave;
215  float *solz;
216  float *senz;
217  float *phi;
218  float *scatt;
219 
220  /* diffuse transmittance spectral bands and angles */
221  float *dtran_wave;
222  float *dtran_theta;
224 
225  aermodstr **model;
226 
227 } aermodtabstr;
228 
229 typedef struct alphaT_struct {
230  int32_t modnum;
231  float angstrom;
232 } alphaTstr;
233 
234 typedef struct epsilonT_struct {
235  int32_t modnum;
236  float eps_obs;
237 } epsilonTstr;
238 
239 /* aerosol table */
240 static aermodtabstr *aertab = NULL;
241 
242 /* structure for carrying the geometry information */
243 typedef struct geom_strdef {
244  int gmult; /* band offset multiplier: 0 for nominal geometry
245  1 for band-dependent geometry */
246  float *senz;
247  float *solz;
248  float *phi;
249  float *csolz; /* cosine of solz */
250  float *csenz; /* cosine of senz */
251  float *airmass;
252  float *airmass_plp;
253  float *airmass_sph;
254 } geom_str;
255 
256 geom_str geom;
257 
258 /* global variable declarations */
259 static int loaded = 0;
260 static int interpol = 0;
261 static int32_t *iwatab;
262 static int32_t *iwdtab;
263 
264 static int32_t iwnir_s = -1;
265 static int32_t iwnir_l = -1;
266 
267 static float mu0;
268 static float mu;
269 static float airmass;
270 
271 static int32_t evalmask = 0;
272 static int32_t aer_opt = 0;
273 static float airmass_plp;
274 static float airmass_sph;
275 
276 int cmpfunc(const void * a, const void * b) {
277  if (*(double*) a > *(double*) b) return 1;
278  else if (*(double*) a < *(double*) b) return -1;
279  else return 0;
280 }
281 
282 
283 
284 /* ---------------------------------------------------------------------------------------- */
285 /* first_deriv() - returns first derivative (dy/dx) of 1st or last array indices using a */
286 /* 4-pt Lagrangian interpolation. NOTE: It is assumed that 4 points exist. */
287 
288 /* ---------------------------------------------------------------------------------------- */
289 float first_deriv(float x[], float y[], int n) {
290  float a1, a2, a3, a4, a5, a6, d1;
291 
292  if (n == 0) {
293 
294  a1 = x[0] - x[1];
295  a2 = x[0] - x[2];
296  a3 = x[0] - x[3];
297  a4 = x[1] - x[2];
298  a5 = x[1] - x[3];
299  a6 = x[2] - x[3];
300 
301  d1 = y[0]*(1.0 / a1 + 1.0 / a2 + 1.0 / a3)
302  - a2 * a3 * y[1] / (a1 * a4 * a5)
303  + a1 * a3 * y[2] / (a2 * a4 * a6)
304  - a1 * a2 * y[3] / (a3 * a5 * a6);
305 
306  } else {
307 
308  a1 = x[n - 1] - x[n - 4];
309  a2 = x[n - 1] - x[n - 3];
310  a3 = x[n - 1] - x[n - 2];
311  a4 = x[n - 2] - x[n - 4];
312  a5 = x[n - 2] - x[n - 3];
313  a6 = x[n - 3] - x[n - 4];
314 
315  d1 = -a2 * a3 * y[n - 4] / (a6 * a4 * a1)
316  + a1 * a3 * y[n - 3] / (a6 * a5 * a2)
317  - a1 * a2 * y[n - 2] / (a4 * a5 * a3)
318  + y[n - 1]*(1.0 / a1 + 1.0 / a2 + 1.0 / a3);
319  }
320 
321  return (d1);
322 }
323 
324 
325 static void read_dimension_size(const char* file_name, int nc_id, const char* dim_name, int32_t *length) {
326  int dim_id;
327  size_t dim_length;
328  int status;
329 
330  status = nc_inq_dimid (nc_id, dim_name, &dim_id);
331  if (status != NC_NOERR) {
332  printf("-E- %s: Error looking for dimension %s from %s.\n", __FILE__, dim_name, file_name);
333  exit(1);
334  }
335  status = nc_inq_dimlen(nc_id, dim_id, &dim_length);
336  if (status != NC_NOERR) {
337  printf("-E- %s: Error reading dimension %s from %s.\n", __FILE__, dim_name, file_name);
338  exit(1);
339  }
340  *length = (int32_t) dim_length;
341 }
342 
343 
344 static void read_lut_variable(const char* file, int nc_id, const char* var_name, float* data) {
345  int var_id;
346  int status;
347 
348  status = nc_inq_varid(nc_id, var_name, &var_id);
349  if (status != NC_NOERR) {
350  printf("-E- %s: Error looking for variable %s from %s.\n", __FILE__, var_name, file);
351  exit(1);
352  }
353  status = nc_get_var_float(nc_id, var_id, data);
354  if (status != NC_NOERR) {
355  printf("-E- %s: Error reading variable %s from %s.\n", __FILE__, var_name, file);
356  exit(1);
357  }
358 }
359 
360 // static void read_lut_variable_short(const char* file, int nc_id, const char* var_name, short* data) {
361 // int var_id;
362 // int status;
363 
364 // status = nc_inq_varid(nc_id, var_name, &var_id);
365 // if (status != NC_NOERR) {
366 // printf("-E- %s: Error looking for variable %s from %s.\n", __FILE__, var_name, file);
367 // exit(1);
368 // }
369 // status = nc_get_var_short(nc_id, var_id, data);
370 // if (status != NC_NOERR) {
371 // printf("-E- %s: Error reading variable %s from %s.\n", __FILE__, var_name, file);
372 // exit(1);
373 // }
374 // }
375 
376 /* ---------------------------------------------------------------------------------------- */
377 /* load_aermod() - loads the entire aerosol model table for the specified model list */
378 
379 /* ---------------------------------------------------------------------------------------- */
380 int load_aermod(int32_t sensorID, float wave[], int32_t nwave, char *aermodfile, char models[MAXAERMOD][32], int32_t nmodels) {
381  int nc_id;
382  int status;
383 
384  int32_t aer_nwave, nsolz, nsenz, nphi, nscatt, dtran_nwave, dtran_ntheta, npc, ntau_870;
385 
386  float d1phase1;
387  float d1phaseN;
388  float rh;
389  int16_t sd;
390 
391  char file [FILENAME_MAX] = "";
392  char path [FILENAME_MAX] = "";
393 
394  int iw, im, is, iwbase, i;
395  static int firstCall = 1;
396 
397  if (firstCall == 1) {
398  if ((iwatab = (int32_t *) calloc(nwave, sizeof (int32_t))) == NULL) {
399  printf("Unable to allocate space for iwatab.\n");
400  exit(1);
401  }
402  if ((iwdtab = (int32_t *) calloc(nwave, sizeof (int32_t))) == NULL) {
403  printf("Unable to allocate space for iwdtab.\n");
404  exit(1);
405  }
406  firstCall = 0;
407  }
408 
409  printf("Loading aerosol models from %s\n", aermodfile);
410 
411  for (im = 0; im < nmodels + 1; im++) {
412 
413  if (im < nmodels) {
414 
415  // try netCDF first
416  strcpy(file, path);
417  strcat(file, aermodfile);
418  strcat(file, "_");
419  strcat(file, models[im]);
420  strcat(file, ".nc");
421  use_netcdf = 1;
422 
423  // if not try HDF4
424  if(access(file, R_OK) == -1) {
425  strcpy(file, path);
426  strcat(file, aermodfile);
427  strcat(file, "_");
428  strcat(file, models[im]);
429  strcat(file, ".hdf");
430  use_netcdf = 0;
431  }
432 
433  } else {
434 
435  // first try netCDF
436  strcpy(file, path);
437  strcat(file, aermodfile);
438  strcat(file, "_default.nc");
439  use_netcdf = 1;
440 
441  // if not try HDF4
442  if(access(file, R_OK) == -1) {
443  strcpy(file, path);
444  strcat(file, aermodfile);
445  strcat(file, "_default.hdf");
446  use_netcdf = 0;
447  }
448  }
449 
450  status = nc_open(file, NC_NOWRITE, &nc_id);
451  if (status != NC_NOERR) {
452  printf("-E- %s: Error opening file %s.\n", __FILE__, file);
453  exit(1);
454  }
455 
456  use_pca_lut = 0;
457  nscatt = 0;
458  dtran_nwave = 0;
459  dtran_ntheta = 0;
460  npc = 0;
461  ntau_870 = 0;
462 
463  /* read dimensions which should be constant between models */
464  if(use_netcdf) {
465  //see if it is a PCA LUT
466  size_t attlen;
467  status = nc_inq_attlen(nc_id, NC_GLOBAL, "title", &attlen);
468  if (status != NC_NOERR) {
469  printf("-E- %s: could not find title in %s.\n", __FILE__, file);
470  exit(1);
471  }
472  char* title = malloc(sizeof(char) * attlen);
473  nc_get_att_text(nc_id, NC_GLOBAL, "title", title);
474  if(strcasestr(title, "pca aerosol model data")) {
475  use_pca_lut = 1;
476  }
477  free(title);
478 
479  if(use_pca_lut) {
480  read_dimension_size(file, nc_id, "wavelength", &aer_nwave);
481  read_dimension_size(file, nc_id, "solar_zenith", &nsolz);
482  read_dimension_size(file, nc_id, "sensor_zenith", &nsenz);
483  read_dimension_size(file, nc_id, "relative_azimuth", &nphi);
484  read_dimension_size(file, nc_id, "principal_component", &npc);
485  read_dimension_size(file, nc_id, "aerosol_optical_thickness", &ntau_870);
486  } else {
487  read_dimension_size(file, nc_id, "nwave", &aer_nwave);
488  read_dimension_size(file, nc_id, "nsolz", &nsolz);
489  read_dimension_size(file, nc_id, "nsenz", &nsenz);
490  read_dimension_size(file, nc_id, "nphi", &nphi);
491  read_dimension_size(file, nc_id, "dtran_nwave", &dtran_nwave);
492  read_dimension_size(file, nc_id, "dtran_ntheta", &dtran_ntheta);
493  }
494  } else {
495  read_dimension_size(file, nc_id, "nwave", &aer_nwave);
496  read_dimension_size(file, nc_id, "nsolz", &nsolz);
497  read_dimension_size(file, nc_id, "nsenz", &nsenz);
498  read_dimension_size(file, nc_id, "nphi", &nphi);
499  read_dimension_size(file, nc_id, "nscatt", &nscatt);
500  read_dimension_size(file, nc_id, "dtran_nwave", &dtran_nwave);
501  read_dimension_size(file, nc_id, "dtran_ntheta", &dtran_ntheta);
502  }
503  // if(aer_nwave != nwave) {
504  // printf("-E- %s:%d - Error nwave dimension = %d not equal to nwave = %d in file = %s.\n",
505  // __FILE__, __LINE__, aer_nwave, nwave, file);
506  // exit(1);
507  // }
508 
509  if (im == 0) {
510  printf("Number of Wavelengths %d\n", aer_nwave);
511  printf("Number of Solar Zenith Angles %d\n", nsolz);
512  printf("Number of View Zenith Angles %d\n", nsenz);
513  printf("Number of Relative Azimuth Angles %d\n", nphi);
514  if(use_pca_lut) {
515  printf("Number of Principal Components %d\n", npc);
516  printf("Number of tau 870 Angles %d\n", ntau_870);
517  } else {
518  printf("Number of Scattering Angles %d\n", nscatt);
519  printf("Number of Diffuse Transmittance Wavelengths %d\n", dtran_nwave);
520  printf("Number of Diffuse Transmittance Zenith Angles %d\n", dtran_ntheta);
521  }
522 
523  first_solz = nsolz;
524  first_senz = nsenz;
525  first_phi = nphi;
526  first_scatt = nscatt;
527  first_dtnwave = dtran_nwave;
528  first_dtntheta = dtran_ntheta;
529  first_npc = npc;
530  first_ntau_870 = ntau_870;
531 
532  // allocate the aerosol table
533  if ((aertab = (aermodtabstr *) calloc(1, sizeof (aermodtabstr))) == NULL) {
534  printf("Unable to allocate space for aerosol table.\n");
535  exit(1);
536  }
537 
538  aertab->nmodel = nmodels;
539  aertab->nwave = aer_nwave;
540  aertab->nsolz = nsolz;
541  aertab->nsenz = nsenz;
542  aertab->nphi = nphi;
543  aertab->nscatt = nscatt;
544  aertab->dtran_nwave = dtran_nwave;
545  aertab->dtran_ntheta = dtran_ntheta;
546 
547  if(use_pca_lut){
548  aertab->npc = npc;
549  aertab->ntau_870 = ntau_870;
550  }
551 
552  aertab->wave = (float *) malloc(aer_nwave * sizeof (float));
553  aertab->solz = (float *) malloc(nsolz * sizeof (float));
554  aertab->senz = (float *) malloc(nsenz * sizeof (float));
555  aertab->phi = (float *) malloc(nphi * sizeof (float));
556  if(use_netcdf)
557  aertab->scatt = NULL;
558  else
559  aertab->scatt = (float *) malloc(nscatt * sizeof (float));
560 
561  if(!use_pca_lut) {
562  aertab->dtran_wave = (float *) malloc(dtran_nwave * sizeof (float));
563  aertab->dtran_theta = (float *) malloc(dtran_ntheta * sizeof (float));
564  aertab->dtran_airmass = (float *) malloc(dtran_ntheta * sizeof (float));
565  }
566 
567  // allocate the model tables
568  if ((aertab->model = (aermodstr **) calloc(1, (nmodels + 1) * sizeof (aermodstr*))) == NULL) {
569  printf("Unable to allocate space for %d aerosol models.\n", nmodels + 1);
570  exit(1);
571  }
572  for (i = 0; i < nmodels + 1; i++) {
573  if ((aertab->model[i] = alloc_aermodstr(aer_nwave, nscatt, nphi, nsolz, nsenz, dtran_ntheta, npc, ntau_870)) == NULL) {
574  printf("Unable to allocate space for aerosol model %d.\n", im);
575  exit(1);
576  }
577  }
578 
579  /* read SDSes which are constant between models */
580 
581  if(!use_netcdf)
582  read_lut_variable(file, nc_id, "scatt", aertab->scatt);
583  if(!use_netcdf){
584  read_lut_variable(file, nc_id, "wave", aertab->wave);
585  read_lut_variable(file, nc_id, "solz", aertab->solz);
586  read_lut_variable(file, nc_id, "senz", aertab->senz);
587  read_lut_variable(file, nc_id, "phi", aertab->phi);
588  }
589  else{
590  if(use_pca_lut){
591  read_lut_variable(file, nc_id, "wavelength", aertab->wave);
592  read_lut_variable(file, nc_id, "solar_zenith", aertab->solz);
593  read_lut_variable(file, nc_id, "sensor_zenith", aertab->senz);
594  read_lut_variable(file, nc_id, "relative_azimuth", aertab->phi);
595  }
596  else{
597  read_lut_variable(file, nc_id, "wave", aertab->wave);
598  read_lut_variable(file, nc_id, "solz", aertab->solz);
599  read_lut_variable(file, nc_id, "senz",aertab->senz);
600  read_lut_variable(file, nc_id, "phi", aertab->phi);
601  }
602  }
603  if(!use_pca_lut) {
604  read_lut_variable(file, nc_id, "dtran_wave", aertab->dtran_wave);
605  read_lut_variable(file, nc_id, "dtran_theta", aertab->dtran_theta);
606  }
607  } else {
608  /* check that all the aerosol files at least have the same
609  main dimensions */
610  if ((aertab->nsolz != first_solz) || (aertab->nsenz != first_senz) ||
611  (aertab->nphi != first_phi) || (aertab->nscatt != first_scatt) ||
612  (aertab->dtran_nwave != first_dtnwave) || (aertab->dtran_ntheta != first_dtntheta) ||
613  (use_pca_lut && aertab->ntau_870 != first_ntau_870) || (use_pca_lut && aertab->npc != first_npc)) {
614  printf("-E- %s, %d: Error, Aerosol table %s\n",
615  __FILE__, __LINE__, file);
616  printf(" has different dimensions from previous tables\n");
617  exit(1);
618  }
619  }
620 
621  if (im < nmodels)
622  strncpy(aertab->model[im]->name, models[im], 32);
623  else
624  strncpy(aertab->model[im]->name, "default", 32);
625 
626  status = nc_get_att_float(nc_id, NC_GLOBAL, "RelativeHumidity", &rh);
627  if(status != NC_NOERR) {
628  status = nc_get_att_float(nc_id, NC_GLOBAL, "Relative Humidity", &rh);
629  }
630  if(status != NC_NOERR) {
631  status = nc_get_att_float(nc_id, NC_GLOBAL, "relative_humidity", &rh);
632  }
633  if (status == NC_NOERR) {
634  if(use_pca_lut)
635  rh=rh*100;
636  aertab->model[im]->rh = rh;
637  have_rh = 1;
638  } else {
639  aertab->model[im]->rh = -1.0;
640  have_rh = 0;
641  }
642 
643  if(use_netcdf) {
644  float fmf;
645  status = nc_get_att_float(nc_id, NC_GLOBAL, "AerosolFMF", &fmf);
646  if(status != NC_NOERR) {
647  status = nc_get_att_float(nc_id, NC_GLOBAL, "fine_mode_fraction", &fmf);
648  if(status!=NC_NOERR){
649  printf("-E- %s, %d: Error, Aerosol table %s does not have AerosolFMF\n",
650  __FILE__, __LINE__, file);
651  exit(1);
652  }
653  }
654  sd = 100 - fmf*100;
655  aertab->model[im]->sd = sd;
656  } else {
657  status = nc_get_att_short(nc_id, NC_GLOBAL, "Size Distribution", &sd);
658  if (status == NC_NOERR) {
659  aertab->model[im]->sd = sd;
660  have_sd = 1;
661  } else {
662  aertab->model[im]->sd = -1;
663  have_sd = 0;
664  }
665  }
666 
667  if(!use_netcdf)
668  read_lut_variable(file, nc_id, "extc", aertab->model[im]->extc);
669  else{
670  if(use_pca_lut)
671  read_lut_variable(file, nc_id, "extinction_coefficient", aertab->model[im]->extc);
672  else
673  read_lut_variable(file, nc_id, "extc", aertab->model[im]->extc);
674  }
675 
676  if(use_pca_lut) {
677  read_lut_variable(file, nc_id, "aerosol_reflectance_score", aertab->model[im]->pc_rhoa[0][0][0][0]);
678  read_lut_variable(file, nc_id, "aerosol_reflectance_component", aertab->model[im]->pc_components_rhoa[0]);
679  read_lut_variable(file, nc_id, "aerosol_reflectance_mean", aertab->model[im]->pc_mean_rhoa);
680  read_lut_variable(file, nc_id, "diffuse_transmittance_score", aertab->model[im]->pc_td[0][0]);
681  read_lut_variable(file, nc_id, "diffuse_transmittance_component", aertab->model[im]->pc_components_td[0]);
682  read_lut_variable(file, nc_id, "diffuse_transmittance_mean", aertab->model[im]->pc_mean_td);
683  read_lut_variable(file, nc_id, "angstrom", aertab->model[im]->angstrom);
684  read_lut_variable(file, nc_id, "aerosol_optical_thickness", aertab->model[im]->tau_870);
685  } else {
686  if(!use_netcdf) {
687  read_lut_variable(file, nc_id, "albedo", aertab->model[im]->albedo);
688  read_lut_variable(file, nc_id, "phase", aertab->model[im]->phase[0]);
689  read_lut_variable(file, nc_id, "acost", aertab->model[im]->acost);
690  read_lut_variable(file, nc_id, "bcost", aertab->model[im]->bcost);
691  read_lut_variable(file, nc_id, "ccost", aertab->model[im]->ccost);
692  }
693 
694  // check for multi-scattering epsilon tables
695  if(nc_inq_varid(nc_id, "ams_all", &status) == NC_NOERR) {
696  have_ms = 1;
697  read_lut_variable(file, nc_id, "ams_all", aertab->model[im]->ams_all);
698  read_lut_variable(file, nc_id, "bms_all", aertab->model[im]->bms_all);
699  read_lut_variable(file, nc_id, "cms_all", aertab->model[im]->cms_all);
700  read_lut_variable(file, nc_id, "dms_all", aertab->model[im]->dms_all);
701  read_lut_variable(file, nc_id, "ems_all", aertab->model[im]->ems_all);
702  }
703 
704  read_lut_variable(file, nc_id, "dtran_a", aertab->model[im]->dtran_a[0]);
705  read_lut_variable(file, nc_id, "dtran_b", aertab->model[im]->dtran_b[0]);
706  }
707 
708  nc_close(nc_id);
709 
710  if(!use_pca_lut) {
711  /* compute angstrom exponent for each model wavelength relative to max wavelength */
712  iwbase = windex(865, aertab->wave, aertab->nwave);
713  for (iw = 0; iw < aertab->nwave; iw++) {
714  if (iw != iwbase)
715  aertab->model[im]->angstrom[iw] = -log(aertab->model[im]->extc[iw] / aertab->model[im]->extc[iwbase]) /
716  log(aertab->wave[iw] / aertab->wave[iwbase]);
717  }
718  aertab->model[im]->angstrom[iwbase] = aertab->model[im]->angstrom[iwbase - 1];
719 
720  /* precompute log of phase function and 2nd derivative (for cubic interp) */
721  if(aertab->scatt) {
722  for (iw = 0; iw < aertab->nwave; iw++) {
723  for (is = 0; is < aertab->nscatt; is++) {
724  aertab->model[im]->lnphase[iw][is] = log(aertab->model[im]->phase[iw][is]);
725  }
726  d1phase1 = first_deriv(aertab->scatt, &aertab->model[im]->lnphase[iw][0], 0);
727  d1phaseN = first_deriv(aertab->scatt, &aertab->model[im]->lnphase[iw][0], aertab->nscatt);
728  spline(aertab->scatt,
729  &aertab->model[im]->lnphase[iw][0],
730  aertab->nscatt,
731  d1phase1,
732  d1phaseN,
733  &aertab->model[im]->d2phase[iw][0]);
734  }
735  }
736  }
737 
738  }
739 
740  aertab->nmodel = nmodels;
741  aertab->sensorID = sensorID;
742 
743  /* Require number of table wavelengths to equal number of sensor wavelengths */
744  if (aertab->nwave != nwave) {
745  printf("Number of aerosol LUT wavelengths (%d) is not equal to number of sensor wavelengths (%d).\n",
746  aertab->nwave,nwave);
747  exit(1);
748  }
749 
750  if(!use_pca_lut) {
751  /* precompute airmass for diffuse transmittance */
752  for (is = 0; is < aertab->dtran_ntheta; is++) {
753  aertab->dtran_airmass[is] = 1.0 / cos(aertab->dtran_theta[is] / radeg);
754  }
755 
756  if (aertab->dtran_nwave != nwave) {
757  printf("Number of aerosol diffue trans LUT wavelengths (%d) is not equal to number of sensor wavelengths (%d).\n",
758  aertab->dtran_nwave,nwave);
759  exit(1);
760  }
761 
762  /* map sensor wavelengths to table wavelengths */
763  printf("Wavelengths - Sensor\tAerosol model\tDiffuse transmittance\n");
764  for (iw = 0; iw < nwave; iw++) {
765  iwatab[iw] = windex(wave[iw], aertab->wave, aertab->nwave);
766  iwdtab[iw] = windex(wave[iw], aertab->dtran_wave, aertab->dtran_nwave);
767  printf("\t %6.2f\t %6.2f\t %6.2f\n", wave[iw],aertab->wave[iwatab[iw]], aertab->dtran_wave[iwdtab[iw]]);
768  }
769 
770  }
771 
772  loaded = 1;
773 
774  return (0);
775 }
776 
777 
778 
779 #define INDEX(iw,isol,iphi,isen) (iw*aertab->nsolz*aertab->nphi*aertab->nsenz + isol*aertab->nphi*aertab->nsenz + iphi*aertab->nsenz + isen)
780 
781 /* ---------------------------------------------------------------------------------------- */
782 /* ss_to_ms_coef() - for one model, return coefficients of function relating single */
783 /* scattering to multiple scattering at the input geometry. */
784 /* */
785 /* This is effectively a C version of M. Wangs linear_a_b_c.f. The program optimizes for */
786 /* multiple calls at the same geometry by computing for all models on the first call with a */
787 /* new geometry. It returns pointers to the internal static arrays of coefficients. */
788 /* */
789 /* B. Franz, 1 June 2004. */
790 /* W. Robinson, SAIC adapt to band-ependent geometry */
791 
792 /* ---------------------------------------------------------------------------------------- */
793 void ss_to_ms_coef(int modnum, geom_str *geom, float **a, float **b, float **c) {
794  static float lastsolz = -999.;
795  static float lastsenz = -999.;
796  static float lastphi = -999.;
797 
798  static int computed[MAXMODEL];
799 
800  static float *a_coef[MAXMODEL];
801  static float *b_coef[MAXMODEL];
802  static float *c_coef[MAXMODEL];
803 
804  static float *p, *q, *r;
805  static float as000, as100, as010, as110, as001, as011, as101, as111;
806  static float ai000, ai100, ai010, ai110, ai001, ai011, ai101, ai111;
807  static float ac000, ac100, ac010, ac110, ac001, ac011, ac101, ac111;
808 
809  static int *isolz1, *isolz2;
810  static int *isenz1, *isenz2;
811  static int *iphi1, *iphi2;
812 
813  static float *p_ar, *q_ar, *r_ar;
814  static float p_cnst, q_cnst, r_cnst;
815  static int *isolz1_ar, *isolz2_ar, isolz1_cnst, isolz2_cnst;
816  static int *isenz1_ar, *isenz2_ar, isenz1_cnst, isenz2_cnst;
817  static int *iphi1_ar, *iphi2_ar, iphi1_cnst, iphi2_cnst;
818 
819  float aphi;
820  float px, qx, rx;
821  int im, iw, i, ig;
822  static int firstCall = 1;
823  static int gmult;
824 
825  if (firstCall == 1) {
826  firstCall = 0;
827  for (i = 0; i < MAXMODEL; i++) {
828  if ((a_coef[i] = (float *) calloc(aertab->nwave, sizeof (float))) == NULL) {
829  printf("Unable to allocate space for a_coef.\n");
830  exit(1);
831  }
832  if ((b_coef[i] = (float *) calloc(aertab->nwave, sizeof (float))) == NULL) {
833  printf("Unable to allocate space for rhoa.\n");
834  exit(1);
835  }
836  if ((c_coef[i] = (float *) calloc(aertab->nwave, sizeof (float))) == NULL) {
837  printf("Unable to allocate space for rhoa.\n");
838  exit(1);
839  }
840  }
841  /* set up indicies, weights for band-dependent or nominal geometry */
842  if ((geom->gmult == 0) || (interpol == 1)) {
843  gmult = 0;
844  p = &p_cnst;
845  q = &q_cnst;
846  r = &r_cnst;
847  isolz1 = &isolz1_cnst;
848  isolz2 = &isolz2_cnst;
849  isenz1 = &isenz1_cnst;
850  isenz2 = &isenz2_cnst;
851  iphi1 = &iphi1_cnst;
852  iphi2 = &iphi2_cnst;
853  } else
854  gmult = 1;
855  {
856  if (((p_ar = (float *) malloc(aertab->nwave * sizeof (float)))
857  == NULL) ||
858  ((q_ar = (float *) malloc(aertab->nwave * sizeof (float)))
859  == NULL) ||
860  ((r_ar = (float *) malloc(aertab->nwave * sizeof (float)))
861  == NULL)) {
862  printf("Unable to allocate space for p, q, r weights.\n");
863  exit(1);
864  }
865  if (((isolz1_ar = (int *) malloc(aertab->nwave * sizeof (int)))
866  == NULL) ||
867  ((isenz1_ar = (int *) malloc(aertab->nwave * sizeof (int)))
868  == NULL) ||
869  ((iphi1_ar = (int *) malloc(aertab->nwave * sizeof (int)))
870  == NULL)) {
871  printf("Unable to allocate space for interp indicies 1.\n");
872  exit(1);
873  }
874  if (((isolz2_ar = (int *) malloc(aertab->nwave * sizeof (int)))
875  == NULL) ||
876  ((isenz2_ar = (int *) malloc(aertab->nwave * sizeof (int)))
877  == NULL) ||
878  ((iphi2_ar = (int *) malloc(aertab->nwave * sizeof (int)))
879  == NULL)) {
880  printf("Unable to allocate space for interp indicies 2.\n");
881  exit(1);
882  }
883  p = p_ar;
884  q = q_ar;
885  r = r_ar;
886  isolz1 = isolz1_ar;
887  isolz2 = isolz2_ar;
888  isenz1 = isenz1_ar;
889  isenz2 = isenz2_ar;
890  iphi1 = iphi1_ar;
891  iphi2 = iphi2_ar;
892  }
893  }
894 
895  if ((geom->solz[0] != lastsolz) || (geom->senz[0] != lastsenz) ||
896  (geom->phi[0] != lastphi)) {
897  for (im = 0; im < aertab->nmodel; im++)
898  computed[im] = 0;
899 
900  for (iw = 0; iw < aertab->nwave; iw++) {
901  ig = iw * gmult;
902  /* find bracketing solar indices */
903  for (i = 0; i < aertab->nsolz; i++) {
904  if (geom->solz[ig] < aertab->solz[i])
905  break;
906  }
907  isolz1[iw] = MAX(i - 1, 0);
908  isolz2[iw] = MIN(i, aertab->nsolz - 1);
909  if (isolz2[iw] != isolz1[iw])
910  r[iw] = (geom->solz[ig] - aertab->solz[isolz1[iw]]) /
911  (aertab->solz[isolz2[iw]] - aertab->solz[isolz1[iw]]);
912  else
913  r[iw] = 0.0;
914 
915  /* find bracketing view indices */
916  for (i = 0; i < aertab->nsenz; i++) {
917  if (geom->senz[ig] < aertab->senz[i])
918  break;
919  }
920  isenz1[iw] = MAX(i - 1, 0);
921  isenz2[iw] = MIN(i, aertab->nsenz - 1);
922  if (isenz2[iw] != isenz1[iw])
923  p[iw] = (geom->senz[ig] - aertab->senz[isenz1[iw]]) /
924  (aertab->senz[isenz2[iw]] - aertab->senz[isenz1[iw]]);
925  else
926  p[iw] = 0.0;
927 
928  /* find bracketing azimuth indices */
929  aphi = fabs(geom->phi[ig]);
930  for (i = 0; i < aertab->nphi; i++) {
931  if (aphi < aertab->phi[i])
932  break;
933  }
934  iphi1[iw] = MAX(i - 1, 0);
935  iphi2[iw] = MIN(i, aertab->nphi - 1);
936  if (iphi2[iw] != iphi1[iw])
937  q[iw] = (aphi - aertab->phi[iphi1[iw]]) /
938  (aertab->phi[iphi2[iw]] - aertab->phi[iphi1[iw]]);
939  else
940  q[iw] = 0.0;
941  if (gmult == 0) break;
942  }
943 
944  /* remember last geometry */
945  lastsolz = geom->solz[0];
946  lastsenz = geom->senz[0];
947  lastphi = geom->phi[0];
948  }
949 
950  if (!computed[modnum]) {
951  im = modnum;
952  computed[modnum] = 1;
953 
954  for (iw = 0; iw < aertab->nwave; iw++) {
955  ig = iw * gmult;
956  px = p[ig];
957  qx = q[ig];
958  rx = r[ig];
959  if (isolz2[ig] == 0) {
960  as000 = aertab->model[im]->acost[INDEX(iw, isolz1[ig], 0, isenz1[ig])];
961  as100 = aertab->model[im]->acost[INDEX(iw, isolz1[ig], 0, isenz2[ig])];
962  as001 = aertab->model[im]->acost[INDEX(iw, isolz2[ig], 0, isenz1[ig])];
963  as101 = aertab->model[im]->acost[INDEX(iw, isolz2[ig], 0, isenz2[ig])];
964 
965  ai000 = aertab->model[im]->bcost[INDEX(iw, isolz1[ig], 0, isenz1[ig])];
966  ai100 = aertab->model[im]->bcost[INDEX(iw, isolz1[ig], 0, isenz2[ig])];
967  ai001 = aertab->model[im]->bcost[INDEX(iw, isolz2[ig], 0, isenz1[ig])];
968  ai101 = aertab->model[im]->bcost[INDEX(iw, isolz2[ig], 0, isenz2[ig])];
969 
970  ac000 = aertab->model[im]->ccost[INDEX(iw, isolz1[ig], 0, isenz1[ig])];
971  ac100 = aertab->model[im]->ccost[INDEX(iw, isolz1[ig], 0, isenz2[ig])];
972  ac001 = aertab->model[im]->ccost[INDEX(iw, isolz2[ig], 0, isenz1[ig])];
973  ac101 = aertab->model[im]->ccost[INDEX(iw, isolz2[ig], 0, isenz2[ig])];
974 
975  a_coef[im][iw] = (1. - px)*(1. - rx) * as000 + px * rx * as101
976  + (1. - px) * rx * as001 + px * (1. - rx) * as100;
977 
978  b_coef[im][iw] = (1. - px)*(1. - rx) * ai000 + px * rx * ai101
979  + (1. - px) * rx * ai001 + px * (1. - qx)*(1. - rx) * ai100;
980 
981  c_coef[im][iw] = (1. - px)*(1. - rx) * ac000 + px * rx * ac101
982  + (1. - px) * rx * ac001 + px * (1. - qx)*(1. - rx) * ac100;
983  } else {
984  as000 = aertab->model[im]->acost[INDEX(iw, isolz1[ig], iphi1[ig], isenz1[ig])];
985  as100 = aertab->model[im]->acost[INDEX(iw, isolz1[ig], iphi1[ig], isenz2[ig])];
986  as010 = aertab->model[im]->acost[INDEX(iw, isolz1[ig], iphi2[ig], isenz1[ig])];
987  as110 = aertab->model[im]->acost[INDEX(iw, isolz1[ig], iphi2[ig], isenz2[ig])];
988  as001 = aertab->model[im]->acost[INDEX(iw, isolz2[ig], iphi1[ig], isenz1[ig])];
989  as011 = aertab->model[im]->acost[INDEX(iw, isolz2[ig], iphi2[ig], isenz1[ig])];
990  as101 = aertab->model[im]->acost[INDEX(iw, isolz2[ig], iphi1[ig], isenz2[ig])];
991  as111 = aertab->model[im]->acost[INDEX(iw, isolz2[ig], iphi2[ig], isenz2[ig])];
992 
993  ai000 = aertab->model[im]->bcost[INDEX(iw, isolz1[ig], iphi1[ig], isenz1[ig])];
994  ai100 = aertab->model[im]->bcost[INDEX(iw, isolz1[ig], iphi1[ig], isenz2[ig])];
995  ai010 = aertab->model[im]->bcost[INDEX(iw, isolz1[ig], iphi2[ig], isenz1[ig])];
996  ai110 = aertab->model[im]->bcost[INDEX(iw, isolz1[ig], iphi2[ig], isenz2[ig])];
997  ai001 = aertab->model[im]->bcost[INDEX(iw, isolz2[ig], iphi1[ig], isenz1[ig])];
998  ai011 = aertab->model[im]->bcost[INDEX(iw, isolz2[ig], iphi2[ig], isenz1[ig])];
999  ai101 = aertab->model[im]->bcost[INDEX(iw, isolz2[ig], iphi1[ig], isenz2[ig])];
1000  ai111 = aertab->model[im]->bcost[INDEX(iw, isolz2[ig], iphi2[ig], isenz2[ig])];
1001 
1002  ac000 = aertab->model[im]->ccost[INDEX(iw, isolz1[ig], iphi1[ig], isenz1[ig])];
1003  ac100 = aertab->model[im]->ccost[INDEX(iw, isolz1[ig], iphi1[ig], isenz2[ig])];
1004  ac010 = aertab->model[im]->ccost[INDEX(iw, isolz1[ig], iphi2[ig], isenz1[ig])];
1005  ac110 = aertab->model[im]->ccost[INDEX(iw, isolz1[ig], iphi2[ig], isenz2[ig])];
1006  ac001 = aertab->model[im]->ccost[INDEX(iw, isolz2[ig], iphi1[ig], isenz1[ig])];
1007  ac011 = aertab->model[im]->ccost[INDEX(iw, isolz2[ig], iphi2[ig], isenz1[ig])];
1008  ac101 = aertab->model[im]->ccost[INDEX(iw, isolz2[ig], iphi1[ig], isenz2[ig])];
1009  ac111 = aertab->model[im]->ccost[INDEX(iw, isolz2[ig], iphi2[ig], isenz2[ig])];
1010 
1011  a_coef[im][iw] = (1. - px)*(1. - qx)*(1. - rx) * as000 + px * qx * rx * as111
1012  + px * (1. - qx) * rx * as101 + (1. - px) * qx * (1. - rx) * as010
1013  + px * qx * (1. - rx) * as110 + (1. - px)*(1. - qx) * rx * as001
1014  + (1. - px) * qx * rx * as011 + px * (1. - qx)*(1. - rx) * as100;
1015 
1016  b_coef[im][iw] = (1. - px)*(1. - qx)*(1. - rx) * ai000 + px * qx * rx * ai111
1017  + px * (1. - qx) * rx * ai101 + (1. - px) * qx * (1. - rx) * ai010
1018  + px * qx * (1. - rx) * ai110 + (1. - px)*(1. - qx) * rx * ai001
1019  + (1. - px) * qx * rx * ai011 + px * (1. - qx)*(1. - rx) * ai100;
1020 
1021  c_coef[im][iw] = (1. - px)*(1. - qx)*(1. - rx) * ac000 + px * qx * rx * ac111
1022  + px * (1. - qx) * rx * ac101 + (1. - px) * qx * (1. - rx) * ac010
1023  + px * qx * (1. - rx) * ac110 + (1. - px)*(1. - qx) * rx * ac001
1024  + (1. - px) * qx * rx * ac011 + px * (1. - qx)*(1. - rx) * ac100;
1025  }
1026  }
1027  }
1028 
1029  /* return pointers to coeffs for this geometry */
1030  *a = &a_coef[modnum][0];
1031  *b = &b_coef[modnum][0];
1032  *c = &c_coef[modnum][0];
1033 
1034  return;
1035 }
1036 
1037 /* ---------------------------------------------------------------------------------------- */
1038 /* fresnel_coef() - computes Fresnel reflectance coefficient for specified index of refr. */
1039 
1040 /* ---------------------------------------------------------------------------------------- */
1041 float fresnel_coef(float mu, float index) {
1042  float sq, r2, q1;
1043 
1044  sq = sqrt(pow(index, 2.0) - 1.0 + pow(mu, 2.0));
1045  r2 = pow((mu - sq) / (mu + sq), 2.0);
1046  q1 = (1.0 - pow(mu, 2.0) - mu * sq) / (1.0 - pow(mu, 2.0) + mu * sq);
1047 
1048  return (r2 * (q1 * q1 + 1.0) / 2.0);
1049 }
1050 
1051 
1052 
1053 /* ---------------------------------------------------------------------------------------- */
1054 /* ms_eps_coef() - for a given model, returns ams, bms, cms, dms and ems coefficients to */
1055 /* compute ms_reflectance at the input geometry. */
1056 /* Also, the program optimizes for multiple calls at the same geometry */
1057 /* by computing for all models on the first call with a new geometry. */
1058 /* It returns pointers to the internal static arrays of coefficients. */
1059 /* */
1060 /* Z. Ahmad July 08, 2014 */
1061 /* W. Robinson, SAIC 23 Mar 2017 add band-dependent geometry to code */
1062 /* M. Zhang 06/19/2019 fixed the interpolation part */
1063 
1064 /* ---------------------------------------------------------------------------------------- */
1065 
1066 
1067 
1068 void ms_eps_coef(int modnum, int32_t iwnir_l, float wave[], geom_str *geom,
1069  float **a, float **b, float **c, float **d, float **e)
1070  {
1071  static float lastsolz = -999.;
1072  static float lastsenz = -999.;
1073  static float lastphi = -999.;
1074 
1075  static int computed[MAXMODEL];
1076 
1077  static float *a_coef[MAXMODEL];
1078  static float *b_coef[MAXMODEL];
1079  static float *c_coef[MAXMODEL];
1080  static float *d_coef[MAXMODEL];
1081  static float *e_coef[MAXMODEL];
1082 
1083  static float *p, *q, *r;
1084  static float as000, as100, as010, as110, as001, as011, as101, as111;
1085  static float ai000, ai100, ai010, ai110, ai001, ai011, ai101, ai111;
1086  static float ac000, ac100, ac010, ac110, ac001, ac011, ac101, ac111;
1087  static float ad000, ad100, ad010, ad110, ad001, ad011, ad101, ad111;
1088  static float ae000, ae100, ae010, ae110, ae001, ae011, ae101, ae111;
1089 
1090  static int *isolz1, *isolz2;
1091  static int *isenz1, *isenz2;
1092  static int *iphi1, *iphi2;
1093 
1094  static float *p_ar, *q_ar, *r_ar;
1095  static float p_cnst, q_cnst, r_cnst;
1096  static int *isolz1_ar, *isolz2_ar, isolz1_cnst, isolz2_cnst;
1097  static int *isenz1_ar, *isenz2_ar, isenz1_cnst, isenz2_cnst;
1098  static int *iphi1_ar, *iphi2_ar, iphi1_cnst, iphi2_cnst;
1099  static int gmult;
1100 
1101  float aphi;
1102  float px, qx, rx;
1103  int im, iw, i, ig;
1104  static int firstCall = 1;
1105 
1106  if (firstCall == 1) {
1107  firstCall = 0;
1108  for (i = 0; i < MAXMODEL; i++) {
1109  if ((a_coef[i] = (float *) calloc(aertab->nwave, sizeof (float))) == NULL) {
1110  printf("Unable to allocate space for a_coef.\n");
1111  exit(1);
1112  }
1113  if ((b_coef[i] = (float *) calloc(aertab->nwave, sizeof (float))) == NULL) {
1114  printf("Unable to allocate space for b_coef.\n");
1115  exit(1);
1116  }
1117  if ((c_coef[i] = (float *) calloc(aertab->nwave, sizeof (float))) == NULL) {
1118  printf("Unable to allocate space for c_coef.\n");
1119  exit(1);
1120  }
1121  if ((d_coef[i] = (float *) calloc(aertab->nwave, sizeof (float))) == NULL) {
1122  printf("Unable to allocate space for d_coef.\n");
1123  exit(1);
1124  }
1125 
1126  if ((e_coef[i] = (float *) calloc(aertab->nwave, sizeof (float))) == NULL) {
1127  printf("Unable to allocate space for e_coef.\n");
1128  exit(1);
1129  }
1130 
1131  }
1132  /* set up indicies, weights for band-dependent or nominal geometry */
1133  if ((geom->gmult == 0) || (interpol == 1)) {
1134  gmult = 0;
1135  p = &p_cnst;
1136  q = &q_cnst;
1137  r = &r_cnst;
1138  isolz1 = &isolz1_cnst;
1139  isolz2 = &isolz2_cnst;
1140  isenz1 = &isenz1_cnst;
1141  isenz2 = &isenz2_cnst;
1142  iphi1 = &iphi1_cnst;
1143  iphi2 = &iphi2_cnst;
1144  } else {
1145  gmult = 1;
1146  if (((p_ar = (float *) malloc(aertab->nwave * sizeof (float)))
1147  == NULL) ||
1148  ((q_ar = (float *) malloc(aertab->nwave * sizeof (float)))
1149  == NULL) ||
1150  ((r_ar = (float *) malloc(aertab->nwave * sizeof (float)))
1151  == NULL)) {
1152  printf("Unable to allocate space for p, q, r weights.\n");
1153  exit(1);
1154  }
1155  if (((isolz1_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1156  == NULL) ||
1157  ((isenz1_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1158  == NULL) ||
1159  ((iphi1_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1160  == NULL)) {
1161  printf("Unable to allocate space for interp indicies 1.\n");
1162  exit(1);
1163  }
1164  if (((isolz2_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1165  == NULL) ||
1166  ((isenz2_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1167  == NULL) ||
1168  ((iphi2_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1169  == NULL)) {
1170  printf("Unable to allocate space for interp indicies 2.\n");
1171  exit(1);
1172  }
1173  p = p_ar;
1174  q = q_ar;
1175  r = r_ar;
1176  isolz1 = isolz1_ar;
1177  isolz2 = isolz2_ar;
1178  isenz1 = isenz1_ar;
1179  isenz2 = isenz2_ar;
1180  iphi1 = iphi1_ar;
1181  iphi2 = iphi2_ar;
1182  }
1183  }
1184 
1185  if (geom->solz[0] != lastsolz || geom->senz[0] != lastsenz ||
1186  geom->phi[0] != lastphi) {
1187  for (im = 0; im < aertab->nmodel; im++)
1188  computed[im] = 0;
1189 
1190  for (iw = 0; iw < aertab->nwave; iw++) {
1191  ig = iw * gmult;
1192  /* find bracketing solar indices */
1193  for (i = 0; i < aertab->nsolz; i++) {
1194  if (geom->solz[ig] < aertab->solz[i])
1195  break;
1196  }
1197  isolz1[iw] = MAX(i - 1, 0);
1198  isolz2[iw] = MIN(i, aertab->nsolz - 1);
1199  if (isolz2[iw] != isolz1[iw])
1200  r[iw] = (geom->solz[ig] - aertab->solz[isolz1[iw]]) /
1201  (aertab->solz[isolz2[iw]] - aertab->solz[isolz1[iw]]);
1202  else
1203  r[iw] = 0.0;
1204 
1205  /* find bracketing view indices */
1206  for (i = 0; i < aertab->nsenz; i++) {
1207  if (geom->senz[ig] < aertab->senz[i])
1208  break;
1209  }
1210  isenz1[iw] = MAX(i - 1, 0);
1211  isenz2[iw] = MIN(i, aertab->nsenz - 1);
1212  if (isenz2[iw] != isenz1[iw])
1213  p[iw] = (geom->senz[ig] - aertab->senz[isenz1[iw]]) /
1214  (aertab->senz[isenz2[iw]] - aertab->senz[isenz1[iw]]);
1215  else
1216  p[iw] = 0.0;
1217 
1218  /* find bracketing azimuth indices */
1219  aphi = fabs(geom->phi[ig]);
1220  for (i = 0; i < aertab->nphi; i++) {
1221  if (aphi < aertab->phi[i])
1222  break;
1223  }
1224  iphi1[iw] = MAX(i - 1, 0);
1225  iphi2[iw] = MIN(i, aertab->nphi - 1);
1226  if (iphi2[iw] != iphi1[iw])
1227  q[iw] = (aphi - aertab->phi[iphi1[iw]]) /
1228  (aertab->phi[iphi2[iw]] - aertab->phi[iphi1[iw]]);
1229  else
1230  q[iw] = 0.0;
1231  if (gmult == 0) break;
1232  }
1233 
1234  /* remember last geometry */
1235  lastsolz = geom->solz[0];
1236  lastsenz = geom->senz[0];
1237  lastphi = geom->phi[0];
1238 
1239  }
1240 
1241  im = modnum;
1242 
1243  if (!computed[modnum]) {
1244  im = modnum;
1245  computed[modnum] = 1;
1246 
1247  for (iw = 0; iw < aertab->nwave; iw++) {
1248  ig = iw * gmult;
1249  px = p[ig];
1250  qx = q[ig];
1251  rx = r[ig];
1252  if (isolz2[ig] == 0) {
1253  as000 = aertab->model[im]->ams_all[INDEX(iw, isolz1[ig], 0, isenz1[ig])];
1254  as100 = aertab->model[im]->ams_all[INDEX(iw, isolz1[ig], 0, isenz2[ig])];
1255  as001 = aertab->model[im]->ams_all[INDEX(iw, isolz2[ig], 0, isenz1[ig])];
1256  as101 = aertab->model[im]->ams_all[INDEX(iw, isolz2[ig], 0, isenz2[ig])];
1257 
1258  ai000 = aertab->model[im]->bms_all[INDEX(iw, isolz1[ig], 0, isenz1[ig])];
1259  ai100 = aertab->model[im]->bms_all[INDEX(iw, isolz1[ig], 0, isenz2[ig])];
1260  ai001 = aertab->model[im]->bms_all[INDEX(iw, isolz2[ig], 0, isenz1[ig])];
1261  ai101 = aertab->model[im]->bms_all[INDEX(iw, isolz2[ig], 0, isenz2[ig])];
1262 
1263  ac000 = aertab->model[im]->cms_all[INDEX(iw, isolz1[ig], 0, isenz1[ig])];
1264  ac100 = aertab->model[im]->cms_all[INDEX(iw, isolz1[ig], 0, isenz2[ig])];
1265  ac001 = aertab->model[im]->cms_all[INDEX(iw, isolz2[ig], 0, isenz1[ig])];
1266  ac101 = aertab->model[im]->cms_all[INDEX(iw, isolz2[ig], 0, isenz2[ig])];
1267 
1268  ad000 = aertab->model[im]->dms_all[INDEX(iw, isolz1[ig], 0, isenz1[ig])];
1269  ad100 = aertab->model[im]->dms_all[INDEX(iw, isolz1[ig], 0, isenz2[ig])];
1270  ad001 = aertab->model[im]->dms_all[INDEX(iw, isolz2[ig], 0, isenz1[ig])];
1271  ad101 = aertab->model[im]->dms_all[INDEX(iw, isolz2[ig], 0, isenz2[ig])];
1272 
1273  ae000 = aertab->model[im]->ems_all[INDEX(iw, isolz1[ig], 0, isenz1[ig])];
1274  ae100 = aertab->model[im]->ems_all[INDEX(iw, isolz1[ig], 0, isenz2[ig])];
1275  ae001 = aertab->model[im]->ems_all[INDEX(iw, isolz2[ig], 0, isenz1[ig])];
1276  ae101 = aertab->model[im]->ems_all[INDEX(iw, isolz2[ig], 0, isenz2[ig])];
1277 
1278  a_coef[im][iw] = (1. - px)*(1. - rx) * as000 + px * rx * as101
1279  + (1. - px) * rx * as001 + px * (1. - rx) * as100;
1280 
1281  b_coef[im][iw] = (1. - px)*(1. - rx) * ai000 + px * rx * ai101
1282  + (1. - px) * rx * ai001 + px * (1. - qx)*(1. - rx) * ai100;
1283 
1284  c_coef[im][iw] = (1. - px)*(1. - rx) * ac000 + px * rx * ac101
1285  + (1. - px) * rx * ac001 + px * (1. - qx)*(1. - rx) * ac100;
1286 
1287  d_coef[im][iw] = (1. - px)*(1. - rx) * ad000 + px * rx * ad101
1288  + (1. - px) * rx * ad001 + px * (1. - qx)*(1. - rx) * ad100;
1289 
1290  e_coef[im][iw] = (1. - px)*(1. - rx) * ae000 + px * rx * ae101
1291  + (1. - px) * rx * ae001 + px * (1. - qx)*(1. - rx) * ae100;
1292  } else {
1293  /* printf("coeffs: as000,ai000,ac000,ad000,ae000\n"); */
1294 
1295  as000 = aertab->model[im]->ams_all[INDEX(iw, isolz1[ig], iphi1[ig], isenz1[ig])];
1296  as100 = aertab->model[im]->ams_all[INDEX(iw, isolz2[ig], iphi1[ig], isenz1[ig])];
1297  as010 = aertab->model[im]->ams_all[INDEX(iw, isolz1[ig], iphi2[ig], isenz1[ig])];
1298  as110 = aertab->model[im]->ams_all[INDEX(iw, isolz2[ig], iphi2[ig], isenz1[ig])];
1299  as001 = aertab->model[im]->ams_all[INDEX(iw, isolz1[ig], iphi1[ig], isenz2[ig])];
1300  as011 = aertab->model[im]->ams_all[INDEX(iw, isolz1[ig], iphi2[ig], isenz2[ig])];
1301  as101 = aertab->model[im]->ams_all[INDEX(iw, isolz2[ig], iphi1[ig], isenz2[ig])];
1302  as111 = aertab->model[im]->ams_all[INDEX(iw, isolz2[ig], iphi2[ig], isenz2[ig])];
1303 
1304  ai000 = aertab->model[im]->bms_all[INDEX(iw, isolz1[ig], iphi1[ig], isenz1[ig])];
1305  ai100 = aertab->model[im]->bms_all[INDEX(iw, isolz2[ig], iphi1[ig], isenz1[ig])];
1306  ai010 = aertab->model[im]->bms_all[INDEX(iw, isolz1[ig], iphi2[ig], isenz1[ig])];
1307  ai110 = aertab->model[im]->bms_all[INDEX(iw, isolz2[ig], iphi2[ig], isenz1[ig])];
1308  ai001 = aertab->model[im]->bms_all[INDEX(iw, isolz1[ig], iphi1[ig], isenz2[ig])];
1309  ai011 = aertab->model[im]->bms_all[INDEX(iw, isolz1[ig], iphi2[ig], isenz2[ig])];
1310  ai101 = aertab->model[im]->bms_all[INDEX(iw, isolz2[ig], iphi1[ig], isenz2[ig])];
1311  ai111 = aertab->model[im]->bms_all[INDEX(iw, isolz2[ig], iphi2[ig], isenz2[ig])];
1312 
1313  ac000 = aertab->model[im]->cms_all[INDEX(iw, isolz1[ig], iphi1[ig], isenz1[ig])];
1314  ac100 = aertab->model[im]->cms_all[INDEX(iw, isolz2[ig], iphi1[ig], isenz1[ig])];
1315  ac010 = aertab->model[im]->cms_all[INDEX(iw, isolz1[ig], iphi2[ig], isenz1[ig])];
1316  ac110 = aertab->model[im]->cms_all[INDEX(iw, isolz2[ig], iphi2[ig], isenz1[ig])];
1317  ac001 = aertab->model[im]->cms_all[INDEX(iw, isolz1[ig], iphi1[ig], isenz2[ig])];
1318  ac011 = aertab->model[im]->cms_all[INDEX(iw, isolz1[ig], iphi2[ig], isenz2[ig])];
1319  ac101 = aertab->model[im]->cms_all[INDEX(iw, isolz2[ig], iphi1[ig], isenz2[ig])];
1320  ac111 = aertab->model[im]->cms_all[INDEX(iw, isolz2[ig], iphi2[ig], isenz2[ig])];
1321 
1322  ad000 = aertab->model[im]->dms_all[INDEX(iw, isolz1[ig], iphi1[ig], isenz1[ig])];
1323  ad100 = aertab->model[im]->dms_all[INDEX(iw, isolz2[ig], iphi1[ig], isenz1[ig])];
1324  ad010 = aertab->model[im]->dms_all[INDEX(iw, isolz1[ig], iphi2[ig], isenz1[ig])];
1325  ad110 = aertab->model[im]->dms_all[INDEX(iw, isolz2[ig], iphi2[ig], isenz1[ig])];
1326  ad001 = aertab->model[im]->dms_all[INDEX(iw, isolz1[ig], iphi1[ig], isenz2[ig])];
1327  ad011 = aertab->model[im]->dms_all[INDEX(iw, isolz1[ig], iphi2[ig], isenz2[ig])];
1328  ad101 = aertab->model[im]->dms_all[INDEX(iw, isolz2[ig], iphi1[ig], isenz2[ig])];
1329  ad111 = aertab->model[im]->dms_all[INDEX(iw, isolz2[ig], iphi2[ig], isenz2[ig])];
1330 
1331  ae000 = aertab->model[im]->ems_all[INDEX(iw, isolz1[ig], iphi1[ig], isenz1[ig])];
1332  ae100 = aertab->model[im]->ems_all[INDEX(iw, isolz2[ig], iphi1[ig], isenz1[ig])];
1333  ae010 = aertab->model[im]->ems_all[INDEX(iw, isolz1[ig], iphi2[ig], isenz1[ig])];
1334  ae110 = aertab->model[im]->ems_all[INDEX(iw, isolz2[ig], iphi2[ig], isenz1[ig])];
1335  ae001 = aertab->model[im]->ems_all[INDEX(iw, isolz1[ig], iphi1[ig], isenz2[ig])];
1336  ae011 = aertab->model[im]->ems_all[INDEX(iw, isolz1[ig], iphi2[ig], isenz2[ig])];
1337  ae101 = aertab->model[im]->ems_all[INDEX(iw, isolz2[ig], iphi1[ig], isenz2[ig])];
1338  ae111 = aertab->model[im]->ems_all[INDEX(iw, isolz2[ig], iphi2[ig], isenz2[ig])];
1339 
1340 
1341  a_coef[im][iw] = (1. - rx)*(1. - qx)*(1. - px) * as000 + rx * qx * px * as111
1342  + rx * (1. - qx) * px * as101 + (1. - rx) * qx * (1. - px) * as010
1343  + rx * qx * (1. - px) * as110 + (1. - rx)*(1. - qx) * px * as001
1344  + (1. - rx) * qx * px * as011 + rx * (1. - qx)*(1. - px) * as100;
1345 
1346  b_coef[im][iw] = (1. - rx)*(1. - qx)*(1. - px) * ai000 + rx * qx * px * ai111
1347  + rx * (1. - qx) * px * ai101 + (1. - rx) * qx * (1. - px) * ai010
1348  + rx * qx * (1. - px) * ai110 + (1. - rx)*(1. - qx) * px * ai001
1349  + (1. - rx) * qx * px * ai011 + rx * (1. - qx)*(1. - px) * ai100;
1350 
1351  c_coef[im][iw] = (1. - rx)*(1. - qx)*(1. - px) * ac000 + rx * qx * px * ac111
1352  + rx * (1. - qx) * px * ac101 + (1. - rx) * qx * (1. - px) * ac010
1353  + rx * qx * (1. - px) * ac110 + (1. - rx)*(1. - qx) * px * ac001
1354  + (1. - rx) * qx * px * ac011 + rx * (1. - qx)*(1. - px) * ac100;
1355 
1356  d_coef[im][iw] = (1. - rx)*(1. - qx)*(1. - px) * ad000 + rx * qx * px * ad111
1357  + rx * (1. - qx) * px * ad101 + (1. - rx) * qx * (1. - px) * ad010
1358  + rx * qx * (1. - px) * ad110 + (1. - rx)*(1. - qx) * px * ad001
1359  + (1. - rx) * qx * px * ad011 + rx * (1. - qx)*(1. - px) * ad100;
1360 
1361  e_coef[im][iw] = (1. - rx)*(1. - qx)*(1. - px) * ae000 + rx * qx * px * ae111
1362  + rx * (1. - qx) * px * ae101 + (1. - rx) * qx * (1. - px) * ae010
1363  + rx * qx * (1. - px) * ae110 + (1. - rx)*(1. - qx) * px * ae001
1364  + (1. - rx) * qx * px * ae011 + rx * (1. - qx)*(1. - px) * ae100;
1365 
1366  }
1367  }
1368  }
1369 
1370  // root finding is quadratic, but table includes cubic term, make sure it's zero
1371  if (fabs(d_coef[modnum][iwnir_l]) > 1e-9) {
1372  printf("non zero cubic term found in longest NIR wavelength of aerosol table. Zia!!\n");
1373  exit(1);
1374  }
1375 
1376  /* return pointers to coeffs for this geometry */
1377  *a = &a_coef[modnum][0];
1378  *b = &b_coef[modnum][0];
1379  *c = &c_coef[modnum][0];
1380  *d = &d_coef[modnum][0];
1381  *e = &e_coef[modnum][0];
1382 
1383 
1384  return;
1385 }
1386 
1387 /* Interpolate pc_rhoa using geometry */
1388 /* pc_rhoa: ntau_870*npc */
1389 /* M.Zhang, Oct. 2022 */
1390 
1391 void get_pc_rhoa(int modnum, geom_str *geom, float **pc_rhoa)
1392  {
1393  static float lastsolz = -999.;
1394  static float lastsenz = -999.;
1395  static float lastphi = -999.;
1396 
1397  static int computed[MAXMODEL];
1398 
1399  static float ***pc_coef; //MAXMODEL*ntau_870*npc
1400  static int ntau_870,npc;
1401 
1402  static float *p, *q, *r;
1403  static float as000, as100, as010, as110, as001, as011, as101, as111;
1404 
1405  static int *isolz1, *isolz2;
1406  static int *isenz1, *isenz2;
1407  static int *iphi1, *iphi2;
1408 
1409  static float *p_ar, *q_ar, *r_ar;
1410  static int *isolz1_ar, *isolz2_ar;
1411  static int *isenz1_ar, *isenz2_ar;
1412  static int *iphi1_ar, *iphi2_ar;
1413  static int gmult;
1414 
1415  float aphi;
1416  float px, qx, rx;
1417  int im, iw, i, ig, itau,ipc;
1418  static int firstCall = 1;
1419 
1420  if (firstCall == 1) {
1421  firstCall = 0;
1422  ntau_870=aertab->ntau_870;
1423  npc=aertab->npc;
1424 
1425  pc_coef=(float ***)calloc(MAXMODEL,sizeof(float **));
1426 
1427  for (i = 0; i < MAXMODEL; i++) {
1428  if ((pc_coef[i] = (float **) calloc(ntau_870, sizeof (float*))) == NULL) {
1429  printf("Unable to allocate space for pc_coef.\n");
1430  exit(1);
1431  }
1432  for(itau=0;itau<ntau_870;itau++){
1433  if ((pc_coef[i][itau] = (float *) calloc(aertab->npc, sizeof (float))) == NULL) {
1434  printf("Unable to allocate space for pc_coef.\n");
1435  exit(1);
1436  }
1437  }
1438  }
1439  /* set up indicies, weights for band-dependent or nominal geometry */
1440  if ((geom->gmult == 0) || (interpol == 1)) {
1441  gmult = 0;
1442  } else {
1443  gmult = 1;
1444  }
1445  if (((p_ar = (float *) malloc(aertab->nwave * sizeof (float)))
1446  == NULL) ||
1447  ((q_ar = (float *) malloc(aertab->nwave * sizeof (float)))
1448  == NULL) ||
1449  ((r_ar = (float *) malloc(aertab->nwave * sizeof (float)))
1450  == NULL)) {
1451  printf("Unable to allocate space for p, q, r weights.\n");
1452  exit(1);
1453  }
1454  if (((isolz1_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1455  == NULL) ||
1456  ((isenz1_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1457  == NULL) ||
1458  ((iphi1_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1459  == NULL)) {
1460  printf("Unable to allocate space for interp indicies 1.\n");
1461  exit(1);
1462  }
1463  if (((isolz2_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1464  == NULL) ||
1465  ((isenz2_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1466  == NULL) ||
1467  ((iphi2_ar = (int *) malloc(aertab->nwave * sizeof (int)))
1468  == NULL)) {
1469  printf("Unable to allocate space for interp indicies 2.\n");
1470  exit(1);
1471  }
1472  p = p_ar;
1473  q = q_ar;
1474  r = r_ar;
1475  isolz1 = isolz1_ar;
1476  isolz2 = isolz2_ar;
1477  isenz1 = isenz1_ar;
1478  isenz2 = isenz2_ar;
1479  iphi1 = iphi1_ar;
1480  iphi2 = iphi2_ar;
1481  }
1482 
1483  if (geom->solz[0] != lastsolz || geom->senz[0] != lastsenz ||
1484  geom->phi[0] != lastphi) {
1485  for (im = 0; im < aertab->nmodel; im++)
1486  computed[im] = 0;
1487 
1488  for (iw = 0; iw < aertab->nwave; iw++) {
1489  ig = iw * gmult;
1490  /* find bracketing solar indices */
1491  for (i = 0; i < aertab->nsolz; i++) {
1492  if (geom->solz[ig] < aertab->solz[i])
1493  break;
1494  }
1495  isolz1[iw] = MAX(i - 1, 0);
1496  isolz2[iw] = MIN(i, aertab->nsolz - 1);
1497  if (isolz2[iw] != isolz1[iw])
1498  r[iw] = (geom->solz[ig] - aertab->solz[isolz1[iw]]) /
1499  (aertab->solz[isolz2[iw]] - aertab->solz[isolz1[iw]]);
1500  else
1501  r[iw] = 0.0;
1502 
1503  /* find bracketing view indices */
1504  for (i = 0; i < aertab->nsenz; i++) {
1505  if (geom->senz[ig] < aertab->senz[i])
1506  break;
1507  }
1508  isenz1[iw] = MAX(i - 1, 0);
1509  isenz2[iw] = MIN(i, aertab->nsenz - 1);
1510  if (isenz2[iw] != isenz1[iw])
1511  p[iw] = (geom->senz[ig] - aertab->senz[isenz1[iw]]) /
1512  (aertab->senz[isenz2[iw]] - aertab->senz[isenz1[iw]]);
1513  else
1514  p[iw] = 0.0;
1515 
1516  /* find bracketing azimuth indices */
1517  aphi = fabs(geom->phi[ig]);
1518  for (i = 0; i < aertab->nphi; i++) {
1519  if (aphi < aertab->phi[i])
1520  break;
1521  }
1522  iphi1[iw] = MAX(i - 1, 0);
1523  iphi2[iw] = MIN(i, aertab->nphi - 1);
1524  if (iphi2[iw] != iphi1[iw])
1525  q[iw] = (aphi - aertab->phi[iphi1[iw]]) /
1526  (aertab->phi[iphi2[iw]] - aertab->phi[iphi1[iw]]);
1527  else
1528  q[iw] = 0.0;
1529  if (gmult == 0) break;
1530  }
1531 
1532  /* remember last geometry */
1533  lastsolz = geom->solz[0];
1534  lastsenz = geom->senz[0];
1535  lastphi = geom->phi[0];
1536 
1537  }
1538 
1539  im = modnum;
1540 
1541  if (!computed[modnum]) {
1542  im = modnum;
1543  computed[modnum] = 1;
1544 
1545  iw=0;
1546  ig = iw * gmult;
1547  px = p[ig];
1548  qx = q[ig];
1549  rx = r[ig];
1550  if (isolz2[ig] == 0) {
1551 
1552  for(itau=0;itau<ntau_870;itau++)
1553  for(ipc=0;ipc<npc;ipc++){
1554  as000 = aertab->model[im]->pc_rhoa[itau][isolz1[ig]][0][isenz1[ig]][ipc];
1555  as100 = aertab->model[im]->pc_rhoa[itau][isolz1[ig]][0][isenz2[ig]][ipc];
1556  as001 = aertab->model[im]->pc_rhoa[itau][isolz2[ig]][0][isenz1[ig]][ipc];
1557  as101 = aertab->model[im]->pc_rhoa[itau][isolz2[ig]][0][isenz2[ig]][ipc];
1558 
1559  pc_coef[im][itau][ipc] = (1. - px)*(1. - rx) * as000 + px * rx * as101
1560  + (1. - px) * rx * as001 + px * (1. - rx) * as100;
1561  }
1562  } else {
1563  /* printf("coeffs: as000,ai000,ac000,ad000,ae000\n"); */
1564 
1565  for(itau=0;itau<ntau_870;itau++)
1566  for(ipc=0;ipc<npc;ipc++){
1567  as000 = aertab->model[im]->pc_rhoa[itau][isolz1[ig]][iphi1[ig]][isenz1[ig]][ipc];
1568  as100 = aertab->model[im]->pc_rhoa[itau][isolz2[ig]][iphi1[ig]][isenz1[ig]][ipc];
1569  as010 = aertab->model[im]->pc_rhoa[itau][isolz1[ig]][iphi2[ig]][isenz1[ig]][ipc];
1570  as110 = aertab->model[im]->pc_rhoa[itau][isolz2[ig]][iphi2[ig]][isenz1[ig]][ipc];
1571  as001 = aertab->model[im]->pc_rhoa[itau][isolz1[ig]][iphi1[ig]][isenz2[ig]][ipc];
1572  as011 = aertab->model[im]->pc_rhoa[itau][isolz1[ig]][iphi2[ig]][isenz2[ig]][ipc];
1573  as101 = aertab->model[im]->pc_rhoa[itau][isolz2[ig]][iphi1[ig]][isenz2[ig]][ipc];
1574  as111 = aertab->model[im]->pc_rhoa[itau][isolz2[ig]][iphi2[ig]][isenz2[ig]][ipc];
1575 
1576  pc_coef[im][itau][ipc] = (1. - rx)*(1. - qx)*(1. - px) * as000 + rx * qx * px * as111
1577  + rx * (1. - qx) * px * as101 + (1. - rx) * qx * (1. - px) * as010
1578  + rx * qx * (1. - px) * as110 + (1. - rx)*(1. - qx) * px * as001
1579  + (1. - rx) * qx * px * as011 + rx * (1. - qx)*(1. - px) * as100;
1580  }
1581  }
1582  }
1583 
1584  /* return pointers to coeffs for this geometry */
1585  // *pc_rhoa=&pc_coef[modnum][0][0];
1586  for(itau=0;itau<ntau_870;itau++)
1587  for(ipc=0;ipc<npc;ipc++){
1588  pc_rhoa[itau][ipc]=pc_coef[modnum][itau][ipc];
1589  }
1590 
1591  /*FILE *fp=fopen("/accounts/mzhang11/Rsdata/OCI/20220321/pc.txt","w");
1592 
1593  for(ipc=0;ipc<npc;ipc++){
1594  fprintf(fp,"%f %f\n",aertab->model[modnum]->pc_rhoa[0][0][0][0][ipc],aertab->model[modnum]->pc_components_rhoa[ipc][176]);
1595  }
1596 
1597  fclose(fp);*/
1598 
1599  return;
1600 }
1601 /* ---------------------------------------------------------------------------------------- */
1602 /* model_select_ahmad() - select two aerosol models whose epsilon values bracket the */
1603 /* the observed ms epsilon, eps_obs */
1604 /* */
1605 /* Z Ahmad July 2014. */
1606 
1607 /* ---------------------------------------------------------------------------------------- */
1608 int comp_epsilonT(epsilonTstr *x, epsilonTstr *y) {
1609  return (x->eps_obs < y->eps_obs ? -1 : 1);
1610 }
1611 
1612 void model_select_ahmad(int32_t nmodels, int32_t *mindx, float eps_pred[], float eps_obs, int32_t *modmin,
1613  int32_t *modmax, float *modrat) {
1614  static epsilonTstr epsilonT[MAXAERMOD];
1615 
1616  int im, im1, im2;
1617 
1618  // set-up table to keep model epsilon and model number pairs together
1619 
1620  for (im = 0; im < nmodels; im++) {
1621  epsilonT[im].eps_obs = eps_pred[im];
1622  epsilonT[im].modnum = im;
1623  /* printf("%d %7.4f %7.4f\n",im,eps_pred[im],eps_obs); */
1624  }
1625 
1626  // sort into ascending model epsilon order
1627 
1628  qsort(epsilonT, nmodels, sizeof (epsilonTstr),
1629  (int (*)(const void *, const void *)) comp_epsilonT);
1630 
1631  // find bounding epsilon indices in table
1632 
1633  for (im = 0; im < nmodels; im++) {
1634  if (eps_obs < epsilonT[im].eps_obs)
1635  break;
1636  }
1637 
1638  //if(im==0) //no lower bounding by M. Zhang
1639  //{
1640  // *modmin=-1;
1641  // return;
1642  //}
1643 
1644 
1645  im1 = MAX(MIN(im - 1, nmodels - 1), 0);
1646  im2 = MAX(MIN(im, nmodels - 1), 0);
1647 
1648 
1649  // convert table indices to model indices of the input order
1650  // compute model weighting
1651 
1652  *modmin = epsilonT[im1].modnum;
1653  *modmax = epsilonT[im2].modnum;
1654  *modrat = (eps_obs - epsilonT[im1].eps_obs) / (epsilonT[im2].eps_obs - epsilonT[im1].eps_obs);
1655  /* printf("%d %d %7.4f %7.4f %7.4f\n",im1,im2,eps_obs,epsilonT[im1].eps_obs,epsilonT[im2].eps_obs); */
1656 
1657  // If eps_obs is higer or lower than epsilon from table, then set the weight to 1
1658  if (*modmin == *modmax)
1659  *modrat = 1;
1660 
1661  return;
1662 }
1663 
1664 
1665 /*------------------------------------------------------------------------------------------ */
1666 /* comp_rhoa_ms_eps() - for a given model, computes the AOT and aerosol reflectance */
1667 /* */
1668 /* Z ahmad July2014 */
1669 
1670 /*------------------------------------------------------------------------------------------ */
1671 int comp_rhoa_ms_eps(int32_t nwave, float wave[], geom_str *geom,
1672  float tau_iwnir_l, int32_t modl, float tau_pred[], float rho_pred[],float derv_rhoa[], float derv_taua_tmp[])
1673 {
1674  float *ac, *bc, *cc, *dc, *ec;
1675  float ext_modl[nwave];
1676  float lg_tau_pred[nwave];
1677  float lg_rho_pred[nwave];
1678  int iw, iwtab;
1679 
1680  /* get the coefficients for lg_rho vs lg_aot */
1681 
1682  // Zia's function ---> something is wrong
1683  ms_eps_coef(modl, iwnir_l, wave, geom, &ac, &bc, &cc, &dc, &ec);
1684  // ms_eps_coef_cal(modl,nwave,solz,senz,phi,&ac,&bc,&cc,&dc,&ec);
1685 
1686 
1687  /* get the extinction coefficients and compute AOT at all wavelengths */
1688 
1689  for (iw = 0; iw < nwave; iw++) {
1690  iwtab = iwatab[iw];
1691  ext_modl[iw] = aertab->model[modl]->extc[iwtab];
1692  }
1693 
1694  /* printf("tau_pred[iw],tau_iwnir_l\n"); */
1695  for (iw = 0; iw < nwave; iw++) {
1696  tau_pred[iw] = (ext_modl[iw] / ext_modl[iwnir_l]) * tau_iwnir_l;
1697  lg_tau_pred[iw] = log(tau_pred[iw]);
1698 
1699  if(derv_taua_tmp){
1700 
1701  derv_taua_tmp[iw] = ext_modl[iw] / ext_modl[iwnir_l];
1702  derv_rhoa[iw] = 1 / tau_pred[iw]
1703  * (ext_modl[iw] / ext_modl[iwnir_l]);
1704  }
1705  }
1706 
1707  /* compute rho_pred */
1708 
1709  for (iw = 0; iw < nwave; iw++) {
1710  iwtab = iwatab[iw];
1711  lg_rho_pred[iw] = ac[iwtab] +
1712  bc[iwtab] * lg_tau_pred[iw] +
1713  cc[iwtab] * pow(lg_tau_pred[iw], 2) +
1714  dc[iwtab] * pow(lg_tau_pred[iw], 3) +
1715  ec[iwtab] * pow(lg_tau_pred[iw], 4);
1716  rho_pred[iw] = exp(lg_rho_pred[iw]);
1717 
1718  if(derv_taua_tmp){
1719  derv_rhoa[iw] *= (bc[iwtab] + 2 * cc[iwtab] * lg_tau_pred[iw]
1720  + 3 * dc[iwtab] * pow(lg_tau_pred[iw], 2)
1721  + 4 * ec[iwtab] * pow(lg_tau_pred[iw], 3));
1722  derv_rhoa[iw] *= rho_pred[iw];
1723  }
1724  }
1725 
1726 
1727  return (0);
1728 }
1729 
1730 /*------------------------------------------------------------------------------------------ */
1731 /* comp_rhoa_pca() - for a given model, computes the AOT and aerosol reflectance */
1732 /* */
1733 /* M. Zhang, Oct. 2022 */
1734 
1735 /*------------------------------------------------------------------------------------------ */
1736 int comp_rhoa_pca(int32_t nwave, float wave[], geom_str *geom,
1737  float tau_iwnir_l, int32_t modl, float tau_pred[], float rho_pred[],float derv_rhoa[], float derv_taua_tmp[])
1738  {
1739  static int firstcall=1;
1740  static float **pc_rhoa;
1741  static int npc, ntau_870;
1742  aermodstr *aermod=aertab->model[modl];
1743 
1744  int iw,itau,ipc, itau1,itau2;
1745  float rhoa1,rhoa2;
1746 
1747  if(firstcall){
1748  firstcall=0;
1749  ntau_870=aertab->ntau_870;
1750  npc=aertab->npc;
1751  pc_rhoa=(float **)malloc(aertab->ntau_870*sizeof(float *));
1752 
1753  for(itau=0;itau<ntau_870;itau++)
1754  pc_rhoa[itau]=(float *)malloc(aertab->npc*sizeof(float));
1755  }
1756 
1757  /* if(tau_iwnir_l<aermod->tau_870[0]|| tau_iwnir_l>aermod->tau_870[ntau_870-1]){
1758  printf("tau_870 is out of the range in LUTs\n");
1759  return -1;
1760  }*/
1761 
1762 
1763  for(itau=0;itau<ntau_870;itau++){
1764  if(tau_iwnir_l<aermod->tau_870[itau])
1765  break;
1766  }
1767  itau1=MAX(itau-1,0);
1768  itau2=MIN(itau,ntau_870-1);
1769 
1770  if(itau1==0)
1771  itau2=1;
1772  if(itau2==ntau_870-1)
1773  itau1=itau2-1;
1774 
1775  get_pc_rhoa(modl,geom,pc_rhoa);
1776 
1777  for(iw=0;iw<nwave;iw++){
1778  rhoa1=0.;
1779  rhoa2=0.;
1780 
1781  for(ipc=0;ipc<npc;ipc++){
1782  rhoa1+=pc_rhoa[itau1][ipc]*aermod->pc_components_rhoa[ipc][iw];
1783  rhoa2+=pc_rhoa[itau2][ipc]*aermod->pc_components_rhoa[ipc][iw];
1784  }
1785  rhoa1=rhoa1+aermod->pc_mean_rhoa[iw];
1786  rhoa2=rhoa2+aermod->pc_mean_rhoa[iw];
1787  rho_pred[iw]=rhoa1+(rhoa2-rhoa1)*(tau_iwnir_l-aermod->tau_870[itau1])/(aermod->tau_870[itau2]-aermod->tau_870[itau1]);
1788  tau_pred[iw]=tau_iwnir_l*aermod->extc[iw]/aermod->extc[iwnir_l];
1789 
1790  if(derv_taua_tmp){
1791  derv_taua_tmp[iw]=aermod->extc[iw]/aermod->extc[iwnir_l];
1792  derv_rhoa [iw]=(rhoa2-rhoa1)/(aermod->tau_870[itau2]-aermod->tau_870[itau1]);
1793  }
1794  }
1795 
1796  return (0);
1797 }
1798 
1799 /*------------------------------------------------------------------------------------------ */
1800 /* comp_rhoa_ms_eps() - for a given model, computes the AOT and aerosol reflectance */
1801 /* */
1802 /* Z ahmad July2014 */
1803 /* Modified by Amir Ibrahim January 2015 for linear space coefficients */
1804 
1805 /*------------------------------------------------------------------------------------------ */
1806 int comp_rhoa_ms_eps_lin(int32_t nwave, float wave[], geom_str *geom,
1807  float tau_iwnir_l, int32_t modl, float tau_pred[], float rho_pred[])
1808  {
1809  float *ac, *bc, *cc, *dc, *ec;
1810  float ext_modl[nwave];
1811  float lg_tau_pred[nwave];
1812  float lg_rho_pred[nwave];
1813  int iw, iwtab;
1814 
1815  /* get the coefficients for lg_rho vs lg_aot */
1816 
1817  // Zia's function ---> something is wrong
1818  ms_eps_coef(modl, iwnir_l, wave, geom, &ac, &bc, &cc, &dc, &ec);
1819  // ms_eps_coef_cal(modl,nwave,geom,&ac,&bc,&cc,&dc,&ec);
1820 
1821 
1822  /* get the extinction coefficients and compute AOT at all wavelengths */
1823 
1824  for (iw = 0; iw < nwave; iw++) {
1825  iwtab = iwatab[iw];
1826  ext_modl[iw] = aertab->model[modl]->extc[iwtab];
1827  }
1828 
1829  /* printf("tau_pred[iw],tau_iwnir_l\n"); */
1830  for (iw = 0; iw < nwave; iw++) {
1831  tau_pred[iw] = (ext_modl[iw] / ext_modl[iwnir_l]) * tau_iwnir_l;
1832  lg_tau_pred[iw] = (tau_pred[iw]);
1833  }
1834 
1835  /* compute rho_pred */
1836 
1837  for (iw = 0; iw < nwave; iw++) {
1838  iwtab = iwatab[iw];
1839  lg_rho_pred[iw] = ac[iwtab] +
1840  bc[iwtab] * lg_tau_pred[iw] +
1841  cc[iwtab] * pow(lg_tau_pred[iw], 2) +
1842  dc[iwtab] * pow(lg_tau_pred[iw], 3) +
1843  ec[iwtab] * pow(lg_tau_pred[iw], 4);
1844  rho_pred[iw] = (lg_rho_pred[iw]);
1845  }
1846 
1847 
1848  return (0);
1849 }
1850 
1851 /*------------------------------------------------------------------------------------------*/
1852 /* ahmad_atm_corr_pca() - compute aerosol reflectance at all wavelengths using pca LUTs */
1853 /* */
1854 /* M. Zhang, Oct. 2022 */
1855 
1856 /*---------------------------------------------------------------------------------------- */
1857 
1858 int ahmad_atm_corr_pca(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l,
1859  int32_t nmodels, int32_t mindx[],
1860  geom_str *geom, float wv, float rhoa[],
1861  int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir,
1862  float tau_pred_max[], float tau_pred_min[], float rho_pred_max[], float rho_pred_min[],
1863  float tau_aer[], float rho_aer[],int ip,uncertainty_t *uncertainty) {
1864 
1865  static int firstcall=1;
1866  static float **pc_rhoa;
1867  static int npc, ntau_870;
1868  aermodstr *aermod;
1869  float tau_iwnir_l[nmodels];
1870  float rho_iwnir_s_pred[nmodels];
1871  float eps_pred[nmodels];
1872  int im, modl;
1873  int im1, im2;
1874  float mwt;
1875 
1876  float derv_taua_rhoa[nmodels]; //derivative of taua[aer_l] to rha[aer_l]
1877  float derv_eps_rhoa_l[nmodels];
1878  float *derv_rhoa_min=NULL,*derv_rhoa_max=NULL; //derivative of rhoa[]to taua[aer_l] for aermodmin and aermodmax
1879  float *derv_taua_min=NULL,*derv_taua_max=NULL; //derivative of taua[]to taua[aer_l] for aermodmin and aermodmax
1880  float derv_mwt_rhoa_s=0., derv_mwt_rhoa_l=0.,derv_mwt_taua_l=0.,derv_mwt_rhow_l=0.;
1881 
1882  float eps_obs;//,deps_obs;
1883 
1884  float derv_eps_Lrc_s,derv_eps_Lrc_l,derv_eps_taua_l,derv_eps_rhow_l,derv_Lg_taua_l;
1885  float derv_eps_mod[4][nmodels]; //derivative of modeled eps to 0: rhorc_s, 1: rhorc_l, 2: taua_l and 3: t_sen*t_sol*rhow[aer_l]
1886 
1887  if(uncertainty){
1888  derv_eps_Lrc_s = uncertainty->derv_eps_Lrc_s;
1889  derv_eps_Lrc_l = uncertainty->derv_eps_Lrc_l;
1890  derv_eps_taua_l = uncertainty->derv_eps_taua_l;
1891  derv_eps_rhow_l = uncertainty->derv_eps_rhow_l;
1892  derv_Lg_taua_l = uncertainty->derv_Lg_taua[iwnir_l];
1893 
1894  derv_rhoa_min=(float *)malloc(nwave*sizeof(float));
1895  derv_rhoa_max=(float *)malloc(nwave*sizeof(float));
1896  derv_taua_min=(float *)malloc(nwave*sizeof(float));
1897  derv_taua_max=(float *)malloc(nwave*sizeof(float));
1898  }
1899 
1900  int iw,itau,ipc;
1901 
1902  int status = 0.0;
1903  static float *rhoa_modl_s,*rhoa_modl_l;
1904 
1905  if(firstcall){
1906  firstcall=0;
1907  ntau_870=aertab->ntau_870;
1908  npc=aertab->npc;
1909  rhoa_modl_s=(float *)malloc(aertab->ntau_870*sizeof(float));
1910  rhoa_modl_l=(float *)malloc(aertab->ntau_870*sizeof(float));
1911  pc_rhoa=(float **)malloc(aertab->ntau_870*sizeof(float *));
1912 
1913  for(itau=0;itau<aertab->ntau_870;itau++)
1914  pc_rhoa[itau]=(float *)malloc(aertab->npc*sizeof(float));
1915  }
1916 
1917 
1918  /* compute the observed epsilon */
1919 
1920  eps_obs = rhoa[iwnir_s] / rhoa[iwnir_l];
1921 
1922  /* printf("rho_869,rho_748,eps_obs\n"); */
1923  /* printf("%10.5f %10.5f %10.5f\n",rhoa[iwnir_l],rhoa[iwnir_s],eps_obs); */
1924 
1925 
1926  // compute MS epsilon for all nmodels. note that nmodels may be only a subset of
1927  // the full model suite. mindx maps from subset index to full index in suite
1928 
1929 
1930  for (im = 0; im < nmodels; im++) {
1931 
1932  modl = mindx[im]; // index in full model suite, needed for coefficient look-up
1933  aermod=aertab->model[modl];
1934 
1935  get_pc_rhoa(modl,geom,pc_rhoa);
1936 
1937  for(itau=0;itau<ntau_870;itau++){
1938  rhoa_modl_l[itau]=0;
1939  rhoa_modl_s[itau]=0;
1940 
1941  for(ipc=0;ipc<npc;ipc++){
1942  rhoa_modl_s[itau]+=pc_rhoa[itau][ipc]*aermod->pc_components_rhoa[ipc][iwnir_s];//
1943  rhoa_modl_l[itau]+=pc_rhoa[itau][ipc]*aermod->pc_components_rhoa[ipc][iwnir_l];
1944  }
1945  rhoa_modl_s[itau]+=aermod->pc_mean_rhoa[iwnir_s];
1946  rhoa_modl_l[itau]+=aermod->pc_mean_rhoa[iwnir_l];
1947  }
1948 
1949  /* compute model epsilon */
1950  if(rhoa[iwnir_l]<rhoa_modl_l[0])
1951  itau=1;
1952  else if (rhoa[iwnir_l]>rhoa_modl_l[ntau_870-1])
1953  itau=ntau_870-1;
1954  else{
1955  for(itau=1;itau<ntau_870;itau++){
1956  if(rhoa[iwnir_l]<rhoa_modl_l[itau] && rhoa[iwnir_l]>rhoa_modl_l[itau-1])
1957  break;
1958  }
1959  }
1960  tau_iwnir_l[im]=aermod->tau_870[itau]+(aermod->tau_870[itau]-aermod->tau_870[itau-1])*(rhoa[iwnir_l]-rhoa_modl_l[itau])/(rhoa_modl_l[itau]-rhoa_modl_l[itau-1]);
1961  rho_iwnir_s_pred[im]=rhoa_modl_s[itau]+(rhoa_modl_s[itau]-rhoa_modl_s[itau-1])*(tau_iwnir_l[im]-aermod->tau_870[itau])/(aermod->tau_870[itau]-aermod->tau_870[itau-1]);
1962 
1963  // rho_iwnir_s_pred[im]=exp(rho_iwnir_s_pred[im]);
1964  eps_pred[im] = rho_iwnir_s_pred[im] / rhoa[iwnir_l];
1965 
1967  if(uncertainty){
1968  derv_taua_rhoa[im]=(aermod->tau_870[itau]-aermod->tau_870[itau-1])/(rhoa_modl_l[itau]-rhoa_modl_l[itau-1]);
1969  derv_eps_rhoa_l[im]=derv_taua_rhoa[im]*((rhoa_modl_s[itau]-rhoa_modl_s[itau-1])/(aermod->tau_870[itau]-aermod->tau_870[itau-1]));
1970 
1971  derv_eps_rhoa_l[im]=derv_eps_rhoa_l[im]/rhoa[iwnir_l]-rho_iwnir_s_pred[im]/rhoa[iwnir_l]/rhoa[iwnir_l];
1972  derv_eps_mod[1][im]=derv_eps_rhoa_l[im];
1973  derv_eps_mod[2][im] = -derv_eps_rhoa_l[im] * uncertainty->derv_Lg_taua[iwnir_l];
1974  derv_eps_mod[3][im] = -derv_eps_rhoa_l[im];
1975  }
1976  }
1977 
1978  *epsnir = eps_obs;
1979 
1980 
1981  /* now, find the bounding models, but skip this if we only have one */
1982  /* model (as when vicariously calibrating) */
1983 
1984  if (nmodels > 1) {
1985 
1986  /* locate two model_epsilons that bracket the observed epsilon */
1987  /* this will return the model numbers for the subset of models */
1988 
1989  model_select_ahmad(nmodels, mindx, eps_pred, eps_obs, &im1, &im2, &mwt);
1990 
1991  if(uncertainty){
1992  if (im1 == im2) {
1993  for(iw=iwnir_s;iw<=iwnir_l;iw++)
1994  uncertainty->derv_modrat_rhorc[iw-iwnir_s]=0.;
1995  uncertainty->derv_modrat_taua_l=0.;
1996  }
1997  else {
1998  derv_mwt_rhoa_s = 1 / (eps_pred[im2] - eps_pred[im1])
1999  * derv_eps_Lrc_s;
2000  //derv_mwt_taua_s = 1 / (eps_pred[im2] - eps_pred[im1])
2001  // * derv_eps_taua_s;
2002 
2003  derv_mwt_rhoa_l = 1 / (eps_pred[im2] - eps_pred[im1])
2004  * derv_eps_Lrc_l;
2005  derv_mwt_rhoa_l -= ((mwt / (eps_pred[im2] - eps_pred[im1])
2006  * derv_eps_mod[1][im2]));
2007  derv_mwt_rhoa_l += ((eps_obs - eps_pred[im2])
2008  / pow(eps_pred[im2] - eps_pred[im1], 2)
2009  * derv_eps_mod[1][im1]);
2010 
2011  derv_mwt_taua_l = 1 / (eps_pred[im2] - eps_pred[im1])
2012  * derv_eps_taua_l;
2013  derv_mwt_taua_l -= ((mwt / (eps_pred[im2] - eps_pred[im1])
2014  * derv_eps_mod[2][im2]));
2015  derv_mwt_taua_l += ((eps_obs - eps_pred[im2])
2016  / pow(eps_pred[im2] - eps_pred[im1], 2)
2017  * derv_eps_mod[2][im1]);
2018 
2019  derv_mwt_rhow_l = 1 / (eps_pred[im2] - eps_pred[im1])
2020  * derv_eps_rhow_l;
2021  derv_mwt_rhow_l -= ((mwt / (eps_pred[im2] - eps_pred[im1])
2022  * derv_eps_mod[3][im2]));
2023  derv_mwt_rhow_l += ((eps_obs - eps_pred[im2])
2024  / pow(eps_pred[im2] - eps_pred[im1], 2)
2025  * derv_eps_mod[3][im1]);
2026 
2027  uncertainty->derv_modrat_rhorc[0] = derv_mwt_rhoa_s;
2028  uncertainty->derv_modrat_rhorc[iwnir_l-iwnir_s] = derv_mwt_rhoa_l;
2029  uncertainty->derv_modrat_taua_l = derv_mwt_taua_l;
2030  uncertainty->derv_modrat_rhow_l = derv_mwt_rhow_l;
2031  }
2032  }
2033  } else {
2034 
2035  /* single model case (allows fixed model by limiting model suite) */
2036 
2037  im1 = 0;
2038  im2 = 0;
2039  mwt = 0.0;
2040  }
2041 
2042  /* map selection to full suite for subsequent processing and return */
2043 
2044  *modmin = mindx[im1];
2045  *modmax = mindx[im2];
2046  *modrat = mwt;
2047 
2048  /* compute tau_pred and rho_predicted */
2049 
2050  if(comp_rhoa_pca(nwave, wave, geom, tau_iwnir_l[im1], *modmin, tau_pred_min, rho_pred_min,derv_rhoa_min,derv_taua_min) !=0)
2051  return -1;
2052  if(comp_rhoa_pca(nwave, wave, geom, tau_iwnir_l[im2], *modmax, tau_pred_max, rho_pred_max,derv_rhoa_max,derv_taua_max) !=0)
2053  return -1;
2054 
2055  /* compute weighted tau_aer and rho_aer */
2056 
2057  for (iw = 0; iw < nwave; iw++) {
2058  tau_aer[iw] = (1.0 - mwt) * tau_pred_min[iw] + mwt * tau_pred_max[iw];
2059  rho_aer[iw] = (1.0 - mwt) * rho_pred_min[iw] + mwt * rho_pred_max[iw];
2060 
2061 
2062  if(uncertainty){
2063  uncertainty->derv_La_rhorc[iw][iwnir_l-iwnir_s] = (1.0 - mwt) * derv_rhoa_min[iw]
2064  * derv_taua_rhoa[im1]
2065  + mwt * derv_rhoa_max[iw] * derv_taua_rhoa[im2]
2066  + (rho_pred_max[iw] - rho_pred_min[iw]) * derv_mwt_rhoa_l;
2067  uncertainty->derv_La_taua_l[iw] = -(1.0 - mwt) * derv_rhoa_min[iw]
2068  * derv_taua_rhoa[im1] * derv_Lg_taua_l
2069  - mwt * derv_rhoa_max[iw] * derv_taua_rhoa[im2]
2070  * derv_Lg_taua_l
2071  + (rho_pred_max[iw] - rho_pred_min[iw]) * derv_mwt_taua_l;
2072  uncertainty->derv_La_rhorc[iw][0] = (rho_pred_max[iw] - rho_pred_min[iw])
2073  * derv_mwt_rhoa_s;
2074  uncertainty->derv_La_rhow_l[iw] = -(1.0 - mwt) * derv_rhoa_min[iw]
2075  * derv_taua_rhoa[im1]
2076  - mwt * derv_rhoa_max[iw] * derv_taua_rhoa[im2]
2077  + (rho_pred_max[iw] - rho_pred_min[iw]) * derv_mwt_rhow_l;
2078  // uncertainty->derv_taua_s[iw] = (rho_pred_max[iw] - rho_pred_min[iw])
2079  // * derv_mwt_taua_s;
2080 
2081  uncertainty->derv_taua_rhorc[iw][iwnir_l-iwnir_s]= (1.0 - mwt) * derv_taua_min[iw]
2082  * derv_taua_rhoa[im1]
2083  + mwt * derv_taua_max[iw] * derv_taua_rhoa[im2]
2084  + (tau_pred_max[iw] - tau_pred_min[iw]) * derv_mwt_rhoa_l;
2085  uncertainty->derv_taua_taua_l[iw] = -(1.0 - mwt) * derv_taua_min[iw]
2086  * derv_taua_rhoa[im1] * derv_Lg_taua_l
2087  - mwt * derv_taua_max[iw] * derv_taua_rhoa[im2]
2088  * derv_Lg_taua_l
2089  + (tau_pred_max[iw] - tau_pred_min[iw]) * derv_mwt_taua_l;
2090  uncertainty->derv_taua_rhorc[iw][0] = (tau_pred_max[iw] - tau_pred_min[iw])
2091  * derv_mwt_rhoa_s;
2092  uncertainty->derv_taua_rhow_l[iw] = -(1.0 - mwt) * derv_taua_min[iw]
2093  * derv_taua_rhoa[im1]
2094  - mwt * derv_taua_max[iw] * derv_taua_rhoa[im2]
2095  + (tau_pred_max[iw] - tau_pred_min[iw]) * derv_mwt_rhow_l;
2096  //uncertainty->derv_taua_taua_s[iw] = (tau_pred_max[iw] - tau_pred_min[iw])
2097  // * derv_mwt_taua_s;
2098 
2099  // derv_taua[0][iw][0] = 0.;
2100  uncertainty->derv_taua_min_rhorc_l[iw] = derv_taua_min[iw] * derv_taua_rhoa[im1];
2101  uncertainty->derv_taua_min_taua_l[iw] = -derv_taua_min[iw] * derv_taua_rhoa[im1]
2102  * derv_Lg_taua_l;
2103  uncertainty->derv_taua_min_rhow_l[iw] = -derv_taua_min[iw] * derv_taua_rhoa[im1];
2104  // derv_taua[0][iw][4] = 0.;
2105 
2106  // derv_taua[1][iw][0] = 0.;
2107  uncertainty->derv_taua_max_rhorc_l[iw]= derv_taua_max[iw] * derv_taua_rhoa[im2];
2108  uncertainty->derv_taua_max_taua_l [iw]= -derv_taua_max[iw] * derv_taua_rhoa[im2]
2109  * derv_Lg_taua_l;
2110  uncertainty->derv_taua_max_rhow_l [iw]= -derv_taua_max[iw] * derv_taua_rhoa[im2];
2111  //derv_taua[1][iw][4] = 0.;
2112  }
2113  }
2114 
2115  if(uncertainty){
2116  free(derv_rhoa_min);
2117  free(derv_rhoa_max);
2118  free(derv_taua_min);
2119  free(derv_taua_max);
2120  }
2121 
2122  return (status);
2123 }
2124 /*------------------------------------------------------------------------------------------*/
2125 /* ahmad_atm_corr() - compute aerosol reflectance at all wavelengths */
2126 /* */
2127 /* Z Ahmad. July 2014 */
2128 
2129 /*---------------------------------------------------------------------------------------- */
2130 int ahmad_atm_corr(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l,
2131  int32_t nmodels, int32_t mindx[],
2132  geom_str *geom, float wv, float rhoa[],
2133  int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir,
2134  float tau_pred_max[], float tau_pred_min[], float rho_pred_max[], float rho_pred_min[],
2135  float tau_aer[], float rho_aer[],int ip,uncertainty_t *uncertainty) {
2136 
2137 
2138  int status = 0.0;
2139  float eps_obs; //,deps_obs;
2140 
2141  /* compute the observed epsilon */
2142 
2143  eps_obs = rhoa[iwnir_s] / rhoa[iwnir_l];
2144 
2145  if (use_pca_lut) {
2146  if (uncertainty) {
2147  uncertainty->derv_eps_Lrc_s = 1 / rhoa[iwnir_l];
2148  uncertainty->derv_eps_Lrc_l = -eps_obs / rhoa[iwnir_l];
2149 
2150  if (uncertainty->ratio_rhow[iwnir_s - iwnir_s] != 0.) {
2151  uncertainty->derv_eps_rhow_l =
2152  -1 / (rhoa[iwnir_l]) * uncertainty->ratio_rhow[iwnir_s - iwnir_s];
2153  uncertainty->derv_eps_rhow_l += eps_obs / rhoa[iwnir_l];
2154  }
2155  }
2156  status = ahmad_atm_corr_pca(sensorID,wave, nwave, iwnir_s, iwnir_l, nmodels, mindx, geom, wv, rhoa,
2157  modmin, modmax, modrat, epsnir, tau_pred_max, tau_pred_min, rho_pred_max,
2158  rho_pred_min, tau_aer, rho_aer, ip, uncertainty);
2159  return status;
2160  }
2161  float *ac, *bc, *cc, *dc, *ec;
2162  float ext_iwnir_l, ext_iwnir_s;
2163  double ax, bx, cx, fx;
2164  float tau_iwnir_l[nmodels];
2165  float lg_tau_iwnir_s[nmodels], tau_iwnir_s[nmodels];
2166  float lg_rho_iwnir_s_pred[nmodels], rho_iwnir_s_pred[nmodels];
2167  float eps_pred[nmodels];
2168  int im, modl;
2169  int im1, im2;
2170  float mwt;
2171  float lg_tau_iwnir_l;
2172  int iwtab_l, iwtab_s;
2173 
2174  float derv_taua_rhoa[nmodels]; //derivative of taua[aer_l] to rhoa[aer_l]
2175  float derv_eps_rhoa_l[nmodels];
2176  float *derv_rhoa_min=NULL,*derv_rhoa_max=NULL; //derivative of rhoa[]to taua[aer_l] for aermodmin and aermodmax
2177  float *derv_taua_min=NULL,*derv_taua_max=NULL; //derivative of taua[]to taua[aer_l] for aermodmin and aermodmax
2178  float derv_mwt_rhoa_s=0., derv_mwt_rhoa_l=0.,derv_mwt_taua_l=0.,derv_mwt_rhow_l=0.;
2179 
2180  float derv_eps_Lrc_s,derv_eps_Lrc_l,derv_eps_taua_l,derv_eps_rhow_l,derv_Lg_taua_l;
2181  float derv_eps_mod[4][nmodels]; //derivative of modeled eps to 0: rhorc_s, 1: rhorc_l, 2: taua_l and 3: t_sen*t_sol*rhow[aer_l]
2182 
2183  int iw;
2184 
2185  /* printf("rho_869,rho_748,eps_obs\n"); */
2186  /* printf("%10.5f %10.5f %10.5f\n",rhoa[iwnir_l],rhoa[iwnir_s],eps_obs); */
2187 
2188  // compute MS epsilon for all nmodels. note that nmodels may be only a subset of
2189  // the full model suite. mindx maps from subset index to full index in suite
2190  if (uncertainty) {
2191  derv_rhoa_min = (float *)malloc(nwave * sizeof(float));
2192  derv_rhoa_max = (float *)malloc(nwave * sizeof(float));
2193  derv_taua_min = (float *)malloc(nwave * sizeof(float));
2194  derv_taua_max = (float *)malloc(nwave * sizeof(float));
2195 
2196  derv_eps_Lrc_s = uncertainty->derv_eps_Lrc_s;
2197  derv_eps_Lrc_l = uncertainty->derv_eps_Lrc_l;
2198  derv_eps_taua_l = uncertainty->derv_eps_taua_l;
2199  derv_eps_rhow_l = uncertainty->derv_eps_rhow_l;
2200  derv_Lg_taua_l = uncertainty->derv_Lg_taua[iwnir_l];
2201  }
2202 
2203  for (im = 0; im < nmodels; im++) {
2204 
2205  modl = mindx[im]; // index in full model suite, needed for coefficient look-up
2206 
2207  /* compute AOT at longest aerosol wavelength (iwnir_l) */
2208 
2209  // Zia's function ---> something is wrong
2210  //ms_eps_coef(modl,iwnir_l,wave,solz,senz,phi,&ac,&bc,&cc,&dc,&ec);
2211 
2212  // ms_eps_coef_cal(modl,nwave,solz,senz,phi,&ac,&bc,&cc,&dc,&ec);
2213  ms_eps_coef(modl, iwnir_l, wave, geom, &ac, &bc, &cc, &dc, &ec);
2214  iwtab_l = iwatab[iwnir_l];
2215  iwtab_s = iwatab[iwnir_s];
2216 
2217  ax = (double) ac[iwtab_l] - log((double) rhoa[iwnir_l]);
2218  bx = (double) bc[iwtab_l];
2219  cx = (double) cc[iwtab_l];
2220 
2221  fx = bx * bx - 4.0 * ax*cx;
2222  if (fx > 0.0 && cx != 0.0) {
2223  lg_tau_iwnir_l = 0.5 * (-bx + sqrt(fx)) / cx;
2224  if(uncertainty)
2225  derv_taua_rhoa[im] = 1 / rhoa[iwnir_l] / sqrt(fx);
2226 
2227  tau_iwnir_l[im] = exp(lg_tau_iwnir_l);
2228  if(uncertainty)
2229  derv_taua_rhoa[im]*=tau_iwnir_l[im];
2230  } else {
2231  status = 1;
2232  break; // TODO: need to think about it
2233  }
2234 
2235  /* compute AOT at shortest aerosol wavelength (iwnir_s) */
2236 
2237  ext_iwnir_l = aertab->model[modl]->extc[iwtab_l];
2238  ext_iwnir_s = aertab->model[modl]->extc[iwtab_s];
2239 
2240  tau_iwnir_s[im] = (ext_iwnir_s / ext_iwnir_l) * tau_iwnir_l[im];
2241  lg_tau_iwnir_s[im] = log(tau_iwnir_s[im]);
2242 
2243  if(uncertainty)
2244  derv_eps_rhoa_l[im]=1/tau_iwnir_s[im]*(ext_iwnir_s / ext_iwnir_l)*derv_taua_rhoa[im];
2245 
2246 
2247  /* compute reflectance at (iwnir_s) */
2248 
2249  lg_rho_iwnir_s_pred[im] = ac[iwtab_s] + bc[iwtab_s] * lg_tau_iwnir_s[im] +
2250  cc[iwtab_s] * pow(lg_tau_iwnir_s[im], 2) +
2251  dc[iwtab_s] * pow(lg_tau_iwnir_s[im], 3) +
2252  ec[iwtab_s] * pow(lg_tau_iwnir_s[im], 4);
2253 
2254  if(uncertainty)
2255  derv_eps_rhoa_l[im]=( bc[iwtab_s]+ 2*cc[iwtab_s]*lg_tau_iwnir_s[im]+3*dc[iwtab_s]*pow(lg_tau_iwnir_s[im], 2)+4*ec[iwtab_s] * pow(lg_tau_iwnir_s[im], 3) )*derv_eps_rhoa_l[im];
2256 
2257  rho_iwnir_s_pred[im] = exp(lg_rho_iwnir_s_pred[im]);
2258 
2259  if(uncertainty)
2260  derv_eps_rhoa_l[im]=rho_iwnir_s_pred[im]*derv_eps_rhoa_l[im];
2261 
2262  /* compute model epsilon */
2263 
2264  eps_pred[im] = rho_iwnir_s_pred[im] / rhoa[iwnir_l];
2265 
2267  if(uncertainty){
2268  derv_eps_rhoa_l[im]=derv_eps_rhoa_l[im]/rhoa[iwnir_l]-rho_iwnir_s_pred[im]/rhoa[iwnir_l]/rhoa[iwnir_l];
2269  derv_eps_mod[1][im]=derv_eps_rhoa_l[im];
2270  derv_eps_mod[2][im] = -derv_eps_rhoa_l[im] * uncertainty->derv_Lg_taua[iwnir_l];
2271  derv_eps_mod[3][im] = -derv_eps_rhoa_l[im];
2272  }
2273  }
2274 
2275 
2276  *epsnir = eps_obs;
2277 
2278 
2279  /* now, find the bounding models, but skip this if we only have one */
2280  /* model (as when vicariously calibrating) */
2281 
2282  if (nmodels > 1) {
2283 
2284  /* locate two model_epsilons that bracket the observed epsilon */
2285  /* this will return the model numbers for the subset of models */
2286 
2287  model_select_ahmad(nmodels, mindx, eps_pred, eps_obs, &im1, &im2, &mwt);
2288 
2289  if(uncertainty){
2290  if (im1 == im2) {
2291  for(iw=iwnir_s;iw<=iwnir_l;iw++)
2292  uncertainty->derv_modrat_rhorc[iw-iwnir_s]=0.;
2293  uncertainty->derv_modrat_taua_l=0.;
2294  }
2295  else {
2296  derv_mwt_rhoa_s = 1 / (eps_pred[im2] - eps_pred[im1])
2297  * derv_eps_Lrc_s;
2298  //derv_mwt_taua_s = 1 / (eps_pred[im2] - eps_pred[im1])
2299  // * derv_eps_taua_s;
2300 
2301  derv_mwt_rhoa_l = 1 / (eps_pred[im2] - eps_pred[im1])
2302  * derv_eps_Lrc_l;
2303  derv_mwt_rhoa_l -= ((mwt / (eps_pred[im2] - eps_pred[im1])
2304  * derv_eps_mod[1][im2]));
2305  derv_mwt_rhoa_l += ((eps_obs - eps_pred[im2])
2306  / pow(eps_pred[im2] - eps_pred[im1], 2)
2307  * derv_eps_mod[1][im1]);
2308 
2309  derv_mwt_taua_l = 1 / (eps_pred[im2] - eps_pred[im1])
2310  * derv_eps_taua_l;
2311  derv_mwt_taua_l -= ((mwt / (eps_pred[im2] - eps_pred[im1])
2312  * derv_eps_mod[2][im2]));
2313  derv_mwt_taua_l += ((eps_obs - eps_pred[im2])
2314  / pow(eps_pred[im2] - eps_pred[im1], 2)
2315  * derv_eps_mod[2][im1]);
2316 
2317  derv_mwt_rhow_l = 1 / (eps_pred[im2] - eps_pred[im1])
2318  * derv_eps_rhow_l;
2319  derv_mwt_rhow_l -= ((mwt / (eps_pred[im2] - eps_pred[im1])
2320  * derv_eps_mod[3][im2]));
2321  derv_mwt_rhow_l += ((eps_obs - eps_pred[im2])
2322  / pow(eps_pred[im2] - eps_pred[im1], 2)
2323  * derv_eps_mod[3][im1]);
2324 
2325  uncertainty->derv_modrat_rhorc[0] = derv_mwt_rhoa_s;
2326  uncertainty->derv_modrat_rhorc[iwnir_l-iwnir_s] = derv_mwt_rhoa_l;
2327  uncertainty->derv_modrat_taua_l = derv_mwt_taua_l;
2328  uncertainty->derv_modrat_rhow_l = derv_mwt_rhow_l;
2329  }
2330  }
2331  } else {
2332 
2333  /* single model case (allows fixed model by limiting model suite) */
2334 
2335  im1 = 0;
2336  im2 = 0;
2337  mwt = 0.0;
2338  }
2339 
2340  /* map selection to full suite for subsequent processing and return */
2341 
2342  *modmin = mindx[im1];
2343  *modmax = mindx[im2];
2344  *modrat = mwt;
2345 
2346  /* compute tau_pred and rho_predicted */
2347 
2348  comp_rhoa_ms_eps(nwave, wave, geom, tau_iwnir_l[im1], *modmin, tau_pred_min, rho_pred_min,derv_rhoa_min,derv_taua_min);
2349  comp_rhoa_ms_eps(nwave, wave, geom, tau_iwnir_l[im2], *modmax, tau_pred_max, rho_pred_max,derv_rhoa_max,derv_taua_max);
2350 
2351  /* compute weighted tau_aer and rho_aer */
2352 
2353  for (iw = 0; iw < nwave; iw++) {
2354  tau_aer[iw] = (1.0 - mwt) * tau_pred_min[iw] + mwt * tau_pred_max[iw];
2355  rho_aer[iw] = (1.0 - mwt) * rho_pred_min[iw] + mwt * rho_pred_max[iw];
2356 
2357 
2358  if(uncertainty){
2359  uncertainty->derv_La_rhorc[iw][iwnir_l-iwnir_s] = (1.0 - mwt) * derv_rhoa_min[iw]
2360  * derv_taua_rhoa[im1]
2361  + mwt * derv_rhoa_max[iw] * derv_taua_rhoa[im2]
2362  + (rho_pred_max[iw] - rho_pred_min[iw]) * derv_mwt_rhoa_l;
2363  uncertainty->derv_La_taua_l[iw] = -(1.0 - mwt) * derv_rhoa_min[iw]
2364  * derv_taua_rhoa[im1] * derv_Lg_taua_l
2365  - mwt * derv_rhoa_max[iw] * derv_taua_rhoa[im2]
2366  * derv_Lg_taua_l
2367  + (rho_pred_max[iw] - rho_pred_min[iw]) * derv_mwt_taua_l;
2368  uncertainty->derv_La_rhorc[iw][0] = (rho_pred_max[iw] - rho_pred_min[iw])
2369  * derv_mwt_rhoa_s;
2370  uncertainty->derv_La_rhow_l[iw] = -(1.0 - mwt) * derv_rhoa_min[iw]
2371  * derv_taua_rhoa[im1]
2372  - mwt * derv_rhoa_max[iw] * derv_taua_rhoa[im2]
2373  + (rho_pred_max[iw] - rho_pred_min[iw]) * derv_mwt_rhow_l;
2374  // uncertainty->derv_taua_s[iw] = (rho_pred_max[iw] - rho_pred_min[iw])
2375  // * derv_mwt_taua_s;
2376 
2377  uncertainty->derv_taua_rhorc[iw][iwnir_l-iwnir_s]= (1.0 - mwt) * derv_taua_min[iw]
2378  * derv_taua_rhoa[im1]
2379  + mwt * derv_taua_max[iw] * derv_taua_rhoa[im2]
2380  + (tau_pred_max[iw] - tau_pred_min[iw]) * derv_mwt_rhoa_l;
2381  uncertainty->derv_taua_taua_l[iw] = -(1.0 - mwt) * derv_taua_min[iw]
2382  * derv_taua_rhoa[im1] * derv_Lg_taua_l
2383  - mwt * derv_taua_max[iw] * derv_taua_rhoa[im2]
2384  * derv_Lg_taua_l
2385  + (tau_pred_max[iw] - tau_pred_min[iw]) * derv_mwt_taua_l;
2386  uncertainty->derv_taua_rhorc[iw][0] = (tau_pred_max[iw] - tau_pred_min[iw])
2387  * derv_mwt_rhoa_s;
2388  uncertainty->derv_taua_rhow_l[iw] = -(1.0 - mwt) * derv_taua_min[iw]
2389  * derv_taua_rhoa[im1]
2390  - mwt * derv_taua_max[iw] * derv_taua_rhoa[im2]
2391  + (tau_pred_max[iw] - tau_pred_min[iw]) * derv_mwt_rhow_l;
2392  //uncertainty->derv_taua_taua_s[iw] = (tau_pred_max[iw] - tau_pred_min[iw])
2393  // * derv_mwt_taua_s;
2394 
2395  // derv_taua[0][iw][0] = 0.;
2396  uncertainty->derv_taua_min_rhorc_l[iw] = derv_taua_min[iw] * derv_taua_rhoa[im1];
2397  uncertainty->derv_taua_min_taua_l[iw] = -derv_taua_min[iw] * derv_taua_rhoa[im1]
2398  * derv_Lg_taua_l;
2399  uncertainty->derv_taua_min_rhow_l[iw] = -derv_taua_min[iw] * derv_taua_rhoa[im1];
2400  // derv_taua[0][iw][4] = 0.;
2401 
2402  // derv_taua[1][iw][0] = 0.;
2403  uncertainty->derv_taua_max_rhorc_l[iw]= derv_taua_max[iw] * derv_taua_rhoa[im2];
2404  uncertainty->derv_taua_max_taua_l [iw]= -derv_taua_max[iw] * derv_taua_rhoa[im2]
2405  * derv_Lg_taua_l;
2406  uncertainty->derv_taua_max_rhow_l [iw]= -derv_taua_max[iw] * derv_taua_rhoa[im2];
2407  //derv_taua[1][iw][4] = 0.;
2408  }
2409  }
2410 
2411  if(uncertainty){
2412  free(derv_rhoa_min);
2413  free(derv_rhoa_max);
2414  free(derv_taua_min);
2415  free(derv_taua_max);
2416  }
2417 
2418  return (status);
2419 }
2420 
2421 /*------------------------------------------------------------------------------------------*/
2422 /* ahmad_atm_corr_lin() - compute aerosol reflectance at all wavelengths in linear space */
2423 /* */
2424 /* Z Ahmad. July 2014 */
2425 /* Modified to linear spaced coefficient by Amir Ibrahim January 2017 */
2426 
2427 /*---------------------------------------------------------------------------------------- */
2428 int ahmad_atm_corr_lin(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l,
2429  int32_t nmodels, int32_t mindx[],
2430  geom_str *geom, float wv, float rhoa[],
2431  int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir,
2432  float tau_pred_max[], float tau_pred_min[], float rho_pred_max[], float rho_pred_min[],
2433  float tau_aer[], float rho_aer[]) {
2434 
2435 
2436  float *ac, *bc, *cc, *dc, *ec;
2437  float ext_iwnir_l, ext_iwnir_s;
2438  double ax, bx, cx, fx;
2439  float tau_iwnir_l[nmodels];
2440  float lg_tau_iwnir_s[nmodels], tau_iwnir_s[nmodels];
2441  float lg_rho_iwnir_s_pred[nmodels], rho_iwnir_s_pred[nmodels];
2442  float eps_pred[nmodels];
2443  int im, modl;
2444  int im1, im2;
2445  float mwt;
2446  float lg_tau_iwnir_l;
2447  int iwtab_l, iwtab_s;
2448 
2449 
2450  static float eps_obs;
2451 
2452  int iw;
2453 
2454  int status = 0.0;
2455 
2456 
2457  /* compute the observed epsilon */
2458 
2459  eps_obs = rhoa[iwnir_s] / rhoa[iwnir_l];
2460 
2461  /* printf("rho_869,rho_748,eps_obs\n"); */
2462  /* printf("%10.5f %10.5f %10.5f\n",rhoa[iwnir_l],rhoa[iwnir_s],eps_obs); */
2463 
2464 
2465  // compute MS epsilon for all nmodels. note that nmodels may be only a subset of
2466  // the full model suite. mindx maps from subset index to full index in suite
2467 
2468 
2469  for (im = 0; im < nmodels; im++) {
2470 
2471  modl = mindx[im]; // index in full model suite, needed for coefficient look-up
2472 
2473  /* compute AOT at longest aerosol wavelength (iwnir_l) */
2474 
2475  // Zia's function ---> something is wrong
2476  //ms_eps_coef(modl,iwnir_l,wave,solz,senz,phi,&ac,&bc,&cc,&dc,&ec);
2477 
2478  // ms_eps_coef_cal(modl,nwave,solz,senz,phi,&ac,&bc,&cc,&dc,&ec);
2479  ms_eps_coef(modl, iwnir_l, wave, geom, &ac, &bc, &cc, &dc, &ec);
2480  iwtab_l = iwatab[iwnir_l];
2481  iwtab_s = iwatab[iwnir_s];
2482 
2483  ax = (double) ac[iwtab_l]-(double) rhoa[iwnir_l];
2484  bx = (double) bc[iwtab_l];
2485  cx = (double) cc[iwtab_l];
2486 
2487  fx = bx * bx - 4.0 * ax*cx;
2488  if (fx > 0.0 && cx != 0.0) {
2489  lg_tau_iwnir_l = 0.5 * (-bx + sqrt(fx)) / cx;
2490  tau_iwnir_l[im] = (lg_tau_iwnir_l);
2491  } else {
2492  status = 1;
2493  break;
2494  }
2495 
2496  /* compute AOT at shortest aerosol wavelength (iwnir_s) */
2497 
2498  ext_iwnir_l = aertab->model[modl]->extc[iwtab_l];
2499  ext_iwnir_s = aertab->model[modl]->extc[iwtab_s];
2500 
2501  tau_iwnir_s[im] = (ext_iwnir_s / ext_iwnir_l) * tau_iwnir_l[im];
2502  lg_tau_iwnir_s[im] = (tau_iwnir_s[im]);
2503 
2504  if (ax > 1e5) {
2505  printf("\nErroneous aerosol option, %d\n", aer_opt);
2506  printf("You are using a log-space LUT. The aerosol LUT coefficients need to be in linear-space. Use aer_opt=-18 instead. \n");
2507  exit(FATAL_ERROR);
2508  }
2509 
2510 
2511  /* compute reflectance at (iwnir_s) */
2512 
2513  lg_rho_iwnir_s_pred[im] = ac[iwtab_s] + bc[iwtab_s] * lg_tau_iwnir_s[im] +
2514  cc[iwtab_s] * pow(lg_tau_iwnir_s[im], 2) +
2515  dc[iwtab_s] * pow(lg_tau_iwnir_s[im], 3) +
2516  ec[iwtab_s] * pow(lg_tau_iwnir_s[im], 4);
2517 
2518  rho_iwnir_s_pred[im] = (lg_rho_iwnir_s_pred[im]);
2519 
2520  /* compute model epsilon */
2521 
2522  eps_pred[im] = rho_iwnir_s_pred[im] / rhoa[iwnir_l];
2523 
2524  }
2525 
2526 
2527  *epsnir = eps_obs;
2528 
2529 
2530  /* now, find the bounding models, but skip this if we only have one */
2531  /* model (as when vicariously calibrating) */
2532 
2533  if (nmodels > 1) {
2534 
2535  /* locate two model_epsilons that bracket the observed epsilon */
2536  /* this will return the model numbers for the subset of models */
2537 
2538  model_select_ahmad(nmodels, mindx, eps_pred, eps_obs, &im1, &im2, &mwt);
2539 
2540  } else {
2541 
2542  /* single model case (allows fixed model by limiting model suite) */
2543 
2544  im1 = 0;
2545  im2 = 0;
2546  mwt = 0.0;
2547  }
2548 
2549  /* map selection to full suite for subsequent processing and return */
2550 
2551  *modmin = mindx[im1];
2552  *modmax = mindx[im2];
2553  *modrat = mwt;
2554 
2555  /* compute tau_pred and rho_predicted */
2556 
2557  comp_rhoa_ms_eps_lin(nwave, wave, geom, tau_iwnir_l[im1], *modmin, tau_pred_min, rho_pred_min);
2558  comp_rhoa_ms_eps_lin(nwave, wave, geom, tau_iwnir_l[im2], *modmax, tau_pred_max, rho_pred_max);
2559 
2560  /* compute weighted tau_aer and rho_aer */
2561 
2562  for (iw = 0; iw < nwave; iw++) {
2563  tau_aer[iw] = (1.0 - mwt) * tau_pred_min[iw] + mwt * tau_pred_max[iw];
2564  rho_aer[iw] = (1.0 - mwt) * rho_pred_min[iw] + mwt * rho_pred_max[iw];
2565  }
2566 
2567 
2568  return (status);
2569 }
2570 
2571 /* ---------------------------------------------------------------------------------------- */
2572 /* model_phase() - return phase function at model wavelengths at the input geometry. */
2573 /* */
2574 /* This is effectively a C version of load_ss.f by M. Wang. The program optimizes for */
2575 /* multiple calls at the same geometry by computing for all models on the first call with a */
2576 /* new geometry. It returns a pointer to the internal static array for the requested model.*/
2577 /* */
2578 /* B. Franz, 1 June 2004. */
2579 /* W. Robinson, SAIC modified to use band-dependent viewing geometry, if avail */
2580 
2581 /* ---------------------------------------------------------------------------------------- */
2582 float *model_phase(int modnum, geom_str *geom) {
2583  static float nw = 1.334;
2584 
2585  static int computed[MAXMODEL];
2586  static float lastsolz = -999.;
2587  static float lastsenz = -999.;
2588  static float lastphi = -999.;
2589  static float *phase[MAXMODEL];
2590  static float *fres1, *fres2;
2591  static float *scatt1, *scatt2;
2592  static float scatt1_cnst, scatt2_cnst, fres1_cnst, fres2_cnst;
2593  static float *scatt1_ar, *scatt2_ar, *fres1_ar, *fres2_ar;
2594  static int firstCall = 1, gmult = 1;
2595 
2596  float phase1, phase2;
2597  int im, iw, ig;
2598 
2599  if (firstCall == 1) {
2600  firstCall = 0;
2601  for (im = 0; im < MAXMODEL; im++) {
2602  if ((phase[im] = (float *) calloc(aertab->nwave, sizeof (float))) == NULL) {
2603  printf("Unable to allocate space for phase.\n");
2604  exit(1);
2605  }
2606  }
2607  /* set up geometry based scattering and fresnel */
2608  if ((geom->gmult == 0) || (interpol == 1)) {
2609  gmult = 0;
2610  scatt1 = &scatt1_cnst;
2611  scatt2 = &scatt2_cnst;
2612  fres1 = &fres1_cnst;
2613  fres2 = &fres2_cnst;
2614  } else {
2615  gmult = 1;
2616  if ((scatt1_ar =
2617  (float *) malloc(aertab->nwave * sizeof (float))) == NULL) {
2618  printf("Unable to allocate space for scatt1.\n");
2619  exit(1);
2620  }
2621  if ((scatt2_ar =
2622  (float *) malloc(aertab->nwave * sizeof (float))) == NULL) {
2623  printf("Unable to allocate space for scatt2.\n");
2624  exit(1);
2625  }
2626  if ((fres1_ar =
2627  (float *) malloc(aertab->nwave * sizeof (float))) == NULL) {
2628  printf("Unable to allocate space for fres1.\n");
2629  exit(1);
2630  }
2631  if ((fres2_ar =
2632  (float *) malloc(aertab->nwave * sizeof (float))) == NULL) {
2633  printf("Unable to allocate space for fres2.\n");
2634  exit(1);
2635  }
2636  scatt1 = scatt1_ar;
2637  scatt2 = scatt2_ar;
2638  fres1 = fres1_ar;
2639  fres2 = fres2_ar;
2640  }
2641  }
2642 
2643  /* recalculate only if geometry changes */
2644 
2645  if ((geom->solz[0] != lastsolz) || (geom->senz[0] != lastsenz) ||
2646  (geom->phi[0] != lastphi)) {
2647 
2648  float temp;
2649 
2650  for (im = 0; im < aertab->nmodel; im++)
2651  computed[im] = 0;
2652 
2653  /* determine scattering angles (direct and surface reflected) */
2654  for (iw = 0; iw < aertab->nwave; iw++) {
2655  ig = gmult * iw;
2656  temp = sqrt((1.0 - geom->csenz[ig] * geom->csenz[ig]) *
2657  (1.0 - geom->csolz[ig] * geom->csolz[ig])) *
2658  cos(geom->phi[ig] / radeg);
2659  scatt1[iw] = acos(
2660  MAX(-geom->csenz[ig] * geom->csolz[ig] + temp, -1.0)) * radeg;
2661  scatt2[iw] = acos(
2662  MIN(geom->csenz[ig] * geom->csolz[ig] + temp, 1.0)) * radeg;
2663 
2664  /* compute Fresnel coefficients */
2665  fres1[iw] = fresnel_coef(geom->csenz[ig], nw);
2666  fres2[iw] = fresnel_coef(geom->csolz[ig], nw);
2667  if (gmult == 0) break;
2668  }
2669 
2670  lastsolz = geom->solz[0];
2671  lastsenz = geom->senz[0];
2672  lastphi = geom->phi[0];
2673  }
2674 
2675  if (!computed[modnum]) {
2676 
2677  im = modnum;
2678  computed[modnum] = 1;
2679 
2680  /* compute phase function for this geometry, all models */
2681  for (iw = 0; iw < aertab->nwave; iw++) {
2682  ig = gmult * iw;
2683  splint(aertab->scatt,
2684  &aertab->model[im]->lnphase[iw][0],
2685  &aertab->model[im]->d2phase[iw][0],
2686  aertab->nscatt, scatt1[ig], &phase1);
2687  splint(aertab->scatt,
2688  &aertab->model[im]->lnphase[iw][0],
2689  &aertab->model[im]->d2phase[iw][0],
2690  aertab->nscatt, scatt2[ig], &phase2);
2691  // incident diffuse reflected diff dir
2692  phase[im][iw] = exp(phase1) +
2693  exp(phase2)*(fres1[ig] + fres2[ig]);
2694  }
2695  }
2696 
2697  return (&phase[modnum][0]);
2698 }
2699 
2700 
2701 /* ---------------------------------------------------------------------------------------- */
2702 /* aeroob_cf() - out-of-band water-vapor scale factor */
2703 
2704 /* ---------------------------------------------------------------------------------------- */
2705 float aeroob_cf(int modnum, geom_str *geom) {
2706  static int firstCall = 1;
2707  static int iw1;
2708  static int iw2;
2709 
2710  float *phase;
2711  float rhoas1, rhoas2;
2712  float eps;
2713  float cf;
2714 
2715  if (firstCall) {
2716  iw1 = windex(765, aertab->wave, aertab->nwave);
2717  iw2 = windex(865, aertab->wave, aertab->nwave);
2718  if (iw1 == iw2) iw1--;
2719  firstCall = 0;
2720  }
2721 
2722  phase = model_phase(modnum, geom);
2723  rhoas1 = aertab->model[modnum]->albedo[iw1] * phase[iw1] * aertab->model[modnum]->extc[iw1];
2724  rhoas2 = aertab->model[modnum]->albedo[iw2] * phase[iw2] * aertab->model[modnum]->extc[iw2];
2725  eps = rhoas1 / rhoas2;
2726  cf = log(eps) / (aertab->wave[iw2] - aertab->wave[iw1]);
2727 
2728  return (cf);
2729 }
2730 
2731 
2732 /* ---------------------------------------------------------------------------------------- */
2733 /* aeroob - out-of-band water-vapor correction */
2734 
2735 /* ---------------------------------------------------------------------------------------- */
2736 float aeroob(int32_t sensorID, int32_t iw, float airmass, float cf, float wv) {
2737  static float *a01;
2738  static float *a02;
2739  static float *a03;
2740  static float *a04;
2741  static float *a05;
2742  static float *a06;
2743  static float *a07;
2744  static float *a08;
2745  static float *a09;
2746  static float *a10;
2747  static float *a11;
2748  static float *a12;
2749 
2750  static int firstCall = 1;
2751 
2752  float f;
2753  f = 1.0;
2754  if ((input->gas_opt & GAS_TRANS_TBL_BIT) == 0) {
2755  if (firstCall) {
2756  firstCall = 0;
2757  rdsensorinfo(sensorID, evalmask, "oobwv01", (void **) &a01); /* coeff #1 per sensor wave */
2758  rdsensorinfo(sensorID, evalmask, "oobwv02", (void **) &a02);
2759  rdsensorinfo(sensorID, evalmask, "oobwv03", (void **) &a03);
2760  rdsensorinfo(sensorID, evalmask, "oobwv04", (void **) &a04);
2761  rdsensorinfo(sensorID, evalmask, "oobwv05", (void **) &a05);
2762  rdsensorinfo(sensorID, evalmask, "oobwv06", (void **) &a06);
2763  rdsensorinfo(sensorID, evalmask, "oobwv07", (void **) &a07);
2764  rdsensorinfo(sensorID, evalmask, "oobwv08", (void **) &a08);
2765  rdsensorinfo(sensorID, evalmask, "oobwv09", (void **) &a09);
2766  rdsensorinfo(sensorID, evalmask, "oobwv10", (void **) &a10);
2767  rdsensorinfo(sensorID, evalmask, "oobwv11", (void **) &a11);
2768  rdsensorinfo(sensorID, evalmask, "oobwv12", (void **) &a12);
2769  printf("\nLoading water-vapor correction coefficients.\n");
2770  }
2771 
2772  f = (a01[iw] + a02[iw] * airmass + cf * (a03[iw] + a04[iw] * airmass))
2773  + (a05[iw] + a06[iw] * airmass + cf * (a07[iw] + a08[iw] * airmass)) * wv
2774  + (a09[iw] + a10[iw] * airmass + cf * (a11[iw] + a12[iw] * airmass)) * wv*wv;
2775  }
2776  return (f);
2777 }
2778 
2779 
2780 /* ---------------------------------------------------------------------------------------- */
2781 /* rhoa_to_rhoas() - MS aerosol reflectance to SS aerosol reflectance */
2782 /* */
2783 /* B. Franz, 1 June 2004. */
2784 
2785 /* ---------------------------------------------------------------------------------------- */
2786 int rhoa_to_rhoas(int32_t sensorID, int modnum, geom_str *geom, float wv,
2787  float rhoa[], float wave[], int32_t nwave, int iw1, int iw2, float rhoas[]) {
2788  float *ac, *bc, *cc;
2789  double a, b, c;
2790  double f;
2791  int iw, ig;
2792  int iwtab;
2793  float cf;
2794  int status = 0;
2795 
2796  ss_to_ms_coef(modnum, geom, &ac, &bc, &cc);
2797 
2798  cf = aeroob_cf(modnum, geom);
2799 
2800  for (iw = iw1; iw <= iw2; iw++) {
2801  ig = iw * geom->gmult;
2802  if (rhoa[iw] < 1.e-20)
2803  rhoas[iw] = rhoa[iw];
2804  else {
2805  iwtab = iwatab[iw];
2806  a = (double) ac[iwtab];
2807  b = (double) bc[iwtab];
2808  c = (double) cc[iwtab];
2809  f = b * b - 4 * c * (a - log((double) rhoa[iw]));
2810  if (f > 0.00001) { // this was 0.0, but small values caused segfault (BAF, 9/2014)
2811  if (fabs(c) > 1.e-20) {
2812  rhoas[iw] = exp(0.5 * (-b + sqrt(f)) / c);
2813  } else if (fabs(a) > 1.e-20 && fabs(b) > 1.e-20) {
2814  rhoas[iw] = pow(rhoa[iw] / a, 1. / b);
2815  } else {
2816  status = 1;
2817  break;
2818  }
2819  rhoas[iw] = rhoas[iw] / aeroob(sensorID, iw, geom->airmass[ig], cf, wv);
2820  if (!isfinite(rhoas[iw]) || rhoas[iw] < 1.e-20) {
2821  status = 1;
2822  break;
2823  }
2824  } else {
2825  status = 1;
2826  break;
2827  }
2828  }
2829  }
2830 
2831  // return input values and failure status if any wavelengths failed
2832 
2833  if (status != 0) {
2834  for (iw = iw1; iw <= iw2; iw++)
2835  rhoas[iw] = rhoa[iw];
2836  }
2837 
2838  return (status);
2839 }
2840 
2841 
2842 
2843 /* ---------------------------------------------------------------------------------------- */
2844 /* rhoas_to_rhoa() - SS aerosol reflectance to MS aerosol reflectance */
2845 /* */
2846 /* B. Franz, 1 June 2004. */
2847 
2848 /* ---------------------------------------------------------------------------------------- */
2849 void rhoas_to_rhoa(int32_t sensorID, int modnum, geom_str *geom, float wv,
2850  float rhoas[], float wave[], int32_t nwave, int iw1, int iw2, float rhoa[]) {
2851  float *ac, *bc, *cc;
2852  float a, b, c;
2853  float lnrhoas;
2854  int iw, ig;
2855  int iwtab;
2856  float cf;
2857 
2858  ss_to_ms_coef(modnum, geom, &ac, &bc, &cc);
2859 
2860  cf = aeroob_cf(modnum, geom);
2861 
2862  for (iw = iw1; iw <= iw2; iw++) {
2863  ig = iw * geom->gmult;
2864 
2865  /* these changes ensure that rhoa1 -> rhoas -> rhoa2 == rhoa1 */
2866  /* but, that changes everything, slightly (tau) */
2867 
2868  if (rhoas[iw] < 1.e-20)
2869  rhoa[iw] = rhoas[iw];
2870  else {
2871  iwtab = iwatab[iw];
2872  a = ac[iwtab];
2873  b = bc[iwtab];
2874  c = cc[iwtab];
2875  lnrhoas = log(rhoas[iw] * aeroob(sensorID, iw, geom->airmass[ig], cf, wv));
2876  rhoa[iw] = exp(a + b * lnrhoas + c * lnrhoas * lnrhoas);
2877  }
2878 
2879  /*
2880  iwtab = iwatab[iw];
2881  a = ac[iwtab];
2882  b = bc[iwtab];
2883  c = cc[iwtab];
2884  lnrhoas = log(rhoas[iw]);
2885  rhoa[iw] = exp(a + b*lnrhoas + c*lnrhoas*lnrhoas)
2886  * aeroob(sensorID,iw, geom->airmass[ig],cf,wv);
2887  */
2888  }
2889 
2890  return;
2891 }
2892 
2893 
2894 /* ---------------------------------------------------------------------------------------- */
2895 /* model_epsilon() - return model epsilon at input wavelengths for input geometry. */
2896 /* */
2897 /* If the input wavelengths are not equal to the model wavelengths, the model epsilon will */
2898 /* be interpolated to the input wavelengths. It is assumed that the longest (last) input */
2899 /* wavelength is equivalent to the longest wavelength of the model table. Hence, */
2900 /* the function should always be called with the full array of input sensor wavelengths. */
2901 /* */
2902 /* The program optimizes for multiple calls at the same geometry by computing for all */
2903 /* models on the first call with a new geometry. It returns a pointer to the internal */
2904 /* static arrays of epsilon for the requested model. . */
2905 /* */
2906 /* B. Franz, 1 June 2004. */
2907 
2908 /* ---------------------------------------------------------------------------------------- */
2909 float *model_epsilon(int modnum, int32_t iwnir_l, float wave[], int32_t nwave, geom_str *geom) {
2910  static float lastsolz = -999.;
2911  static float lastsenz = -999.;
2912  static float lastphi = -999.;
2913  static int32_t lastiwl = -999;
2914  static int lastmod = -999;
2915  static float *epsilon[MAXMODEL];
2916  static int firstCall = 1;
2917  int i;
2918  float maxwave;
2919  /* recalculate only if geometry changes */
2920 
2921  if (firstCall == 1) {
2922  firstCall = 0;
2923  maxwave = MAX(aertab->nwave, nwave);
2924  for (i = 0; i < MAXMODEL; i++) {
2925  if ((epsilon[i] = (float *) calloc(maxwave, sizeof (float))) == NULL) {
2926  printf("Unable to allocate space for epsilon.\n");
2927  exit(1);
2928  }
2929 
2930  }
2931  }
2932 
2933  /* recalculate only if geometry changes */
2934 
2935  if (modnum != lastmod || geom->solz[0] != lastsolz ||
2936  geom->senz[0] != lastsenz || geom->phi[0] != lastphi ||
2937  iwnir_l != lastiwl) {
2938 
2939  int iwnir = iwatab[iwnir_l];
2940  float *phase;
2941  float *lneps;
2942  float rhoas1, rhoas2;
2943  int im, iw, iwtab;
2944 
2945  if ((lneps = (float *) calloc(aertab->nwave, sizeof (float))) == NULL) {
2946  printf("Unable to allocate space for lneps.\n");
2947  exit(1);
2948  }
2949 
2950  im = modnum;
2951  phase = model_phase(im, geom);
2952  for (iw = 0; iw < aertab->nwave; iw++) {
2953  rhoas1 = aertab->model[im]->albedo[iw] * phase[iw] * aertab->model[im]->extc[iw];
2954  rhoas2 = aertab->model[im]->albedo[iwnir] * phase[iwnir] * aertab->model[im]->extc[iwnir];
2955  epsilon[im][iw] = rhoas1 / rhoas2;
2956  if (interpol)
2957  lneps[iw] = log(epsilon[im][iw]);
2958  }
2959  if (interpol) {
2960  for (iw = 0; iw < nwave; iw++) {
2961  iwtab = iwatab[iw];
2962  if (aertab->wave[iwtab] != wave[iw] && wave[iw] > 0)
2963  epsilon[im][iw] = exp(linterp(aertab->wave, lneps, aertab->nwave, wave[iw]));
2964  else
2965  epsilon[im][iw] = exp(lneps[iwtab]);
2966  }
2967  }
2968 
2969  lastsolz = geom->solz[0];
2970  lastsenz = geom->senz[0];
2971  lastphi = geom->phi[0];
2972  lastiwl = iwnir_l;
2973  lastmod = modnum;
2974  free(lneps);
2975 
2976  }
2977 
2978  return (&epsilon[modnum][0]);
2979 }
2980 
2981 
2982 /* ---------------------------------------------------------------------------------------- */
2983 /* model_select_wang() - M. Wang aerosol model selection process . */
2984 /* */
2985 /* B. Franz, 1 June 2004. */
2986 
2987 /* ---------------------------------------------------------------------------------------- */
2988 int model_select_wang(int32_t sensorID, float wave[], int32_t nwave,
2989  int32_t nmodel, int32_t mindx[], geom_str *geom, float wv,
2990  float rhoa[], int32_t iwnir_s, int32_t iwnir_l, int32_t *modmin,
2991  int32_t *modmax, float *modrat, float *epsnir) {
2992  float *rhoas;
2993  float eps_ret [MAXMODEL];
2994  float eps_mod [MAXMODEL];
2995  float eps_err [MAXMODEL];
2996  int imod [MAXMODEL];
2997  int nmod = nmodel;
2998  float eps_ave;
2999  float *eps;
3000  float err_m;
3001  float err_p;
3002  int jm, im, iim;
3003  int eps_flg = 0;
3004  float wt;
3005  float tot_err;
3006  int itmp;
3007 
3008  *modmin = -1;
3009  *modmax = -1;
3010  *modrat = 0.0;
3011  *epsnir = 0.0;
3012 
3013  if ((rhoas = (float *) calloc(nwave, sizeof (float))) == NULL) {
3014  printf("Unable to allocate space for rhoas.\n");
3015  exit(1);
3016  }
3017 
3018  /* get theoretical and retrieved epsilon for each model, and */
3019  /* compute average retrieved epsilon */
3020 
3021  eps_ave = 0.0;
3022  for (jm = 0; jm < nmod; jm++) {
3023 
3024  im = mindx[jm];
3025 
3026  /* retrieve epsilon in NIR assuming each model */
3027  rhoa_to_rhoas(sensorID, im, geom, wv, rhoa, wave, nwave, iwnir_s, iwnir_l, rhoas);
3028 
3029  if (rhoas[iwnir_l] > 0.0000001)
3030  eps_ret[jm] = rhoas[iwnir_s] / rhoas[iwnir_l];
3031  else
3032  eps_ret[jm] = 0;
3033 
3034  /* get model epsilon for each model at this geometry */
3035  eps = model_epsilon(im, iwnir_l, wave, nwave, geom);
3036  eps_mod[jm] = eps[iwnir_s];
3037 
3038  eps_ave += eps_ret[jm];
3039  }
3040  if (isfinite(eps_ave))
3041  eps_ave /= nmod;
3042  else
3043  eps_ave = 1.0;
3044 
3045 
3046  /* determine average retrieved epsilon for the four retrievals which most */
3047  /* closely match the theoretical model epsilons. the model set is reduced */
3048  /* from the full suite to the final four by iterative outlier rejection. */
3049 
3050  while (nmod > 4) {
3051 
3052  /* compute differences between retrieved and model epsilon */
3053  for (im = 0; im < nmodel; im++) {
3054  imod[im] = im;
3055  eps_err[im] = eps_ave - eps_mod[im];
3056  }
3057 
3058  /* sort model indices by smallest to largest absolute differences */
3059  for (im = 0; im < nmodel - 1; im++) {
3060  for (iim = im + 1; iim < nmodel; iim++)
3061  if (fabs(eps_err[imod[im]]) > fabs(eps_err[imod[iim]])) {
3062  itmp = imod[im ];
3063  imod[im ] = imod[iim];
3064  imod[iim] = itmp;
3065  }
3066  }
3067 
3068  /* recompute average retrieved epsilon over the n-2 closest models */
3069  /* averaging is done as a weighted mean with wt=1-|eps_err|/tot_err */
3070  /* note that the sum of the weights is equal to n-1 */
3071 
3072  nmod = nmod - 2;
3073 
3074  tot_err = 0.0;
3075  for (iim = 0; iim < nmod; iim++) {
3076  im = imod[iim];
3077  tot_err += fabs(eps_err[im]);
3078  }
3079 
3080  eps_ave = 0.0;
3081  for (iim = 0; iim < nmod; iim++) {
3082  im = imod[iim];
3083  wt = 1.0 - fabs(eps_err[im]) / tot_err;
3084  eps_ave += eps_ret[im] * wt;
3085  }
3086  eps_ave /= (nmod - 1);
3087  }
3088 
3089  /* now select the two models which bracket eps_ave */
3090  err_m = 0 - FLT_MAX;
3091  err_p = FLT_MAX;
3092  for (im = 0; im < nmodel; im++) {
3093  eps_err[im] = eps_ave - eps_mod[im];
3094  if (eps_err[im] >= 0.0) {
3095  if (eps_err[im] < err_p) {
3096  err_p = eps_err[im];
3097  *modmin = im;
3098  }
3099  } else {
3100  if (eps_err[im] > err_m) {
3101  err_m = eps_err[im];
3102  *modmax = im;
3103  }
3104  }
3105  }
3106 
3107  /* compute interpolation ratio */
3108  if (*modmin < 0) {
3109  /* no lower-bounding model */
3110  *modmin = *modmax;
3111  *modrat = 0.0;
3112  eps_flg = -1;
3113  } else if (*modmax < 0) {
3114  /* no upper-bounding model */
3115  *modmax = *modmin;
3116  *modrat = 0.0;
3117  eps_flg = 1;
3118  } else
3119  *modrat = (eps_ave - eps_mod[*modmin]) / (eps_mod[*modmax] - eps_mod[*modmin]);
3120 
3121  *modmin = mindx[*modmin];
3122  *modmax = mindx[*modmax];
3123 
3124  /* return retrieved epsilon */
3125  *epsnir = eps_ave;
3126 
3127  free(rhoas);
3128 
3129  return (eps_flg);
3130 }
3131 
3132 
3133 /* ---------------------------------------------------------------------------------------- */
3134 /* model_select_angst() - Select model pair based on input Angstrom coefficient */
3135 /* */
3136 /* B. Franz, 1 August 2004. */
3137 /* ---------------------------------------------------------------------------------------- */
3138 int compalphaT(alphaTstr *x, alphaTstr *y) {
3139  return (x->angstrom < y->angstrom ? -1 : 1);
3140 }
3141 
3142 void model_select_angstrom(float angstrom, int32_t *modmin, int32_t *modmax, float *modrat) {
3143  static alphaTstr alphaT[MAXAERMOD];
3144  static int firstCall = 1;
3145 
3146  int im, im1, im2;
3147 
3148  if (firstCall) {
3149 
3150  int ib = windex(520, aertab->wave, aertab->nwave);
3151 
3152  /* grab angstrom coefficients and sort in ascending order */
3153  for (im = 0; im < aertab->nmodel; im++) {
3154  alphaT[im].angstrom = aertab->model[im]->angstrom[ib];
3155  alphaT[im].modnum = im;
3156  }
3157  qsort(alphaT, aertab->nmodel, sizeof (alphaTstr),
3158  (int (*)(const void *, const void *)) compalphaT);
3159 
3160  firstCall = 0;
3161  }
3162 
3163  for (im = 0; im < aertab->nmodel; im++) {
3164  if (angstrom < alphaT[im].angstrom)
3165  break;
3166  }
3167  im1 = MAX(MIN(im - 1, aertab->nmodel - 1), 0);
3168  im2 = MAX(MIN(im, aertab->nmodel - 1), 0);
3169 
3170  *modmin = alphaT[im1].modnum;
3171  *modmax = alphaT[im2].modnum;
3172 
3173  if (im1 == im2)
3174  *modrat = 1.0;
3175  else
3176  *modrat = (angstrom - alphaT[im1].angstrom) /
3177  (alphaT[im2].angstrom - alphaT[im1].angstrom);
3178 
3179  return;
3180 
3181 }
3182 
3183 /* ---------------------------------------------------------------------------------------- */
3184 /* model_taua() - compute AOT at input wavelengths using specified model */
3185 /* Note by W. Robinson - the aot is determined for SENSOR wavelength nir_l
3186  using the mu, mu0 for the geometry for that band. To get the aot at other
3187  TABLE bands, it starts with the aot(nir_l). So, how would the geometry
3188  change get properly translated to the other table bands? For now, I'm
3189  not accounting for that translation. Possible method would be to (for
3190  interpol=0 only) compute the aot(nir_l, geom(sensor band)) and use
3191  that aot to get the aot(geom(sensor band)) */
3192 
3193 /* ---------------------------------------------------------------------------------------- */
3194 void model_taua(int32_t sensorID, int modnum, float wave[], int32_t nwave,
3195  int32_t iwnir_l, float rhoa[], geom_str *geom, float wv, float taua[]) {
3196  float *aot;
3197  float *lnaot;
3198  float *rhoas;
3199 
3200  int iwnir = iwatab[iwnir_l];
3201  float *phase = model_phase(modnum, geom);
3202  int iw, iwg, iwtab;
3203  float maxwave;
3204 
3205  iwg = iwnir * geom->gmult; /* index for geometry */
3206 
3207  maxwave = MAX(aertab->nwave, nwave);
3208 
3209  if ((rhoas = (float *) calloc(nwave, sizeof (float))) == NULL) {
3210  printf("Unable to allocate space for rhoas.\n");
3211  exit(1);
3212  }
3213  if ((aot = (float *) calloc(maxwave, sizeof (float))) == NULL) {
3214  printf("Unable to allocate space for aot.\n");
3215  exit(1);
3216  }
3217  if ((lnaot = (float *) calloc(maxwave, sizeof (float))) == NULL) {
3218  printf("Unable to allocate space for lnaot.\n");
3219  exit(1);
3220  }
3221 
3222  /* get SS aerosol reflectance at longest sensor wavelength */
3223  rhoa_to_rhoas(sensorID, modnum, geom, wv, rhoa, wave, nwave, iwnir_l, iwnir_l, rhoas);
3224 
3225  /* get aerosol optical thickness at longest sensor wavelength */
3226  aot[iwnir] = rhoas[iwnir_l]*(4.0 * geom->csolz[iwg] * geom->csenz[iwg])
3227  / (phase[iwnir] * aertab->model[modnum]->albedo[iwnir]);
3228 
3229  /* get aerosol optical thickness at all other table wavelengths */
3230  for (iw = 0; iw < aertab->nwave; iw++) {
3231  /* note to self: i actually have aot(865) for czcs at this point */
3232  aot[iw] = aot[iwnir] * aertab->model[modnum]->extc[iw] / aertab->model[modnum]->extc[iwnir];
3233  if (interpol)
3234  lnaot[iw] = log(aot[iw]);
3235  }
3236 
3237  /* interpolate aot from table to sensor wavelengths */
3238  if (interpol) {
3239  for (iw = 0; iw < nwave; iw++) {
3240  iwtab = iwatab[iw];
3241  if (aertab->wave[iwtab] != wave[iw] && wave[iw] > 0)
3242  taua[iw] = exp(linterp(aertab->wave, lnaot, aertab->nwave, wave[iw]));
3243  else
3244  taua[iw] = aot[iwtab];
3245  }
3246  } else
3247  for (iw = 0; iw < nwave; iw++)
3248  taua[iw] = aot[iw];
3249 
3250  free(rhoas);
3251  free(aot);
3252  free(lnaot);
3253  return;
3254 }
3255 
3256 /*------------------------------------------------------------------------------------------ */
3257 /* model_taua_mseps_pca() - for a given model and rhoa[iwnir_l], computes the AOT using PCA LUTs */
3258 
3259 /*------------------------------------------------------------------------------------------ */
3260 int model_taua_mseps_pca(int32_t modl, float wave[], int32_t nwave, int32_t iwnir_l,
3261  float rhoa[], geom_str *geom, float tau_pred[])
3262 {
3263  static int firstcall=1;
3264  static float **pc_rhoa;
3265  static int npc, ntau_870;
3266  aermodstr *aermod=aertab->model[modl];
3267 
3268  int iw,itau,ipc;
3269  static float *rhoa_l;
3270 
3271  if(firstcall){
3272  firstcall=0;
3273  ntau_870=aertab->ntau_870;
3274  npc=aertab->npc;
3275  pc_rhoa=(float **)malloc(aertab->ntau_870*sizeof(float *));
3276 
3277  for(itau=0;itau<ntau_870;itau++)
3278  pc_rhoa[itau]=(float *)malloc(aertab->npc*sizeof(float));
3279  rhoa_l=(float *)malloc(ntau_870*sizeof(float));
3280  }
3281 
3282  get_pc_rhoa(modl,geom,pc_rhoa);
3283 
3284  for(itau=0;itau<ntau_870;itau++){
3285  rhoa_l[itau]=0;
3286  for(ipc=0;ipc<npc;ipc++){
3287  rhoa_l[itau]+=pc_rhoa[itau][ipc]*aermod->pc_components_rhoa[ipc][iwnir_l];
3288  rhoa_l[itau]+=aermod->pc_mean_rhoa[iwnir_l];
3289  }
3290  }
3291 
3292  for(itau=0;itau<ntau_870;itau++){
3293  if(rhoa[iwnir_l]<rhoa_l[itau] && rhoa[iwnir_l]>rhoa_l[itau-1])
3294  break;
3295  }
3296  tau_pred[iwnir_l]=aermod->tau_870[itau]+(aermod->tau_870[itau]-aermod->tau_870[itau-1])*(rhoa[iwnir_l]-rhoa_l[itau])/(rhoa_l[itau]-rhoa_l[itau-1]);
3297 
3298  for(iw=0;iw<nwave;iw++)
3299  tau_pred[iw]=tau_pred[iwnir_l]*aermod->extc[iw]/aermod->extc[iwnir_l];
3300 
3301  return 0;
3302 
3303 }
3304 
3305 /*------------------------------------------------------------------------------------------ */
3306 /* model_taua_mseps() - for a given model and rhoa[iwnir_l], computes the AOT using MSEPS */
3307 /* coefficients relating rhoa to taua (in log space) */
3308 /*------------------------------------------------------------------------------------------ */
3309 int model_taua_mseps(int32_t modl, float wave[], int32_t nwave, int32_t iwnir_l,
3310  float rhoa[], geom_str *geom, float tau_pred[])
3311  {
3312  float *ac, *bc, *cc, *dc, *ec;
3313  double ax, bx, cx, fx;
3314  float ext_modl[nwave];
3315  float tau_iwnir_l;
3316  int iw, iwtab;
3317  int iwtab_l = iwatab[iwnir_l];
3318 
3319  /* get the coefficients for lg_rho vs lg_aot */
3320  ms_eps_coef(modl, iwnir_l, wave, geom, &ac, &bc, &cc, &dc, &ec);
3321 
3322 
3323  ax = (double) ac[iwtab_l] - log((double) rhoa[iwnir_l]);
3324  bx = (double) bc[iwtab_l];
3325  cx = (double) cc[iwtab_l];
3326 
3327  fx = bx * bx - 4.0 * ax*cx;
3328  if (fx > 0.0 && cx != 0.0) {
3329  tau_iwnir_l = exp(0.5*(-bx + sqrt(fx)) / cx);
3330  } else {
3331  tau_iwnir_l = 0.0;
3332  }
3333 
3334  /* get the extinction coefficients and compute AOT at all wavelengths */
3335  for (iw = 0; iw < nwave; iw++) {
3336  iwtab = iwatab[iw];
3337  ext_modl[iw] = aertab->model[modl]->extc[iwtab];
3338  }
3339  for (iw = 0; iw < nwave; iw++) {
3340  tau_pred[iw] = (ext_modl[iw] / ext_modl[iwnir_l]) * tau_iwnir_l;
3341  }
3342 
3343  return (0);
3344 }
3345 
3346 /* ---------------------------------------------------------------------------------------- */
3347 /* model_transmittance() - compute path Rayleigh-aerosol diffuse trans for specified model */
3348 /* */
3349 /* W. Robinson, SAIC, 24 Mar 2017, modify for band-dependent geometry */
3350 /* M. Zhang, SAIC, July 2021, adding the uncertainty propagation */
3351 
3352 /* ---------------------------------------------------------------------------------------- */
3353 void model_transmittance(int modnum, float wave[], int32_t nwave,
3354  float *theta, int gmult, float taua[], float dtran[], float dt[]) {
3355 
3356  int i1, i2, i, ig;
3357  int iw, iwtab;
3358  float a1, b1;
3359  float a2, b2;
3360  float x1, x2;
3361  float y1, y2;
3362  float xbar;
3363  float wt;
3364 
3365  /* disable interpolation, since we now allow LUT wavelengths to differ from sensor nominal wavelengths
3366  BAF, 6/2022
3367 
3368  if (firstCall) {
3369  float taur1, um1;
3370  float taur2, um2;
3371  firstCall = 0;
3372 
3373  intexp = (float *) malloc(nwave * sizeof (float));
3374  inttst = (int *) malloc(nwave * sizeof (int));
3375 
3376  for (iw = 0; iw < nwave; iw++) {
3377  intexp[iw] = 1.0;
3378  inttst[iw] = 0;
3379  iwtab = iwdtab[iw];
3380  if (fabs(wave[iw] - aertab->dtran_wave[iwtab]) > 0.51) {
3381  um1 = aertab->dtran_wave[iwtab] / 1000.0;
3382  um2 = wave[iw] / 1000.0;
3383  taur1 = 0.008569 * pow(um1, -4)*(1.0 + (0.0113 * pow(um1, -2))+(0.00013 * pow(um1, -4)));
3384  taur2 = 0.008569 * pow(um2, -4)*(1.0 + (0.0113 * pow(um2, -2))+(0.00013 * pow(um2, -4)));
3385  intexp[iw] = taur2 / taur1;
3386  inttst[iw] = 1;
3387  printf("Interpolating diffuse transmittance for %d from %f by %f\n",
3388  (int) wave[iw], aertab->dtran_wave[iwtab], intexp[iw]);
3389  }
3390  }
3391  }
3392  */
3393 
3394  /* use coefficients of nearest wavelength */
3395  for (iw = 0; iw < nwave; iw++) {
3396  if ((iw == 0) || (gmult != 0)) {
3397  ig = iw * gmult;
3398  /* find bracketing zenith angle indices */
3399  for (i = 0; i < aertab->dtran_ntheta; i++) {
3400  if (theta[ig] < aertab->dtran_theta[i])
3401  break;
3402  }
3403  if (i == aertab->dtran_ntheta) {
3404  i1 = i - 1;
3405  i2 = i - 1;
3406  wt = 0.0;
3407  } else {
3408  i1 = MIN(MAX(i - 1, 0), aertab->dtran_ntheta - 2);
3409  i2 = i1 + 1;
3410  x1 = aertab->dtran_airmass[i1];
3411  x2 = aertab->dtran_airmass[i2];
3412  xbar = 1.0 / cos(theta[ig] / radeg);
3413  wt = (xbar - x1) / (x2 - x1);
3414  }
3415  }
3416  iwtab = iwdtab[iw];
3417 
3418  a1 = aertab->model[modnum]->dtran_a[iwtab][i1];
3419  b1 = aertab->model[modnum]->dtran_b[iwtab][i1];
3420 
3421  a2 = aertab->model[modnum]->dtran_a[iwtab][i2];
3422  b2 = aertab->model[modnum]->dtran_b[iwtab][i2];
3423 
3424  /* disable interpolation, BAF, 6/2022
3425  if (inttst[iw]) {
3426  a1 = pow(a1, intexp[iw]);
3427  a2 = pow(a2, intexp[iw]);
3428  }
3429  */
3430 
3431  y1 = a1 * exp(-b1 * taua[iw]);
3432  y2 = a2 * exp(-b2 * taua[iw]);
3433 
3434  dtran[iw] = MAX(MIN((1.0 - wt) * y1 + wt*y2, 1.0), 1e-5);
3435 
3436  if(dt){
3437  if( fabs(dtran[iw]-1.0)<0.0000001 || fabs(dtran[iw]-1e-5)<0.0000001 )
3438  dt[iw]=0;
3439  else
3440  dt[iw]=-(1.0-wt)*y1*b1-wt*y2*b2;
3441  }
3442  }
3443 
3444  return;
3445 }
3446 void model_transmittance_pca(int modnum, float wave[], int32_t nwave,
3447  float *theta, int gmult, float taua[], float dtran[], float dt[]) {
3448 
3449  static int firstcall=1;
3450  static float *pc_td, *solz;
3451  static float *deriv_pc; //derivative of pc_td to taua[npc]
3452  static int npc, ntau_870,nsolz,nir_base;
3453  aermodstr *aermod=aertab->model[modnum];
3454  float a00,a01,a10,a11;
3455 
3456  int iw,itau,itheta,ipc,itau1,itau2,itheta1,itheta2;
3457  float r,p,deriv_r=0.;
3458 
3459  if(firstcall){
3460  firstcall=0;
3461  nir_base=windex(input->aer_wave_base,wave,nwave);
3462  solz=aertab->senz;
3463  nsolz=aertab->nsenz;
3464  ntau_870=aertab->ntau_870;
3465  npc=aertab->npc;
3466  pc_td=(float *)malloc(aertab->npc*sizeof(float));
3467  if(dt)
3468  deriv_pc=(float *)malloc(npc*sizeof(float));
3469  }
3470 
3472 
3473  if(taua[nir_base]<aermod->tau_870[0]){
3474  itau1=0;
3475  itau2=1;
3476  }else if(taua[nir_base]>=aermod->tau_870[ntau_870-1]){
3477  itau1=ntau_870-2;
3478  itau2=ntau_870-1;
3479  }else{
3480  for(itau=0;itau<ntau_870;itau++)
3481  if(taua[nir_base]<aermod->tau_870[itau])
3482  break;
3483  itau1=itau-1;
3484  itau2=itau;
3485  }
3486  if(itau1!=itau2){
3487  if(dt)
3488  deriv_r=1/(aermod->tau_870[itau2]-aermod->tau_870[itau1]);
3489  r=(taua[nir_base]-aermod->tau_870[itau1])/(aermod->tau_870[itau2]-aermod->tau_870[itau1]);
3490  }
3491  else
3492  r=0.0;
3493 
3494  for(itheta=0;itheta<nsolz;itheta++)
3495  if(*theta<solz[itheta])
3496  break;
3497  itheta1=MAX(itheta-1,0);
3498  itheta2=MIN(itheta,nsolz-1);
3499  if(itheta1!=itheta2)
3500  p=(*theta-solz[itheta1])/(solz[itheta2]-solz[itheta1]);
3501  else
3502  p=0.0;
3503 
3504  for(ipc=0;ipc<npc;ipc++){
3505  a00=aermod->pc_td[itau1][itheta1][ipc];
3506  a01=aermod->pc_td[itau1][itheta2][ipc];
3507  a10=aermod->pc_td[itau2][itheta1][ipc];
3508  a11=aermod->pc_td[itau2][itheta2][ipc];
3509 
3510  pc_td[ipc]=a00*(1-r)*(1-p)+a01*(1-r)*p+a10*r*(1-p)+a11*r*p;
3511  if(dt)
3512  deriv_pc[ipc]=(-a00*(1-p)-a01*p+a10*(1-p)+a11*p)*deriv_r;
3513  }
3514 
3515  for(iw=0;iw<nwave;iw++){
3516  dtran[iw]=0.;
3517  if(dt)
3518  dt[iw]=0.;
3519  for(ipc=0;ipc<npc;ipc++){
3520  dtran[iw]+=pc_td[ipc]*aermod->pc_components_td[ipc][iw];
3521  if(dt)
3522  dt[iw]+=aermod->pc_components_td[ipc][iw]*deriv_pc[ipc];
3523  }
3524  dtran[iw]+=aermod->pc_mean_td[iw];
3525  dtran[iw]=exp(dtran[iw]);
3526  if(dt)
3527  dt[iw]*=dtran[iw];
3528  }
3529  return;
3530 }
3531 void diff_tran_pca(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_l,
3532  geom_str *geom, float wv, float pr, float taur[], int32_t modmin,
3533  int32_t modmax, float modrat, float rhoa[], float taua[], float tsol[],
3534  float tsen[], float tauamin[], float tauamax[], int taua_opt, int ip,uncertainty_t *uncertainty) {
3535 
3536  int iw, gmult, ig,inir,ib;
3537  float *tsolmin;
3538  float *tsolmax;
3539  float *tsenmin;
3540  float *tsenmax;
3541  float *dtmin=NULL,*dtmax=NULL;// derivative of tsol[iw] or tsen [iw] with respect to taua[nir_l]
3542  float tmp;
3543  static int firstcall=1;
3544  static int32_t nbands_ac, *acbands_index;
3545 
3546 
3547  if(firstcall){
3548  firstcall=0;
3549  nbands_ac=input->nbands_ac;
3550  acbands_index=input->acbands_index;
3551  }
3552 
3553 
3554  if ((tsolmin = (float *) calloc(nwave, sizeof (float))) == NULL) {
3555  printf("Unable to allocate space for tsolmin.\n");
3556  exit(1);
3557  }
3558  if ((tsolmax = (float *) calloc(nwave, sizeof (float))) == NULL) {
3559  printf("Unable to allocate space for tsolmax.\n");
3560  exit(1);
3561  }
3562  if ((tsenmin = (float *) calloc(nwave, sizeof (float))) == NULL) {
3563  printf("Unable to allocate space for tsenmin.\n");
3564  exit(1);
3565  }
3566  if ((tsenmax = (float *) calloc(nwave, sizeof (float))) == NULL) {
3567  printf("Unable to allocate space for tsenmax.\n");
3568  exit(1);
3569  }
3570 
3571  if(uncertainty){
3572  iwnir_s=bindex_get(input->aer_wave_short);
3573  //dmodrat=uncertainty->dmodrat;
3574  if ((dtmin = (float *) calloc(nwave, sizeof(float))) == NULL) {
3575  printf("Unable to allocate space for dtmin.\n");
3576  exit(1);
3577  }
3578  if ((dtmax = (float *) calloc(nwave, sizeof(float))) == NULL) {
3579  printf("Unable to allocate space for dtmax.\n");
3580  exit(1);
3581  }
3582  }
3583 
3584 
3585  gmult = geom->gmult;
3586  if (interpol == 1) gmult = 0; /* geom used for model wavelengths */
3587 
3588  /* get AOT per band for each model, if not already computed */
3589  if (taua_opt == 0) {
3590  // using single scattering approximation space (Gordan and Wang)
3591  model_taua(sensorID, modmin, wave, nwave, iwnir_l, rhoa, geom, wv, tauamin);
3592  model_taua(sensorID, modmax, wave, nwave, iwnir_l, rhoa, geom, wv, tauamax);
3593  //printf("%d %d %d %f %f %f\n",taua_opt,modmin, iwnir_l, rhoa[iwnir_l], tauamin[0], tauamin[iwnir_l]);
3594  } else if (taua_opt == 2) {
3595  // using multi-scattering relationship between rhoa and taua (Ahmad)
3596  model_taua_mseps_pca(modmin, wave, nwave, iwnir_l, rhoa, geom, tauamin);
3597  model_taua_mseps_pca(modmax, wave, nwave, iwnir_l, rhoa, geom, tauamax);
3598  //printf("%d %d %d %f %f %f\n",taua_opt,modmin, iwnir_l, rhoa[iwnir_l], tauamin[0], tauamin[iwnir_l]);
3599  }
3600 
3601  /* get diff trans sun to ground, per band for each model */
3602  model_transmittance_pca(modmin, wave, nwave, geom->solz, gmult, tauamin, tsolmin, dtmin);
3603  model_transmittance_pca(modmax, wave, nwave, geom->solz, gmult, tauamax, tsolmax, dtmax);
3604 
3605  for (iw = 0; iw < nwave; iw++) {
3606  ig = iw * geom->gmult; /* geom used for sensor wavelengths */
3607  tsol[iw] = tsolmin[iw]*(1.0 - modrat) + tsolmax[iw] * modrat;
3608  //uncertainty->dt_sol[ip*nwave+iw]=sqrt( pow((1.0-modrat)*dtmin[iw],2) + pow(modrat*dtmax[iw],2) + pow((tsolmax[iw]-tsolmin[iw])*dmodrat[ip],2) );
3609 
3610  if(uncertainty){
3611  for(ib=0;ib<nbands_ac;ib++){
3612  inir=acbands_index[ib]-iwnir_s;
3613  uncertainty->derv_tsol_rhorc[iw][inir]=(tsolmax[iw]-tsolmin[iw])*uncertainty->derv_modrat_rhorc[inir];
3614  if(acbands_index[ib]==iwnir_l){
3615  uncertainty->derv_tsol_rhorc[iw][inir]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_rhorc_l[iwnir_l];
3616  uncertainty->derv_tsol_rhorc[iw][inir]+= modrat *dtmax[iw]*uncertainty->derv_taua_max_rhorc_l[iwnir_l];
3617  }
3618  }
3619  uncertainty->derv_tsol_taua_l[iw]=(tsolmax[iw]-tsolmin[iw])*uncertainty->derv_modrat_taua_l;
3620  uncertainty->derv_tsol_taua_l[iw]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_taua_l[iw];
3621  uncertainty->derv_tsol_taua_l[iw]+= modrat *dtmax[iw]*uncertainty->derv_taua_max_taua_l[iw];
3622 
3623  uncertainty->derv_tsol_rhow_l[iw]=(tsolmax[iw]-tsolmin[iw])*uncertainty->derv_modrat_rhow_l;
3624  uncertainty->derv_tsol_rhow_l[iw]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_rhow_l[iw];
3625  uncertainty->derv_tsol_rhow_l[iw]+=modrat *dtmax[iw]*uncertainty->derv_taua_max_rhow_l[iw];
3626  }
3627 
3628  /* correct for pressure difference from standard pressure */
3629  double tmp_pressure_diff = exp(-0.5 * taur[iw] / geom->csolz[ig]*(pr / p0 - 1));
3630  tsol[iw] = tsol[iw] * tmp_pressure_diff;
3631 
3632  //uncertainty->dt_sol[ip*nwave+iw]*=tmp_pressure_diff;
3633 
3634  if(uncertainty){
3635  for(ib=0;ib<nbands_ac;ib++){
3636  inir=acbands_index[ib]-iwnir_s;
3637  uncertainty->derv_tsol_rhorc[iw][inir]*=tmp_pressure_diff;
3638  }
3639  uncertainty->derv_tsol_taua_l[iw]*=tmp_pressure_diff;
3640  uncertainty->derv_tsol_rhow_l[iw]*=tmp_pressure_diff;
3641  }
3642 
3643  if ((evalmask & TRANSSPHER) != 0) {
3644  /* correct for airmass difference, plane-parallel to spherical atmosphere */
3645  tmp=tsol[iw];
3646  tsol[iw] = pow(tsol[iw], geom->airmass_sph[ig] / geom->airmass_plp[ig]);
3647 
3648  if(uncertainty)
3649  uncertainty->dt_sol[ip*nwave+iw]*= ( geom->airmass_sph[ig] / geom->airmass_plp[ig] *pow(tmp,geom->airmass_sph[ig] / geom->airmass_plp[ig]-1) );
3650  }
3651  }
3652 
3653  /* get diff trans ground to sensor, per band for each model */
3654  model_transmittance_pca(modmin, wave, nwave, geom->senz, gmult, tauamin, tsenmin, dtmin);
3655  model_transmittance_pca(modmax, wave, nwave, geom->senz, gmult, tauamax, tsenmax, dtmax);
3656 
3657  /* interpolate and pressure correct */
3658  for (iw = 0; iw < nwave; iw++) {
3659  ig = iw * geom->gmult; /* geom used for sensor wavelengths */
3660  taua[iw] = tauamin[iw]*(1.0 - modrat) + tauamax[iw] * modrat;
3661  tsen[iw] = tsenmin[iw]*(1.0 - modrat) + tsenmax[iw] * modrat;
3662 
3663  if(uncertainty){
3664  for(ib=0;ib<nbands_ac;ib++){
3665  inir=acbands_index[ib]-iwnir_s;
3666  uncertainty->derv_tsen_rhorc[iw][inir]=(tsenmax[iw]-tsenmin[iw])*uncertainty->derv_modrat_rhorc[inir];
3667  if(acbands_index[ib]==iwnir_l){
3668  uncertainty->derv_tsen_rhorc[iw][inir]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_rhorc_l[iwnir_l];
3669  uncertainty->derv_tsen_rhorc[iw][inir]+= modrat *dtmax[iw]*uncertainty->derv_taua_max_rhorc_l[iwnir_l];
3670  }
3671  }
3672  uncertainty->derv_tsen_taua_l[iw]=(tsenmax[iw]-tsenmin[iw])*uncertainty->derv_modrat_taua_l;
3673  uncertainty->derv_tsen_taua_l[iw]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_taua_l[iw];
3674  uncertainty->derv_tsen_taua_l[iw]+= modrat *dtmax[iw]*uncertainty->derv_taua_max_taua_l[iw];
3675 
3676  uncertainty->derv_tsen_rhow_l[iw]=(tsenmax[iw]-tsenmin[iw])*uncertainty->derv_modrat_rhow_l;
3677  uncertainty->derv_tsen_rhow_l[iw]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_rhow_l[iw];
3678  uncertainty->derv_tsen_rhow_l[iw]+=modrat *dtmax[iw]*uncertainty->derv_taua_max_rhow_l[iw];
3679  }
3680  /* correct for pressure difference from standard pressure */
3681  double tmp_pressure_diff = exp(-0.5 * taur[iw] / geom->csenz[ig] *(pr / p0 - 1));
3682  tsen[iw] = tsen[iw] * tmp_pressure_diff;
3683 
3684  if(uncertainty){
3685  for(ib=0;ib<nbands_ac;ib++){
3686  inir=acbands_index[ib]-iwnir_s;
3687  uncertainty->derv_tsen_rhorc[iw][inir]*=tmp_pressure_diff;
3688  }
3689  uncertainty->derv_tsen_taua_l[iw]*=tmp_pressure_diff;
3690  uncertainty->derv_tsen_rhow_l[iw]*=tmp_pressure_diff;
3691  }
3692 
3693  if ((evalmask & TRANSSPHER) != 0) {
3694  /* correct for airmass difference, plane-parallel to spherical atmosphere */
3695  tmp=tsen[iw];
3696  tsen[iw] = pow(tsen[iw], geom->airmass_sph[ig] / geom->airmass_plp[ig]);
3697  if(uncertainty)
3698  uncertainty->dt_sen[ip*nwave+iw]*= ( geom->airmass_sph[ig] / geom->airmass_plp[ig] *pow(tmp,geom->airmass_sph[ig] / geom->airmass_plp[ig]-1) );
3699  }
3700  }
3701 
3702  free(tsolmin);
3703  free(tsolmax);
3704  free(tsenmin);
3705  free(tsenmax);
3706  if(uncertainty){
3707  free(dtmin);
3708  free(dtmax);
3709  }
3710 
3711  return;
3712 }
3713 
3714 /* ---------------------------------------------------------------------------------------- */
3715 /* diff_tran() - compute Rayleigh-aerosol diffuse trans for selected model pair, both paths */
3716 /* ---------------------------------------------------------------------------------------- */
3717 void diff_tran(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_l,
3718  geom_str *geom, float wv, float pr, float taur[], int32_t modmin,
3719  int32_t modmax, float modrat, float rhoa[], float taua[], float tsol[],
3720  float tsen[], float tauamin[], float tauamax[], int taua_opt, int ip,uncertainty_t *uncertainty) {
3721 
3722  int iw, gmult, ig;
3723  float *tsolmin;
3724  float *tsolmax;
3725  float *tsenmin;
3726  float *tsenmax;
3727  float *dtmin=NULL,*dtmax=NULL;// derivative of tsol or tsen with respect to the corresponding taua
3728  float tmp;
3729 
3730  int iwnir_s;
3731  int inir;
3732 
3733  if(use_pca_lut){
3734  diff_tran_pca(sensorID,wave,nwave,iwnir_l,geom,wv,pr,taur,modmin,modmax,modrat,rhoa,taua,tsol,tsen,\
3735  tauamin,tauamax,taua_opt,ip,uncertainty);
3736  return;
3737  }
3738 
3739  if ((tsolmin = (float *) calloc(nwave, sizeof (float))) == NULL) {
3740  printf("Unable to allocate space for tsolmin.\n");
3741  exit(1);
3742  }
3743  if ((tsolmax = (float *) calloc(nwave, sizeof (float))) == NULL) {
3744  printf("Unable to allocate space for tsolmax.\n");
3745  exit(1);
3746  }
3747  if ((tsenmin = (float *) calloc(nwave, sizeof (float))) == NULL) {
3748  printf("Unable to allocate space for tsenmin.\n");
3749  exit(1);
3750  }
3751  if ((tsenmax = (float *) calloc(nwave, sizeof (float))) == NULL) {
3752  printf("Unable to allocate space for tsenmax.\n");
3753  exit(1);
3754  }
3755 
3756  if(uncertainty){
3757  iwnir_s=bindex_get(input->aer_wave_short);
3758  //dmodrat=uncertainty->dmodrat;
3759  if ((dtmin = (float *) calloc(nwave, sizeof(float))) == NULL) {
3760  printf("Unable to allocate space for dtmin.\n");
3761  exit(1);
3762  }
3763  if ((dtmax = (float *) calloc(nwave, sizeof(float))) == NULL) {
3764  printf("Unable to allocate space for dtmax.\n");
3765  exit(1);
3766  }
3767  }
3768 
3769 
3770  gmult = geom->gmult;
3771  if (interpol == 1) gmult = 0; /* geom used for model wavelengths */
3772 
3773  /* get AOT per band for each model, if not already computed */
3774  if (taua_opt == 0) {
3775  // using single scattering approximation space (Gordan and Wang)
3776  model_taua(sensorID, modmin, wave, nwave, iwnir_l, rhoa, geom, wv, tauamin);
3777  model_taua(sensorID, modmax, wave, nwave, iwnir_l, rhoa, geom, wv, tauamax);
3778  //printf("%d %d %d %f %f %f\n",taua_opt,modmin, iwnir_l, rhoa[iwnir_l], tauamin[0], tauamin[iwnir_l]);
3779  } else if (taua_opt == 2) {
3780  // using multi-scattering relationship between rhoa and taua (Ahmad)
3781  model_taua_mseps(modmin, wave, nwave, iwnir_l, rhoa, geom, tauamin);
3782  model_taua_mseps(modmax, wave, nwave, iwnir_l, rhoa, geom, tauamax);
3783  //printf("%d %d %d %f %f %f\n",taua_opt,modmin, iwnir_l, rhoa[iwnir_l], tauamin[0], tauamin[iwnir_l]);
3784  }
3785 
3786  /* get diff trans sun to ground, per band for each model */
3787  model_transmittance(modmin, wave, nwave, geom->solz, gmult, tauamin, tsolmin, dtmin);
3788  model_transmittance(modmax, wave, nwave, geom->solz, gmult, tauamax, tsolmax, dtmax);
3789 
3790  for (iw = 0; iw < nwave; iw++) {
3791  ig = iw * geom->gmult; /* geom used for sensor wavelengths */
3792  tsol[iw] = tsolmin[iw]*(1.0 - modrat) + tsolmax[iw] * modrat;
3793  //uncertainty->dt_sol[ip*nwave+iw]=sqrt( pow((1.0-modrat)*dtmin[iw],2) + pow(modrat*dtmax[iw],2) + pow((tsolmax[iw]-tsolmin[iw])*dmodrat[ip],2) );
3794 
3795  if(uncertainty){
3796  for(inir=iwnir_s;inir<=iwnir_l;inir++){
3797  uncertainty->derv_tsol_rhorc[iw][inir-iwnir_s]=(tsolmax[iw]-tsolmin[iw])*uncertainty->derv_modrat_rhorc[inir-iwnir_s];
3798  if(inir==iwnir_l){
3799  uncertainty->derv_tsol_rhorc[iw][inir-iwnir_s]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_rhorc_l[iw];
3800  uncertainty->derv_tsol_rhorc[iw][inir-iwnir_s]+= modrat *dtmax[iw]*uncertainty->derv_taua_max_rhorc_l[iw];
3801  }
3802  }
3803  uncertainty->derv_tsol_taua_l[iw]=(tsolmax[iw]-tsolmin[iw])*uncertainty->derv_modrat_taua_l;
3804  uncertainty->derv_tsol_taua_l[iw]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_taua_l[iw];
3805  uncertainty->derv_tsol_taua_l[iw]+= modrat *dtmax[iw]*uncertainty->derv_taua_max_taua_l[iw];
3806 
3807  uncertainty->derv_tsol_rhow_l[iw]=(tsolmax[iw]-tsolmin[iw])*uncertainty->derv_modrat_rhow_l;
3808  uncertainty->derv_tsol_rhow_l[iw]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_rhow_l[iw];
3809  uncertainty->derv_tsol_rhow_l[iw]+=modrat *dtmax[iw]*uncertainty->derv_taua_max_rhow_l[iw];
3810  }
3811 
3812  /* correct for pressure difference from standard pressure */
3813  double tmp_pressure_diff = exp(-0.5 * taur[iw] / geom->csolz[ig]*(pr / p0 - 1));
3814  tsol[iw] = tsol[iw] * tmp_pressure_diff;
3815 
3816  //uncertainty->dt_sol[ip*nwave+iw]*=tmp_pressure_diff;
3817 
3818  if(uncertainty){
3819  for(inir=iwnir_s;inir<=iwnir_l;inir++)
3820  uncertainty->derv_tsol_rhorc[iw][inir-iwnir_s]*=tmp_pressure_diff;
3821  uncertainty->derv_tsol_taua_l[iw]*=tmp_pressure_diff;
3822  uncertainty->derv_tsol_rhow_l[iw]*=tmp_pressure_diff;
3823  }
3824 
3825  if ((evalmask & TRANSSPHER) != 0) {
3826  /* correct for airmass difference, plane-parallel to spherical atmosphere */
3827  tmp=tsol[iw];
3828  tsol[iw] = pow(tsol[iw], geom->airmass_sph[ig] / geom->airmass_plp[ig]);
3829 
3830  if(uncertainty)
3831  uncertainty->dt_sol[ip*nwave+iw]*= ( geom->airmass_sph[ig] / geom->airmass_plp[ig] *pow(tmp,geom->airmass_sph[ig] / geom->airmass_plp[ig]-1) );
3832  }
3833  }
3834 
3835  /* get diff trans ground to sensor, per band for each model */
3836  model_transmittance(modmin, wave, nwave, geom->senz, gmult, tauamin, tsenmin, dtmin);
3837  model_transmittance(modmax, wave, nwave, geom->senz, gmult, tauamax, tsenmax, dtmax);
3838 
3839  /* interpolate and pressure correct */
3840  for (iw = 0; iw < nwave; iw++) {
3841  ig = iw * geom->gmult; /* geom used for sensor wavelengths */
3842  taua[iw] = tauamin[iw]*(1.0 - modrat) + tauamax[iw] * modrat;
3843  tsen[iw] = tsenmin[iw]*(1.0 - modrat) + tsenmax[iw] * modrat;
3844 
3845  if(uncertainty){
3846  for(inir=iwnir_s;inir<=iwnir_l;inir++){
3847  uncertainty->derv_tsen_rhorc[iw][inir-iwnir_s]=(tsenmax[iw]-tsenmin[iw])*uncertainty->derv_modrat_rhorc[inir-iwnir_s];
3848  if(inir==iwnir_l){
3849  uncertainty->derv_tsen_rhorc[iw][inir-iwnir_s]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_rhorc_l[iw];
3850  uncertainty->derv_tsen_rhorc[iw][inir-iwnir_s]+= modrat *dtmax[iw]*uncertainty->derv_taua_max_rhorc_l[iw];
3851  }
3852  }
3853  uncertainty->derv_tsen_taua_l[iw]=(tsenmax[iw]-tsenmin[iw])*uncertainty->derv_modrat_taua_l;
3854  uncertainty->derv_tsen_taua_l[iw]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_taua_l[iw];
3855  uncertainty->derv_tsen_taua_l[iw]+= modrat *dtmax[iw]*uncertainty->derv_taua_max_taua_l[iw];
3856 
3857  uncertainty->derv_tsen_rhow_l[iw]=(tsenmax[iw]-tsenmin[iw])*uncertainty->derv_modrat_rhow_l;
3858  uncertainty->derv_tsen_rhow_l[iw]+=(1.0 - modrat)*dtmin[iw]*uncertainty->derv_taua_min_rhow_l[iw];
3859  uncertainty->derv_tsen_rhow_l[iw]+=modrat *dtmax[iw]*uncertainty->derv_taua_max_rhow_l[iw];
3860  }
3861  /* correct for pressure difference from standard pressure */
3862  double tmp_pressure_diff = exp(-0.5 * taur[iw] / geom->csenz[ig] *(pr / p0 - 1));
3863  tsen[iw] = tsen[iw] * tmp_pressure_diff;
3864 
3865  if(uncertainty){
3866  for(inir=iwnir_s;inir<=iwnir_l;inir++)
3867  uncertainty->derv_tsen_rhorc[iw][inir-iwnir_s]*=tmp_pressure_diff;
3868  uncertainty->derv_tsen_taua_l[iw]*=tmp_pressure_diff;
3869  uncertainty->derv_tsen_rhow_l[iw]*=tmp_pressure_diff;
3870  }
3871 
3872  if ((evalmask & TRANSSPHER) != 0) {
3873  /* correct for airmass difference, plane-parallel to spherical atmosphere */
3874  tmp=tsen[iw];
3875  tsen[iw] = pow(tsen[iw], geom->airmass_sph[ig] / geom->airmass_plp[ig]);
3876  if(uncertainty)
3877  uncertainty->dt_sen[ip*nwave+iw]*= ( geom->airmass_sph[ig] / geom->airmass_plp[ig] *pow(tmp,geom->airmass_sph[ig] / geom->airmass_plp[ig]-1) );
3878  }
3879  }
3880 
3881  free(tsolmin);
3882  free(tsolmax);
3883  free(tsenmin);
3884  free(tsenmax);
3885  if(uncertainty){
3886  free(dtmin);
3887  free(dtmax);
3888  }
3889 
3890  return;
3891 }
3892 
3893 /* ---------------------------------------------------------------------------------------- */
3894 /* smaer_pca() - spectral matching approach based on PCA LUTs */
3895 /*
3896  * M. Zhang, Dec. 2022. */
3897 
3898 /* ---------------------------------------------------------------------------------------- */
3899 
3900 int smaer_pca(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s,
3901  int32_t iwnir_l, int32_t nmodels, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t *modmin, int32_t *modmax,
3902  float32 *modrat, float *tau_pred_min, float *tau_pred_max, int32_t ip, float chi[], float *mbac_w,uncertainty_t *uncertainty) {
3903  static float *tau_iwnir_l;//[nmodels]
3904  static int firstcall=1, nir_l;
3905  static float **pc_rhoa;
3906  static int npc, ntau_870;
3907  aermodstr *aermod;
3908  static int wave_base_index; //index of the nir_l in the mbac_wave
3909 
3910  int iw, ib, itau,ipc,itemp;
3911 
3912  int status = 0;
3913 
3914  static float *rho_all_wav_pred,*rho_pred_min,*rho_pred_max;
3915 
3916  int im, modl;
3917 
3918  float diff_2 = 0.0,diff_1=0.0;
3919  float mbac_wsum = 0.0;
3920  static float *chi_old;
3921 
3922  float *noise=&noise_global[ip*nwave];
3923 
3924  static float **derv_chi_rhorc;//dimension: [nmodels][nbands_ac], deivative of chi to rhorc
3925  static float *derv_chi_taua_l; //dimension: [nmodels], deivative of chi to taua_l
3926  static float **derv_rhoa_rhorc_l;// derivative of modeled rhoa[nwave] to rhorc[iwnir_l]
3927  float *derv_modrat_rhorc;// dimension: [nbands_ac], deivative of modrat to rhorc[iwnir_s to iwnir_l]
3928  float derv_modrat_taua_l=0.; // deivative of modrat to taua [iwnir_l]
3929  float derv_modrat_rhow_l=0.;
3930  float *derv_taua_min_rhorc_l;
3931  float *derv_taua_min_taua_l;
3932  float *derv_taua_min_rhow_l;
3933  float *derv_taua_max_rhorc_l;
3934  float *derv_taua_max_taua_l;
3935  float *derv_taua_max_rhow_l;
3936  static float *derv_taua_rhorc_l;//[nmodels], derivative of modeled taua[nir_l] to rhorc_l
3937  static float *derv_chi_obs_rhorc; //[nbands_ac], derivative of chi_obs to rhorc at nbands_ac
3938  float derv_chi_obs_taua_l; // derivative of chi_obs to taua_l
3939 
3940  static float *derv_rhoa_min=NULL,*derv_rhoa_max=NULL; //derivative of rhoa[]to taua[aer_l] for aermodmin and aermodmax
3941  static float *derv_taua_min=NULL,*derv_taua_max=NULL; //derivative of taua[]to taua[aer_l] for aermodmin and aermodmax
3942 
3943 
3944  float derv_temp_rhorc;
3945  float derv_modrat_chi0,derv_modrat_chi1;
3946 
3947  static float **rhoa_modl; //[ntau_870][nwave]
3948  struct str chi_struct[nmodels];
3949 
3950  static int32_t nbands_ac, *acbands_index;
3951 
3952  if(firstcall){
3953  firstcall=0;
3954  nir_l=bindex_get(input->aer_wave_base);
3955 
3956  if(nir_l!=iwnir_l){
3957  printf("aer_wave_base is different from the aer_wave_long, which may break the uncertainty for mbac\n");
3958  exit(1);
3959  }
3960 
3961  ntau_870=aertab->ntau_870;
3962  npc=aertab->npc;
3963  rhoa_modl=(float **)malloc(aertab->ntau_870*sizeof(float*));
3964  pc_rhoa=(float **)malloc(aertab->ntau_870*sizeof(float *));
3965 
3966  for(itau=0;itau<aertab->ntau_870;itau++){
3967  pc_rhoa[itau]=(float *)malloc(aertab->npc*sizeof(float));
3968  rhoa_modl[itau]=(float *)malloc(nwave*sizeof(float));
3969  }
3970  rho_all_wav_pred = (float*) malloc(nwave * sizeof (float));
3971  rho_pred_min = (float*) malloc(nwave * sizeof (float));
3972  rho_pred_max = (float*) malloc(nwave * sizeof (float));
3973  chi_old=(float*) malloc((nmodels) * sizeof (float));
3974  tau_iwnir_l=(float*) malloc((nmodels) * sizeof (float));
3975 
3976  nbands_ac=input->nbands_ac;
3977  acbands_index=input->acbands_index;
3978 
3979  float *tempwave=(float *)malloc(nbands_ac*sizeof(float));
3980  for(iw=0;iw<nbands_ac;iw++)
3981  tempwave[iw]=input->mbac_wave[iw];
3982 
3983  wave_base_index=windex(input->aer_wave_base*1.,tempwave,nbands_ac);
3984  free(tempwave);
3985 
3986  if(uncertainty){
3987  derv_chi_taua_l =(float *)malloc(nmodels*sizeof(float));
3988  derv_chi_rhorc =(float **)malloc(nmodels*sizeof(float *));
3989  derv_rhoa_rhorc_l=(float **)malloc(nmodels*sizeof(float*));
3990  derv_taua_rhorc_l=(float *)malloc(nmodels*sizeof(float));
3991 
3992  for(im=0;im<nmodels;im++){
3993  derv_chi_rhorc[im] =(float *)malloc(nbands_ac*sizeof(float));
3994  derv_rhoa_rhorc_l[im]=(float *)malloc(nwave*sizeof(float));
3995  }
3996  derv_chi_obs_rhorc=(float *)malloc(nbands_ac*sizeof(float));
3997  derv_rhoa_min=(float *)malloc(nwave*sizeof(float));
3998  derv_rhoa_max=(float *)malloc(nwave*sizeof(float));
3999  derv_taua_min=(float *)malloc(nwave*sizeof(float));
4000  derv_taua_max=(float *)malloc(nwave*sizeof(float));
4001  }
4002  }
4003 
4004  if(uncertainty){
4005  derv_modrat_rhorc=uncertainty->derv_modrat_rhorc;
4006  derv_taua_min_rhorc_l=uncertainty->derv_taua_min_rhorc_l;
4007  derv_taua_min_taua_l=uncertainty->derv_taua_min_taua_l;
4008  derv_taua_min_rhow_l=uncertainty->derv_taua_min_rhow_l;
4009  derv_taua_max_rhorc_l=uncertainty->derv_taua_max_rhorc_l;
4010  derv_taua_max_taua_l=uncertainty->derv_taua_max_taua_l;
4011  derv_taua_max_rhow_l=uncertainty->derv_taua_max_rhow_l;
4012  }
4013 
4014  float chi_obs=0.0;
4015  if(uncertainty){
4016  for(iw = 0; iw <nbands_ac; iw++)
4017  derv_chi_obs_rhorc[iw]=0.;
4018  derv_chi_obs_taua_l=0.;
4019  }
4020 
4021  for (ib = 0; ib <nbands_ac; ib++) {
4022 
4023  iw=acbands_index[ib];
4024  if(iw==nir_l)
4025  continue;
4026  chi_obs += rhoa[iw]/rhoa[nir_l];
4027  mbac_wsum += mbac_w[iw];
4028  if(uncertainty){
4029  derv_chi_obs_rhorc[ib]=1/rhoa[nir_l];
4030  derv_chi_obs_rhorc[wave_base_index]+=(-rhoa[iw]/rhoa[nir_l]/rhoa[nir_l]);
4031  derv_chi_obs_taua_l+=(-1/rhoa[nir_l]*uncertainty->derv_Lg_taua[iw]+rhoa[iw]/rhoa[nir_l]/rhoa[nir_l]*uncertainty->derv_Lg_taua[nir_l]);
4032  }
4033  }
4034  chi_obs/=mbac_wsum;
4035  if(uncertainty){
4036  derv_chi_obs_taua_l/=mbac_wsum;
4037  for (ib = 0; ib <nbands_ac; ib++)
4038  derv_chi_obs_rhorc[ib]/=mbac_wsum;
4039  }
4040 
4041  for (im = 0; im < nmodels; im++) {
4042 
4043  modl = mindx[im];
4044  aermod=aertab->model[modl];
4045  //ext_iwnir_l=aermod->extc[nir_l];
4046 
4047  get_pc_rhoa(modl,geom,pc_rhoa);
4048 
4049  for(itau=0;itau<ntau_870;itau++)
4050  for (ib = 0; ib <nbands_ac; ib++){
4051 
4052  iw=acbands_index[ib];
4053  rhoa_modl[itau][iw]=0;
4054 
4055  for(ipc=0;ipc<npc;ipc++)
4056  rhoa_modl[itau][iw]+=pc_rhoa[itau][ipc]*aermod->pc_components_rhoa[ipc][iw];
4057 
4058  rhoa_modl[itau][iw]+=aermod->pc_mean_rhoa[iw];
4059  //rhoa_modl[itau][iw]=exp(rhoa_modl[itau][iw]);
4060  }
4061 
4062 
4063  /* compute model epsilon */
4064  if(rhoa[nir_l]<=rhoa_modl[0][nir_l])
4065  itau=1;
4066  else if (rhoa[nir_l]>= rhoa_modl[ntau_870-1][nir_l])
4067  itau=ntau_870-1;
4068  else{
4069  for(itau=1;itau<ntau_870;itau++){
4070  if(rhoa[nir_l]<rhoa_modl[itau][nir_l] && rhoa[nir_l]>=rhoa_modl[itau-1][nir_l])
4071  break;
4072  }
4073  }
4074  tau_iwnir_l[im]=aermod->tau_870[itau]+(aermod->tau_870[itau]-aermod->tau_870[itau-1])*(rhoa[nir_l]-rhoa_modl[itau][nir_l])/(rhoa_modl[itau][nir_l]-rhoa_modl[itau-1][nir_l]);
4075 
4076  if(nmodels<=1){
4077  if(comp_rhoa_pca(nwave, wave, geom, tau_iwnir_l[im], modl, tau_pred_min, rhoa,derv_rhoa_min,derv_taua_min) !=0)
4078  return -1;
4079  for(ib=0;ib<nwave;ib++)
4080  tau_pred_max[ib]=tau_pred_min[ib];
4081  *modmin=modl;*modmax=modl;*modrat=1.0;
4082  return 0;
4083  }
4084 
4085  if(uncertainty)
4086  derv_taua_rhorc_l[im]=(aermod->tau_870[itau]-aermod->tau_870[itau-1])/(rhoa_modl[itau][nir_l]-rhoa_modl[itau-1][nir_l]);
4087 
4088  /* compute reflectance at all wavelength */
4089  for (ib = 0; ib <nbands_ac; ib++){
4090  iw=acbands_index[ib];
4091  rho_all_wav_pred[iw]=rhoa_modl[itau][iw]+(rhoa_modl[itau][iw]-rhoa_modl[itau-1][iw])*(tau_iwnir_l[im]-aermod->tau_870[itau])/(aermod->tau_870[itau]-aermod->tau_870[itau-1]);
4092 
4093  // ext_coef = aermod->extc[iw];
4094  if(uncertainty){
4095  derv_rhoa_rhorc_l[im][iw]=derv_taua_rhorc_l[im]*(rhoa_modl[itau][iw]-rhoa_modl[itau-1][iw])/(aermod->tau_870[itau]-aermod->tau_870[itau-1]);
4096  // derv_taua_rhorc_l[im][iw]=(ext_coef / ext_iwnir_l)*derv_temp_rhorc;
4097  }
4098  }
4099  if(uncertainty){
4100  derv_chi_rhorc[im][wave_base_index]=0.;
4101  derv_chi_taua_l[im]=0.;
4102  }
4103  mbac_wsum=0.;
4104  for (ib = 0; ib <nbands_ac; ib++){
4105  iw=acbands_index[ib];
4106  if(iw==nir_l)
4107  continue;
4108 
4109  diff_2 += rho_all_wav_pred[iw]/rhoa[nir_l];
4110  diff_1 +=pow((rhoa[iw] - rho_all_wav_pred[iw])/noise[iw], 2)*mbac_w[iw];//
4111  mbac_wsum += mbac_w[iw];
4112 
4113  if(uncertainty){
4114  derv_temp_rhorc=(derv_rhoa_rhorc_l[im][iw]/rhoa[nir_l]-rho_all_wav_pred[iw]/rhoa[nir_l]/rhoa[nir_l]);
4115  derv_chi_rhorc [im][wave_base_index]+=derv_temp_rhorc;
4116  derv_chi_taua_l[im]+=(-derv_temp_rhorc*uncertainty->derv_Lg_taua[nir_l]);
4117  }
4118  }
4119 
4120  chi[im] = diff_2 / mbac_wsum;
4121  chi_old[im]=diff_1/mbac_wsum;
4122  if(uncertainty){
4123  derv_chi_rhorc[im][wave_base_index]/=mbac_wsum;
4124  derv_chi_taua_l [im]/=mbac_wsum;
4125  }
4126 
4127  diff_2 = 0.0;
4128  diff_1 = 0.0;
4129  mbac_wsum = 0.0;
4130  chi_struct[im].value=chi_old[im];
4131  chi_struct[im].index=im;
4132  }
4133 
4134  qsort(chi_struct,nmodels,sizeof(chi_struct[0]),cmp);
4135 
4136  /* for (im = 0; im < nmodels; im++)
4137  if(chi_obs<chi_struct[im].value)
4138  break;
4139  *modmin = MAX(MIN(im - 1, nmodels - 1), 0);
4140  *modmax = MAX(MIN(im, nmodels - 1), 0);*/
4141 
4142  *modrat=chi_struct[0].value/(chi_struct[0].value+chi_struct[1].value);
4143  chi_old[0]=chi_struct[0].value*(1-*modrat)+chi_struct[1].value*(*modrat); //temporary keeping the chi2 value from two closest aerosol models
4144 
4145  /*chi_struc is switched back to the ratio after selecting the model using the chi based on difference*/
4146  for(im=0;im<nmodels;im++)
4147  chi_struct[im].value=chi[chi_struct[im].index];
4148 
4149 
4150  /*if( (chi_obs-chi_struct[0].value)*(chi_obs-chi_struct[1].value)>0){
4151  *modrat=1.0; //need to flag
4152  *modmin=chi_struct[0].index;
4153  *modmax=*modmin;
4154  } else*/
4155  {
4156  if(chi_obs>chi_struct[1].value){
4157  im=chi_struct[0].index;
4158  diff_1=chi_struct[0].value;
4159 
4160  chi_struct[0].value=chi_struct[1].value;
4161  chi_struct[0].index=chi_struct[1].index;
4162 
4163  chi_struct[1].value=diff_1;
4164  chi_struct[1].index=im;
4165  }
4166  *modmin=chi_struct[0].index;
4167  *modmax=chi_struct[1].index;
4168 
4169  *modrat=(chi_obs-chi_struct[0].value)/(chi_struct[1].value-chi_struct[0].value);
4170  if(uncertainty){
4171  derv_modrat_chi0= (chi_obs-chi_struct[1].value)/pow(chi_struct[1].value-chi_struct[0].value,2);
4172  derv_modrat_chi1=-(chi_obs-chi_struct[0].value)/pow(chi_struct[1].value-chi_struct[0].value,2);
4173 
4174  for (ib = 0; ib <nbands_ac; ib++){
4175  iw=acbands_index[ib];
4176  if(iw!=nir_l){
4177  derv_modrat_rhorc[ib]=derv_chi_obs_rhorc[ib]/(chi_struct[1].value-chi_struct[0].value);
4178  derv_modrat_rhow_l+=-derv_modrat_rhorc[ib]*uncertainty->ratio_rhow[ib];
4179  }
4180  }
4181 
4182  derv_modrat_rhorc[wave_base_index]=derv_modrat_chi0*derv_chi_rhorc[*modmin][wave_base_index]+derv_modrat_chi1*derv_chi_rhorc[*modmax][wave_base_index];
4183  derv_modrat_rhorc[wave_base_index]+=derv_chi_obs_rhorc[wave_base_index]/(chi_struct[1].value-chi_struct[0].value);
4184  derv_modrat_rhow_l+=-derv_modrat_rhorc[wave_base_index];
4185 
4186  derv_modrat_taua_l =derv_modrat_chi0*derv_chi_taua_l [*modmin]+derv_modrat_chi1*derv_chi_taua_l [*modmax];
4187  derv_modrat_taua_l +=derv_chi_obs_taua_l/(chi_struct[1].value-chi_struct[0].value);
4188 
4189  uncertainty->derv_modrat_rhow_l=derv_modrat_rhow_l;
4190  uncertainty->derv_modrat_taua_l=derv_modrat_taua_l;
4191  }
4192  }
4193 
4194  if(comp_rhoa_pca(nwave, wave, geom, tau_iwnir_l[*modmin], mindx[*modmin], tau_pred_min, rho_pred_min,derv_rhoa_min,derv_taua_min) !=0)
4195  return -1;
4196  if(comp_rhoa_pca(nwave, wave, geom, tau_iwnir_l[*modmax], mindx[*modmax], tau_pred_max, rho_pred_max,derv_rhoa_max,derv_taua_max) !=0)
4197  return -1;
4198 
4199  for (iw = 0; iw <nwave; iw++) {
4200 
4201  rhoa[iw]=rho_pred_min[iw]*(1-*modrat)+rho_pred_max[iw]*(*modrat);
4202 
4203  if(uncertainty){
4204  for(itemp=0;itemp<nbands_ac;itemp++){
4205  ib=acbands_index[itemp];
4206  if(ib!=nir_l){
4207  uncertainty->derv_La_rhorc[iw][itemp]=(rho_pred_max[iw]-rho_pred_min[iw])*derv_modrat_rhorc[itemp];
4208  uncertainty->derv_La_rhow_l[iw]+=-uncertainty->derv_La_rhorc[iw][itemp]*uncertainty->ratio_rhow[itemp];
4209  }
4210  }
4211  uncertainty->derv_La_rhorc[iw][wave_base_index]=(rho_pred_max[iw]-rho_pred_min[iw])*derv_modrat_rhorc[wave_base_index];
4212  uncertainty->derv_La_rhorc[iw][wave_base_index]+= (1-*modrat)*derv_rhoa_min[iw]*derv_taua_rhorc_l[*modmin];
4213  uncertainty->derv_La_rhorc[iw][wave_base_index]+= (*modrat) *derv_rhoa_max[iw]*derv_taua_rhorc_l[*modmax];
4214  uncertainty->derv_La_rhow_l[iw]+=-uncertainty->derv_La_rhorc[iw][wave_base_index];
4215 
4216  uncertainty->derv_La_taua_l[iw]=(rho_pred_max[iw]-rho_pred_min[iw])*derv_modrat_taua_l;
4217  uncertainty->derv_La_taua_l[iw]+=(1-*modrat)*(-derv_rhoa_min[iw]*derv_taua_rhorc_l[*modmin]*uncertainty->derv_Lg_taua[iw]);
4218  uncertainty->derv_La_taua_l[iw]+=(*modrat) *(-derv_rhoa_max[iw]*derv_taua_rhorc_l[*modmax]*uncertainty->derv_Lg_taua[iw]);
4219 
4220  derv_taua_min_rhorc_l[iw]=derv_taua_min[iw]*derv_taua_rhorc_l[*modmin];
4221  derv_taua_max_rhorc_l[iw]=derv_taua_max[iw]*derv_taua_rhorc_l[*modmax];
4222  derv_taua_min_taua_l[iw]=-derv_taua_min_rhorc_l[iw]*uncertainty->derv_Lg_taua[iw];
4223  derv_taua_max_taua_l[iw]=-derv_taua_max_rhorc_l[iw]*uncertainty->derv_Lg_taua[iw];
4224  derv_taua_min_rhow_l[iw]=-derv_taua_min_rhorc_l[iw];
4225  derv_taua_max_rhow_l[iw]=-derv_taua_max_rhorc_l[iw];
4226 
4227  }
4228  }
4229 
4230  *modmin=mindx[*modmin];
4231  *modmax=mindx[*modmax];
4232  chi[0]=chi_old[0];
4233 
4234 
4235 
4236  return (status);
4237 }
4238 
4239 
4240 
4241 /* ---------------------------------------------------------------------------------------- */
4242 /* smaer() - compute aerosol reflectance using MSEPS approach of Ahmad
4243  * perform spectral matching in reflectance space */
4244 /* output the reflectance of the two bracketing aerosol models */
4245 /*
4246  * Amir Ibrahim, Jul 2016. */
4247 
4248 /* ---------------------------------------------------------------------------------------- */
4249 
4250 int smaer(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s,
4251  int32_t iwnir_l, int32_t nmodels, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t *modmin, int32_t *modmax,
4252  float32 *modrat, float *tau_pred_min, float *tau_pred_max, int32_t ip, float chi[], float *mbac_w,uncertainty_t *uncertainty) {
4253 
4254  if (!have_ms && !use_pca_lut) {
4255  printf("\nThe multi-scattering spectral matching atmospheric correction method requires\n");
4256  printf("ams_all, bms_all, cms_all, dms_all, ems in the aerosol model tables.\n");
4257  exit(1);
4258  }
4259 
4260  int status = 0;
4261 
4262  if(use_pca_lut){
4263  status=smaer_pca(sensorID,wave,nwave,iwnir_s,iwnir_l,nmodels,mindx,geom,wv,rhoa,
4264  modmin,modmax,modrat,tau_pred_min,tau_pred_max,ip,chi,mbac_w,uncertainty);
4265  return status;
4266  }
4267 
4268  float *ac, *bc, *cc, *dc, *ec;
4269  float ext_iwnir_l,tau_iwnir_l;
4270  double ax, bx, cx, fx;
4271  static int firstcall=1, nir_l;
4272 
4273  int iw, i,ib;
4274 
4275  static float **tau_all_wav, **rho_all_wav_pred;
4276 
4277  float ext_coef, lg_taua, lg_rhoa;
4278 
4279  int iwtab, im, modl;
4280 
4281  float diff_2 = 0.0, diff_1 = 0.0;
4282  float mbac_wsum = 0.0;
4283  static float *chi_old;
4284 
4285  float *noise;
4286  int iwtab_l;
4287  static int32_t nbands_ac, *acbands_index,wave_base_index;
4288 
4289  float **derv_chi_rhorc;//dimension: [nmodels][nbands_ac], deivative of chi to rhorc
4290  float *derv_chi_taua_l; //dimension: [nmodels], deivative of chi to taua_l
4291  float **derv_rhoa_rhorc_l;// derivative of modeled rhoa[nwave] to rhorc[iwnir_l]
4292  float *derv_modrat_rhorc;// dimension: [nbands_ac], deivative of modrat to rhorc[iwnir_s to iwnir_l]
4293  float derv_modrat_taua_l=0.; // deivative of modrat to taua [iwnir_l]
4294  float derv_modrat_rhow_l=0.;
4295  float *derv_taua_min_rhorc_l;
4296  float *derv_taua_min_taua_l;
4297  float *derv_taua_min_rhow_l;
4298  float *derv_taua_max_rhorc_l;
4299  float *derv_taua_max_taua_l;
4300  float *derv_taua_max_rhow_l;
4301  float **derv_taua_rhorc_l;//[nmodels][nwave], derivative of modeled taua[nwave] to rhorc_l
4302  float *derv_chi_obs_rhorc; //[nbands_ac], derivative of chi_obs to rhorc at nbands_ac
4303  float derv_chi_obs_taua_l; // derivative of chi_obs to taua_l
4304 
4305  float derv_temp_rhorc;
4306  float derv_modrat_chi0,derv_modrat_chi1;
4307 
4308  if(uncertainty){
4309  derv_modrat_rhorc=uncertainty->derv_modrat_rhorc;
4310  derv_taua_min_rhorc_l=uncertainty->derv_taua_min_rhorc_l;
4311  derv_taua_min_taua_l=uncertainty->derv_taua_min_taua_l;
4312  derv_taua_min_rhow_l=uncertainty->derv_taua_min_rhow_l;
4313  derv_taua_max_rhorc_l=uncertainty->derv_taua_max_rhorc_l;
4314  derv_taua_max_taua_l=uncertainty->derv_taua_max_taua_l;
4315  derv_taua_max_rhow_l=uncertainty->derv_taua_max_rhow_l;
4316 
4317  derv_chi_taua_l =(float *)malloc(nmodels*sizeof(float));
4318  derv_chi_rhorc =(float **)malloc(nmodels*sizeof(float *));
4319  derv_rhoa_rhorc_l=(float **)malloc(nmodels*sizeof(float*));
4320  derv_taua_rhorc_l=(float **)malloc(nmodels*sizeof(float*));
4321 
4322  for(im=0;im<nmodels;im++){
4323  derv_chi_rhorc[im] =(float *)malloc(nbands_ac*sizeof(float));
4324  derv_rhoa_rhorc_l[im]=(float *)malloc(nwave*sizeof(float));
4325  derv_taua_rhorc_l[im]=(float *)malloc(nwave*sizeof(float));
4326  }
4327  for(im=0;im<nmodels;im++)
4328  for(iw=0;iw<nbands_ac;iw++)
4329  derv_chi_rhorc[im][iw]=0.;
4330 
4331  for (iw = 0; iw < nbands_ac; iw++)
4332  derv_modrat_rhorc[iw] = 0.;
4333 
4334  derv_chi_obs_rhorc = (float *)malloc(nbands_ac * sizeof(float));
4335  }
4336 
4337  if(firstcall){
4338  firstcall=0;
4339  nir_l=bindex_get(input->aer_wave_base);
4340 
4341  tau_all_wav = (float**) malloc(nwave * sizeof (float*));
4342  rho_all_wav_pred = (float**) malloc(nwave * sizeof (float*));
4343 
4344  chi_old = (float *)malloc((nmodels) * sizeof(float));
4345 
4346  for (i = 0; i < nwave; i++) {
4347  tau_all_wav[i] = (float*) malloc((nmodels) * sizeof (float));
4348  rho_all_wav_pred[i] = (float*) malloc((nmodels) * sizeof (float));
4349  }
4350 
4351  nbands_ac=input->nbands_ac;
4352  acbands_index=input->acbands_index;
4353 
4354  float *tempwave=(float *)malloc(nbands_ac*sizeof(float));
4355  for(iw=0;iw<nbands_ac;iw++)
4356  tempwave[iw]=input->mbac_wave[iw];
4357 
4358  wave_base_index=windex(input->aer_wave_base*1.,tempwave,nbands_ac);
4359  free(tempwave);
4360  }
4361 
4362  noise= &noise_global[ip*nwave];
4363 
4364  // sorting in ascending way elements of chi-squared -- will need clean-up
4365  struct str { float value;int index;};
4366  struct str chi_struct[nmodels];
4367 
4368  iwtab_l = iwatab[nir_l];
4369 
4370  float chi_obs = 0.0;
4371  if (uncertainty) {
4372  for (iw = 0; iw <nbands_ac; iw++)
4373  derv_chi_obs_rhorc[iw ] = 0.;
4374  derv_chi_obs_taua_l = 0.;
4375  }
4376 
4377  for (ib = 0; ib <nbands_ac; ib++) {
4378 
4379  iw=acbands_index[ib];
4380  if (mbac_w[iw] == 0. || iw == nir_l)
4381  continue;
4382  chi_obs +=rhoa[iw] / rhoa[nir_l]; // pow((rhoa[iw] - rho_all_wav_pred[iw][im])/noise[iw], 2)*mbac_w[iw];//
4383  mbac_wsum += mbac_w[iw];
4384  if (uncertainty) {
4385  derv_chi_obs_rhorc[wave_base_index] = 1 / rhoa[nir_l];
4386  derv_chi_obs_rhorc[wave_base_index] += (-rhoa[iw] / rhoa[nir_l] / rhoa[nir_l]);
4387  derv_chi_obs_taua_l += (-1 / rhoa[nir_l] * uncertainty->derv_Lg_taua[iw] +rhoa[iw] / rhoa[nir_l] / rhoa[nir_l] * uncertainty->derv_Lg_taua[nir_l]);
4388  }
4389  }
4390  chi_obs /= mbac_wsum;
4391  if (uncertainty) {
4392  derv_chi_obs_taua_l /= mbac_wsum;
4393  for (ib = 0; ib <nbands_ac; ib++)
4394  derv_chi_obs_rhorc[ib] /= mbac_wsum;
4395  }
4396 
4397  for (im = 0; im < nmodels; im++) {
4398 
4399  modl = mindx[im];
4400 
4401  ms_eps_coef(modl, nir_l, wave, geom, &ac, &bc, &cc, &dc, &ec);
4402 
4403  ax = (double) ac[iwtab_l] - log((double) rhoa[nir_l]);
4404  bx = (double) bc[iwtab_l];
4405  cx = (double) cc[iwtab_l];
4406 
4407  fx = bx * bx - 4.0 * ax*cx;
4408  if (fx > 0.0 && cx != 0.0) {
4409  tau_iwnir_l = 0.5 * (-bx + sqrt(fx)) / cx;
4410  if(uncertainty)
4411  derv_temp_rhorc= 1 / rhoa[nir_l] / sqrt(fx);
4412 
4413  tau_iwnir_l = exp(tau_iwnir_l);
4414  if(uncertainty)
4415  derv_temp_rhorc *= tau_iwnir_l;
4416  } else {
4417  status = 1;
4418  return(status);
4419  //break;
4420  }
4421 
4422  /* compute reflectance at all wavelength */
4423 
4424  ext_iwnir_l = aertab->model[modl]->extc[iwtab_l];
4425  for (iw = 0; iw <nwave ; iw++) {
4426  iwtab = iwatab[iw];
4427  ext_coef = aertab->model[modl]->extc[iwtab];
4428  tau_all_wav[iw][im] = (ext_coef / ext_iwnir_l) * tau_iwnir_l;
4429  lg_taua = log(tau_all_wav[iw][im]);
4430  if(uncertainty){
4431  derv_taua_rhorc_l[im][iw]=(ext_coef / ext_iwnir_l)*derv_temp_rhorc;
4432  derv_rhoa_rhorc_l[im][iw]=1/tau_all_wav[iw][im]*(ext_coef / ext_iwnir_l)*derv_temp_rhorc;
4433  }
4434 
4435  lg_rhoa = ac[iwtab] + bc[iwtab] * lg_taua + cc[iwtab] * pow(lg_taua, 2) +
4436  dc[iwtab] * pow(lg_taua, 3) + ec[iwtab] * pow(lg_taua, 4);
4437 
4438  if (uncertainty)
4439  derv_rhoa_rhorc_l[im][iw] *=
4440  (bc[iwtab] + 2 * cc[iwtab] * lg_taua + 3 * dc[iwtab] * pow(lg_taua, 2) +
4441  4 * ec[iwtab] * pow(lg_taua, 3));
4442 
4443  rho_all_wav_pred[iw][im] = exp(lg_rhoa);
4444 
4445  if(uncertainty){
4446  derv_rhoa_rhorc_l[im][iw]*= rho_all_wav_pred[iw][im];
4447  // derv_rhoa_taua_l [im][iw] =
4448  }
4449  }
4450 
4451  if(uncertainty){
4452  derv_chi_rhorc[im][wave_base_index]=0.;
4453  derv_chi_taua_l[im]=0.;
4454  }
4455  mbac_wsum = 0.;
4456  for (ib = 0; ib <nbands_ac; ib++) {
4457  iw=acbands_index[ib];
4458  if(mbac_w[iw]==0.|| iw==nir_l)
4459  continue;
4460  //noise[iw]=uncertainty->dsensor[ip*nwave+iw];
4461  diff_2 += rho_all_wav_pred[iw][im] / rhoa[nir_l];
4462  diff_1 += pow((rhoa[iw] - rho_all_wav_pred[iw][im]) / noise[iw], 2) * mbac_w[iw]; //
4463  mbac_wsum += mbac_w[iw];
4464 
4465  if (uncertainty) {
4466  derv_temp_rhorc = (derv_rhoa_rhorc_l[im][iw] / rhoa[nir_l] -
4467  rho_all_wav_pred[iw][im] / rhoa[nir_l] / rhoa[nir_l]);
4468  derv_chi_rhorc[im][wave_base_index] += derv_temp_rhorc;
4469  derv_chi_taua_l[im] += (-derv_temp_rhorc * uncertainty->derv_Lg_taua[nir_l]);
4470  }
4471  }
4472 
4473  chi[im] = diff_2 / mbac_wsum;
4474  chi_old[im] = diff_1 / mbac_wsum; // diff_1
4475  if (uncertainty) {
4476  derv_chi_rhorc[im][wave_base_index] /= mbac_wsum;
4477  derv_chi_taua_l[im] /= mbac_wsum;
4478  }
4479 
4480  diff_2 = 0.;
4481  diff_1 = 0.;
4482  mbac_wsum = 0.0;
4483  chi_struct[im].value = chi_old[im];
4484  chi_struct[im].index = im;
4485  }
4486 
4487  qsort(chi_struct,nmodels,sizeof(chi_struct[0]),cmp);
4488 
4489  *modrat = chi_struct[0].value / (chi_struct[0].value + chi_struct[1].value);
4490  chi_old[0] =
4491  chi_struct[0].value * (1 - *modrat) +
4492  chi_struct[1].value * (*modrat); // temporary keeping the chi2 value from two closest aerosol models
4493 
4494  /*chi_struc is switched back to the ratio after selecting the model using the chi based on
4495  * difference*/
4496  for (im = 0; im < nmodels; im++)
4497  chi_struct[im].value = chi[chi_struct[im].index];
4498 
4499  if ((chi_obs - chi_struct[0].value) * (chi_obs - chi_struct[1].value) > 0) {
4500  *modrat = 1.0; // need to flag
4501  *modmin = chi_struct[0].index;
4502  *modmax = *modmin;
4503  return (1);
4504  } else {
4505  if (chi_obs > chi_struct[1].value) {
4506  im = chi_struct[0].index;
4507  diff_1 = chi_struct[0].value;
4508 
4509  chi_struct[0].value = chi_struct[1].value;
4510  chi_struct[0].index = chi_struct[1].index;
4511 
4512  chi_struct[1].value = diff_1;
4513  chi_struct[1].index = im;
4514  }
4515  *modmin = chi_struct[0].index;
4516  *modmax = chi_struct[1].index;
4517 
4518  *modrat = (chi_obs - chi_struct[0].value) / (chi_struct[1].value - chi_struct[0].value);
4519  if (uncertainty) {
4520  derv_modrat_chi0 =
4521  (chi_obs - chi_struct[1].value) / pow(chi_struct[1].value - chi_struct[0].value, 2);
4522  derv_modrat_chi1 =
4523  -(chi_obs - chi_struct[0].value) / pow(chi_struct[1].value - chi_struct[0].value, 2);
4524 
4525  for (ib = 0; ib < nbands_ac; iw++) {
4526  iw=acbands_index[ib];
4527  if (iw != nir_l) {
4528  derv_modrat_rhorc[ib] =
4529  derv_chi_obs_rhorc[ib] / (chi_struct[1].value - chi_struct[0].value);
4530  derv_modrat_rhow_l +=
4531  -derv_modrat_rhorc[ib] * uncertainty->ratio_rhow[ib];
4532  }
4533  }
4534 
4535  derv_modrat_rhorc[wave_base_index] = derv_modrat_chi0 * derv_chi_rhorc[*modmin][wave_base_index] +
4536  derv_modrat_chi1 * derv_chi_rhorc[*modmax][wave_base_index];
4537  derv_modrat_rhorc[wave_base_index] +=
4538  derv_chi_obs_rhorc[wave_base_index] / (chi_struct[1].value - chi_struct[0].value);
4539  derv_modrat_rhow_l += -derv_modrat_rhorc[wave_base_index];
4540 
4541  derv_modrat_taua_l =
4542  derv_modrat_chi0 * derv_chi_taua_l[*modmin] + derv_modrat_chi1 * derv_chi_taua_l[*modmax];
4543  derv_modrat_taua_l += derv_chi_obs_taua_l / (chi_struct[1].value - chi_struct[0].value);
4544 
4545  uncertainty->derv_modrat_rhow_l=derv_modrat_rhow_l;
4546  uncertainty->derv_modrat_taua_l=derv_modrat_taua_l;
4547  }
4548  }
4549 
4550  for (iw = 0; iw <nwave; iw++) {
4551 
4552  tau_pred_min[iw] = tau_all_wav[iw][*modmin];
4553  tau_pred_max[iw] = tau_all_wav[iw][*modmax];
4554  rhoa[iw]=rho_all_wav_pred[iw][*modmin]*(1-*modrat)+rho_all_wav_pred[iw][*modmax]*(*modrat);
4555 
4556  if(uncertainty){
4557  for (ib = 0; ib < nbands_ac; ib++) {
4558  i=acbands_index[ib];
4559  if (i != nir_l) {
4560  uncertainty->derv_La_rhorc[iw][ib] =
4561  (rho_all_wav_pred[iw][*modmax] - rho_all_wav_pred[iw][*modmin]) *
4562  derv_modrat_rhorc[ib];
4563  uncertainty->derv_La_rhow_l[iw] +=
4564  -uncertainty->derv_La_rhorc[iw][ib] * uncertainty->ratio_rhow[ib];
4565  }
4566  }
4567  uncertainty->derv_La_rhorc[iw][wave_base_index] =
4568  (rho_all_wav_pred[iw][*modmax] - rho_all_wav_pred[iw][*modmin]) *
4569  derv_modrat_rhorc[nir_l - iwnir_s];
4570  uncertainty->derv_La_rhorc[iw][wave_base_index] +=
4571  (1 - *modrat) * derv_rhoa_rhorc_l[*modmin][iw];
4572  uncertainty->derv_La_rhorc[iw][wave_base_index] += (*modrat) * derv_rhoa_rhorc_l[*modmax][iw];
4573  uncertainty->derv_La_rhow_l[iw] += -uncertainty->derv_La_rhorc[iw][wave_base_index];
4574 
4575  uncertainty->derv_La_taua_l[iw]=(rho_all_wav_pred[iw][*modmax]-rho_all_wav_pred[iw][*modmin])*derv_modrat_taua_l;
4576  uncertainty->derv_La_taua_l[iw]+=(1-*modrat)*(-derv_rhoa_rhorc_l[*modmin][iw]*uncertainty->derv_Lg_taua[iw]);
4577  uncertainty->derv_La_taua_l[iw]+=(*modrat) *(-derv_rhoa_rhorc_l[*modmax][iw]*uncertainty->derv_Lg_taua[iw]);
4578 
4579  derv_taua_min_rhorc_l[iw]=derv_taua_rhorc_l[*modmin][iw];
4580  derv_taua_max_rhorc_l[iw]=derv_taua_rhorc_l[*modmax][iw];
4581  derv_taua_min_taua_l[iw]=-derv_taua_rhorc_l[*modmin][iw]*uncertainty->derv_Lg_taua[iw];
4582  derv_taua_max_taua_l[iw]=-derv_taua_rhorc_l[*modmax][iw]*uncertainty->derv_Lg_taua[iw];
4583  derv_taua_min_rhow_l[iw]=-derv_taua_rhorc_l[*modmin][iw];
4584  derv_taua_max_rhow_l[iw]=-derv_taua_rhorc_l[*modmax][iw];
4585 
4586  }
4587  }
4588 
4589  *modmin = mindx[*modmin];
4590  *modmax = mindx[*modmax];
4591  chi[0] = chi_old[0];
4592 
4593  /* for (i = 0; i < nwave; i++) {
4594  free(tau_all_wav[i]);
4595  free(rho_all_wav_pred[i]);
4596  }
4597  free(tau_all_wav);
4598  free(rho_all_wav_pred);*/
4599 
4600  if(uncertainty){
4601  for(im=0;im<nmodels;im++){
4602  free(derv_chi_rhorc[im]);
4603  free(derv_rhoa_rhorc_l[im]);
4604  free(derv_taua_rhorc_l[im]);
4605  }
4606  free(derv_chi_rhorc);
4607  free(derv_chi_taua_l);
4608  free(derv_rhoa_rhorc_l);
4609  free(derv_taua_rhorc_l);
4610  free(derv_chi_obs_rhorc);
4611  }
4612 
4613  return (status);
4614 }
4615 
4616 /* ---------------------------------------------------------------------------------------- */
4617 /* ahmadaer() - compute aerosol reflectance using MSEPS approach of Ahmad */
4618 /* */
4619 /* Z. Ahmad, August 2014. */
4620 /* M. Zhang, SAIC, July 2021, adding the uncertainty propagation */
4621 
4622 /* ---------------------------------------------------------------------------------------- */
4623 int ahmadaer(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l,
4624  int32_t nmodels, int32_t mindx[],
4625  geom_str *geom, float wv, float rhoa[],
4626  int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir,
4627  float tau_pred_min[], float tau_pred_max[],int ip,uncertainty_t *uncertainty) {
4628  int iw;
4629 
4630  float rho_pred_min[nwave], rho_pred_max[nwave];
4631  float rho_aer[nwave], tau_aer[nwave];
4632 
4633  if (!have_ms && !use_pca_lut) {
4634  printf("\nThe multi-scattering epsilon atmospheric correction method requires\n");
4635  printf("ams_all, bms_all, cms_all, dms_all, ems in the aerosol model tables.\n");
4636  exit(1);
4637  }
4638  if (aer_opt == AERRHMSEPS_lin) {
4639  if (ahmad_atm_corr_lin(sensorID, wave, nwave, iwnir_s, iwnir_l, nmodels, mindx, geom, wv,
4640  rhoa, modmin, modmax, modrat, epsnir,
4641  tau_pred_max, tau_pred_min, rho_pred_max, rho_pred_min, tau_aer, rho_aer) != 0)
4642  return (1);
4643  } else {
4644  /* use the ms_epsilon method to get rhoa */
4645  if (ahmad_atm_corr(sensorID, wave, nwave, iwnir_s, iwnir_l, nmodels, mindx, geom, wv,
4646  rhoa, modmin, modmax, modrat, epsnir,
4647  tau_pred_max, tau_pred_min, rho_pred_max, rho_pred_min, tau_aer, rho_aer,ip,uncertainty) != 0)
4648  return (1);
4649  }
4650 
4651  for (iw = 0; iw < nwave; iw++) {
4652  rhoa[iw] = rho_aer[iw];
4653  }
4654 
4655  return (0);
4656 }
4657 
4658 
4659 /* ---------------------------------------------------------------------------------------- */
4660 /* wangaer() - compute aerosol reflectance using Gordon & Wang 1994 algorithm */
4661 /* */
4662 /* B. Franz, 1 June 2004. */
4663 
4664 /* ---------------------------------------------------------------------------------------- */
4665 
4666 int wangaer(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s,
4667  int32_t iwnir_l, int32_t nmodels, int32_t mindx[], geom_str *geom,
4668  float wv, float rhoa[], int32_t *modmin, int32_t *modmax,
4669  float *modrat, float *epsnir, float tauamin[], float tauamax[]) {
4670  int modflg;
4671  float *epsmin;
4672  float *epsmax;
4673 
4674  float epsmin1;
4675  float epsmax1;
4676 
4677  float *rhoasmin;
4678  float *rhoasmax;
4679  float *rhoamin;
4680  float *rhoamax;
4681 
4682  float cc = 0.0;
4683  int iw;
4684 
4685  if ((rhoasmin = (float *) calloc(nwave, sizeof (float))) == NULL) {
4686  printf("Unable to allocate space for rhoasmin.\n");
4687  exit(1);
4688  }
4689  if ((rhoasmax = (float *) calloc(nwave, sizeof (float))) == NULL) {
4690  printf("Unable to allocate space for rhoasmax.\n");
4691  exit(1);
4692  }
4693  if ((rhoamin = (float *) calloc(nwave, sizeof (float))) == NULL) {
4694  printf("Unable to allocate space for rhoamin.\n");
4695  exit(1);
4696  }
4697  if ((rhoamax = (float *) calloc(nwave, sizeof (float))) == NULL) {
4698  printf("Unable to allocate space for rhoasmax.\n");
4699  exit(1);
4700  }
4701 
4702  /* find upper and lower-bounding models */
4703  modflg = model_select_wang(sensorID, wave, nwave, nmodels, mindx, geom, wv,
4704  rhoa, iwnir_s, iwnir_l, modmin, modmax, modrat, epsnir);
4705 
4706  /* if no lower-bounding aerosol model, set-up for extrapolation */
4707  if (modflg < 0)
4708  cc = log(*epsnir) / (wave[iwnir_l] - wave[iwnir_s]);
4709 
4710  /* get model epsilon for each bounding model, all wavelengths */
4711  epsmin = model_epsilon(*modmin, iwnir_l, wave, nwave, geom);
4712  epsmax = model_epsilon(*modmax, iwnir_l, wave, nwave, geom);
4713 
4714  /* get SS aerosol reflectance at longest wavelength for the two models */
4715  if (rhoa_to_rhoas(sensorID, *modmin, geom, wv, rhoa, wave, nwave, iwnir_l, iwnir_l, rhoasmin) != 0) {
4716  free(rhoamin);
4717  free(rhoasmin);
4718  free(rhoamax);
4719  free(rhoasmax);
4720  return (1);
4721  }
4722  if (rhoa_to_rhoas(sensorID, *modmax, geom, wv, rhoa, wave, nwave, iwnir_l, iwnir_l, rhoasmax) != 0) {
4723  free(rhoamin);
4724  free(rhoasmin);
4725  free(rhoamax);
4726  free(rhoasmax);
4727  return (1);
4728  }
4729  /* compute SS aerosol reflectance in all bands */
4730  for (iw = 0; iw < nwave; iw++) {
4731 
4732  epsmin1 = epsmin[iw];
4733  epsmax1 = epsmax[iw];
4734 
4735  if (modflg < 0) {
4736  epsmin1 = exp(cc * (wave[iwnir_l] - wave[iw]));
4737  epsmax1 = epsmin1;
4738  }
4739 
4740  rhoasmin[iw] = rhoasmin[iwnir_l] * epsmin1;
4741  rhoasmax[iw] = rhoasmax[iwnir_l] * epsmax1;
4742  }
4743 
4744  /* compute MS aerosol reflectance in visible bands */
4745  rhoas_to_rhoa(sensorID, *modmin, geom, wv, rhoasmin, wave, nwave, 0, nwave - 1, rhoamin);
4746  rhoas_to_rhoa(sensorID, *modmax, geom, wv, rhoasmax, wave, nwave, 0, nwave - 1, rhoamax);
4747 
4748  /* interpolate between upper and lower-bounding models */
4749  for (iw = 0; iw < nwave; iw++) {
4750  rhoa[iw] = rhoamin[iw]*(1.0 - (*modrat)) + rhoamax[iw]*(*modrat);
4751  }
4752 
4753  model_taua(sensorID, *modmin, wave, nwave, iwnir_l, rhoa, geom, wv, tauamin);
4754  model_taua(sensorID, *modmax, wave, nwave, iwnir_l, rhoa, geom, wv, tauamax);
4755 
4756  free(rhoamin);
4757  free(rhoasmin);
4758  free(rhoamax);
4759  free(rhoasmax);
4760 
4761  return (0);
4762 }
4763 
4764 /* ---------------------------------------------------------------------------------------- */
4765 /* model_select_franz() - Franz aerosol model selection process. */
4766 /* */
4767 /* B. Franz, 1 February 2009. */
4768 
4769 /* ---------------------------------------------------------------------------------------- */
4770 
4771 typedef struct rhoaT_struct {
4772  int32_t modnum;
4773  float rhoa;
4774  float eps;
4775 } rhoaTstr;
4776 
4777 int comp_rhoaT(rhoaTstr *x, rhoaTstr *y) {
4778  return (x->rhoa < y->rhoa ? -1 : 1);
4779 }
4780 
4781 int model_select_franz(int32_t sensorID, float wave[], int32_t nwave,
4782  int32_t nmodel, int32_t mindx[], geom_str *geom, float wv,
4783  float rhoa[], int32_t iwnir_s, int32_t iwnir_l, int32_t *modmin,
4784  int32_t *modmax, float *modrat, float *epsnir) {
4785 
4786  float *rhoas;
4787  float *rhoa_tmp;
4788  rhoaTstr rhoa_tab[MAXMODEL];
4789 
4790  float *eps;
4791  int jm, im;
4792  int jm1, jm2;
4793  float wt;
4794 
4795  *modmin = -1;
4796  *modmax = -1;
4797  *modrat = 0.0;
4798  *epsnir = 0.0;
4799 
4800  if ((rhoas = (float *) calloc(nwave, sizeof (float))) == NULL) {
4801  printf("Unable to allocate space for rhoas.\n");
4802  exit(1);
4803  }
4804  if ((rhoa_tmp = (float *) calloc(nwave, sizeof (float))) == NULL) {
4805  printf("Unable to allocate space for rhoas_tmp.\n");
4806  exit(1);
4807  }
4808 
4809  // predict MS aerosol reflectance assuming each model
4810 
4811  for (jm = 0; jm < nmodel; jm++) {
4812 
4813  im = mindx[jm];
4814 
4815  // get model epsilon at this geometry
4816  eps = model_epsilon(im, iwnir_l, wave, nwave, geom);
4817 
4818  // get SS aerosol reflectance at iwnir_l
4819  if (rhoa_to_rhoas(sensorID, im, geom, wv, rhoa, wave, nwave, iwnir_l, iwnir_l, rhoas) != 0) {
4820  free(rhoas);
4821  free(rhoa_tmp);
4822  return (1);
4823  }
4824  // get SS aerosol reflectance at iwnir_s
4825  rhoas[iwnir_s] = rhoas[iwnir_l] * eps[iwnir_s];
4826 
4827  // get MS aerosol reflectance at iwnir_s and save
4828  rhoas_to_rhoa(sensorID, im, geom, wv, rhoas, wave, nwave, iwnir_s, iwnir_s, rhoa_tmp);
4829 
4830  rhoa_tab[jm].modnum = im;
4831  rhoa_tab[jm].rhoa = rhoa_tmp[iwnir_s];
4832  rhoa_tab[jm].eps = eps[iwnir_s];
4833  }
4834 
4835  // put results in ascending order of predicted rhoa[iwnir_s]
4836  qsort(rhoa_tab, nmodel, sizeof (rhoaTstr), (int (*)(const void *, const void *)) comp_rhoaT);
4837 
4838  // compare observed rhoa with model predictions at iwnir_s to select models
4839  for (jm = 0; jm < nmodel; jm++) {
4840  if (rhoa_tab[jm].rhoa > rhoa[iwnir_s])
4841  break;
4842  }
4843  if (jm == 0) {
4844  jm1 = 0;
4845  jm2 = 1;
4846  } else if (jm == nmodel) {
4847  jm1 = nmodel - 2;
4848  jm2 = nmodel - 1;
4849  } else {
4850  jm1 = jm - 1;
4851  jm2 = jm1 + 1;
4852  }
4853  wt = (rhoa[iwnir_s] - rhoa_tab[jm1].rhoa) / (rhoa_tab[jm2].rhoa - rhoa_tab[jm1].rhoa);
4854 
4855  *modmin = rhoa_tab[jm1].modnum;
4856  *modmax = rhoa_tab[jm2].modnum;
4857  *modrat = wt;
4858  *epsnir = rhoa_tab[jm1].eps * (1.0 - wt) + rhoa_tab[jm2].eps*wt;
4859 
4860  free(rhoas);
4861  free(rhoa_tmp);
4862 
4863  return (0);
4864 }
4865 
4866 
4867 /* ---------------------------------------------------------------------------------------- */
4868 /* order_models is the sorting function used in rhaer */
4869 
4870 /* ---------------------------------------------------------------------------------------- */
4871 static int order_models(const void *p1, const void *p2) {
4872  aermodstr *x = *(aermodstr **) p1;
4873  aermodstr *y = *(aermodstr **) p2;
4874 
4875  if (x->rh == y->rh) {
4876  if (x->sd > y->sd)
4877  return ( 1);
4878  else
4879  return (-1);
4880  } else {
4881  if (x->rh > y->rh)
4882  return ( 1);
4883  else
4884  return (-1);
4885  }
4886 }
4887 
4888 
4889 /* ---------------------------------------------------------------------------------------- */
4890 /* rhaer() - compute aerosol reflectance using RH descrimination + desired selection scheme */
4891 /* M. Zhang, SAIC, July 2021, adding the uncertainty propagation */
4892 
4893 /* ---------------------------------------------------------------------------------------- */
4894 int rhaer(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l,
4895  geom_str *geom, float wv, float rh, float pr, float taur[], float rhoa[],
4896  int32_t *modmin1, int32_t *modmax1, float *modrat1, int32_t *modmin2, int32_t *modmax2, float *modrat2,
4897  float *eps, float taua[], float tsol[], float tsen[], int32_t ip, float *mbac_w,float *chi, uncertainty_t *uncertainty) {
4898  static int firstCall = 1;
4899  static int nrh;
4900  static float rhtab[MAXAERMOD];
4901  static int nsd;
4902  static int sdtab[MAXAERMOD];
4903 
4904  float *rhoa1;
4905  float *rhoa2;
4906  float *taua1;
4907  float *taua2;
4908  float *tsol1;
4909  float *tsol2;
4910  float *tsen1;
4911  float *tsen2;
4912  float eps1=1.0;
4913  float eps2=1.0;
4914  //float modrat1;
4915  //float modrat2;
4916  int nmodels;
4917  float *chi1, *chi2;
4918 
4919  float *tau_pred_min1;
4920  float *tau_pred_max1;
4921  float *tau_pred_min2;
4922  float *tau_pred_max2;
4923 
4924  int32_t mindx1[MAXAERMOD];
4925  int32_t mindx2[MAXAERMOD];
4926  int irh1, irh2, irh;
4927  //int irh3; // Third RH index --> Amir
4928  int isd;
4929  float wt;
4930  static uncertainty_t *uncertainty1=NULL, *uncertainty2=NULL;
4931  float derv_wt_rh; //derivative of wt to rh
4932 
4933  int iw, im, inir;
4934 
4935  if (firstCall) {
4936  firstCall = 0;
4937  float lastrh = -1.0;
4938  int lastsd = -1;
4939  if (!have_rh) {
4940  printf("-E- %s line %d: This aerosol selection method requires models with a Relative Humidity attribute and size distribution.\n",
4941  __FILE__, __LINE__);
4942  exit(1);
4943  }
4944 
4945  if(uncertainty){
4946  uncertainty1 = (uncertainty_t *) malloc(sizeof(uncertainty_t));
4947  uncertainty2 = (uncertainty_t *) malloc(sizeof(uncertainty_t));
4948 
4949  if (alloc_uncertainty(uncertainty->nbands, uncertainty->nbands_ac, uncertainty->npix, uncertainty1) != 0) {
4950  printf("unable to allocate error record in rhaer()\n");
4951  exit(1);
4952  }
4953  if (alloc_uncertainty(uncertainty->nbands, uncertainty->nbands_ac, uncertainty->npix, uncertainty2) != 0) {
4954  printf("unable to allocate error record in rhaer()\n");
4955  exit(1);
4956  }
4957  }
4958  // need in order of rh and sd within rh
4959  qsort(aertab->model, aertab->nmodel, sizeof (aermodstr*), (int (*)(const void *, const void *)) order_models);
4960 
4961  // count the number of model humidities and the number of model size distributions
4962  // note that use of a single model suite will yield nrh=1, which inherently avoids RH weighting that case
4963 
4964  nsd = 0;
4965  nrh = 0;
4966 
4967  for (im = 0; im < aertab->nmodel; im++) {
4968  if (aertab->model[im]->rh != lastrh) {
4969  rhtab[nrh] = aertab->model[im]->rh;
4970  lastrh = rhtab[nrh];
4971  nrh++;
4972  }
4973  if (nrh == 1 && aertab->model[im]->sd != lastsd) {
4974  sdtab[nsd] = aertab->model[im]->sd;
4975  lastsd = sdtab[nsd];
4976  nsd++;
4977  }
4978  }
4979  if (nrh * nsd != aertab->nmodel) {
4980  printf("-E- %s line %d: number of humidities (%d) x number of size distributions (%d) must equal number of models (%d).\n",
4981  __FILE__, __LINE__, nrh, nsd, aertab->nmodel);
4982  exit(1);
4983  } else {
4984  printf("%d aerosol models: %d humidities x %d size fractions\n", aertab->nmodel, nrh, nsd);
4985  for (irh = 0; irh < nrh; irh++) {
4986  for (isd = 0; isd < nsd; isd++) {
4987  im = irh * nsd + isd;
4988  printf("model %d, rh=%f, sd=%d, alpha=%f, name=%s\n",
4989  im, aertab->model[im]->rh, aertab->model[im]->sd, aertab->model[im]->angstrom[0], aertab->model[im]->name);
4990  }
4991  }
4992  }
4993  }
4994 
4995  nmodels=nsd;
4996 
4997  if(uncertainty){
4998  init_uncertainty(uncertainty1,0);
4999  init_uncertainty(uncertainty2,0);
5000  if (cp_uncertainty(uncertainty, uncertainty1, ip) != 0) {
5001  printf("unable to copy the error record in rhaer()\n");
5002  exit(1);
5003  }
5004  if (cp_uncertainty(uncertainty, uncertainty2, ip) != 0) {
5005  printf("unable to copy the error record in rhaer()\n");
5006  exit(1);
5007  }
5008  }
5009 
5010  // initialize
5011  if ((taua1 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5012  printf("Unable to allocate space for taua1.\n");
5013  exit(1);
5014  }
5015  if ((taua2 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5016  printf("Unable to allocate space for taua2.\n");
5017  exit(1);
5018  }
5019  if ((tsol1 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5020  printf("Unable to allocate space for tsol1.\n");
5021  exit(1);
5022  }
5023  if ((tsol2 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5024  printf("Unable to allocate space for tsol2.\n");
5025  exit(1);
5026  }
5027  if ((rhoa1 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5028  printf("Unable to allocate space for rhoa1.\n");
5029  exit(1);
5030  }
5031  if ((rhoa2 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5032  printf("Unable to allocate space for rhoa2.\n");
5033  exit(1);
5034  }
5035  if ((tsen1 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5036  printf("Unable to allocate space for tsen1.\n");
5037  exit(1);
5038  }
5039  if ((tsen2 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5040  printf("Unable to allocate space for tsen2.\n");
5041  exit(1);
5042  }
5043  if ((tau_pred_min1 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5044  printf("Unable to allocate space for tau_pred_min1.\n");
5045  exit(1);
5046  }
5047  if ((tau_pred_min2 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5048  printf("Unable to allocate space for tau_pred_min2.\n");
5049  exit(1);
5050  }
5051  if ((tau_pred_max1 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5052  printf("Unable to allocate space for tau_pred_max1.\n");
5053  exit(1);
5054  }
5055  if ((tau_pred_max2 = (float *) malloc(nwave * sizeof (float))) == NULL) {
5056  printf("Unable to allocate space for tau_pred_max2.\n");
5057  exit(1);
5058  }
5059 
5060  if ((chi1 = (float *) calloc(nmodels, sizeof (float))) == NULL) {
5061  printf("Unable to allocate space for chi1.\n");
5062  exit(1);
5063  }
5064  if ((chi2 = (float *) calloc(nmodels, sizeof (float))) == NULL) {
5065  printf("Unable to allocate space for chi2.\n");
5066  exit(1);
5067  }
5068 
5069 
5070  for (iw = 0; iw < nwave; iw++) {
5071  taua[iw] = -1.0;
5072  tsol[iw] = -1.0;
5073  tsen[iw] = -1.0;
5074  rhoa1[iw] = rhoa[iw];
5075  rhoa2[iw] = rhoa[iw];
5076  rhoa [iw] = BAD_FLT;
5077  }
5078 
5079 
5080  // adjust rh for spectral matching
5081  if (aer_opt == AERRHSM) {
5082  if (rh >= 95) {
5083  //printf("Warning rh is greater than 95%%. Reset to 94%% rh=%f\n", rh);
5084  rh = 94;
5085  }
5086  }
5087 
5088  // find RH index and wts
5089  if (nrh == 1 || rhtab[0] > rh) { // actual RH < smallest model RH or only one model RH
5090  irh1 = 0;
5091  irh2 = 0;
5092  wt = 0.0;
5093  derv_wt_rh=0.0;
5094  } else if (rhtab[nrh - 1] < rh) { // actual RH > smallestlargest model RH
5095  irh1 = nrh - 1;
5096  irh2 = nrh - 1;
5097  wt = 0.0;
5098  derv_wt_rh=0.0;
5099  } else {
5100  for (irh = 0; irh < nrh; irh++) {
5101  if (rhtab[irh] > rh)
5102  break;
5103  }
5104  irh1 = MIN(MAX(0, irh - 1), nrh - 2);
5105  irh2 = irh1 + 1;
5106  wt = (rh - rhtab[irh1]) / (rhtab[irh2] - rhtab[irh1]);
5107  if(uncertainty)
5108  derv_wt_rh = 1.0 / (rhtab[irh2] - rhtab[irh1]);
5109  }
5110 
5111  // set indices of active model sets
5112 
5113  for (im = 0; im < nsd; im++) {
5114  mindx1[im] = irh1 * nsd + im;
5115  mindx2[im] = irh2 * nsd + im;
5116 
5117  chi1[im] = BAD_FLT;
5118  chi2[im] = BAD_FLT;
5119  }
5120 
5121  // compute aerosol reflectances, aot, diffuse trans, eps from first model set
5122 
5123  /* perform spectral matching from Red to SWIR in radiance space, based on Ahmad
5124  * Multi-scattering coeff method --> Amir*/
5125  if (aer_opt == AERRHSM) {
5126 
5127  if (smaer(sensorID, wave, nwave, iwnir_s, iwnir_l, nmodels, mindx1,geom, wv, rhoa1, modmin1, modmax1, modrat1, tau_pred_min1, tau_pred_max1,ip, chi1, mbac_w,uncertainty1) != 0) {
5128 
5129  free(taua1);
5130  free(taua2);
5131  free(tsol1);
5132  free(tsol2);
5133  free(tsen1);
5134  free(tsen2);
5135  free(rhoa1);
5136  free(rhoa2);
5137  free(tau_pred_min1);
5138  free(tau_pred_max1);
5139  free(tau_pred_min2);
5140  free(tau_pred_max2);
5141  return (1);
5142  }
5143  } else if (aer_opt == AERRHMSEPS || aer_opt == AERRHMSEPS_lin) {
5144  if (ahmadaer(sensorID, wave, nwave, iwnir_s, iwnir_l, nsd, mindx1,
5145  geom, wv, rhoa1, modmin1, modmax1, modrat1, &eps1, tau_pred_min1, tau_pred_max1,ip,uncertainty1) != 0) {
5146 
5147  free(taua1);
5148  free(taua2);
5149  free(tsol1);
5150  free(tsol2);
5151  free(tsen1);
5152  free(tsen2);
5153  free(rhoa1);
5154  free(rhoa2);
5155  free(tau_pred_min1);
5156  free(tau_pred_max1);
5157  free(tau_pred_min2);
5158  free(tau_pred_max2);
5159  return (1);
5160 
5161  }
5162  } else {
5163  if (wangaer(sensorID, wave, nwave, iwnir_s, iwnir_l, nsd, mindx1,
5164  geom, wv, rhoa1, modmin1, modmax1, modrat1, &eps1, tau_pred_min1, tau_pred_max1) != 0) {
5165  free(taua1);
5166  free(taua2);
5167  free(tsol1);
5168  free(tsol2);
5169  free(tsen1);
5170  free(tsen2);
5171  free(rhoa1);
5172  free(rhoa2);
5173  free(tau_pred_min1);
5174  free(tau_pred_max1);
5175  free(tau_pred_min2);
5176  free(tau_pred_max2);
5177  return (1);
5178  }
5179  }
5180 
5181  diff_tran(sensorID, wave, nwave, iwnir_l, geom, wv, pr, taur,
5182  *modmin1, *modmax1, *modrat1, rhoa1, taua1, tsol1, tsen1, tau_pred_min1, tau_pred_max1, 1, ip,uncertainty1);
5183 
5184  // compute aerosol reflectances, aot, diffuse trans, eps from second model set (if needed)
5185 
5186  if (irh2 != irh1) {
5187 
5188  if (aer_opt == AERRHSM) {
5189 
5190  if (smaer(sensorID, wave, nwave, iwnir_s, iwnir_l, nmodels, mindx2,
5191  geom, wv, rhoa2, modmin2, modmax2, modrat2, tau_pred_min2, tau_pred_max2, ip, chi2, mbac_w,uncertainty2) != 0) {
5192 
5193  free(taua1);
5194  free(taua2);
5195  free(tsol1);
5196  free(tsol2);
5197  free(tsen1);
5198  free(tsen2);
5199  free(rhoa1);
5200  free(rhoa2);
5201  free(tau_pred_min1);
5202  free(tau_pred_max1);
5203  free(tau_pred_min2);
5204  free(tau_pred_max2);
5205 
5206  return (1);
5207  }
5208 
5209  }
5210 
5211  else if (aer_opt == AERRHMSEPS || aer_opt == AERRHMSEPS_lin) {
5212  if (ahmadaer(sensorID, wave, nwave, iwnir_s, iwnir_l, nsd, mindx2,
5213  geom, wv, rhoa2, modmin2, modmax2, modrat2, &eps2, tau_pred_min2, tau_pred_max2,ip,uncertainty2) != 0) {
5214  free(taua1);
5215  free(taua2);
5216  free(tsol1);
5217  free(tsol2);
5218  free(tsen1);
5219  free(tsen2);
5220  free(rhoa1);
5221  free(rhoa2);
5222  free(tau_pred_min1);
5223  free(tau_pred_max1);
5224  free(tau_pred_min2);
5225  free(tau_pred_max2);
5226  return (1);
5227  }
5228  } else {
5229  if (wangaer(sensorID, wave, nwave, iwnir_s, iwnir_l, nsd, mindx2,
5230  geom, wv, rhoa2, modmin2, modmax2, modrat2, &eps2, tau_pred_min2, tau_pred_max2) != 0) {
5231  free(taua1);
5232  free(taua2);
5233  free(tsol1);
5234  free(tsol2);
5235  free(tsen1);
5236  free(tsen2);
5237  free(rhoa1);
5238  free(rhoa2);
5239  free(tau_pred_min1);
5240  free(tau_pred_max1);
5241  free(tau_pred_min2);
5242  free(tau_pred_max2);
5243  return (1);
5244  }
5245  }
5246 
5247  diff_tran(sensorID, wave, nwave, iwnir_l, geom, wv, pr, taur,
5248  *modmin2, *modmax2, *modrat2, rhoa2, taua2, tsol2, tsen2, tau_pred_min2, tau_pred_max2, 1,ip,uncertainty2);
5249 
5250  for (iw = 0; iw < nwave; iw++) {
5251  rhoa[iw] = rhoa1[iw]*(1 - wt) + rhoa2[iw] * wt;
5252  taua[iw] = taua1[iw]*(1 - wt) + taua2[iw] * wt;
5253  tsol[iw] = tsol1[iw]*(1 - wt) + tsol2[iw] * wt;
5254  tsen[iw] = tsen1[iw]*(1 - wt) + tsen2[iw] * wt;
5255 
5256  if(uncertainty){
5257  for(inir=0;inir<=iwnir_l-iwnir_s;inir++){
5258  uncertainty->derv_La_rhorc[iw][inir]=(1-wt)*uncertainty1->derv_La_rhorc[iw][inir]+ wt*uncertainty2->derv_La_rhorc[iw][inir];
5259  uncertainty->derv_taua_rhorc[iw][inir]=(1-wt)*uncertainty1->derv_taua_rhorc[iw][inir]+ wt*uncertainty2->derv_taua_rhorc[iw][inir];
5260  uncertainty->derv_tsen_rhorc[iw][inir]=(1-wt)*uncertainty1->derv_tsen_rhorc[iw][inir]+ wt*uncertainty2->derv_tsen_rhorc[iw][inir];
5261  uncertainty->derv_tsol_rhorc[iw][inir]=(1-wt)*uncertainty1->derv_tsol_rhorc[iw][inir]+ wt*uncertainty2->derv_tsol_rhorc[iw][inir];
5262  }
5263  uncertainty->derv_La_taua_l[iw]=(1-wt)*uncertainty1->derv_La_taua_l[iw]+ wt*uncertainty2->derv_La_taua_l[iw];
5264  uncertainty->derv_La_rhow_l[iw]=(1-wt)*uncertainty1->derv_La_rhow_l[iw]+ wt*uncertainty2->derv_La_rhow_l[iw];
5265  uncertainty->derv_La_rh[iw]=(rhoa2[iw]-rhoa1[iw])*derv_wt_rh;
5266 
5267  //uncertainty->derv_taua_rhoa_l[iw]=(1-wt)*uncertainty1->derv_taua_rhoa_l[iw]+ wt*uncertainty2->derv_taua_rhoa_l[iw];
5268  uncertainty->derv_taua_taua_l[iw]=(1-wt)*uncertainty1->derv_taua_taua_l[iw]+ wt*uncertainty2->derv_taua_taua_l[iw];
5269  //rrrec->derv_taua_rhoa_s[iw]=(1-wt)*uncertainty1->derv_taua_rhoa_s[iw]+ wt*uncertainty2->derv_taua_rhoa_s[iw];
5270  uncertainty->derv_taua_rhow_l[iw]=(1-wt)*uncertainty1->derv_taua_rhow_l[iw]+ wt*uncertainty2->derv_taua_rhow_l[iw];
5271  uncertainty->derv_taua_rh[iw]=(taua2[iw]-taua1[iw])*derv_wt_rh;
5272  //uncertainty->derv_taua_taua_s[iw]=(1-wt)*uncertainty1->derv_taua_taua_s[iw]+ wt*uncertainty2->derv_taua_taua_s[iw];
5273 
5274  // uncertainty->derv_tsol_rhoa_l[iw]=(1-wt)*uncertainty1->derv_tsol_rhoa_l[iw]+ wt*uncertainty2->derv_tsol_rhoa_l[iw];
5275  //uncertainty->derv_tsol_rhoa_s[iw]=(1-wt)*uncertainty1->derv_tsol_rhoa_s[iw]+ wt*uncertainty2->derv_tsol_rhoa_s[iw];
5276  uncertainty->derv_tsol_taua_l[iw]=(1-wt)*uncertainty1->derv_tsol_taua_l[iw]+ wt*uncertainty2->derv_tsol_taua_l[iw];
5277  uncertainty->derv_tsol_rhow_l[iw]=(1-wt)*uncertainty1->derv_tsol_rhow_l[iw]+ wt*uncertainty2->derv_tsol_rhow_l[iw];
5278  uncertainty->derv_tsol_rh[iw]=(tsol2[iw]-tsol1[iw])*derv_wt_rh;
5279  //uncertainty->derv_tsol_taua_s[iw]=(1-wt)*uncertainty1->derv_tsol_taua_s[iw]+ wt*uncertainty2->derv_tsol_taua_s[iw];
5280 
5281  //uncertainty->derv_tsen_rhoa_l[iw]=(1-wt)*uncertainty1->derv_tsen_rhoa_l[iw]+ wt*uncertainty2->derv_tsen_rhoa_l[iw];
5282  //uncertainty->derv_tsen_rhoa_s[iw]=(1-wt)*uncertainty1->derv_tsen_rhoa_s[iw]+ wt*uncertainty2->derv_tsen_rhoa_s[iw];
5283  uncertainty->derv_tsen_taua_l[iw]=(1-wt)*uncertainty1->derv_tsen_taua_l[iw]+ wt*uncertainty2->derv_tsen_taua_l[iw];
5284  uncertainty->derv_tsen_rhow_l[iw]=(1-wt)*uncertainty1->derv_tsen_rhow_l[iw]+ wt*uncertainty2->derv_tsen_rhow_l[iw];
5285  uncertainty->derv_tsen_rh[iw]=(tsen2[iw]-tsen1[iw])*derv_wt_rh;
5286  //uncertainty->derv_tsen_taua_s[iw]=(1-wt)*uncertainty1->derv_tsen_taua_s[iw]+ wt*uncertainty2->derv_tsen_taua_s[iw];
5287  }
5288  }
5289  *eps = eps1 * (1 - wt) + eps2*wt;
5290  *chi =chi1[0]*(1-wt) +chi2[0]*wt;
5291 
5292  } else {
5293 
5294  for (iw = 0; iw < nwave; iw++) {
5295  rhoa[iw] = rhoa1[iw];
5296  taua[iw] = taua1[iw];
5297  tsol[iw] = tsol1[iw];
5298  tsen[iw] = tsen1[iw];
5299  *chi=chi1[0];
5300 
5301  if(uncertainty){
5302  for(inir=0;inir<=iwnir_l-iwnir_s;inir++){
5303  uncertainty->derv_La_rhorc[iw][inir]=uncertainty1->derv_La_rhorc[iw][inir];
5304  uncertainty->derv_taua_rhorc[iw][inir]=uncertainty1->derv_taua_rhorc[iw][inir];
5305  uncertainty->derv_tsen_rhorc[iw][inir]=uncertainty1->derv_tsen_rhorc[iw][inir];
5306  uncertainty->derv_tsol_rhorc[iw][inir]=uncertainty1->derv_tsol_rhorc[iw][inir];
5307  }
5308  uncertainty->derv_La_taua_l[iw]=uncertainty1->derv_La_taua_l[iw];
5309  //uncertainty->derv_rhoa_l[iw]=uncertainty1->derv_rhoa_l[iw];
5310  uncertainty->derv_La_rhow_l[iw]=uncertainty1->derv_La_rhow_l[iw];
5311  //uncertainty->derv_rhoa_s[iw]=uncertainty1->derv_rhoa_s[iw];
5312  //uncertainty->derv_taua_s[iw]=uncertainty1->derv_taua_s[iw];
5313 
5314  // uncertainty->derv_taua_rhoa_l[iw]=uncertainty1->derv_taua_rhoa_l[iw];
5315  uncertainty->derv_taua_taua_l[iw]=uncertainty1->derv_taua_taua_l[iw];
5316  // uncertainty->derv_taua_rhoa_s[iw]=uncertainty1->derv_taua_rhoa_s[iw];
5317  uncertainty->derv_taua_rhow_l[iw]=uncertainty1->derv_taua_rhow_l[iw];
5318  //uncertainty->derv_taua_taua_s[iw]=uncertainty1->derv_taua_taua_s[iw];
5319 
5320  // uncertainty->derv_tsol_rhoa_l[iw]=uncertainty1->derv_tsol_rhoa_l[iw];
5321  // uncertainty->derv_tsol_rhoa_s[iw]=uncertainty1->derv_tsol_rhoa_s[iw];
5322  uncertainty->derv_tsol_taua_l[iw]=uncertainty1->derv_tsol_taua_l[iw];
5323  uncertainty->derv_tsol_rhow_l[iw]=uncertainty1->derv_tsol_rhow_l[iw];
5324  //uncertainty->derv_tsol_taua_s[iw]=uncertainty1->derv_tsol_taua_s[iw];
5325 
5326  //uncertainty->derv_tsen_rhoa_l[iw]=uncertainty1->derv_tsen_rhoa_l[iw];
5327  //uncertainty->derv_tsen_rhoa_s[iw]=uncertainty1->derv_tsen_rhoa_s[iw];
5328  uncertainty->derv_tsen_taua_l[iw]=uncertainty1->derv_tsen_taua_l[iw];
5329  uncertainty->derv_tsen_rhow_l[iw]=uncertainty1->derv_tsen_rhow_l[iw];
5330  //uncertainty->derv_tsen_taua_s[iw]=uncertainty1->derv_tsen_taua_s[iw];
5331  }
5332  }
5333  *eps = eps1;
5334  }
5335 
5336  free(taua1);
5337  free(taua2);
5338  free(tsol1);
5339  free(tsol2);
5340  free(tsen1);
5341  free(tsen2);
5342  free(rhoa1);
5343  free(rhoa2);
5344  free(tau_pred_min1);
5345  free(tau_pred_max1);
5346  free(tau_pred_min2);
5347  free(tau_pred_max2);
5348  free(chi1);
5349  free(chi2);
5350 
5351  return (0);
5352 }
5353 
5354 
5355 /* ---------------------------------------------------------------------------------------- */
5356 /* fixedaer() - compute aerosol reflectance for fixed aerosol model */
5357 /* */
5358 /* B. Franz, August 2004. */
5359 
5360 /* ---------------------------------------------------------------------------------------- */
5361 int fixedaer(int32_t sensorID, int32_t modnum, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l,
5362  char models[MAXAERMOD][32], int32_t nmodels,
5363  geom_str *geom, float wv, float rhoa[], float *epsnir) {
5364  float *eps;
5365  float *rhoas;
5366  int iw;
5367 
5368  if ((rhoas = (float *) calloc(nwave, sizeof (float))) == NULL) {
5369  printf("Unable to allocate space for rhoas.\n");
5370  exit(1);
5371  }
5372 
5373  if (rhoa[iwnir_l] < 0.0) {
5374  *epsnir = BAD_FLT;
5375  // for (iw=0; iw<nwave; iw++)
5376  // rhoas[iw] = BAD_FLT;
5377  free(rhoas);
5378  return (1);
5379  }
5380 
5381  /* get model epsilon for all wavelengths at this geometry */
5382  eps = model_epsilon(modnum, iwnir_l, wave, nwave, geom);
5383 
5384  /* get SS aerosol reflectance at longest wavelength */
5385  if (rhoa_to_rhoas(sensorID, modnum, geom, wv, rhoa, wave, nwave, iwnir_l, iwnir_l, rhoas) != 0) {
5386  printf("Error getting rhoas\n");
5387  free(rhoas);
5388  return (1);
5389  }
5390 
5391  /* compute SS aerosol reflectance in visible bands */
5392  for (iw = 0; iw < nwave; iw++) {
5393  rhoas[iw] = rhoas[iwnir_l] * eps[iw];
5394  }
5395 
5396  /* compute MS aerosol reflectance in visible bands */
5397  rhoas_to_rhoa(sensorID, modnum, geom, wv, rhoas, wave, nwave, 0, nwave - 1, rhoa);
5398 
5399  if (iwnir_s == iwnir_l)
5400  *epsnir = eps[iwnir_l - 1];
5401  else
5402  *epsnir = eps[iwnir_s];
5403 
5404  free(rhoas);
5405 
5406  return (0);
5407 }
5408 
5409 
5410 /* ---------------------------------------------------------------------------------------- */
5411 /* fixedmodpair() - compute aerosol reflectance for fixed model pair */
5412 /* */
5413 /* B. Franz, August 2004. */
5414 
5415 /* ---------------------------------------------------------------------------------------- */
5416 int fixedmodpair(int32_t sensorID, float wave[], int32_t nwave,
5417  int32_t iwnir_s, int32_t iwnir_l, geom_str *geom, float wv,
5418  int32_t modmin, int32_t modmax, float modrat, float rhoa[], float *eps) {
5419  float *rhoa1;
5420  float *rhoa2;
5421  float eps1;
5422  float eps2;
5423  int iw;
5424  int status;
5425 
5426  if ((rhoa1 = (float *) calloc(nwave, sizeof (float))) == NULL) {
5427  printf("Unable to allocate space for rhoa1.\n");
5428  exit(1);
5429  }
5430  if ((rhoa2 = (float *) calloc(nwave, sizeof (float))) == NULL) {
5431  printf("Unable to allocate space for rhoa2.\n");
5432  exit(1);
5433  }
5434 
5435  if (modmin < 0 || modmin >= input->naermodels ||
5436  modmax < 0 || modmax >= input->naermodels ||
5437  modrat < 0.0 || modrat > 1.0) {
5438  printf("Bogus input for fixed model pair: %d %d %f\n", modmin + 1, modmax + 1, modrat);
5439  exit(1);
5440  }
5441 
5442 
5443  if (rhoa[iwnir_l] > input->rhoamin) {
5444 
5445  rhoa2[iwnir_l] = rhoa1[iwnir_l] = rhoa[iwnir_l];
5446 
5447  /* get aerosol reflectance in visible for fixed model, and epsilon */
5448  status = fixedaer(sensorID, modmin, wave, nwave, iwnir_s, iwnir_l,
5449  input->aermodels, input->naermodels, geom, wv, rhoa1, &eps1);
5450  status = fixedaer(sensorID, modmax, wave, nwave, iwnir_s, iwnir_l,
5451  input->aermodels, input->naermodels, geom, wv, rhoa2, &eps2);
5452 
5453  /* convert aerosol relectance to radiance */
5454  if (status == 0) {
5455  for (iw = 0; iw < nwave; iw++) {
5456  if (iw != iwnir_l) // without this check tLw-La may go slight negative
5457  rhoa[iw] = MAX((1.0 - modrat) * rhoa1[iw] + modrat * rhoa2[iw], 0.0);
5458  }
5459  *eps = (1.0 - modrat) * eps1 + modrat*eps2;
5460  }
5461 
5462  } else if (rhoa[iwnir_l] > -(input->rhoamin)) {
5463 
5464  /* if input NIR is near zero, assume a small white aerosol signal */
5465  *eps = 1.0;
5466  for (iw = 0; iw < nwave; iw++) {
5467  rhoa[iw] = MAX(rhoa[iwnir_l], 1e-6);
5468  }
5469 
5470  status = 0;
5471 
5472  } else {
5473 
5474  /* if input NIR is very negative, fail the case */
5475  status = 1;
5476  }
5477 
5478  free(rhoa1);
5479  free(rhoa2);
5480 
5481  return (status);
5482 }
5483 
5484 
5485 /* ---------------------------------------------------------------------------------------- */
5486 /* fixedaot() - compute aerosol reflectance for fixed aot(lambda) */
5487 /* */
5488 /* B. Franz, August 2004. */
5489 
5490 /* ---------------------------------------------------------------------------------------- */
5491 
5492 int fixedaot(int32_t sensorID, float aot[], float wave[], int32_t nwave,
5493  int32_t iwnir_s, int32_t iwnir_l, geom_str *geom, float wv,
5494  int32_t *modmin, int32_t *modmax, float *modrat, float rhoa[],
5495  float *epsnir) {
5496  static int firstCall = 1;
5497  static int angst_band1 = -1;
5498  static int angst_band2 = -1;
5499 
5500  float *phase1;
5501  float *phase2;
5502  float *f1;
5503  float *f2;
5504  float *lnf1;
5505  float *lnf2;
5506  float *rhoas1;
5507  float *rhoas2;
5508  float *rhoa1;
5509  float *rhoa2;
5510  float eps1;
5511  float eps2;
5512  float angstrom;
5513  int ig, gmult, iw, iwtab;
5514  float maxwave;
5515 
5516  maxwave = MAX(aertab->nwave, nwave);
5517 
5518  if ((rhoa1 = (float *) calloc(nwave, sizeof (float))) == NULL) {
5519  printf("Unable to allocate space for rhoa1.\n");
5520  exit(1);
5521  }
5522  if ((rhoa2 = (float *) calloc(nwave, sizeof (float))) == NULL) {
5523  printf("Unable to allocate space for rhoa2.\n");
5524  exit(1);
5525  }
5526  if ((rhoas1 = (float *) calloc(nwave, sizeof (float))) == NULL) {
5527  printf("Unable to allocate space for rhoas1.\n");
5528  exit(1);
5529  }
5530  if ((rhoas2 = (float *) calloc(nwave, sizeof (float))) == NULL) {
5531  printf("Unable to allocate space for rhoas2.\n");
5532  exit(1);
5533  }
5534  if ((f1 = (float *) calloc(maxwave, sizeof (float))) == NULL) {
5535  printf("Unable to allocate space for f1.\n");
5536  exit(1);
5537  }
5538  if ((f2 = (float *) calloc(maxwave, sizeof (float))) == NULL) {
5539  printf("Unable to allocate space for f2.\n");
5540  exit(1);
5541  }
5542  if ((lnf1 = (float *) calloc(maxwave, sizeof (float))) == NULL) {
5543  printf("Unable to allocate space for lnf1.\n");
5544  exit(1);
5545  }
5546  if ((lnf2 = (float *) calloc(maxwave, sizeof (float))) == NULL) {
5547  printf("Unable to allocate space for lnf2.\n");
5548  exit(1);
5549  }
5550 
5551  if (firstCall) {
5552  angst_band1 = windex(520, wave, nwave);
5553  angst_band2 = windex(865, wave, nwave);
5554  firstCall = 0;
5555  }
5556 
5557  /* bail on negative input aot */
5558  for (iw = 0; iw < nwave; iw++) {
5559  if (aot[iw] < 0.0) {
5560  free(rhoa1);
5561  free(rhoa2);
5562  free(rhoas1);
5563  free(rhoas2);
5564  free(f1);
5565  free(f2);
5566  free(lnf1);
5567  free(lnf2);
5568  return (1);
5569  }
5570  }
5571 
5572  /* compute angstrom and use to select bounding models */
5573  if (aot[iwnir_l] > 0.0)
5574  angstrom = -log(aot[angst_band1] / aot[angst_band2]) /
5575  log(wave[angst_band1] / wave[angst_band2]);
5576  else
5577  angstrom = 0.0;
5578 
5579  model_select_angstrom(angstrom, modmin, modmax, modrat);
5580 
5581 
5582  /* get model phase function for all wavelengths at this geometry for the two models */
5583  phase1 = model_phase(*modmin, geom);
5584  phase2 = model_phase(*modmax, geom);
5585 
5586  gmult = (interpol == 1) ? 0 : geom->gmult;
5587 
5588  /* compute factor for SS approximation, set-up for interpolation */
5589  for (iw = 0; iw < aertab->nwave; iw++) {
5590  ig = gmult * iw;
5591  f1[iw] = aertab->model[*modmin]->albedo[iw] *
5592  phase1[iw] / 4.0 / geom->csolz[ig] / geom->csenz[ig];
5593  f2[iw] = aertab->model[*modmax]->albedo[iw] *
5594  phase2[iw] / 4.0 / geom->csolz[ig] / geom->csenz[ig];
5595  if (interpol) {
5596  lnf1[iw] = log(f1[iw]);
5597  lnf2[iw] = log(f2[iw]);
5598  }
5599  }
5600 
5601  /* compute SS aerosol reflectance */
5602  if (interpol) {
5603  for (iw = 0; iw < nwave; iw++) {
5604  iwtab = iwatab[iw];
5605  if (aertab->wave[iwtab] != wave[iw] && wave[iw] > 0) {
5606  rhoas1[iw] = aot[iw] * exp(linterp(aertab->wave, lnf1, aertab->nwave, wave[iw]));
5607  rhoas2[iw] = aot[iw] * exp(linterp(aertab->wave, lnf2, aertab->nwave, wave[iw]));
5608  } else {
5609  rhoas1[iw] = aot[iw] * f1[iwtab];
5610  rhoas2[iw] = aot[iw] * f2[iwtab];
5611  }
5612  }
5613  } else {
5614  for (iw = 0; iw < nwave; iw++) {
5615  iwtab = iwatab[iw];
5616  rhoas1[iw] = aot[iw] * f1[iwtab];
5617  rhoas2[iw] = aot[iw] * f2[iwtab];
5618  }
5619  }
5620  eps1 = rhoas1[iwnir_s] / rhoas1[iwnir_l];
5621  eps2 = rhoas2[iwnir_s] / rhoas2[iwnir_l];
5622 
5623  /* compute MS aerosol reflectance */
5624  rhoas_to_rhoa(sensorID, *modmin, geom, wv, rhoas1, wave, nwave, 0, nwave - 1, rhoa1);
5625  rhoas_to_rhoa(sensorID, *modmax, geom, wv, rhoas2, wave, nwave, 0, nwave - 1, rhoa2);
5626 
5627  for (iw = 0; iw < nwave; iw++) {
5628  rhoa[iw] = (1.0 - *modrat) * rhoa1[iw] + *modrat * rhoa2[iw];
5629  }
5630  *epsnir = (1.0 - *modrat) * eps1 + *modrat * eps2;
5631 
5632  free(rhoa1);
5633  free(rhoa2);
5634  free(rhoas1);
5635  free(rhoas2);
5636  free(f1);
5637  free(f2);
5638  free(lnf1);
5639  free(lnf2);
5640 
5641  return (0);
5642 }
5643 
5644 
5645 /* ---------------------------------------------------------------------------------------- */
5646 /* aerosol() - compute aerosol reflectance using specified algorithm */
5647 /* */
5648 /* B. Franz, 1 June 2004. */
5649 
5650 /* ---------------------------------------------------------------------------------------- */
5651 int aerosol(l2str *l2rec, int32_t aer_opt_in, aestr *aerec, int32_t ip,
5652  float wave[], int32_t nwave, int32_t iwnir_s_in, int32_t iwnir_l_in,
5653  float F0_in[], float La1_in[], float La2_out[],
5654  float t_sol_out[], float t_sen_out[], float *eps, float taua_out[],
5655  int32_t *modmin, int32_t *modmax, float *modrat,
5656  int32_t *modmin2, int32_t *modmax2, float *modrat2, float *mbac_w) {
5657  static int firstCall = 1;
5658  static int32_t mindx[MAXAERMOD];
5659 
5660  int status = 1;
5661  float *rhoa;
5662  float *radref;
5663  float temp;
5664  float *aot;
5665  float angstrom;
5666 
5667  int iw, ipb, inir;
5668 
5669  float *F0;
5670  float *taur;
5671  float *La1;
5672  float *La2;
5673  float *t_sol;
5674  float *t_sen;
5675  float *taua;
5676  float *taua_pred_min;
5677  float *taua_pred_max;
5678 
5679  static int32_t last_scan=-99;
5680  static int32_t aer_wave_base;
5681  float eps_tmp;
5682  float chi2 = BAD_FLT;
5683 
5684  l1str *l1rec = l2rec->l1rec;
5685  uncertainty_t *uncertainty=l1rec->uncertainty;
5686 
5687  static float *noise_temp;
5688 
5689  if(input->aer_opt==AERRHSM && firstCall){
5690  noise_global=(float *)malloc(l1rec->npix*nwave*sizeof(float));
5691  }
5692 
5693  if (input->aer_opt == AERRHSM && l1rec->iscan != last_scan) {
5694  noise_temp = get_uncertainty(l1rec);
5695  last_scan = l1rec->iscan;
5696  }
5697 
5698  int32_t sensorID = l1rec->l1file->sensorID;
5699  float solz = l1rec->solz [ip];
5700  float senz = l1rec->senz [ip];
5701  float wv = l1rec->wv [ip];
5702  float rh = l1rec->rh [ip];
5703  float pr = l1rec->pr [ip];
5704  int taua_opt;
5705 
5706  if (firstCall) {
5707  Nbands = nwave;
5708  Maxband = nwave + 1; /* Must be >= Nbands */
5709  }
5710 
5711  if ((rhoa = (float *) calloc(nwave, sizeof (float))) == NULL) {
5712  printf("Unable to allocate space for rhoa.\n");
5713  exit(1);
5714  }
5715  if ((radref = (float *) calloc(nwave, sizeof (float))) == NULL) {
5716  printf("Unable to allocate space for raderef.\n");
5717  exit(1);
5718  }
5719  if ((F0 = (float *) calloc(nwave, sizeof (float))) == NULL) {
5720  printf("Unable to allocate space for F0.\n");
5721  exit(1);
5722  }
5723  if ((taur = (float *) calloc(nwave, sizeof (float))) == NULL) {
5724  printf("Unable to allocate space for taur.\n");
5725  exit(1);
5726  }
5727  if ((La1 = (float *) calloc(nwave, sizeof (float))) == NULL) {
5728  printf("Unable to allocate space for La1.\n");
5729  exit(1);
5730  }
5731  if ((La2 = (float *) calloc(nwave, sizeof (float))) == NULL) {
5732  printf("Unable to allocate space for La2.\n");
5733  exit(1);
5734  }
5735  if ((t_sol = (float *) calloc(nwave, sizeof (float))) == NULL) {
5736  printf("Unable to allocate space for t_sol.\n");
5737  exit(1);
5738  }
5739  if ((t_sen = (float *) calloc(nwave, sizeof (float))) == NULL) {
5740  printf("Unable to allocate space for t_sen.\n");
5741  exit(1);
5742  }
5743  if ((taua = (float *) calloc(nwave, sizeof (float))) == NULL) {
5744  printf("Unable to allocate space for taua.\n");
5745  exit(1);
5746  }
5747  if ((taua_pred_min = (float *) calloc(nwave, sizeof (float))) == NULL) {
5748  printf("Unable to allocate space for taua_pred_min.\n");
5749  exit(1);
5750  }
5751  if ((taua_pred_max = (float *) calloc(nwave, sizeof (float))) == NULL) {
5752  printf("Unable to allocate space for taua_pred_max.\n");
5753  exit(1);
5754  }
5755 
5756  /* set up the geometry structure to be passed */
5757  if (l1rec->geom_per_band == NULL) {
5758  /* nominal geometry setup */
5759  geom.senz = &l1rec->senz[ip];
5760  geom.solz = &l1rec->solz[ip];
5761  geom.phi = &l1rec->delphi[ip];
5762  geom.csolz = &l1rec->csolz[ip];
5763  geom.csenz = &l1rec->csenz[ip];
5764  geom.gmult = 0;
5765 
5766  geom.airmass = (float *) malloc(sizeof (float));
5767  *geom.airmass = 1. / geom.csolz[0] + 1. / geom.csenz[0];
5768  if ((evalmask & TRANSSPHER) != 0) {
5769  geom.airmass_sph = (float *) malloc(sizeof (float));
5770  geom.airmass_plp = (float *) malloc(sizeof (float));
5771  *geom.airmass_sph = ky_airmass(geom.solz[0]) +
5772  ky_airmass(geom.senz[0]);
5773  *geom.airmass_plp = pp_airmass(geom.solz[0]) +
5774  pp_airmass(geom.senz[0]);
5775  }
5776  } else {
5777  ipb = ip * Nbands;
5778  geom.senz = &l1rec->geom_per_band->senz[ipb];
5779  geom.solz = &l1rec->geom_per_band->solz[ipb];
5780  geom.phi = &l1rec->geom_per_band->delphi[ipb];
5781  geom.csolz = &l1rec->geom_per_band->csolz[ipb];
5782  geom.csenz = &l1rec->geom_per_band->csenz[ipb];
5783  geom.gmult = 1;
5784 
5785  geom.airmass = (float *) malloc(Nbands * sizeof (float));
5786  for (iw = 0; iw < Nbands; iw++) {
5787  geom.airmass[iw] = 1. / geom.csolz[iw] + 1. / geom.csenz[iw];
5788  }
5789  if ((evalmask & TRANSSPHER) != 0) {
5790  geom.airmass_plp = (float *) malloc(Nbands * sizeof (float));
5791  geom.airmass_sph = (float *) malloc(Nbands * sizeof (float));
5792  for (iw = 0; iw < Nbands; iw++) {
5793  geom.airmass_plp[iw] = pp_airmass(geom.solz[iw]) +
5794  pp_airmass(geom.senz[iw]);
5795  geom.airmass_sph[iw] = ky_airmass(geom.solz[iw]) +
5796  ky_airmass(geom.senz[iw]);
5797  }
5798  }
5799  }
5800 
5801  /* set static global evaluation level */
5802  evalmask = l1_input->evalmask;
5803  aer_opt = aer_opt_in;
5804 
5805  /* transfer inputs per band to inputs per wavelength */
5806  for (iw = 0; iw < nwave; iw++) {
5807  F0 [iw] = F0_in [iw];
5808  taur[iw] = l1rec->l1file->Tau_r[iw];
5809  La1 [iw] = La1_in[iw];
5810  if (iw == iwnir_s_in) iwnir_s = iw;
5811  if (iw == iwnir_l_in) iwnir_l = iw;
5812  }
5813 
5814  /* compute total airmass (static global) */
5815  mu0 = cos(solz / radeg);
5816  mu = cos(senz / radeg);
5817  airmass = 1.0 / mu0 + 1.0 / mu;
5818  if ((evalmask & TRANSSPHER) != 0) {
5819  airmass_plp = pp_airmass(solz) + pp_airmass(senz);
5820  airmass_sph = ky_airmass(solz) + ky_airmass(senz);
5821  }
5822 
5823  /* initialize epsilon and diffuse transmittance to defaults */
5824  *eps = 1.0;
5825  *modmin = BAD_INT;
5826  *modmax = BAD_INT;
5827  *modrat = BAD_FLT;
5828  *modmin2 = BAD_INT;
5829  *modmax2 = BAD_INT;
5830  *modrat2 = BAD_FLT;
5831  for (iw = 0; iw < nwave; iw++) {
5832  taua [iw] = 0.0;
5833  t_sol [iw] = 1.0;
5834  t_sen [iw] = 1.0;
5835  La2 [iw] = 0.0;
5836  radref[iw] = pi / F0[iw] / geom.csolz[iw * geom.gmult];
5837 
5838  if (input->aer_opt == AERRHSM) {
5839  if (noise_temp) {
5840  ipb = ip * nwave + iw;
5841  noise_global[ipb] = noise_temp[ipb] * radref[iw];
5842  } else
5843  noise_global[ipb] = 1.0;
5844  }
5845  }
5846 
5847  /* load aerosol model tables */
5848  if (!loaded) {
5849  int32_t im;
5850  load_aermod(sensorID, wave, nwave, input->aermodfile, input->aermodels, input->naermodels);
5851  for (im = 0; im < aertab->nmodel; im++) mindx[im] = im;
5852  if (have_rh && aertab->nmodel >= 30) {
5853  printf("\nLimiting aerosol models based on RH.\n");
5854  use_rh = 1;
5855  }
5856  }
5857  /* do not permit use of geom_per_band if interpolation is done */
5858  /* WDR note that it CAN work, but currently, we don't want users to
5859  use this combination */
5860  if ((interpol == 1) && (geom.gmult == 1)) {
5861  fprintf(stderr, "-E- %s line %d: Interpolated aerosol tables are\n",
5862  __FILE__, __LINE__);
5863  fprintf(stderr, " not permitted for use with band-dependent geometry, set geom_per_band=0\n");
5864  exit(1);
5865  }
5866 
5867  /* Change the aerosol option if need be */
5868  if (use_rh)
5869  switch (aer_opt) {
5870  case AERWANG: aer_opt = AERRH;
5871  break;
5872  case AERWANGNIR: aer_opt = AERRHNIR;
5873  break;
5874  case AERWANGSWIR: aer_opt = AERRHSWIR;
5875  break;
5876  case AERMUMM: aer_opt = AERRHMUMM;
5877  break;
5878  }
5879 
5880 
5881  if (firstCall) {
5882  aer_wave_base=bindex_get(input->aer_wave_base);
5883  if (aer_opt > 0 && aer_opt <= MAXAERMOD) {
5884  printf("\nUsing fixed aerosol model #%d (%s)\n", aer_opt, input->aermodels[aer_opt - 1]);
5885  printf("Extrapolating from %4.1f nm\n", wave[iwnir_l]);
5886  } else {
5887  switch (aer_opt) {
5888  case AERRHSM: // Spectral Matching --> Amir
5889  printf("\nUsing Spectral Matching of aerosols reflectance for\n");
5890  printf("wavelength from %4.1f nm to %4.1f nm for model selection\n", wave[iwnir_s], wave[iwnir_l]);
5891  break;
5892  case AERWHITE:
5893  printf("\nUsing white-aerosol approximation\n");
5894  printf("Extrapolating from %4.1f nm\n", wave[iwnir_l]);
5895  break;
5896  case AERWANG:
5897  case AERRH:
5898  printf("\nUsing Gordon & Wang aerosol model selection\n");
5899  printf("Using bands at %4.1f and %4.1f nm for model selection\n", wave[iwnir_s], wave[iwnir_l]);
5900  printf("Extrapolating from %4.1f nm\n", wave[iwnir_l]);
5901  break;
5902  case AERWANGNIR:
5903  case AERRHNIR:
5904  printf("\nUsing Gordon & Wang aerosol model selection\n");
5905  printf(" and NIR correction with up to %d iterations\n", input->aer_iter_max);
5906  printf("Using bands at %4.1f and %4.1f nm for model selection\n", wave[iwnir_s], wave[iwnir_l]);
5907  printf("Extrapolating from %4.1f nm\n", wave[iwnir_l]);
5908  break;
5909  case AERWANGSWIR:
5910  case AERRHSWIR:
5911  printf("\nUsing Gordon & Wang aerosol model selection with NIR/SWIR switching.\n");
5912  printf("NIR correction with up to %d iterations\n", input->aer_iter_max);
5913  printf("NIR bands at %d and %d nm\n", input->aer_wave_short, input->aer_wave_long);
5914  printf("SWIR bands at %d and %d nm\n\n", input->aer_swir_short, input->aer_swir_long);
5915  break;
5916  case AERMUMM:
5917  case AERRHMUMM:
5918  printf("\nUsing Gordon & Wang aerosol model selection\n");
5919  printf(" and MUMM correction\n");
5920  printf("Using bands at %4.1f and %4.1f nm for model selection\n", wave[iwnir_s], wave[iwnir_l]);
5921  printf("Extrapolating from %4.1f nm\n", wave[iwnir_l]);
5922  break;
5923  case AERRHMSEPS:
5924  printf("\nUsing multi-scattering aerosol model selection.\n");
5925  printf(" and NIR correction with up to %d iterations\n", input->aer_iter_max);
5926  printf("Using bands at %4.1f and %4.1f nm for model selection\n", wave[iwnir_s], wave[iwnir_l]);
5927  printf("Extrapolating from %4.1f nm\n", wave[iwnir_l]);
5928  break;
5929  case AERRHMSEPS_lin:
5930  printf("\nUsing multi-scattering aerosol model selection in linear space.\n");
5931  printf(" and NIR correction with up to %d iterations\n", input->aer_iter_max);
5932  printf("Using bands at %4.1f and %4.1f nm for model selection\n", wave[iwnir_s], wave[iwnir_l]);
5933  printf("Extrapolating from %4.1f nm\n", wave[iwnir_l]);
5934  break;
5935  case FIXAOT:
5936  printf("\nUsing fixed, input aerosol optical thicknesses for aerosol selection.\n");
5937  break;
5938  case FIXMODPAIR:
5939  printf("\nUsing multiple scattering aerosols with fixed model pair\n");
5940  break;
5941  case FIXMODPAIRNIR:
5942  printf("\nUsing multiple scattering aerosols with fixed model pair\n");
5943  printf(" and NIR iteration with up to %d iterations\n", input->aer_iter_max);
5944  printf("Extrapolating from %4.1f nm\n", wave[iwnir_l]);
5945  break;
5946  case FIXANGSTROM:
5947  printf("\nUsing fixed aerosol model based on predefined Angstrom exponent\n");
5948  printf("Extrapolating from %4.1f nm\n", wave[iwnir_l]);
5949  break;
5950  case FIXANGSTROMNIR:
5951  printf("\nUsing fixed aerosol model based on predefined Angstrom exponent\n");
5952  printf(" and NIR iteration with up to %d iterations\n", input->aer_iter_max);
5953  printf("Extrapolating from %4.1f nm\n", wave[iwnir_l]);
5954  break;
5955  default:
5956  printf("\nErroneous aerosol option, %d\n", aer_opt);
5957  exit(FATAL_ERROR);
5958  break;
5959  }
5960  }
5961  firstCall = 0;
5962  }
5963 
5964 
5965  /* convert input aerosol radiances to relectance */
5966  for (iw = iwnir_s; iw <= iwnir_l; iw += MAX(iwnir_l - iwnir_s, 1))
5967  rhoa[iw] = La1[iw] * radref[iw];
5968 
5969 
5970  /* compute aerosol using requested method */
5971  /* -------------------------------------- */
5972 
5973  switch (aer_opt) {
5974 
5975  case AERWANG: case AERWANGNIR: case AERWANGSWIR: case AERMUMM:
5976 
5977  if (iwnir_l <= iwnir_s || wave[iwnir_s] < 600) {
5978  printf("Aerosol selection bands must be greater than 600nm with short wave less than long wave (%d,%d)\n", iwnir_l, iwnir_s);
5979  exit(1);
5980  }
5981 
5982  /* Multi-Scattering with Gordon & Wang Aerosol Selection */
5983  /* ----------------------------------------------------- */
5984 
5985  /* convert input NIR aerosol radiances to reflectance */
5986  for (iw = iwnir_s; iw <= iwnir_l; iw++) {
5987  rhoa[iw] = La1[iw] * radref[iw];
5988  }
5989 
5990  /* require sufficient signal in two NIR bands */
5991  if (rhoa[iwnir_s] > input->rhoamin && rhoa[iwnir_l] > input->rhoamin) {
5992 
5993  /* require MS epsilon to be reasonable */
5994  if (La1[iwnir_s] / La1[iwnir_l] > 0.1) {
5995 
5996  status = wangaer(sensorID, wave, nwave, iwnir_s, iwnir_l,
5997  aertab->nmodel, mindx,
5998  &geom, wv, rhoa, modmin, modmax, modrat, eps, taua, taua); // this taua is not used //
5999 
6000  if (status == 0)
6001  for (iw = 0; iw < nwave; iw++)
6002  La2[iw] = rhoa[iw] / radref[iw];
6003  }
6004 
6005  } else if (rhoa[iwnir_s] > -(input->rhoamin) && rhoa[iwnir_l] > -(input->rhoamin)) {
6006 
6007  /* if input NIR is near zero, assume a small white aerosol signal */
6008  *eps = 1.0;
6009  *modmin = aertab->nmodel;
6010  *modmax = aertab->nmodel;
6011  *modrat = 0.0;
6012  temp = MAX(rhoa[iwnir_l], 1e-6);
6013  for (iw = 0; iw < nwave; iw++) {
6014  rhoa[iw] = temp;
6015  La2 [iw] = rhoa[iw] / radref[iw];
6016  }
6017 
6018  status = 0;
6019 
6020  } else {
6021 
6022  /* if input NIR is very negative, fail the case */
6023  status = 1;
6024  }
6025 
6026  break;
6027 
6028  case AERRH:
6029  case AERRHNIR:
6030  case AERRHSWIR:
6031  case AERRHMUMM:
6032  case AERRHMSEPS:
6033  case AERRHMSEPS_lin:
6034  case AERRHSM: // spectral matching --> Amir
6035 
6036  if (iwnir_l <= iwnir_s || wave[iwnir_s] < 600) {
6037  printf("Aerosol selection bands must be greater than 600nm with short wave less than long wave");
6038  exit(1);
6039  }
6040 
6041  /* Multi-Scattering with RH-based selection */
6042  /* ----------------------------------------------------- */
6043 
6044  /* convert input NIR aerosol radiances to relectance */
6045  for (iw = iwnir_s; iw <= iwnir_l; iw++) {
6046  rhoa[iw] = La1[iw] * radref[iw];
6047  }
6048 
6049  /* require sufficient signal in two NIR bands */
6050  if (rhoa[iwnir_s] > input->rhoamin && rhoa[iwnir_l] > input->rhoamin) {
6051 
6052  /* require MS epsilon to be reasonable */
6053  eps_tmp=rhoa[iwnir_s] / rhoa[iwnir_l];
6054  if(aer_opt==AERRHSM)
6055  eps_tmp=rhoa[iwnir_s] / rhoa[aer_wave_base];
6056  if (eps_tmp > 0.1 && eps_tmp < 10.0) {
6057 
6058  status = rhaer(sensorID, wave, nwave, iwnir_s, iwnir_l,
6059  &geom, wv, rh, pr, taur, rhoa,
6060  modmin, modmax, modrat, modmin2, modmax2, modrat2, eps, taua, t_sol, t_sen, ip,mbac_w,&chi2,uncertainty);
6061  status = 0;
6062  if (status == 0){
6063  l2rec->chi2[ip]=chi2;
6064  for (iw = 0; iw < nwave; iw++){
6065  La2[iw] = rhoa[iw] / radref[iw];
6066 
6067  if(uncertainty){
6068  uncertainty->derv_La_taua_l[iw] /= radref[iw];
6069  uncertainty->derv_La_rhow_l[iw] /= radref[iw];
6070  uncertainty->derv_La_rh[iw] /= radref[iw];
6071  for(inir=0;inir<=iwnir_l-iwnir_s;inir++){
6072  uncertainty->derv_La_rhorc[iw][inir] /= radref[iw];
6073  }
6074  }
6075  }
6076  }
6077  }
6078 
6079  } else if (rhoa[iwnir_s] > -(input->rhoamin) && rhoa[iwnir_l] > -(input->rhoamin)) {
6080 
6081  /* if input NIR is near zero, assume a small white aerosol signal */
6082  *eps = 1.0;
6083  *modmin = aertab->nmodel;
6084  *modmax = aertab->nmodel;
6085  *modrat = 0.0;
6086  *modmin2 = aertab->nmodel;
6087  *modmax2 = aertab->nmodel;
6088  *modrat2 = 0.0;
6089  temp = MAX(rhoa[iwnir_l], 1e-6);
6090  for (iw = 0; iw < nwave; iw++) {
6091  rhoa[iw] = temp;
6092  La2 [iw] = rhoa[iw] / radref[iw];
6093  }
6094 
6095  // The diff_tran function needs taua. In this exception case, taua was not yet computed. The taua_opt
6096  // tells diff_tran what method to use for the computation (0=SS, 2=MS). I used the aer_opt to decide,
6097  // but we could use the global have_ms flag. For now I want to limit the impact, as some sensors are
6098  // run with the G&W SS aerosol option, but their tables "have_ms". BAF, 6/2022.
6099 
6100  if (aer_opt == AERRHMSEPS || aer_opt == AERRHMSEPS_lin|| aer_opt == AERRHSM)
6101  taua_opt = 2;
6102  else
6103  taua_opt = 0;
6104 
6105  diff_tran(sensorID, wave, nwave, iwnir_l, &geom, wv, pr, taur,
6106  *modmin, *modmax, *modrat, rhoa, taua, t_sol, t_sen, taua_pred_min, taua_pred_max, taua_opt, ip, uncertainty);
6107 
6108 
6109  status = 0;
6110 
6111  } else {
6112 
6113  /* if input NIR is very negative, fail the case */
6114  status = 1;
6115  }
6116 
6117  break;
6118 
6119  case AERWHITE:
6120 
6121  /* White Aerosol */
6122  /* ------------- */
6123 
6124  if (La1[iwnir_l] > 0.0) {
6125 
6126  *eps = 1.0;
6127  *modmin = 0;
6128  *modmax = 0;
6129  *modrat = 0.0;
6130 
6131  for (iw = 0; iw < nwave; iw++) {
6132  La2 [iw] = *eps * F0[iw] / F0[iwnir_l] * La1[iwnir_l];
6133  rhoa[iw] = La2[iw] * radref[iw];
6134  }
6135 
6136 
6137  status = 0;
6138  }
6139  break;
6140 
6141  case FIXMODPAIR: case FIXMODPAIRNIR:
6142 
6143  /* Multi-Scattering with Fixed Model Pair */
6144  /* -------------------------------------- */
6145 
6146  if (aerec != NULL && aerec->mode == ON) {
6147  *modmin = aerec->mod_min[ip] - 1;
6148  *modmax = aerec->mod_max[ip] - 1;
6149  *modrat = aerec->mod_rat[ip];
6150  } else {
6151  *modmin = input->aermodmin - 1;
6152  *modmax = input->aermodmax - 1;
6153  *modrat = input->aermodrat;
6154  }
6155 
6156  status = fixedmodpair(sensorID, wave, nwave, iwnir_s, iwnir_l, &geom, wv,
6157  *modmin, *modmax, *modrat, rhoa, eps);
6158  if (status == 0) {
6159  for (iw = 0; iw < nwave; iw++)
6160  La2[iw] = rhoa[iw] / radref[iw];
6161  }
6162 
6163  break;
6164 
6165  case FIXANGSTROM: case FIXANGSTROMNIR:
6166 
6167  if (input->aer_angstrom > -2) {
6168  angstrom = input->aer_angstrom;
6169  } else {
6170  int16_t year, day;
6171  double sec;
6172  unix2yds(l2rec->l1rec->scantime, &year, &day, &sec);
6173  angstrom = bin_climatology(input->aerbinfile, day, l1rec->lon[ip], l1rec->lat[ip], "angstrom");
6174  }
6175 
6176  if (angstrom > -2) {
6177 
6178  model_select_angstrom(angstrom, modmin, modmax, modrat);
6179 
6180  status = fixedmodpair(sensorID, wave, nwave, iwnir_s, iwnir_l, &geom, wv,
6181  *modmin, *modmax, *modrat, rhoa, eps);
6182  } else
6183  status = 1;
6184 
6185  if (status == 0) {
6186  for (iw = 0; iw < nwave; iw++)
6187  La2[iw] = rhoa[iw] / radref[iw];
6188  }
6189 
6190  break;
6191 
6192  case FIXAOT:
6193 
6194  /* Multi-Scattering with fixed AOT */
6195  /* ------------------------------- */
6196  if (aerec != NULL && aerec->mode == ON)
6197  aot = &aerec->taua[ip * Nbands];
6198  else
6199  aot = input->taua;
6200 
6201  status = fixedaot(sensorID, aot, wave, nwave, iwnir_s, iwnir_l, &geom, wv,
6202  modmin, modmax, modrat, rhoa, eps);
6203  if (status == 0) {
6204  for (iw = 0; iw < nwave; iw++)
6205  La2[iw] = rhoa[iw] / radref[iw];
6206  }
6207 
6208  break;
6209 
6210  default:
6211 
6212  /* Multi-Scattering with Fixed Model */
6213  /* --------------------------------- */
6214 
6215  *modmin = aer_opt - 1;
6216  *modmax = aer_opt - 1;
6217  *modrat = 0.0;
6218 
6219  if (*modmin < 0 || *modmin > input->naermodels - 1) {
6220  printf("Invalid aerosol option: %d\n", *modmin);
6221  exit(1);
6222  }
6223 
6224  /* convert input NIR aerosol radiance to relectance */
6225  rhoa[iwnir_l] = La1[iwnir_l] * radref[iwnir_l];
6226 
6227  /* get aerosol reflectance in visible for fixed model, and epsilon */
6228  status = fixedaer(sensorID, *modmin, wave, nwave, iwnir_s, iwnir_l,
6229  input->aermodels, input->naermodels,
6230  &geom, wv, rhoa, eps);
6231 
6232  /* convert aerosol relectance to radiance */
6233  if (status == 0)
6234  for (iw = 0; iw < nwave; iw++)
6235  La2[iw] = rhoa[iw] / radref[iw];
6236  break;
6237  }
6238 
6239  /* compute diffuse transmittance through aerosol and Rayleigh, if not yet computed */
6240  if (status == 0 && aer_opt != AERRHNIR && aer_opt != AERRHSWIR && aer_opt != AERRH && aer_opt != AERRHMSEPS && aer_opt != AERRHSM) {
6241 
6242  diff_tran(sensorID, wave, nwave, iwnir_l, &geom, wv, pr, taur,
6243  *modmin, *modmax, *modrat, rhoa, taua, t_sol, t_sen, taua_pred_min, taua_pred_max, 0,ip, uncertainty);
6244  }
6245 
6246  /* transfer outputs per wavelength to outputs per band */
6247  for (iw = 0; iw < nwave; iw++) {
6248  La2_out [iw] = La2 [iw];
6249  taua_out [iw] = taua [iw];
6250  t_sol_out[iw] = t_sol[iw];
6251  t_sen_out[iw] = t_sen[iw];
6252  }
6253 
6254  /* model numbers are reported as 1-based */
6255  *modmin = *modmin + 1;
6256  *modmax = *modmax + 1;
6257  *modmin2 = *modmin2 + 1;
6258  *modmax2 = *modmax2 + 1;
6259 
6260  free(rhoa);
6261  free(radref);
6262  free(F0);
6263  free(taur);
6264  free(La1);
6265  free(La2);
6266  free(t_sol);
6267  free(t_sen);
6268  free(taua);
6269  free(taua_pred_min);
6270  free(taua_pred_max);
6271  free(geom.airmass);
6272  if ((evalmask & TRANSSPHER) != 0) {
6273  free(geom.airmass_plp);
6274  free(geom.airmass_sph);
6275  }
6276 
6277  return (status);
6278 }
6279 
6280 
6281 
6282 /* --------------------------------------------------------------- */
6283 /* get_angstrom.c - compute angstrom coefficient */
6284 /* */
6285 /* Inputs: */
6286 /* l2rec - level-2 structure containing one complete scan */
6287 /* after atmospheric correction. */
6288 /* band = band number 0-7 */
6289 /* Outputs: */
6290 /* angst - angstrom coefficient */
6291 /* */
6292 /* Written By: B. A. Franz, SAIC, August 2004 */
6293 /* */
6294 
6295 /* --------------------------------------------------------------- */
6296 void get_angstrom(l2str *l2rec, int band, float angst[]) {
6297  static int firstCall = 1;
6298  static int32_t ib2;
6299  static float wave2;
6300 
6301  int32_t ip;
6302  int32_t ib1;
6303  float wave1;
6304  float aot1;
6305  float aot2;
6306 
6307  l1str *l1rec = l2rec->l1rec;
6308  filehandle *l1file = l1rec->l1file;
6309 
6310  if (firstCall) {
6311  ib2 = windex(865.0, l1file->fwave, l1file->nbands);
6312  wave2 = l1file->fwave[ib2];
6313  firstCall = 0;
6314  }
6315 
6316  if (band < 0)
6317  ib1 = windex(443.0, l1file->fwave, l1file->nbands);
6318  else
6319  ib1 = band;
6320  wave1 = l1file->fwave[ib1];
6321 
6322  for (ip = 0; ip < l1rec->npix; ip++) {
6323  aot1 = l2rec->taua[ip * l1file->nbands + ib1];
6324  aot2 = l2rec->taua[ip * l1file->nbands + ib2];
6325  if (aot1 > 0.0 && aot2 > 0.0)
6326  angst[ip] = -log(aot1 / aot2) / log(wave1 / wave2);
6327  else if (aot1 == 0.0 && aot2 == 0.0)
6328  angst[ip] = 0.0;
6329  else {
6330  angst[ip] = BAD_FLT;
6331  l1rec->flags[ip] |= PRODFAIL;
6332  }
6333  // printf("angst = %f aot1= %f aot2= %f ib1=%d ib2=%d\n",angst[ip],aot1,aot2,ib1,ib2);
6334  }
6335 
6336  return;
6337 }
6338 
6339 
6340 /* --------------------------------------------------------------- */
6341 /* get_ms_epsilon.c - */
6342 
6343 /* --------------------------------------------------------------- */
6344 void get_ms_epsilon(l2str *l2rec, float eps[]) {
6345  int32_t ip, ipb1, ipb2;
6346 
6347  l1str *l1rec = l2rec->l1rec;
6348  filehandle *l1file = l1rec->l1file;
6349 
6350  for (ip = 0; ip < l1rec->npix; ip++) {
6351  ipb1 = ip * l1file->nbands + iwnir_s;
6352  ipb2 = ip * l1file->nbands + iwnir_l;
6353  if (l2rec->La[ipb2] > 0.0) {
6354  eps[ip] = l2rec->La[ipb1] / l2rec->La[ipb2]
6355  * l1rec->Fo[iwnir_l] / l1rec->Fo[iwnir_s];
6356  } else {
6357  /* "should" indicate ATMFAIL, but just to be safe */
6358  eps[ip] = BAD_FLT;
6359  l1rec->flags[ip] |= PRODFAIL;
6360  }
6361  }
6362 
6363  return;
6364 }
float rhoa
Definition: aerosol.c:4773
void get_pc_rhoa(int modnum, geom_str *geom, float **pc_rhoa)
Definition: aerosol.c:1391
int32 l1file(int32 sdfid, int32 *nsamp, int32 *nscans, int16 *dtynum)
Definition: l1stat_chk.c:586
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 index(0-based) was previously being used the frame number(1-based) should have been used. There were only a few minor changes to the uncertainty index(maximum of 1 digit). 3. Some inefficient arrays(Sigma_RVS_norm_sq) were eliminated and some code lines in Preprocess_L1A_Data were moved into Process_OBCEng_Emiss. There were no changes to the product. Required RAM was reduced by 20 MB. Now
#define MAX(A, B)
Definition: swl0_utils.h:25
float * senz
Definition: aerosol.c:216
data_t q
Definition: decode_rs.h:74
int32 value
Definition: Granule.c:1235
void ss_to_ms_coef(int modnum, geom_str *geom, float **a, float **b, float **c)
Definition: aerosol.c:793
#define MIN(x, y)
Definition: rice.h:169
int r
Definition: decode_rs.h:73
float pp_airmass(float theta)
Definition: airmass.c:14
void ms_eps_coef(int modnum, int32_t iwnir_l, float wave[], geom_str *geom, float **a, float **b, float **c, float **d, float **e)
Definition: aerosol.c:1068
float * tau_870
Definition: aerosol.c:130
#define AERRH
Definition: l12_parms.h:34
int smaer(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, int32_t nmodels, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t *modmin, int32_t *modmax, float32 *modrat, float *tau_pred_min, float *tau_pred_max, int32_t ip, float chi[], float *mbac_w, uncertainty_t *uncertainty)
Definition: aerosol.c:4250
float ** d2phase
Definition: aerosol.c:121
void model_transmittance(int modnum, float wave[], int32_t nwave, float *theta, int gmult, float taua[], float dtran[], float dt[])
Definition: aerosol.c:3353
Utility functions for allocating and freeing three-dimensional arrays of various types.
float * senz
Definition: aerosol.c:246
int32_t day
int32_t sensorID
Definition: aerosol.c:199
int status
Definition: l1_czcs_hdf.c:32
float * pc_mean_td
Definition: aerosol.c:129
int model_select_wang(int32_t sensorID, float wave[], int32_t nwave, int32_t nmodel, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t iwnir_s, int32_t iwnir_l, int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir)
Definition: aerosol.c:2988
int smaer_pca(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, int32_t nmodels, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t *modmin, int32_t *modmax, float32 *modrat, float *tau_pred_min, float *tau_pred_max, int32_t ip, float chi[], float *mbac_w, uncertainty_t *uncertainty)
Definition: aerosol.c:3900
float eps
Definition: aerosol.c:4774
#define FIXMODPAIRNIR
Definition: l12_parms.h:27
float * airmass_sph
Definition: aerosol.c:253
float f1(float x)
void model_transmittance_pca(int modnum, float wave[], int32_t nwave, float *theta, int gmult, float taua[], float dtran[], float dt[])
Definition: aerosol.c:3446
float aeroob_cf(int modnum, geom_str *geom)
Definition: aerosol.c:2705
#define INDEX(iw, isol, iphi, isen)
Definition: aerosol.c:779
void rhoas_to_rhoa(int32_t sensorID, int modnum, geom_str *geom, float wv, float rhoas[], float wave[], int32_t nwave, int iw1, int iw2, float rhoa[])
Definition: aerosol.c:2849
float *** pc_td
Definition: aerosol.c:127
#define AERRHSM
Definition: l12_parms.h:37
float * ams_all
Definition: aerosol.c:108
float bin_climatology(char *l3file, int32_t day, float lon, float lat, char *prodname)
int compalphaT(alphaTstr *x, alphaTstr *y)
Definition: aerosol.c:3138
#define NULL
Definition: decode_rs.h:63
map< string, float > F0
Definition: DDSensor.cpp:39
float * bcost
Definition: aerosol.c:104
float ** pc_components_rhoa
Definition: aerosol.c:125
#define FIXANGSTROMNIR
Definition: l12_parms.h:29
char name[32]
Definition: aerosol.c:90
read l1rec
PARAM_TYPE_NONE Default value No parameter is buried in the product name name_prefix is case insensitive string compared to the product name PARAM_TYPE_VIS_WAVE The visible wavelength bands from the sensor are buried in the product name The product name is compared by appending and name_suffix ie aph_412_giop where prod_ix will be set to PARAM_TYPE_IR_WAVE same search method as PARAM_TYPE_VIS_WAVE except only wavelength above are looped through but prod_ix is still based ie aph_2_giop for the second band
int32_t nmodel
Definition: aerosol.c:203
float * ems_all
Definition: aerosol.c:112
const double pi
subroutine spline(s, x, y, n, in, t, il, iu, vl, vu, e, u)
Definition: phs.f:1348
float ** dtran_a
Definition: aerosol.c:116
#define PRODFAIL
Definition: l2_flags.h:41
#define ON
Definition: l1.h:44
int ahmad_atm_corr_pca(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, int32_t nmodels, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir, float tau_pred_max[], float tau_pred_min[], float rho_pred_max[], float rho_pred_min[], float tau_aer[], float rho_aer[], int ip, uncertainty_t *uncertainty)
Definition: aerosol.c:1858
this program makes no use of any feature of the SDP Toolkit that could generate such a then geolocation is calculated at that and then aggregated up to Resolved feature request Bug by adding three new int8 SDSs for each high resolution offsets between the high resolution geolocation and a bi linear interpolation extrapolation of the positions This can be used to reconstruct the high resolution geolocation Resolved Bug by delaying cumulation of gflags until after validation of derived products Resolved Bug by setting Latitude and Longitude to the correct fill resolving to support Near Real Time because they may be unnecessary if use of entrained ephemeris and attitude data is turned resolving bug report Corrected to filter out Aqua attitude records with missing status helping resolve bug MOD_PR03 will still correctly write scan and pixel data that does not depend upon the start thereby resolving MODur00108 Changed header guard macro names to avoid reserved name resolving MODur00104 Maneuver list file for Terra satellite was updated to include data from Jecue DuChateu Maneuver list files for both Terra and Aqua were updated to include two maneuvers from recent IOT weekly reports The limits for Z component of angular momentum was and to set the fourth GEO scan quality flag for a scan depending upon whether or not it occurred during one of them Added _FillValue attributes to many and changed the fill value for the sector start times from resolving MODur00072 Writes boundingcoordinate metadata to L1A archived metadata For PERCENT *ECS change to treat rather resolving GSFcd01518 Added a LogReport Changed to create the Average Temperatures vdata even if the number of scans is
Definition: HISTORY.txt:301
int aerosol(l2str *l2rec, int32_t aer_opt_in, aestr *aerec, int32_t ip, float wave[], int32_t nwave, int32_t iwnir_s_in, int32_t iwnir_l_in, float F0_in[], float La1_in[], float La2_out[], float t_sol_out[], float t_sen_out[], float *eps, float taua_out[], int32_t *modmin, int32_t *modmax, float *modrat, int32_t *modmin2, int32_t *modmax2, float *modrat2, float *mbac_w)
Definition: aerosol.c:5651
#define AERWHITE
Definition: l12_parms.h:22
#define TRANSSPHER
Definition: l1.h:84
double eps
Definition: gha2000.c:3
instead the metadata field ProcessingEnvinronment is filled in from the output of a call to the POSIX compliant function uname from within the L1B code A small bug in L1B_Tables an incorrect comparison of RVS coefficients for TEBs to RVS coefficients for RSBs was being made This was replaced with a comparison between TEB coefficients This error never resulted in an incorrect RVS correction but did lead to recalculating the coefficients for each detector in a thermal band even if the coefficients were the same for all detectors To reduce to overall size of the reflective LUT HDF fill values were eliminated from all LUTs previously dimensioned where and where NUM_TIMES is the number of time dependent table pieces In Preprocess a small error where the trailing dropped scan counter was incremented when the leading dropped scan counter should have been was fixed This counter is internal only and is not yet used for any chiefly to casting of were added to make it LINUX compatible Output of code run on LINUX machines displays differences of at most scaled sector incalculable values of the Emissive calibration factor and incalculable values of SV or BB averages was moved outside the loop over frames in Emissive_Cal c since none of these quantities are frame dependent Initialization of b1 and XMS values in Preprocess c routine Process_OBCENG_Emiss was moved inside the detector loops The code was altered so that if up to five scans are dropped between the leading middle or middle trailing the leading or trailing granule will still be used in emissive calibration to form a cross granule average QA bits and are set for a gap between the leading middle and middle trailing granules respectively This may in rare instances lead to a change in emissive calibration coefficients for scans at the beginning or end of a granule A small bug in the Band correction algorithm was corrected an uncertainty value was being checked against an upper bound whereas the proper quantity to be checked was the corresponding which is the product of the Band radiance times the ratio of the Band to Band scaling factors times the LUT correction value for that detector In addition a new LUT which allows for a frame offset with regard to the Band radiance was added A LUT which switches the correction off or on was also added Changes which do not affect scientific output of the the pixel is flagged with the newly created flag and the number of pixels for which this occurs is counted in the QA_common table The array of b1s in Preprocess c was being initialized to outside the loop over which meant that if b1 could not be computed
Definition: HISTORY.txt:627
void model_taua(int32_t sensorID, int modnum, float wave[], int32_t nwave, int32_t iwnir_l, float rhoa[], geom_str *geom, float wv, float taua[])
Definition: aerosol.c:3194
#define AERRHNIR
Definition: l12_parms.h:24
float * pc
Definition: aerosol.c:131
float * albedo
Definition: aerosol.c:98
int32_t ntau_870
Definition: aerosol.c:211
float * model_phase(int modnum, geom_str *geom)
Definition: aerosol.c:2582
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed file
Definition: HISTORY.txt:413
int32_t im
Definition: atrem_corl1.h:161
instr * input
int model_taua_mseps_pca(int32_t modl, float wave[], int32_t nwave, int32_t iwnir_l, float rhoa[], geom_str *geom, float tau_pred[])
Definition: aerosol.c:3260
int gmult
Definition: aerosol.c:244
int32_t nsolz
Definition: aerosol.c:204
#define PI
Definition: l3_get_org.c:6
float ***** pc_rhoa
Definition: aerosol.c:124
float f2(float y)
aermodstr * alloc_aermodstr(int nbands, int nscatt, int nphi, int nsolz, int nsenz, int ntheta, int npc, int ntau_870)
Definition: aerosol.c:146
float ** lnphase
Definition: aerosol.c:120
float ** phase
Definition: aerosol.c:100
int32_t dtran_nwave
Definition: aerosol.c:208
geom_str geom
Definition: aerosol.c:256
#define FIXMODPAIR
Definition: l12_parms.h:26
int bindex_get(int32_t wave)
Definition: windex.c:45
@ Nbands
Definition: hybrid.c:24
int ahmad_atm_corr_lin(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, int32_t nmodels, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir, float tau_pred_max[], float tau_pred_min[], float rho_pred_max[], float rho_pred_min[], float tau_aer[], float rho_aer[])
Definition: aerosol.c:2428
double precision function f(R1)
Definition: tmd.lp.f:1454
float eps_obs
Definition: aerosol.c:236
data_t tmp
Definition: decode_rs.h:74
#define AERWANG
Definition: l12_parms.h:23
float linterp(float xin[], float yin[], int32_t nin, float xout)
Definition: lspline.c:59
int ahmadaer(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, int32_t nmodels, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir, float tau_pred_min[], float tau_pred_max[], int ip, uncertainty_t *uncertainty)
Definition: aerosol.c:4623
float * angstrom
Definition: aerosol.c:95
void diff_tran(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_l, geom_str *geom, float wv, float pr, float taur[], int32_t modmin, int32_t modmax, float modrat, float rhoa[], float taua[], float tsol[], float tsen[], float tauamin[], float tauamax[], int taua_opt, int ip, uncertainty_t *uncertainty)
Definition: aerosol.c:3717
string path
Definition: color_dtdb.py:221
float * dtran_wave
Definition: aerosol.c:221
float * extc
Definition: aerosol.c:99
aermodstr ** model
Definition: aerosol.c:225
float * dtran_airmass
Definition: aerosol.c:223
int32_t modnum
Definition: aerosol.c:235
float * dtran_theta
Definition: aerosol.c:222
#define AERRHSWIR
Definition: l12_parms.h:33
float * solz
Definition: aerosol.c:247
int rhaer(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, geom_str *geom, float wv, float rh, float pr, float taur[], float rhoa[], int32_t *modmin1, int32_t *modmax1, float *modrat1, int32_t *modmin2, int32_t *modmax2, float *modrat2, float *eps, float taua[], float tsol[], float tsen[], int32_t ip, float *mbac_w, float *chi, uncertainty_t *uncertainty)
Definition: aerosol.c:4894
int comp_epsilonT(epsilonTstr *x, epsilonTstr *y)
Definition: aerosol.c:1608
int32_t nphi
Definition: aerosol.c:206
l1_input_t * l1_input
Definition: l1_options.c:9
#define MAXAERMOD
Definition: l12_parms.h:21
#define FATAL_ERROR
Definition: swl0_parms.h:5
float *** allocate3d_float(size_t nz, size_t ny, size_t nx)
Allocate a three-dimensional array of type float of a given size.
Definition: allocate3d.c:77
void get_angstrom(l2str *l2rec, int band, float angst[])
Definition: aerosol.c:6296
int cp_uncertainty(uncertainty_t *oldrec, uncertainty_t *newrec, int32_t ip)
Definition: uncertainty.c:140
int32_t nsenz
Definition: aerosol.c:205
void unix2yds(double usec, short *year, short *day, double *secs)
#define MAXMODEL
Definition: aerosol.c:57
float rh
Definition: aerosol.c:91
float * csolz
Definition: aerosol.c:249
float * ac[MAX_BANDS]
#define AERMUMM
Definition: l12_parms.h:32
float ky_airmass(float theta)
Definition: airmass.c:4
int32_t dtran_ntheta
Definition: aerosol.c:209
float * csenz
Definition: aerosol.c:250
void diff_tran_pca(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_l, geom_str *geom, float wv, float pr, float taur[], int32_t modmin, int32_t modmax, float modrat, float rhoa[], float taua[], float tsol[], float tsen[], float tauamin[], float tauamax[], int taua_opt, int ip, uncertainty_t *uncertainty)
Definition: aerosol.c:3531
integer, parameter double
float * pc_mean_rhoa
Definition: aerosol.c:126
float * airmass_plp
Definition: aerosol.c:252
float * phi
Definition: aerosol.c:248
float * ccost
Definition: aerosol.c:105
void init_uncertainty(uncertainty_t *uncertainty, int ifscan)
Definition: uncertainty.c:177
float * scatt
Definition: aerosol.c:218
#define RADEG
Definition: czcs_ctl_pt.c:5
Utility functions for allocating and freeing two-dimensional arrays of various types.
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
instead the metadata field ProcessingEnvinronment is filled in from the output of a call to the POSIX compliant function uname from within the L1B code A small bug in L1B_Tables an incorrect comparison of RVS coefficients for TEBs to RVS coefficients for RSBs was being made This was replaced with a comparison between TEB coefficients This error never resulted in an incorrect RVS correction but did lead to recalculating the coefficients for each detector in a thermal band even if the coefficients were the same for all detectors To reduce to overall size of the reflective LUT HDF fill values were eliminated from all LUTs previously dimensioned where and where NUM_TIMES is the number of time dependent table pieces In Preprocess a small error where the trailing dropped scan counter was incremented when the leading dropped scan counter should have been was fixed This counter is internal only and is not yet used for any chiefly to casting of were added to make it LINUX compatible Output of code run on LINUX machines displays differences of at most scaled sector incalculable values of the Emissive calibration factor b1
Definition: HISTORY.txt:576
#define AERRHMSEPS
Definition: l12_parms.h:36
float fresnel_coef(float mu, float index)
Definition: aerosol.c:1041
#define FIXANGSTROM
Definition: l12_parms.h:28
float * wave
Definition: aerosol.c:214
int rhoa_to_rhoas(int32_t sensorID, int modnum, geom_str *geom, float wv, float rhoa[], float wave[], int32_t nwave, int iw1, int iw2, float rhoas[])
Definition: aerosol.c:2786
data_t b[NROOTS+1]
Definition: decode_rs.h:77
#define STDPR
Definition: l12_parms.h:85
int wangaer(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, int32_t nmodels, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir, float tauamin[], float tauamax[])
Definition: aerosol.c:4666
int index
Definition: aerosol.c:136
int comp_rhoa_pca(int32_t nwave, float wave[], geom_str *geom, float tau_iwnir_l, int32_t modl, float tau_pred[], float rho_pred[], float derv_rhoa[], float derv_taua_tmp[])
Definition: aerosol.c:1736
#define BAD_FLT
Definition: jplaeriallib.h:19
subroutine phase
Definition: phase.f:2
int model_select_franz(int32_t sensorID, float wave[], int32_t nwave, int32_t nmodel, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t iwnir_s, int32_t iwnir_l, int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir)
Definition: aerosol.c:4781
float * acost
Definition: aerosol.c:103
int32_t nscatt
Definition: aerosol.c:207
float ** pc_components_td
Definition: aerosol.c:128
float ** dtran_b
Definition: aerosol.c:117
#define AERRHMUMM
Definition: l12_parms.h:35
int32_t modnum
Definition: aerosol.c:4772
int32_t nbands
float * dms_all
Definition: aerosol.c:111
int cmpfunc(const void *a, const void *b)
Definition: aerosol.c:276
float * model_epsilon(int modnum, int32_t iwnir_l, float wave[], int32_t nwave, geom_str *geom)
Definition: aerosol.c:2909
#define fabs(a)
Definition: misc.h:93
int fixedaot(int32_t sensorID, float aot[], float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, geom_str *geom, float wv, int32_t *modmin, int32_t *modmax, float *modrat, float rhoa[], float *epsnir)
Definition: aerosol.c:5492
float * bms_all
Definition: aerosol.c:109
int windex(float wave, float twave[], int ntwave)
Definition: windex.c:73
float ***** allocate5d_float(size_t nq, size_t nr, size_t nz, size_t ny, size_t nx)
Allocate a five-dimensional array of type float of a given size.
Definition: allocate5d.c:12
#define GAS_TRANS_TBL_BIT
Definition: l12_parms.h:62
subroutine splint(xa, ya, y2a, n, x, y)
#define BAD_INT
Definition: genutils.h:23
PARAM_TYPE_NONE Default value No parameter is buried in the product name name_prefix is case insensitive string compared to the product name PARAM_TYPE_VIS_WAVE The visible wavelength bands from the sensor are buried in the product name The product name is compared by appending and name_suffix ie aph_412_giop where prod_ix will be set to PARAM_TYPE_IR_WAVE same search method as PARAM_TYPE_VIS_WAVE except only wavelength above are looped through but prod_ix is still based ie aph_2_giop for the second and prod_ix set to PARAM_TYPE_INT name_prefix is compared with the beginning of the product name If name_suffix is not empty the it must match the end of the product name The characters right after the prefix are read as an integer and prod_ix is set to that number strncpy(l2prod->name_prefix, "myprod", UNITLEN)
int comp_rhoa_ms_eps_lin(int32_t nwave, float wave[], geom_str *geom, float tau_iwnir_l, int32_t modl, float tau_pred[], float rho_pred[])
Definition: aerosol.c:1806
int comp_rhoaT(rhoaTstr *x, rhoaTstr *y)
Definition: aerosol.c:4777
void model_select_ahmad(int32_t nmodels, int32_t *mindx, float eps_pred[], float eps_obs, int32_t *modmin, int32_t *modmax, float *modrat)
Definition: aerosol.c:1612
float first_deriv(float x[], float y[], int n)
Definition: aerosol.c:289
float angstrom
Definition: aerosol.c:231
float * get_uncertainty(l1str *l1rec)
int32_t rdsensorinfo(int32_t, int32_t, const char *, void **)
Definition: rdsensorinfo.c:69
float ** allocate2d_float(size_t h, size_t w)
Allocate a two-dimensional array of type float of a given size.
Definition: allocate2d.c:123
int32_t model
Definition: atrem_corl1.h:132
int ahmad_atm_corr(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, int32_t nmodels, int32_t mindx[], geom_str *geom, float wv, float rhoa[], int32_t *modmin, int32_t *modmax, float *modrat, float *epsnir, float tau_pred_max[], float tau_pred_min[], float rho_pred_max[], float rho_pred_min[], float tau_aer[], float rho_aer[], int ip, uncertainty_t *uncertainty)
Definition: aerosol.c:2130
for(i=0;i< NROOTS;i++) s[i]
Definition: decode_rs.h:85
float * solz
Definition: aerosol.c:215
void model_select_angstrom(float angstrom, int32_t *modmin, int32_t *modmax, float *modrat)
Definition: aerosol.c:3142
#define AERRHMSEPS_lin
Definition: l12_parms.h:38
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
float value
Definition: aerosol.c:136
float * airmass
Definition: aerosol.c:251
#define AERWANGNIR
Definition: l12_parms.h:25
float * cms_all
Definition: aerosol.c:110
float * phi
Definition: aerosol.c:217
Utility functions for allocating and freeing five-dimensional arrays of various types.
float * noise_global
Definition: aerosol.c:87
int alloc_uncertainty(int32_t nbands, int32_t nbands_ac, int32_t npix, uncertainty_t *uncertainty)
Definition: uncertainty.c:21
int i
Definition: decode_rs.h:71
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int model_taua_mseps(int32_t modl, float wave[], int32_t nwave, int32_t iwnir_l, float rhoa[], geom_str *geom, float tau_pred[])
Definition: aerosol.c:3309
int32_t nwave
Definition: aerosol.c:202
PGE01 indicating that PGE02 PGE01 V6 for and PGE01 V2 for MOD03 were used to produce the granule By convention adopted in all MODIS Terra PGE02 code versions are The fourth digit of the PGE02 version denotes the LUT version used to produce the granule The source of the metadata environment variable ProcessingCenter was changed from a QA LUT value to the Process Configuration A sign used in error in the second order term was changed to a
Definition: HISTORY.txt:424
int32_t sensorID[MAXNFILES]
Definition: l2bin.cpp:91
float aeroob(int32_t sensorID, int32_t iw, float airmass, float cf, float wv)
Definition: aerosol.c:2736
#define FIXAOT
Definition: l12_parms.h:30
void get_ms_epsilon(l2str *l2rec, float eps[])
Definition: aerosol.c:6344
Definition: aerosol.c:136
int comp_rhoa_ms_eps(int32_t nwave, float wave[], geom_str *geom, float tau_iwnir_l, int32_t modl, float tau_pred[], float rho_pred[], float derv_rhoa[], float derv_taua_tmp[])
Definition: aerosol.c:1671
#define AERWANGSWIR
Definition: l12_parms.h:31
int load_aermod(int32_t sensorID, float wave[], int32_t nwave, char *aermodfile, char models[MAXAERMOD][32], int32_t nmodels)
Definition: aerosol.c:380
float p[MODELMAX]
Definition: atrem_corl1.h:131
int fixedmodpair(int32_t sensorID, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, geom_str *geom, float wv, int32_t modmin, int32_t modmax, float modrat, float rhoa[], float *eps)
Definition: aerosol.c:5416
int32_t modnum
Definition: aerosol.c:230
int32_t npc
Definition: aerosol.c:210
int fixedaer(int32_t sensorID, int32_t modnum, float wave[], int32_t nwave, int32_t iwnir_s, int32_t iwnir_l, char models[MAXAERMOD][32], int32_t nmodels, geom_str *geom, float wv, float rhoa[], float *epsnir)
Definition: aerosol.c:5361