computations.cpp 48 KB

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