1 #include <cstring>
2
3 extern "C" {
4 #include <grass/gis.h>
5 #include <grass/glocale.h>
6 }
7
8 #include "common.h"
9 #include "geomcond.h"
10 #include "atmosmodel.h"
11 #include "aerosolmodel.h"
12 #include "aerosolconcentration.h"
13 #include "altitude.h"
14 #include "iwave.h"
15 #include "gauss.h"
16 #include "transform.h"
17 #ifdef WIN32
18 #pragma warning (disable : 4305)
19 #endif
20
21 struct OpticalAtmosProperties
22 {
23 double rorayl, romix, roaero;
24 double ddirtr, ddiftr;
25 double ddirtt, ddiftt;
26 double ddirta, ddifta;
27 double udirtr, udiftr;
28 double udirtt, udiftt;
29 double udirta, udifta;
30 double sphalbr, sphalbt, sphalba;
31 };
32
33 /* To compute the molecular optical depth as a function of wavelength for any
34 atmosphere defined by the pressure and temperature profiles. */
odrayl(const AtmosModel & atms,const double wl)35 double odrayl(const AtmosModel &atms, const double wl)
36 {
37 /* air refraction index edlen 1966 / metrologia,2,71-80 putting pw=0 */
38 double ak=1/wl;
39 double awl= wl*wl*wl*wl * 0.0254743;
40 double a1 = 130 - ak * ak;
41 double a2 = 38.9 - ak * ak;
42 double a3 = 2406030 / a1;
43 double a4 = 15997 / a2;
44 double an = (8342.13 + a3 + a4) * 1.0e-08 + 1;
45 double a = (24 * M_PI * M_PI * M_PI) * ((an * an - 1) * (an * an - 1))
46 * (6 + 3 * delta) / (6 - 7 * delta) / ((an * an + 2) * (an * an + 2));
47
48 double tray = 0;
49 for(int k = 0; k < 33; k++)
50 {
51 double dppt = (288.15 / 1013.25) * (atms.p[k] / atms.t[k] + atms.p[k+1] / atms.t[k+1]) / 2;
52 double sr = a * dppt / awl;
53 tray += (double)((atms.z[k+1] - atms.z[k]) * sr);
54 }
55
56 return tray;
57 }
58
59 /*
60 decompose the aerosol phase function in series of Legendre polynomial used in
61 OS.f and ISO.f and compute truncation coefficient f to modify aerosol optical thickness t and single
62 scattering albedo w0 according to:
63 t' = (1-w0 f) t
64
65 w0' = w0 (1- f)
66 --------
67 (1-w0 f)
68 */
trunca()69 double trunca()
70 {
71 double ptemp[83];
72 double cosang[80];
73 double weight[80];
74 double rmu[83];
75 double ga[83];
76
77 int i;
78 for(i = 0; i < 83; i++) ptemp[i] = sixs_trunc.pha[i];
79
80 Gauss::gauss(-1,1,cosang,weight,80);
81
82 for(i = 0; i < 40; i++)
83 {
84 rmu[i+1] = cosang[i];
85 ga[i+1] = weight[i];
86 }
87
88 rmu[0] = -1;
89 ga[0] = 0;
90 rmu[41] = 0;
91 ga[41] = 0;
92
93 for(i = 40; i < 80; i++)
94 {
95 rmu[i+2] = cosang[i];
96 ga[i+2] = weight[i];
97 }
98
99 rmu[82] = 1;
100 ga[82] = 0;
101
102 int k = 0;
103 for(i = 0; i < 83; i++)
104 {
105 if(rmu[i] > 0.8) break;
106 k = i - 1;
107 }
108
109 int kk = 0;
110 for(i = 0; i < 83; i++)
111 {
112 if(rmu[i] > 0.94) break;
113 kk = i - 1;
114 }
115
116
117 double aa = (double)((log10(sixs_trunc.pha[kk]) - log10(sixs_trunc.pha[k])) /
118 (acos(rmu[kk]) - acos(rmu[k])));
119 double x1 = (double)(log10(sixs_trunc.pha[kk]));
120 double x2 = (double)acos(rmu[kk]);
121
122 for(i = kk + 1; i < 83; i++)
123 {
124 double a;
125 if(fabs(rmu[i] - 1) <= 1e-08) a = x1 - aa * x2;
126 else a = x1 + aa * (acos(rmu[i]) - x2);
127 ptemp[i] = (double)pow(10,a);
128 }
129
130
131 for(i = 0; i < 83; i++) sixs_trunc.pha[i] = ptemp[i];
132 for(i = 0; i < 80; i++) sixs_trunc.betal[i] = 0;
133
134 double pl[83];
135
136 #define IPL(X) ((X)+1)
137
138
139 for(i = 0; i < 83; i++)
140 {
141 double x = sixs_trunc.pha[i] * ga[i];
142 double rm = rmu[i];
143 pl[IPL(-1)] = 0;
144 pl[IPL(0)] = 1;
145
146 for(k = 0; k <= 80; k++)
147 {
148 pl[IPL(k+1)] = ((2 * k + 1) * rm * pl[IPL(k)] - k * pl[IPL(k-1)]) / (k + 1);
149 sixs_trunc.betal[k] += x * pl[IPL(k)];
150 }
151 }
152
153 for(i = 0; i <= 80; i++) sixs_trunc.betal[i] *= (2 * i + 1) * 0.5f;
154
155 double z1 = sixs_trunc.betal[0];
156 for(i = 0; i <= 80; i++) sixs_trunc.betal[i] /= z1;
157 if(sixs_trunc.betal[80] < 0) sixs_trunc.betal[80] = 0;
158
159 return 1 - z1;
160 }
161
162
163 /*
164 Decompose the atmosphere in a finite number of layers. For each layer, DISCRE
165 provides the optical thickness, the proportion of molecules and aerosols assuming an exponential
166 distribution for each constituents. Figure 1 illustrate the way molecules and aerosols are mixed in a
167 realistic atmosphere. For molecules, the scale height is 8km. For aerosols it is assumed to be 2km
168 unless otherwise specified by the user (using aircraft measurements).
169 */
170
discre(const double ta,const double ha,const double tr,const double hr,const int it,const int ntd,const double yy,const double dd,const double ppp2,const double ppp1)171 double discre(const double ta, const double ha, const double tr, const double hr,
172 const int it, const int ntd, const double yy, const double dd,
173 const double ppp2, const double ppp1)
174 {
175 if( ha >= 7 )
176 {
177 G_warning(_("Check aerosol measurements or plane altitude"));
178 return 0;
179 }
180
181 double dt;
182 if( it == 0 ) dt = 1e-17;
183 else dt = 2 * (ta + tr - yy) / (ntd - it + 1);
184
185 double zx; /* return value */
186 double ecart = 0;
187 do {
188 dt = dt / 2;
189 double ti = yy + dt;
190 double y1 = ppp2;
191 double y2;
192 double y3 = ppp1;
193
194 while(true)
195 {
196 y2 = (y1 + y3) * 0.5f;
197
198 double xx = -y2 / ha;
199 double x2;
200 if (xx < -18) x2 = tr * exp(-y2 / hr);
201 else x2 = ta * exp(xx) + tr * exp(-y2 / hr);
202
203 if(fabs(ti - x2) < 0.00001) break;
204
205 if(ti - x2 < 0) y3 = y2;
206 else y1 = y2;
207 }
208
209 zx = y2;
210 double cdelta = (double)(1. / (1 + ta * hr / tr / ha * exp((zx - ppp1) * (1. / hr - 1. / ha))));
211 if(dd != 0) ecart = (double)fabs((dd - cdelta) / dd);
212 } while((ecart > 0.75) && (it != 0));
213 return zx;
214
215 }
216
217
218 /* indexing macro for the psl variable */
219 #define PSI(X) ((X)+1)
220 /*
221 Compute the values of Legendre polynomials used in the successive order of
222 scattering method.
223 */
kernel(const int is,double (& xpl)[2* mu+1],double (& bp)[26][2* mu+1],Gauss & gauss)224 void kernel(const int is, double (&xpl)[2*mu + 1], double (&bp)[26][2*mu + 1], Gauss &gauss)
225 {
226 const double rac3 = 1.7320508075688772935274463415059;
227 #define PSI(X) ((X)+1)
228 double psl[82][2*mu + 1];
229
230 if(is == 0)
231 {
232 for(int j = 0; j <= mu; j++)
233 {
234 psl[PSI(0)][STDI(-j)] = 1;
235 psl[PSI(0)][STDI(j)] = 1;
236 psl[PSI(1)][STDI(j)] = gauss.rm[STDI(j)];
237 psl[PSI(1)][STDI(-j)] = -gauss.rm[STDI(j)];
238
239 double xdb = (3 * gauss.rm[STDI(j)] * gauss.rm[STDI(j)] - 1) * 0.5;
240 if(fabs(xdb) < 1e-30) xdb = 0;
241 psl[PSI(2)][STDI(-j)] = (double)xdb;
242 psl[PSI(2)][STDI(j)] = (double)xdb;
243 }
244 psl[PSI(1)][STDI(0)] = gauss.rm[STDI(0)];
245 }
246 else if(is == 1)
247 {
248 for(int j = 0; j <= mu; j++)
249 {
250 double x = 1 - gauss.rm[STDI(j)] * gauss.rm[STDI(j)];
251 psl[PSI(0)][STDI(j)] = 0;
252 psl[PSI(0)][STDI(-j)] = 0;
253 psl[PSI(1)][STDI(-j)] = (double)sqrt(x * 0.5);
254 psl[PSI(1)][STDI(j)] = (double)sqrt(x * 0.5);
255 psl[PSI(2)][STDI(j)] = (double)(gauss.rm[STDI(j)] * psl[PSI(1)][STDI(j)] * rac3);
256 psl[PSI(2)][STDI(-j)] = -psl[PSI(2)][STDI(j)];
257
258 }
259 psl[PSI(2)][STDI(0)] = -psl[PSI(2)][STDI(0)];
260 }
261 else
262 {
263 double a = 1;
264 for(int i = 1; i <= is; i++) a *= sqrt((double)(i + is) / (double)i) * 0.5;
265 /* double b = a * sqrt((double)is / (is + 1.)) * sqrt((is - 1.) / (is + 2.));*/
266
267 for(int j = 0; j <= mu; j++)
268 {
269 double xx = 1 - gauss.rm[STDI(j)] * gauss.rm[STDI(j)];
270 psl[PSI(is - 1)][STDI(j)] = 0;
271 double xdb = a * pow(xx, is * 0.5);
272 if(fabs(xdb) < 1e-30) xdb = 0;
273 psl[PSI(is)][STDI(-j)] = (double)xdb;
274 psl[PSI(is)][STDI(j)] = (double)xdb;
275 }
276 }
277
278 int k = 2;
279 int ip = 80;
280
281 if(is > 2) k = is;
282 if(k != ip)
283 {
284 int ig = -1;
285 if( is == 1 ) ig = 1;
286 for(int l = k; l < ip; l++)
287 {
288 double a = (2 * l + 1.) / sqrt((l + is + 1.) * (l - is + 1.));
289 double b = sqrt(double((l + is) * (l - is))) / (2. * l + 1.);
290
291 for(int j = 0; j <= mu; j++)
292 {
293 double xdb = a * (gauss.rm[STDI(j)] * psl[PSI(l)][STDI(j)] - b * psl[PSI(l-1)][STDI(j)]);
294 if (fabs(xdb) < 1e-30) xdb = 0;
295 psl[PSI(l+1)][STDI(j)] = (double)xdb;
296 if(j != 0) psl[PSI(l+1)][STDI(-j)] = ig * psl[PSI(l+1)][STDI(j)];
297 }
298 ig = -ig;
299 }
300 }
301
302 int j;
303 for(j = -mu; j <= mu; j++) xpl[STDI(j)] = psl[PSI(2)][STDI(j)];
304
305 for(j = 0; j <= mu; j++)
306 {
307 for(k = -mu; k <= mu; k++)
308 {
309 double sbp = 0;
310 if(is <= 80)
311 {
312 for(int l = is; l <= 80; l++)
313 sbp += psl[PSI(l)][STDI(j)] * psl[PSI(l)][STDI(k)] * sixs_trunc.betal[l];
314
315 if(fabs(sbp) < 1e-30) sbp = 0;
316 bp[j][STDI(k)] = (double)sbp;
317 }
318 }
319 }
320
321 }
322
323
324
325 #define accu 1e-20
326 #define accu2 1e-3
327 #define mum1 (mu - 1)
328
os(const double tamoy,const double trmoy,const double pizmoy,const double tamoyp,const double trmoyp,double (& xl)[2* mu+1][np],Gauss & gauss,const Altitude & alt,const GeomCond & geom)329 void os(const double tamoy, const double trmoy, const double pizmoy,
330 const double tamoyp, const double trmoyp, double (&xl)[2*mu + 1][np],
331 Gauss &gauss, const Altitude &alt, const GeomCond &geom)
332 {
333 double trp = trmoy - trmoyp;
334 double tap = tamoy - tamoyp;
335 int iplane = 0;
336
337 /* if plane observations recompute scale height for aerosol knowing:
338 the aerosol optical depth as measure from the plane = tamoyp
339 the rayleigh scale height = = hr (8km)
340 the rayleigh optical depth at plane level = trmoyp
341 the altitude of the plane = palt
342 the rayleigh optical depth for total atmos = trmoy
343 the aerosol optical depth for total atmos = tamoy
344 if not plane observations then ha is equal to 2.0km
345 ntp local variable: if ntp=nt no plane observation selected
346 ntp=nt-1 plane observation selected
347 it's a mixing rayleigh+aerosol */
348
349 double ha = 2;
350 int snt = nt;
351 int ntp = snt;
352 if(alt.palt <= 900 && alt.palt > 0)
353 {
354 if(tap > 1.e-03) ha = -alt.palt / (double)log(tap / tamoy);
355 ntp = snt - 1;
356 }
357
358 double xmus = -gauss.rm[STDI(0)];
359
360 /* compute mixing rayleigh, aerosol
361 case 1: pure rayleigh
362 case 2: pure aerosol
363 case 3: mixing rayleigh-aerosol */
364
365 double h[31];
366 memset(h, 0, sizeof(h));
367 double ch[31];
368 double ydel[31];
369
370 double xdel[31];
371 double altc[31];
372 if( (tamoy <= accu2) && (trmoy > tamoy) )
373 {
374 for(int j = 0; j <= ntp; j++)
375 {
376 h[j] = j * trmoy / ntp;
377 ch[j]= (double)exp(-h[j] / xmus) / 2;
378 ydel[j] = 1;
379 xdel[j] = 0;
380
381 if (j == 0) altc[j] = 300;
382 else altc[j] = -(double)log(h[j] / trmoy) * 8;
383 }
384 }
385
386
387 if( (trmoy <= accu2) && (tamoy > trmoy) )
388 {
389 for(int j = 0; j <= ntp; j++)
390 {
391 h[j] = j * tamoy / ntp;
392 ch[j]= (double)exp(-h[j] / xmus) / 2;
393 ydel[j] = 0;
394 xdel[j] = pizmoy;
395
396 if (j == 0) altc[j] = 300;
397 else altc[j] = -(double)log(h[j] / tamoy) * ha;
398 }
399 }
400
401 if(trmoy > accu2 && tamoy > accu2)
402 {
403 ydel[0] = 1;
404 xdel[0] = 0;
405 h[0] = 0;
406 ch[0] = 0.5;
407 altc[0] = 300;
408 double zx = 300;
409 iplane = 0;
410
411 for(int it = 0; it <= ntp; it++)
412 {
413 if(it == 0) zx = discre(tamoy, ha, trmoy, 8.0, it, ntp, 0, 0, 300, 0);
414 else zx = discre(tamoy, ha, trmoy, 8.0, it, ntp, h[it - 1], ydel[it - 1], 300, 0);
415
416 double xx = -zx / ha;
417 double ca;
418 if( xx <= -20 ) ca = 0;
419 else ca = tamoy * (double)exp(xx);
420
421 xx = -zx / 8;
422 double cr = trmoy * (double)exp(xx);
423 h[it] = cr + ca;
424
425
426 altc[it] = zx;
427 ch[it] = (double)exp(-h[it] / xmus) / 2;
428 cr = cr / 8;
429 ca = ca / ha;
430 double ratio = cr / (cr + ca);
431 xdel[it] = (1 - ratio) * pizmoy;
432 ydel[it] = ratio;
433 }
434 }
435
436 /* update plane layer if necessary */
437 if (ntp == (snt - 1))
438 {
439 /* compute position of the plane layer */
440 double taup = tap + trp;
441 iplane = -1;
442 for(int i = 0; i <= ntp; i++) if (taup >= h[i]) iplane = i;
443
444 /* update the layer from the end to the position to update if necessary */
445 double xt1 = (double)fabs(h[iplane] - taup);
446 double xt2 = (double)fabs(h[iplane+1] - taup);
447
448 if ((xt1 > 0.0005) && (xt2 > 0.0005))
449 {
450 for(int i = snt; i >= iplane+1; i--)
451 {
452 xdel[i] = xdel[i-1];
453 ydel[i] = ydel[i-1];
454 h[i] = h[i-1];
455 altc[i] = altc[i-1];
456 ch[i] = ch[i-1];
457 }
458 }
459 else
460 {
461 snt = ntp;
462 if (xt2 > xt1) iplane++;
463
464 }
465
466 h[iplane] = taup;
467 if ( trmoy > accu2 && tamoy > accu2 )
468 {
469
470 double ca = tamoy * (double)exp(-alt.palt / ha);
471 double cr = trmoy * (double)exp(-alt.palt / 8);
472 h[iplane] = ca + cr;
473 cr = cr / 8;
474 ca = ca / ha;
475 double ratio = cr / (cr + ca);
476 xdel[iplane] = (1 - ratio) * pizmoy;
477 ydel[iplane] = ratio;
478 altc[iplane] = alt.palt;
479 ch[iplane] = (double)exp(-h[iplane] / xmus) / 2;
480 }
481
482 if ( trmoy > accu2 && tamoy <= accu2 )
483 {
484 ydel[iplane] = 1;
485 xdel[iplane] = 0;
486 altc[iplane] = alt.palt;
487 }
488
489 if ( trmoy <= accu2 && tamoy > accu2 )
490 {
491 ydel[iplane] = 0;
492 xdel[iplane] = pizmoy;
493 altc[iplane] = alt.palt;
494 }
495 }
496
497
498 double phi = (double)geom.phirad;
499 int i, k;
500 for(i = 0; i < np; i++) for(int m = -mu; m <= mu; m++) xl[STDI(m)][i] = 0;
501
502 /* ************ incident angle mus ******* */
503
504 double aaaa = delta / (2 - delta);
505 double ron = (1 - aaaa) / (1 + 2 * aaaa);
506
507 /* rayleigh phase function */
508
509 double beta0 = 1;
510 double beta2 = 0.5f * ron;
511
512 /* fourier decomposition */
513 double i1[31][2*mu + 1];
514 double i2[31][2*mu + 1];
515 double i3[2*mu + 1];
516 double i4[2*mu + 1];
517 double in[2*mu + 1];
518 double inm1[2*mu + 1];
519 double inm2[2*mu + 1];
520 for(i = -mu; i <= mu; i++) i4[STDI(i)] = 0;
521
522 int iborm = 80;
523 if(fabs(xmus - 1.000000) < 1e-06) iborm = 0;
524
525 for(int is = 0; is <= iborm; is++)
526 {
527 /* primary scattering */
528 int ig = 1;
529 double roavion0 = 0;
530 double roavion1 = 0;
531 double roavion2 = 0;
532 double roavion = 0;
533
534 int j;
535 for(j = -mu; j <= mu; j++) i3[STDI(j)] = 0;
536
537 /* kernel computations */
538 double xpl[2*mu + 1];
539 double bp[26][2*mu + 1];
540 memset(xpl, 0, sizeof(double)*(2*mu+1));
541 memset(bp, 0, sizeof(double)*26*(2*mu+1));
542
543 kernel(is,xpl,bp,gauss);
544
545 if(is > 0) beta0 = 0;
546
547 for(j = -mu; j <= mu; j++)
548 {
549 double sa1;
550 double sa2;
551
552 if((is - 2) <= 0)
553 {
554 double spl = xpl[STDI(0)];
555 sa1 = beta0 + beta2 * xpl[STDI(j)] * spl;
556 sa2 = bp[0][STDI(j)];
557 }
558 else
559 {
560 sa2 = bp[0][STDI(j)];
561 sa1 = 0;
562 }
563 /* primary scattering source function at every level within the layer */
564
565 for(k = 0; k <= snt; k++)
566 {
567 double c = ch[k];
568 double a = ydel[k];
569 double b = xdel[k];
570 i2[k][STDI(j)] = (double)(c * (sa2 * b + sa1 * a));
571 }
572 }
573
574 /* vertical integration, primary upward radiation */
575 for(k = 1; k <= mu; k++)
576 {
577 i1[snt][STDI(k)] = 0;
578 double zi1 = i1[snt][STDI(k)];
579
580 for(i = snt - 1; i >= 0; i--)
581 {
582 double f = h[i + 1] - h[i];
583 double a = (i2[i + 1][STDI(k)] - i2[i][STDI(k)]) / f;
584 double b = i2[i][STDI(k)] - a * h[i];
585 double c = (double)exp(-f / gauss.rm[STDI(k)]);
586
587 double xx = h[i] - h[i + 1] * c;
588 zi1 = (double)(c * zi1 + ((1 - c) * (b + a * gauss.rm[STDI(k)]) + a * xx) / 2);
589 i1[i][STDI(k)] = zi1;
590 }
591 }
592
593 /* vertical integration, primary downward radiation */
594 for(k = -mu; k <= -1; k++)
595 {
596 i1[0][STDI(k)] = 0;
597 double zi1 = i1[0][STDI(k)];
598
599 for(i = 1; i <= snt; i++)
600 {
601 double f = h[i] - h[i - 1];
602 double c = (double)exp(f / gauss.rm[STDI(k)]);
603 double a = (i2[i][STDI(k)] -i2[i - 1][STDI(k)]) / f;
604 double b = i2[i][STDI(k)] - a * h[i];
605 double xx = h[i] - h[i - 1] * c;
606 zi1 = (double)(c * zi1 + ((1 - c) * (b + a * gauss.rm[STDI(k)]) + a * xx)/ 2);
607 i1[i][STDI(k)] = zi1;
608 }
609 }
610
611 /* inm2 is inialized with scattering computed at n-2
612 i3 is inialized with primary scattering */
613 for(k = -mu; k <= mu; k++)
614 {
615 if(k < 0)
616 {
617 inm1[STDI(k)] = i1[snt][STDI(k)];
618 inm2[STDI(k)] = i1[snt][STDI(k)];
619 i3[STDI(k)] = i1[snt][STDI(k)];
620 }
621 else if(k > 0)
622 {
623 inm1[STDI(k)] = i1[0][STDI(k)];
624 inm2[STDI(k)] = i1[0][STDI(k)];
625 i3[STDI(k)] = i1[0][STDI(k)];
626 }
627 }
628 roavion2 = i1[iplane][STDI(mu)];
629 roavion = i1[iplane][STDI(mu)];
630
631 do
632 {
633 /* loop on successive order */
634 ig++;
635
636 /* successive orders
637 multiple scattering source function at every level within the laye
638 if is < ou = 2 kernels are a mixing of aerosols and molecules kern
639 if is >2 aerosols kernels only */
640
641 if(is - 2 <= 0)
642 {
643 for(k = 1; k <= mu; k++)
644 {
645 for(i = 0; i <= snt; i++)
646 {
647 double ii1 = 0;
648 double ii2 = 0;
649
650 for(j = 1; j <= mu; j++)
651 {
652 double bpjk = bp[j][STDI(k)] * xdel[i] + ydel[i] * (beta0 + beta2 * xpl[STDI(j)] * xpl[STDI(k)]);
653 double bpjmk = bp[j][STDI(-k)] * xdel[i] + ydel[i] * (beta0 + beta2 * xpl[STDI(j)] * xpl[STDI(-k)]);
654 double xdb = gauss.gb[STDI(j)] * (i1[i][STDI(j)] * bpjk + i1[i][STDI(-j)] * bpjmk);
655 ii2 += xdb;
656 xdb = gauss.gb[STDI(j)] * (i1[i][STDI(j)] * bpjmk + i1[i][STDI(-j)] * bpjk);
657 ii1 += xdb;
658 }
659
660 if (ii2 < 1e-30) ii2 = 0;
661 if (ii1 < 1e-30) ii1 = 0;
662 i2[i][STDI(k)] = (double)ii2;
663 i2[i][STDI(-k)]= (double)ii1;
664 }
665 }
666 }
667 else
668 {
669 for(k = 1; k <= mu; k++)
670 {
671 double ii1;
672 double ii2;
673
674 for(i = 0; i <= snt; i++)
675 {
676 ii1 = 0;
677 ii2 = 0;
678
679 for(j = 1; j <= mu; j++)
680 {
681 double bpjk = bp[j][STDI(k)] * xdel[i];
682 double bpjmk = bp[j][STDI(-k)] * xdel[i];
683 double xdb = gauss.gb[STDI(j)] * (i1[i][STDI(j)] * bpjk + i1[i][STDI(-j)] * bpjmk);
684 ii2 += xdb;
685 xdb = gauss.gb[STDI(j)] * (i1[i][STDI(j)] * bpjmk + i1[i][STDI(-j)] * bpjk);
686 ii1 += xdb;
687 }
688
689 if (ii2 < 1e-30) ii2 = 0;
690 if (ii1 < 1e-30) ii1 = 0;
691 i2[i][STDI(k)] = (double)ii2;
692 i2[i][STDI(-k)] = (double)ii1;
693 }
694 }
695 }
696
697
698 /* vertical integration, upward radiation */
699 for(k = 1; k <= mu; k++)
700 {
701 i1[snt][STDI(k)] = 0;
702 double zi1 = i1[snt][STDI(k)];
703
704 for(i = snt-1; i >= 0; i--)
705 {
706 double f = h[i + 1] - h[i];
707 double a = (i2[i + 1][STDI(k)] - i2[i][STDI(k)]) / f;
708 double b = i2[i][STDI(k)] - a * h[i];
709 double c = (double)exp(-f / gauss.rm[STDI(k)]);
710 double xx = h[i] - h[i + 1] * c;
711 zi1 = (double)(c * zi1 + ((1 - c) * (b + a * gauss.rm[STDI(k)]) + a * xx) / 2);
712 if (fabs(zi1) <= 1e-20) zi1 = 0;
713 i1[i][STDI(k)] = zi1;
714 }
715 }
716
717 /* vertical integration, downward radiation */
718 for(k = -mu; k <= -1; k++)
719 {
720 i1[0][STDI(k)] = 0;
721 double zi1 = i1[0][STDI(k)];
722
723 for(i = 1; i <= snt; i++)
724 {
725 double f = h[i] - h[i - 1];
726 double c = (double)exp(f / gauss.rm[STDI(k)]);
727 double a = (i2[i][STDI(k)] - i2[i - 1][STDI(k)]) / f;
728 double b = i2[i][STDI(k)] - a * h[i];
729 double xx = h[i] - h[i - 1] * c;
730 zi1 = (double)(c * zi1 + ((1 - c) * (b + a * gauss.rm[STDI(k)]) + a * xx) / 2);
731
732 if (fabs(zi1) <= 1e-20) zi1 = 0;
733 i1[i][STDI(k)] = zi1;
734 }
735 }
736
737 /* in is the nieme scattering order */
738 for(k = -mu; k <= mu; k++)
739 {
740 if(k < 0) in[STDI(k)] = i1[snt][STDI(k)];
741 else if(k > 0) in[STDI(k)] = i1[0][STDI(k)];
742 }
743 roavion0 = i1[iplane][STDI(mu)];
744
745 /* convergence test (geometrical serie) */
746 if(ig > 2)
747 {
748 double a1 = roavion2;
749 double d1 = roavion1;
750
751 double g1 = roavion0;
752
753
754 double z = 0;
755 if(a1 >= accu && d1 >= accu && roavion >= accu)
756 {
757 double y = ((g1 / d1 - d1 / a1) / ((1 - g1 / d1) * (1 - g1 / d1)) * (g1 / roavion));
758 y = fabs(y);
759 z = y > z ? y : z;
760 }
761
762 for(int l = -mu; l <= mu; l++)
763 {
764 if (l == 0) continue;
765 a1 = inm2[STDI(l)];
766 d1 = inm1[STDI(l)];
767 g1 = in[STDI(l)];
768 if(a1 <= accu) continue;
769 if(d1 <= accu) continue;
770 if(i3[STDI(l)] <= accu) continue;
771
772 double y = ((g1 / d1 - d1 / a1) / ((1 - g1 / d1) * (1 - g1 / d1)) * (g1 / i3[STDI(l)]));
773 y = fabs(y);
774 z = y > z ? y : z;
775 }
776
777 if(z < 0.0001)
778 {
779 /* successful test (geometrical serie) */
780 double y1;
781
782 for(int l = -mu; l <= mu; l++)
783 {
784 y1 = 1;
785 d1 = inm1[STDI(l)];
786 g1 = in[STDI(l)];
787 if(d1 <= accu) continue;
788 y1 = 1 - g1 / d1;
789 if(fabs(g1 - d1) <= accu) continue;
790 g1 /= y1;
791 i3[STDI(l)] += g1;
792 }
793
794
795 d1 = roavion1;
796 g1 = roavion0;
797 y1 = 1;
798 if(d1 >= accu)
799 {
800 if(fabs(g1 - d1) >= accu)
801 {
802 y1 = 1 - g1 / d1;
803 g1 /= y1;
804 }
805
806 roavion += g1;
807 }
808
809 break; /* break out of the while loop */
810 }
811
812 /* inm2 is the (n-2)ieme scattering order */
813 for(k = -mu; k <= mu; k++) inm2[STDI(k)] = inm1[STDI(k)];
814 roavion2 = roavion1;
815 }
816
817 /* inm1 is the (n-1)ieme scattering order */
818 for(k = -mu; k <= mu; k++) inm1[STDI(k)] = in[STDI(k)];
819 roavion1 = roavion0;
820
821 /* sum of the n-1 orders */
822 for(k = -mu; k <= mu; k++) i3[STDI(k)] += in[STDI(k)];
823 roavion += roavion0;
824
825 /* stop if order n is less than 1% of the sum */
826 double z = 0;
827 for(k = -mu; k <= mu; k++)
828 {
829 if (fabs(i3[STDI(k)]) >= accu)
830 {
831 double y = fabs(in[STDI(k)] / i3[STDI(k)]);
832 z = z >= y ? z : y;
833 }
834 }
835 if(z < 0.00001) break;
836
837 } while( ig <= 20 ); /* stop if order n is greater than 20 in any case */
838
839 /* sum of the fourier component s */
840 double delta0s = 1;
841 if(is != 0) delta0s = 2;
842 for(k = -mu; k <= mu; k++) i4[STDI(k)] += delta0s * i3[STDI(k)];
843
844 /* stop of the fourier decomposition */
845 int l;
846 for(l = 0; l < np; l++)
847 {
848 phi = gauss.rp[l];
849
850 for(int m = -mum1; m <= mum1; m++)
851 {
852 if(m > 0) xl[STDI(m)][l] += (double)(delta0s * i3[STDI(m)] * cos(is * (phi + M_PI)));
853 else xl[STDI(m)][l] += (double)(delta0s * i3[STDI(m)] * cos(is * phi));
854 }
855 }
856
857 if(is == 0)
858 for(k = 1; k <= mum1; k++) xl[STDI(0)][0] += gauss.rm[STDI(k)] * gauss.gb[STDI(k)] * i3[STDI(-k)];
859
860 xl[STDI(mu)][0] += (double)(delta0s * i3[STDI(mu)] * cos(is * (geom.phirad + M_PI)));
861 xl[STDI(-mu)][0] += (double)(delta0s * roavion * cos(is * (geom.phirad + M_PI)));
862
863 double z = 0;
864 for(l = -mu; l <= mu; l++)
865 {
866 if(l == 0) continue;
867 if (fabs(i4[STDI(l)]) > accu) continue;
868 double x = fabs(i3[STDI(l)] / i4[STDI(l)]);
869 z = z > x ? z : x;
870 }
871
872 if(z <= 0.001) break;
873 }
874 }
875
876
877 /*
878 Compute the atmospheric transmission for either a satellite or aircraft observation
879 as well as the spherical albedo of the atmosphere.
880 */
iso(const double tamoy,const double trmoy,const double pizmoy,const double tamoyp,const double trmoyp,double (& xf)[3],Gauss & gauss,const Altitude & alt)881 void iso(const double tamoy, const double trmoy, const double pizmoy,
882 const double tamoyp, const double trmoyp, double (&xf)[3],
883 Gauss &gauss, const Altitude &alt)
884 {
885 /* molecular ratio within the layer
886 computations are performed assuming a scale of 8km for
887 molecules and 2km for aerosols */
888
889 /* the optical thickness above plane are recomputed to give o.t above pla */
890 double trp = trmoy - trmoyp;
891 double tap = tamoy - tamoyp;
892
893 /* if plane observations recompute scale height for aerosol knowing:
894 the aerosol optical depth as measure from the plane = tamoyp
895 the rayleigh scale height = = hr (8km)
896 the rayleigh optical depth at plane level = trmoyp
897 the altitude of the plane = palt
898 the rayleigh optical depth for total atmos = trmoy
899 the aerosol optical depth for total atmos = tamoy
900 if not plane observations then ha is equal to 2.0km
901 sntp local variable: if sntp=snt no plane observation selected
902 sntp=snt-1 plane observation selected */
903
904 /* it's a mixing rayleigh+aerosol */
905 int snt = nt;
906 int iplane = 0;
907 int ntp = snt;
908 double ha = 2.0;
909 if(alt.palt <= 900. && alt.palt > 0.0)
910 {
911 if (tap > 1.e-03) ha = (double)(-alt.palt / log(tap / tamoy));
912 else ha = 2.;
913 ntp = snt - 1;
914 }
915
916 /* compute mixing rayleigh, aerosol
917 case 1: pure rayleigh
918 case 2: pure aerosol
919 case 3: mixing rayleigh-aerosol */
920
921 double h[31];
922 double ydel[31];
923 double xdel[31];
924 double altc[31];
925
926 if((tamoy <= accu2) && (trmoy > tamoy))
927 {
928 for(int j = 0; j <= ntp; j++)
929 {
930 h[j] = j * trmoy / ntp;
931 ydel[j] = 1.0;
932 xdel[j] = 0.0;
933 }
934 }
935
936 if((trmoy <= accu2) && (tamoy > trmoy))
937 {
938 for(int j = 0; j <= ntp; j++)
939 {
940 h[j] = j * tamoy / ntp;
941 ydel[j] = 0.0;
942 xdel[j] = pizmoy;
943 }
944 }
945
946 if(trmoy > accu2 && tamoy > accu2)
947 {
948 ydel[0] = 1.0;
949 xdel[0] = 0.0;
950 h[0] = 0;
951 altc[0] = 300;
952 double zx = 300;
953 iplane = 0;
954
955 for(int it = 0; it <= ntp; it++)
956
957 {
958 if (it == 0) zx = discre(tamoy,ha,trmoy,8.0,it,ntp,0,0,300.0,0.0);
959 else zx = discre(tamoy,ha,trmoy,8.0,it,ntp,h[it-1],ydel[it-1],300.0,0.0);
960
961 double ca;
962 if ((-zx / ha) < -18) ca = 0;
963 else ca = (double)(tamoy * exp(-zx / ha));
964
965 double cr = (double)(trmoy * exp(-zx / 8.0));
966 h[it] = cr + ca;
967 altc[it] = zx;
968
969 cr = cr / 8;
970 ca = ca / ha;
971 double ratio = cr / (cr + ca);
972 xdel[it] = (1 - ratio) * pizmoy;
973 ydel[it] = ratio;
974
975 }
976 }
977
978 /* update plane layer if necessary */
979 if (ntp == (snt-1))
980 {
981 /* compute position of the plane layer */
982 double taup = tap + trp;
983 iplane = -1;
984 for(int i = 0; i <= ntp; i++) if (taup >= h[i]) iplane = i;
985
986 /* update the layer from the end to the position to update if necessary */
987 double xt1 = (double)fabs(h[iplane] - taup);
988 double xt2 = (double)fabs(h[iplane + 1] - taup);
989 if ((xt1 > 0.005) && (xt2 > 0.005))
990 {
991 for(int i = snt; i >= iplane + 1; i--)
992 {
993 xdel[i] = xdel[i-1];
994
995
996 ydel[i] = ydel[i-1];
997 h[i] = h[i-1];
998 altc[i] = altc[i-1];
999 }
1000 }
1001 else
1002 {
1003 snt = ntp;
1004 if (xt2 < xt1) iplane = iplane + 1;
1005 }
1006
1007 h[iplane] = taup;
1008 if ( trmoy > accu2 && tamoy > accu2)
1009 {
1010 double ca = (double)(tamoy * exp(-alt.palt / ha));
1011 double cr = (double)(trmoy * exp(-alt.palt / 8.0));
1012 cr = cr / 8;
1013 ca = ca / ha;
1014 double ratio = cr / (cr + ca);
1015 xdel[iplane] = (1 - ratio) * pizmoy;
1016
1017 ydel[iplane] = ratio;
1018 altc[iplane] = alt.palt;
1019 }
1020
1021 if ( trmoy > accu2 && tamoy <= accu2)
1022 {
1023 ydel[iplane] = 1;
1024 xdel[iplane] = 0;
1025 altc[iplane] = alt.palt;
1026 }
1027
1028 if ( trmoy <= accu2 && tamoy > accu2)
1029 {
1030 ydel[iplane] = 0;
1031 xdel[iplane] = 1 * pizmoy;
1032 altc[iplane] = alt.palt;
1033 }
1034 }
1035
1036 double aaaa = delta / (2-delta);
1037 double ron = (1 - aaaa) / (1 + 2 * aaaa);
1038
1039 /* rayleigh phase function */
1040 double beta0 = 1;
1041 double beta2 = 0.5f * ron;
1042
1043 /* primary scattering */
1044 int ig = 1;
1045 double tavion0 = 0;
1046 double tavion1 = 0;
1047 double tavion2 = 0;
1048 double tavion = 0;
1049
1050 double i1[31][2*mu + 1];
1051 double i2[31][2*mu + 1];
1052 double i3[2*mu + 1];
1053 double in[2*mu + 1];
1054 double inm1[2*mu + 1];
1055 double inm2[2*mu + 1];
1056 int j;
1057 for(j = -mu; j <= mu; j++) i3[STDI(j)] = 0;
1058
1059 /* kernel computations */
1060 double xpl[2*mu + 1];
1061 double bp[26][2*mu + 1];
1062 kernel(0, xpl, bp, gauss);
1063
1064 for(j = -mu; j <= mu; j++)
1065 for(int k = 0; k <= snt; k++) i2[k][STDI(j)] = 0;
1066
1067 /* vertical integration, primary upward radiation */
1068 int k;
1069 for(k = 1; k <= mu; k++)
1070 {
1071 i1[snt][STDI(k)] = 1.0;
1072 for(int i = snt-1; i >= 0; i--)
1073 i1[i][STDI(k)] = (double)(exp(-(tamoy + trmoy - h[i]) / gauss.rm[STDI(k)]));
1074 }
1075
1076
1077 /* vertical integration, primary downward radiation */
1078 for(k = -mu; k <= -1; k++)
1079 for(int i = 0; i <= snt; i++) i1[i][STDI(k)] = 0.0;
1080
1081 /* inm2 is inialized with scattering computed at n-2
1082 i3 is inialized with primary scattering */
1083 for(k = -mu; k <= mu; k++)
1084 {
1085 if(k == 0) continue;
1086 if(k < 0)
1087 {
1088 inm1[STDI(k)] = i1[snt][STDI(k)];
1089 inm2[STDI(k)] = i1[snt][STDI(k)];
1090 i3[STDI(k)] = i1[snt][STDI(k)];
1091 }
1092 else
1093 {
1094 inm1[STDI(k)] = i1[0][STDI(k)];
1095 inm2[STDI(k)] = i1[0][STDI(k)];
1096 i3[STDI(k)] = i1[0][STDI(k)];
1097 }
1098 }
1099 tavion = i1[iplane][STDI(mu)];
1100 tavion2 = i1[iplane][STDI(mu)];
1101
1102 do {
1103 /* loop on successive order */
1104 ig++;
1105
1106 /* successive orders
1107 multiple scattering source function at every level within the layer */
1108 for(k = 1; k <= mu; k++)
1109 {
1110 for(int i = 0; i <= snt; i++)
1111 {
1112 double ii1 = 0;
1113 double ii2 = 0;
1114 double x = xdel[i];
1115 double y = ydel[i];
1116
1117 for(j = 1; j <= mu; j++)
1118 {
1119 double bpjk = bp[j][STDI(k)] * x + y * (beta0 + beta2 * xpl[STDI(j)] * xpl[STDI(k)]);
1120 double bpjmk= bp[j][STDI(-k)] * x + y * (beta0 + beta2 * xpl[STDI(j)] * xpl[STDI(-k)]);
1121 ii2 += gauss.gb[STDI(j)] * (i1[i][STDI(j)] * bpjk + i1[i][STDI(-j)] * bpjmk);
1122 ii1 += gauss.gb[STDI(j)] * (i1[i][STDI(j)] * bpjmk + i1[i][STDI(-j)] * bpjk);
1123 }
1124
1125 i2[i][STDI(k)] = (double)ii2;
1126 i2[i][STDI(-k)] = (double)ii1;
1127 }
1128 }
1129
1130 /* vertical integration, upward radiation */
1131 for(k = 1; k <= mu; k++)
1132 {
1133 i1[snt][STDI(k)] = 0.0;
1134 double zi1 = i1[snt][STDI(k)];
1135
1136 for(int i = snt-1; i >= 0; i--)
1137 {
1138 double f = h[i+1] - h[i];
1139 double a = (i2[i+1][STDI(k)] -i2[i][STDI(k)]) / f;
1140 double b = i2[i][STDI(k)] - a * h[i];
1141 double c = (double)exp(-f / gauss.rm[STDI(k)]);
1142 double xx = h[i] - h[i+1] * c;
1143
1144 zi1 = c * zi1 + ((1 - c) * (b + a * gauss.rm[STDI(k)]) + a * xx) / 2;
1145 i1[i][STDI(k)] = zi1;
1146 }
1147 }
1148
1149 /* vertical integration, downward radiation */
1150 for(k = -mu; k <= -1; k++)
1151 {
1152 i1[0][STDI(k)] = 0;
1153 double zi1 = i1[0][STDI(k)];
1154
1155 for(int i = 1; i <= snt; i++)
1156 {
1157 double f = h[i] - h[i-1];
1158 double c = (double)exp(f / gauss.rm[STDI(k)]);
1159 double a = (i2[i][STDI(k)] - i2[i-1][STDI(k)]) / f;
1160 double b = i2[i][STDI(k)] - a * h[i];
1161 double xx = h[i] - h[i-1] * c;
1162 zi1 = c * zi1 + ((1 - c) * (b + a * gauss.rm[STDI(k)]) + a * xx) / 2;
1163 i1[i][STDI(k)] = zi1;
1164 }
1165 }
1166
1167 /* in is the nieme scattering order */
1168 for(k = -mu; k <= mu; k++)
1169 {
1170 if(k == 0) continue;
1171 if(k < 0) in[STDI(k)] = i1[snt][STDI(k)];
1172 else in[STDI(k)] = i1[0][STDI(k)];
1173 }
1174 tavion0 = i1[iplane][STDI(mu)];
1175
1176 /* convergence test (geometrical serie) */
1177 if(ig > 2)
1178 {
1179 double z = 0;
1180 double a1 = tavion2;
1181 double d1 = tavion1;
1182 double g1 = tavion0;
1183 if (a1 >= accu && d1 >= accu && tavion >= accu)
1184 {
1185 double y = ((g1 / d1 - d1 / a1) / ((1 - g1 / d1) * (1 - g1 / d1)) * (g1 / tavion));
1186 y = (double)fabs(y);
1187 z = z >= y ? z : y;
1188 }
1189
1190 for(int l = -mu; l <= mu; l++)
1191 {
1192 if (l == 0) continue;
1193 a1 = inm2[STDI(l)];
1194 d1 = inm1[STDI(l)];
1195 g1 = in[STDI(l)];
1196 if(a1 == 0) continue;
1197 if(d1 == 0) continue;
1198 if(i3[STDI(l)] == 0) continue;
1199
1200 double y = ((g1 / d1 - d1 / a1) / ((1 - g1 / d1) * (1 - g1 / d1)) * (g1 / i3[STDI(l)]));
1201 y = (double)fabs(y);
1202 z = z >= y ? z : y;
1203 }
1204
1205 if(z < 0.0001)
1206 {
1207 /* successful test (geometrical serie) */
1208
1209 for(int l = -mu; l <= mu; l++)
1210 {
1211 if (l == 0) continue;
1212 double y1 = 1;
1213 d1 = inm1[STDI(l)];
1214 g1 = in[STDI(l)];
1215 if(d1 == 0) continue;
1216 y1 = 1 - g1 / d1;
1217 g1 = g1 / y1;
1218 i3[STDI(l)] += g1;
1219 }
1220
1221 d1 = tavion1;
1222 g1 = tavion0;
1223 if (d1 >= accu)
1224 {
1225 if (fabs(g1 - d1) >= accu)
1226 {
1227 double y1 = 1 - g1 / d1;
1228 g1 = g1 / y1;
1229 }
1230 tavion = tavion + g1;
1231
1232 }
1233
1234 break; /* go to 505 */
1235 }
1236
1237 /* inm2 is the (n-2)ieme scattering order */
1238 for(k = -mu; k <= mu; k++) inm2[STDI(k)] = inm1[STDI(k)];
1239 tavion2 = tavion1;
1240 }
1241
1242 /* inm1 is the (n-1)ieme scattering order */
1243 for(k = -mu; k <= mu; k++) inm1[STDI(k)] = in[STDI(k)];
1244 tavion1 = tavion0;
1245
1246 /* sum of the n-1 orders */
1247 for(k = -mu; k <= mu; k++) i3[STDI(k)] += in[STDI(k)];
1248 tavion = tavion + tavion0;
1249
1250 /* stop if order n is less than 1% of the sum */
1251 double z = 0;
1252 for(k = -mu; k <= mu; k++)
1253 {
1254 if(i3[STDI(k)] != 0)
1255 {
1256 double y = (double)fabs(in[STDI(k)] / i3[STDI(k)]);
1257 z = z >= y ? z : y;
1258 }
1259 }
1260 if(z < 0.00001) break;
1261
1262 /* stop if order n is greater than 20 in any case */
1263 } while(ig <= 20);
1264
1265 /* dimension for os computation */
1266 xf[0] = tavion;
1267 xf[1] = 0;
1268 xf[2] = 0;
1269
1270 xf[2] += i3[STDI(mu)];
1271 for(k = 1; k <= mu; k++) xf[1] += gauss.rm[STDI(k)] * gauss.gb[STDI(k)] * i3[STDI(-k)];
1272
1273 }
1274
1275 /*
1276 To compute the atmospheric reflectance for the molecular atmosphere in
1277 case of satellite observation.
1278 */
chand(const double xtau,const GeomCond & geom)1279 double chand(const double xtau, const GeomCond &geom)
1280 {
1281 /* input parameters: xphi,xmus,xmuv,xtau
1282 xphi: azimuthal difference between sun and observation (xphi=0,
1283 in backscattering) and expressed in degree (0.:360.)
1284 xmus: cosine of the sun zenith angle
1285 xmuv: cosine of the observation zenith angle
1286 xtau: molecular optical depth
1287 output parameter: xrray : molecular reflectance (0.:1.)
1288 constant : xdep: depolarization factor (0.0279) */
1289
1290 const double xdep = 0.0279;
1291
1292 static const double as0[10] = {
1293 .33243832,-6.777104e-02,.16285370,1.577425e-03,-.30924818,
1294 -1.240906e-02,-.10324388,3.241678e-02,.11493334,-3.503695e-02
1295 };
1296
1297 static const double as1[2] = { .19666292, -5.439061e-02 };
1298 static const double as2[2] = { .14545937,-2.910845e-02 };
1299
1300 double phios = (180 - geom.phi);
1301 double xcosf1 = 1;
1302 double xcosf2 = cos(phios * M_PI / 180);
1303 double xcosf3 = cos(2 * phios * M_PI / 180);
1304
1305
1306 double xfd = xdep / (2 - xdep);
1307 xfd = (1 - xfd) / (1 + 2 * xfd);
1308
1309 double xph1 = 1 + (3 * geom.xmus * geom.xmus - 1) * (3 * geom.xmuv * geom.xmuv - 1) * xfd / 8;
1310 double xph2 = -geom.xmus * geom.xmuv * sqrt(1 - geom.xmus * geom.xmus) * sqrt(1 - geom.xmuv * geom.xmuv);
1311 xph2 *= xfd * 0.75;
1312 double xph3 = (1 - geom.xmus * geom.xmus) * (1 - geom.xmuv * geom.xmuv);
1313 xph3 *= xfd * 0.1875;
1314
1315 double xitm = (1 - exp(-xtau * (1 / geom.xmus + 1 / geom.xmuv))) * geom.xmus / (4 * (geom.xmus + geom.xmuv));
1316 double xp1 = xph1 * xitm;
1317 double xp2 = xph2 * xitm;
1318 double xp3 = xph3 * xitm;
1319
1320 xitm = (1 - exp(-xtau / geom.xmus)) * (1 - exp(-xtau / geom.xmuv));
1321 double cfonc1 = xph1 * xitm;
1322 double cfonc2 = xph2 * xitm;
1323 double cfonc3 = xph3 * xitm;
1324 double xlntau = log(xtau);
1325
1326 double pl[10];
1327 pl[0] = 1;
1328 pl[1] = xlntau;
1329 pl[2] = geom.xmus + geom.xmuv;
1330 pl[3] = xlntau * pl[2];
1331 pl[4] = geom.xmus * geom.xmuv;
1332 pl[5] = xlntau * pl[4];
1333 pl[6] = geom.xmus * geom.xmus + geom.xmuv * geom.xmuv;
1334 pl[7] = xlntau * pl[6];
1335 pl[8] = geom.xmus * geom.xmus * geom.xmuv * geom.xmuv;
1336 pl[9] = xlntau * pl[8];
1337
1338 double fs0 = 0;
1339 for(int i = 0; i < 10; i++) fs0 += pl[i] * as0[i];
1340
1341 double fs1 = pl[0] * as1[0] + pl[1] * as1[1];
1342 double fs2 = pl[0] * as2[0] + pl[1] * as2[1];
1343 double xitot1 = xp1 + cfonc1 * fs0 * geom.xmus;
1344 double xitot2 = xp2 + cfonc2 * fs1 * geom.xmus;
1345 double xitot3 = xp3 + cfonc3 * fs2 * geom.xmus;
1346
1347 double xrray = (double)(xitot1 * xcosf1);
1348 xrray += (double)(xitot2 * xcosf2 * 2);
1349
1350 xrray += (double)(xitot3 * xcosf3 * 2);
1351 xrray /= (double)geom.xmus;
1352
1353 return xrray;
1354 }
1355
1356 /*
1357 To compute the atmospheric reflectance for the molecular and aerosol atmospheres
1358 and the mixed atmosphere. In 6S instead of an approximation as in 5S, we use the scalar Successive
1359 Order of Scattering method (subroutine OS.f). The polarization terms of aerosol or rayleigh phase
1360 are not accounted for in the computation of the aerosol reflectance and the mixed Rayleigh-aerosol
1361 reflectance. The polarization is addressed in computing the Rayleigh reflectance (Subroutine
1362 CHAND.f) by semi-empirical fitting of the vectorized Successive Orders of Scattering method
1363 (Deuz� et al, 1989).
1364 */
atmref(const double tamoy,const double trmoy,const double pizmoy,const double tamoyp,const double trmoyp,OpticalAtmosProperties & oap,Gauss & gauss,const GeomCond & geom,const AerosolModel & aero,const Altitude & alt)1365 void atmref(const double tamoy, const double trmoy, const double pizmoy,
1366 const double tamoyp, const double trmoyp, OpticalAtmosProperties &oap,
1367 Gauss &gauss, const GeomCond &geom, const AerosolModel &aero,
1368 const Altitude &alt)
1369 {
1370 double xlm1[2 * mu + 1][np];
1371 double xlm2[2 * mu + 1][np];
1372
1373 /* atmospheric reflectances */
1374 oap.rorayl = 0;
1375 oap.roaero = 0;
1376
1377 /* rayleigh reflectance 3 cases (satellite,plane,ground) */
1378 if(alt.palt < 900 && alt.palt > 0)
1379 {
1380 gauss.rm[STDI(-mu)] = -(double)geom.xmuv;
1381 gauss.rm[STDI(mu)] = (double)geom.xmuv;
1382 gauss.rm[STDI(0)] = -(double)geom.xmus;
1383
1384 os(0, trmoy, pizmoy, 0, trmoyp, xlm1, gauss, alt, geom);
1385
1386 oap.rorayl = (double)(xlm1[STDI(-mu)][0] / geom.xmus);
1387 }
1388 else if(alt.palt <= 0) oap.rorayl = 0;
1389 else oap.rorayl = chand(trmoy, geom);
1390
1391 if (aero.iaer == 0)
1392 {
1393 oap.romix = oap.rorayl;
1394 return;
1395 }
1396
1397 /* rayleigh+aerosol=romix,aerosol=roaero reflectance computed
1398 using successive order of scattering method
1399 3 cases: satellite,plane,ground */
1400 if (alt.palt > 0)
1401 {
1402 gauss.rm[STDI(-mu)] = -(double)geom.xmuv;
1403 gauss.rm[STDI(mu)] = (double)geom.xmuv;
1404 gauss.rm[STDI(0)] = -(double)geom.xmus;
1405
1406 os(tamoy, trmoy, pizmoy, tamoyp, trmoyp, xlm2, gauss, alt, geom);
1407 oap.romix = (double)(xlm2[STDI(-mu)][0] / geom.xmus);
1408
1409 os(tamoy, 0, pizmoy, tamoyp, 0, xlm2, gauss, alt, geom);
1410 oap.roaero = (double)(xlm2[STDI(-mu)][0] / geom.xmus);
1411 }
1412 else
1413 {
1414 oap.roaero = 0;
1415 oap.romix = 0;
1416 }
1417 }
1418
1419
fintexp1(const double xtau)1420 double fintexp1(const double xtau)
1421 {
1422 /* accuracy 2e-07... for 0<xtau<1 */
1423 double a[6] = { -.57721566,0.99999193,-0.24991055,0.05519968,-0.00976004,0.00107857 };
1424 double xftau = 1;
1425 double xx = a[0];
1426 for(int i = 1; i <= 5; i++)
1427 {
1428 xftau *= xtau;
1429 xx += a[i] * xftau;
1430 }
1431 return (double)(xx - log(xtau));
1432 }
1433
fintexp3(const double xtau)1434 double fintexp3(const double xtau)
1435 {
1436 return (double)((exp(-xtau) * (1. - xtau) + xtau * xtau * fintexp1(xtau)) / 2.);
1437 }
1438
1439 /* To compute the spherical albedo of the molecular layer. */
csalbr(const double xtau,double & xalb)1440 void csalbr(const double xtau, double& xalb)
1441 {
1442 xalb = (double)((3. * xtau - fintexp3(xtau) * (4. + 2. * xtau) + 2. * exp(-xtau)));
1443 xalb = (double)(xalb / (4. + 3. * xtau));
1444 }
1445
scatra(const double taer,const double taerp,const double tray,const double trayp,const double piza,OpticalAtmosProperties & oap,Gauss & gauss,const GeomCond & geom,const Altitude & alt)1446 void scatra(const double taer, const double taerp,
1447 const double tray, const double trayp,
1448 const double piza, OpticalAtmosProperties& oap,
1449 Gauss &gauss, const GeomCond &geom, const Altitude &alt)
1450 {
1451 /* computations of the direct and diffuse transmittances
1452 for downward and upward paths , and spherical albedo */
1453 double tamol,tamolp;
1454 double xtrans[3];
1455
1456 oap.ddirtt = 1; oap.ddiftt = 0;
1457 oap.udirtt = 1; oap.udiftt = 0;
1458 oap.ddirtr = 1; oap.ddiftr = 0;
1459 oap.udirtr = 1; oap.udiftr = 0;
1460 oap.ddirta = 1; oap.ddifta = 0;
1461 oap.udirta = 1; oap.udifta = 0;
1462 oap.sphalbt = 0;
1463 oap.sphalbr = 0;
1464 oap.sphalba = 0;
1465
1466 for(int it = 1; it <= 3; it++)
1467
1468 {
1469 /* it=1 rayleigh only, it=2 aerosol only, it=3 rayleigh+aerosol */
1470 if (it == 2 && taer <= 0) continue;
1471
1472 /* compute upward,downward diffuse transmittance for rayleigh,aerosol */
1473 if (it == 1)
1474 {
1475 if (alt.palt > 900)
1476 {
1477 oap.udiftt = (double)((2. / 3. + geom.xmuv) + (2. / 3. - geom.xmuv) * exp(-tray / geom.xmuv));
1478
1479 oap.udiftt = (double)(oap.udiftt / ((4. / 3.) + tray) - exp(-tray / geom.xmuv));
1480 oap.ddiftt = (double)((2. / 3. + geom.xmus) + (2. / 3. - geom.xmus) * exp(-tray / geom.xmus));
1481 oap.ddiftt = (double)(oap.ddiftt / ((4. / 3.) + tray) - exp(-tray / geom.xmus));
1482 oap.ddirtt = (double)exp(-tray / geom.xmus);
1483 oap.udirtt = (double)exp(-tray / geom.xmuv);
1484
1485 csalbr(tray, oap.sphalbt);
1486 }
1487 else if (alt.palt > 0 && alt.palt <= 900)
1488 {
1489 tamol = 0;
1490 tamolp= 0;
1491 gauss.rm[STDI(-mu)] = -(double)geom.xmuv;
1492 gauss.rm[STDI(mu)] = (double)geom.xmuv;
1493 gauss.rm[STDI(0)] = (double)geom.xmus;
1494
1495 iso(tamol, tray, piza, tamolp, trayp, xtrans, gauss, alt);
1496
1497 oap.udiftt = (double)(xtrans[0] - exp(-trayp / geom.xmuv));
1498 oap.udirtt = (double)exp(-trayp / geom.xmuv);
1499 gauss.rm[STDI(-mu)] = -(double)geom.xmus;
1500 gauss.rm[STDI(mu)] = (double)geom.xmus;
1501 gauss.rm[STDI(0)] = (double)geom.xmus;
1502
1503 oap.ddiftt = (double)((2. / 3. + geom.xmus) + (2. / 3. - geom.xmus) * exp(-tray / geom.xmus));
1504 oap.ddiftt = (double)(oap.ddiftt / ((4. / 3.) + tray) - exp(-tray / geom.xmus));
1505 oap.ddirtt = (double)exp(-tray / geom.xmus);
1506 oap.udirtt = (double)exp(-tray / geom.xmuv);
1507
1508 csalbr(tray, oap.sphalbt);
1509 }
1510 else if (alt.palt <= 0.)
1511 {
1512 oap.udiftt = 0;
1513 oap.udirtt = 1;
1514 }
1515
1516 oap.ddirtr = oap.ddirtt;
1517 oap.ddiftr = oap.ddiftt;
1518 oap.udirtr = oap.udirtt;
1519 oap.udiftr = oap.udiftt;
1520 oap.sphalbr = oap.sphalbt;
1521 }
1522
1523 else if (it == 2)
1524 {
1525 tamol = 0;
1526 tamolp= 0;
1527 gauss.rm[STDI(-mu)] = -(double)geom.xmuv;
1528 gauss.rm[STDI(mu)] = (double)geom.xmuv;
1529 gauss.rm[STDI(0)] = (double)geom.xmus;
1530
1531 iso(taer, tamol, piza, taerp, tamolp, xtrans, gauss, alt);
1532
1533 oap.udiftt = (double)(xtrans[0] - exp(-taerp / geom.xmuv));
1534 oap.udirtt = (double)exp(-taerp / geom.xmuv);
1535 gauss.rm[STDI(-mu)] = -(double)geom.xmus;
1536 gauss.rm[STDI(mu)] = (double)geom.xmus;
1537 gauss.rm[STDI(0)] = (double)geom.xmus;
1538
1539 double tmp_alt = alt.palt;
1540 alt.palt = 999;
1541 iso(taer, tamol, piza, taerp, tamolp, xtrans, gauss, alt);
1542 alt.palt = tmp_alt;
1543
1544 oap.ddirtt = (double)exp(-taer / geom.xmus);
1545 oap.ddiftt = (double)(xtrans[2] - exp(-taer / geom.xmus));
1546 oap.sphalbt= (double)(xtrans[1] * 2);
1547
1548 if(alt.palt <= 0)
1549 {
1550 oap.udiftt = 0;
1551 oap.udirtt = 1;
1552 }
1553
1554 oap.ddirta = oap.ddirtt;
1555 oap.ddifta = oap.ddiftt;
1556 oap.udirta = oap.udirtt;
1557 oap.udifta = oap.udiftt;
1558 oap.sphalba = oap.sphalbt;
1559 }
1560 else if(it == 3)
1561 {
1562 gauss.rm[STDI(-mu)] = -(double)geom.xmuv;
1563 gauss.rm[STDI(mu)] = (double)geom.xmuv;
1564 gauss.rm[STDI(0)] = (double)geom.xmus;
1565
1566 iso(taer, tray, piza, taerp, trayp, xtrans, gauss, alt);
1567
1568 oap.udirtt = (double)exp(-(taerp + trayp) / geom.xmuv);
1569 oap.udiftt = (double)(xtrans[0] - exp(-(taerp + trayp) / geom.xmuv));
1570 gauss.rm[STDI(-mu)] = -(double)geom.xmus;
1571 gauss.rm[STDI(mu)] = (double)geom.xmus;
1572 gauss.rm[STDI(0)] = (double)geom.xmus;
1573
1574 double tmp_alt = alt.palt;
1575 alt.palt = 999;
1576 iso(taer, tray, piza, taerp, trayp, xtrans, gauss, alt);
1577 alt.palt = tmp_alt;
1578
1579 oap.ddiftt = (double)(xtrans[2] - exp(-(taer + tray) / geom.xmus));
1580 oap.ddirtt = (double)exp(-(taer + tray) / geom.xmus);
1581
1582 oap.sphalbt= (double)(xtrans[1] * 2);
1583
1584 if (alt.palt <= 0)
1585 {
1586 oap.udiftt = 0;
1587 oap.udirtt = 1;
1588 }
1589 }
1590 }
1591 }
1592
1593 /* To compute the optical properties of the atmosphere at the 10 discrete
1594 wavelengths. */
discom(const GeomCond & geom,const AtmosModel & atms,const AerosolModel & aero,const AerosolConcentration & aerocon,const Altitude & alt,const IWave & iwave)1595 void discom(const GeomCond &geom, const AtmosModel &atms,
1596 const AerosolModel &aero, const AerosolConcentration &aerocon,
1597 const Altitude &alt, const IWave &iwave)
1598 {
1599 OpticalAtmosProperties oap;
1600 memset(&oap, 0, sizeof(oap));
1601
1602 Gauss gauss;
1603
1604 gauss.init(); /* discom is the only function that uses the gauss data */
1605
1606 memset(&sixs_trunc, 0, sizeof(sixs_trunc)); /* clear this to keep preconditions the same and output consistent */
1607
1608 /* computation of all scattering parameters at wavelength
1609 discrete values,so we
1610 can interpolate at any wavelength */
1611 int i;
1612 for(i = 0; i < 10; i++)
1613 {
1614 if(!((((i < 2) && iwave.ffu.wlsup < sixs_disc.wldis[0])) || ((iwave.ffu.wlinf > sixs_disc.wldis[9]) && (i >= 8))))
1615 if (((i < 9) && (sixs_disc.wldis[i] < iwave.ffu.wlinf) && (sixs_disc.wldis[i+1] < iwave.ffu.wlinf)) ||
1616 ((i > 0) && (sixs_disc.wldis[i] > iwave.ffu.wlsup) && (sixs_disc.wldis[i-1] > iwave.ffu.wlsup))) continue;
1617
1618 double wl = sixs_disc.wldis[i];
1619 /* computation of rayleigh optical depth at wl */
1620 double tray = odrayl(atms, wl);
1621 double trayp;
1622
1623 /* plane case discussed here above */
1624 if (alt.idatmp == 0) trayp = 0;
1625 else if (alt.idatmp == 4) trayp = tray;
1626 else trayp = tray * alt.ftray;
1627
1628 sixs_disc.trayl[i] = tray;
1629 sixs_disc.traypl[i] = trayp;
1630
1631 /* computation of aerosol optical properties at wl */
1632
1633 double taer = aerocon.taer55 * sixs_aer.ext[i] / sixs_aer.ext[3];
1634 double taerp = alt.taer55p * sixs_aer.ext[i] / sixs_aer.ext[3];
1635 double piza = sixs_aer.ome[i];
1636
1637 /* computation of atmospheric reflectances
1638
1639 rorayl is rayleigh ref
1640 roaero is aerosol ref
1641 call plegen to decompose aerosol phase function in Betal */
1642
1643 double coeff = 0;
1644 if(aero.iaer != 0)
1645 {
1646 for(int k = 0; k < 83; k++) sixs_trunc.pha[k] = sixs_sos.phasel[i][k];
1647 coeff = trunca();
1648 }
1649
1650 double tamoy = taer * (1 - piza * coeff);
1651 double tamoyp = taerp * (1 - piza * coeff);
1652 double pizmoy = piza * (1 - coeff) / (1 - piza * coeff);
1653
1654 atmref(tamoy, tray, pizmoy, tamoyp, trayp, oap, gauss, geom, aero, alt);
1655
1656 /* computation of scattering transmitances (direct and diffuse)
1657 first time for rayleigh ,next total (rayleigh+aerosols) */
1658
1659 scatra(tamoy, tamoyp, tray, trayp, pizmoy, oap, gauss, geom, alt);
1660
1661 sixs_disc.roatm[0][i] = oap.rorayl;
1662 sixs_disc.roatm[1][i] = oap.romix;
1663 sixs_disc.roatm[2][i] = oap.roaero;
1664 sixs_disc.dtdir[0][i] = oap.ddirtr;
1665 sixs_disc.dtdif[0][i] = oap.ddiftr;
1666 sixs_disc.dtdir[1][i] = oap.ddirtt;
1667 sixs_disc.dtdif[1][i] = oap.ddiftt;
1668 sixs_disc.dtdir[2][i] = oap.ddirta;
1669 sixs_disc.dtdif[2][i] = oap.ddifta;
1670 sixs_disc.utdir[0][i] = oap.udirtr;
1671 sixs_disc.utdif[0][i] = oap.udiftr;
1672 sixs_disc.utdir[1][i] = oap.udirtt;
1673 sixs_disc.utdif[1][i] = oap.udiftt;
1674 sixs_disc.utdir[2][i] = oap.udirta;
1675 sixs_disc.utdif[2][i] = oap.udifta;
1676 sixs_disc.sphal[0][i] = oap.sphalbr;
1677 sixs_disc.sphal[1][i] = oap.sphalbt;
1678 sixs_disc.sphal[2][i] = oap.sphalba;
1679 }
1680
1681 }
1682
1683 /*
1684 To compute the atmospheric properties at the equivalent wavelength (see
1685 EQUIVWL.f) needed for the calculation of the downward radiation field used
1686 in the computation of the non lambertian target contribution (main.f).
1687 */
specinterp(const double wl,double & tamoy,double & tamoyp,double & pizmoy,double & pizmoyp,const AerosolConcentration & aerocon,const Altitude & alt)1688 void specinterp(const double wl, double& tamoy, double& tamoyp, double& pizmoy, double& pizmoyp,
1689 const AerosolConcentration &aerocon, const Altitude &alt)
1690 {
1691
1692 int linf = 0;
1693 int i = 8;
1694 while (i >= 0 && linf == 0) {
1695 if (wl >= sixs_disc.wldis[i] && wl <= sixs_disc.wldis[i+1]) linf = i;
1696 i--;
1697 }
1698 if(wl > sixs_disc.wldis[9]) linf = 8;
1699
1700 int lsup = linf + 1;
1701 double coef = (double)log(sixs_disc.wldis[lsup] / sixs_disc.wldis[linf]);
1702 double wlinf = sixs_disc.wldis[linf];
1703
1704 double alphaa = (double)(log(sixs_aer.ext[lsup] * sixs_aer.ome[lsup] /
1705 (sixs_aer.ext[linf] * sixs_aer.ome[linf])) / coef);
1706 double betaa = (double)(sixs_aer.ext[linf] * sixs_aer.ome[linf] / pow(wlinf,alphaa));
1707 double tsca = (double)(aerocon.taer55 * betaa * pow(wl,alphaa) / sixs_aer.ext[3]);
1708 alphaa = (double)(log(sixs_aer.ext[lsup] / sixs_aer.ext[linf]) / coef);
1709 betaa = (double)(sixs_aer.ext[linf] / pow(wlinf,alphaa));
1710 tamoy = (double)(aerocon.taer55 * betaa * pow(wl,alphaa) / sixs_aer.ext[3]);
1711 tamoyp= (double)(alt.taer55p * betaa * pow(wl,alphaa) / sixs_aer.ext[3]);
1712 pizmoy= tsca / tamoy;
1713 pizmoyp = pizmoy;
1714
1715 for(int k = 0; k < 83; k++)
1716 {
1717 alphaa = (double)log(sixs_sos.phasel[lsup][k] / sixs_sos.phasel[linf][k]) / coef;
1718 betaa = (double)(sixs_sos.phasel[linf][k] / pow(wlinf,alphaa));
1719 sixs_trunc.pha[k] = (double)(betaa * pow(wl,alphaa));
1720 }
1721
1722 double coeff = trunca();
1723
1724 tamoy *= 1 - pizmoy * coeff;
1725 tamoyp *= 1 - pizmoyp * coeff;
1726 pizmoy *= (1 - coeff) / (1 - pizmoy * coeff);
1727 }
1728
1729 /**********************************************************************c
1730 c c
1731 c start of computations c
1732 c c
1733 c**********************************************************************/
1734
1735 /*
1736 To compute the environment functions F(r) which allows us to account for an
1737 inhomogeneous ground.
1738 */
enviro(const double difr,const double difa,const double r,const double palt,const double xmuv,double & fra,double & fae,double & fr)1739 void enviro (const double difr, const double difa, const double r, const double palt,
1740 const double xmuv, double& fra, double& fae, double& fr)
1741 {
1742 double fae0, fra0, xlnv;
1743 static const double alt[16] = {
1744 0.5,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,
1745 10.0,12.0,14.0,16.0,18.0,20.0,60.0
1746 };
1747
1748 static const double cfr1[16] = {
1749 0.730,0.710,0.656,0.606,0.560,0.516,0.473,
1750 0.433,0.395,0.323,0.258,0.209,0.171,0.142,0.122,0.070
1751 };
1752
1753 static const double cfr2[16] = {
1754 2.8,1.51,0.845,0.634,0.524,0.465,0.429,
1755 0.405,0.390,0.386,0.409,0.445,0.488,0.545,0.608,0.868
1756 };
1757
1758 static const double cfa1[16] = {
1759 0.239,0.396,0.588,0.626,0.612,0.505,0.454,
1760 0.448,0.444,0.445,0.444,0.448,0.448,0.448,0.448,0.448
1761 };
1762
1763 static const double cfa2[16] = {
1764 1.40,1.20,1.02,0.86,0.74,0.56,0.46,0.42,
1765 0.38,0.34,0.3,0.28,0.27,0.27,0.27,0.27
1766 };
1767
1768 static const double cfa3[16] = {
1769 9.17,6.26,5.48,5.16,4.74,3.65,3.24,3.15,
1770 3.07,2.97,2.88,2.83,2.83,2.83,2.83,2.83
1771 };
1772
1773
1774 /* calculation of the environmental function for
1775 rayleigh and aerosols contribution.
1776
1777 this calculation have been done for nadir observation
1778 and are corrected of the effect of the view zenith angle. */
1779
1780 const double a0 = 1.3347;
1781 const double b0 = 0.57757;
1782 const double a1 = -1.479;
1783 const double b1 = -1.5275;
1784
1785 if (palt >= 60)
1786 {
1787 fae0 = (double)(1. - 0.448 * exp( -r * 0.27) - 0.552 * exp( -r * 2.83));
1788 fra0 = (double)(1. - 0.930 * exp( -r * 0.080) - 0.070 * exp( -r * 1.100));
1789 }
1790 else
1791 {
1792 int i;
1793 for(i = 0; palt >= alt[i]; i++);
1794 double xcfr1 = 0, xcfr2 = 0, xcfa1 = 0, xcfa2 = 0, xcfa3 = 0;
1795
1796 if ((i > 0) && (i < 16))
1797 {
1798 double zmin = alt[i - 1];
1799 double zmax = alt[i];
1800 xcfr1 = cfr1[i - 1] + (cfr1[i] - cfr1[i - 1]) * (palt - zmin) / (zmax - zmin);
1801 xcfr2 = cfr2[i - 1] + (cfr2[i] - cfr2[i - 1]) * (palt - zmin) / (zmax - zmin);
1802 xcfa1 = cfa1[i - 1] + (cfa1[i] - cfa1[i - 1]) * (palt - zmin) / (zmax - zmin);
1803 xcfa2 = cfa2[i - 1] + (cfa2[i] - cfa2[i - 1]) * (palt - zmin) / (zmax - zmin);
1804 xcfa3 = cfa3[i - 1] + (cfa3[i] - cfa3[i - 1]) * (palt - zmin) / (zmax - zmin);
1805 }
1806
1807 if (i == 0)
1808 {
1809 xcfr1 = cfr1[0];
1810 xcfr2 = cfr2[0];
1811 xcfa1 = cfa1[0];
1812 xcfa2 = cfa2[0];
1813 xcfa3 = cfa3[0];
1814 }
1815
1816 fra0 = (double)(1. - xcfr1 * exp(-r * xcfr2) - (1. - xcfr1) * exp(-r * 0.08));
1817 fae0 = (double)(1. - xcfa1 * exp(-r * xcfa2) - (1. - xcfa1) * exp(-r * xcfa3));
1818 }
1819
1820 /* correction of the effect of the view zenith angle */
1821 xlnv = (double)log(xmuv);
1822 fra = (double)(fra0 * (xlnv * (1 - fra0) + 1));
1823 fae = (double)(fae0 * ((1 + a0 * xlnv + b0 * xlnv * xlnv) + fae0 * (a1 * xlnv + b1 * xlnv * xlnv) +
1824 fae0 * fae0 * ((-a1 - a0) * xlnv + ( - b1 - b0) * xlnv * xlnv)));
1825
1826 if ((difa + difr) > 1e-03) fr = (fae * difa + fra * difr) / (difa + difr);
1827 else fr = 1;
1828 }
1829
1830
1831