AerosolModel.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. extern "C" {
  2. #include <grass/gis.h>
  3. #include <grass/glocale.h>
  4. }
  5. #include "common.h"
  6. #include "AerosolModel.h"
  7. #include "AtmosModel.h"
  8. #ifdef WIN32
  9. #pragma warning(disable:4305) /* disable warning about initialization of a float by a double */
  10. #endif /* WIN32 */
  11. /* (background desert model...) */
  12. void AerosolModel::bdm()
  13. {
  14. sixs_aerbas.ph = &sixs_aerbas.bdm_ph;
  15. }
  16. /* (biomass burning model...) */
  17. void AerosolModel::bbm()
  18. {
  19. sixs_aerbas.ph = &sixs_aerbas.bbm_ph;
  20. }
  21. /* (stratospherique aerosol model...) */
  22. void AerosolModel::stm()
  23. {
  24. sixs_aerbas.ph = &sixs_aerbas.stm_ph;
  25. }
  26. /* dust model */
  27. void AerosolModel::dust()
  28. {
  29. sixs_aerbas.ph = &(sixs_aerbas.dust_ph);
  30. }
  31. /* water model */
  32. void AerosolModel::wate()
  33. {
  34. sixs_aerbas.ph = &(sixs_aerbas.wate_ph);
  35. }
  36. /* ocean model */
  37. void AerosolModel::ocea()
  38. {
  39. sixs_aerbas.ph = &sixs_aerbas.ocea_ph;
  40. }
  41. /* soot model */
  42. void AerosolModel::soot()
  43. {
  44. sixs_aerbas.ph = &sixs_aerbas.soot_ph;
  45. }
  46. /* (user defined model from size distribution) */
  47. /* To compute, using the scattering of electromagnetic waves by a homogeneous
  48. isotropic sphere, the physical properties of particles whose sizes are
  49. comparable to or larger than the wavelength, and to generate mixture of
  50. dry particles. */
  51. void AerosolModel::mie(float (&ex)[4][10], float (&sc)[4][10], float (&asy)[4][10])
  52. {
  53. double np[4];
  54. double ext[10][4];
  55. double sca[10][4];
  56. double p1[10][4][83];
  57. const double rmul = 0.99526231496887960135245539673954; /*rlogpas = 0.030; (10**rlogpas-1.D+00)*/
  58. int i;
  59. for(i = 0; i < mie_in.icp; i++)
  60. {
  61. np[i] = 0;
  62. for(int j = 0; j < 10; j++)
  63. {
  64. ex[i][j] = 0;
  65. sc[i][j] = 0;
  66. ext[j][i] = 0;
  67. sca[j][i] = 0;
  68. for(int k = 0; k < 83; k++) p1[j][i][k] = 0;
  69. }
  70. }
  71. double r;
  72. double dr;
  73. double nr = 0;
  74. /* LOOPS ON THE NUMBER OF PARTICLE TYPE (4 max) */
  75. for(i = 0; i < mie_in.icp; i++)
  76. {
  77. r = mie_in.rmin;
  78. dr = r*rmul;
  79. /* LOOPS ON THE RADIUS OF THE PARTICLE */
  80. do {
  81. /* call of the size distribution nr. For our computation, we need dn/dr for */
  82. /* all functions except for sun-photometer inputs for which we need dV/dlog(r) */
  83. switch(iaer-7)
  84. {
  85. case 1:
  86. {
  87. /* --- Mixture of particles (Log-Normal distribution functions, up to 5)*/
  88. const double sqrt2PI = 2.506628274631000502415765284811;
  89. const double ln10 = 2.3025850929940456840179914546844;
  90. double log10_x2 = log10(mie_in.x2[i]);
  91. double sq = log10(r/mie_in.x1[i])/log10_x2;
  92. nr = exp(-0.5*sq*sq);
  93. nr /= sqrt2PI * log10_x2 * ln10 * r;
  94. break;
  95. }
  96. case 2:
  97. {
  98. /* --- Modified Gamma distribution function */
  99. const double ldexp = -300.;
  100. double arg=-mie_in.x2[i]*pow(r,(double)mie_in.x3[i]);
  101. if(arg > ldexp) nr = pow(r,(double)mie_in.x1[i])*exp(arg);
  102. else nr = 0;
  103. break;
  104. }
  105. case 3:
  106. {
  107. /* --- Junge power-law function */
  108. nr = pow(0.1,-(double)mie_in.x1[i]);
  109. if(r > 0.1) nr = pow(r,-(double)mie_in.x1[i]);
  110. break;
  111. }
  112. case 4:
  113. {
  114. /* --- from sun photometer */
  115. nr = 0;
  116. for(int j = 1; j < mie_in.irsunph; j++)
  117. if((r-mie_in.rsunph[j]) < 0.000001)
  118. {
  119. nr = (r - mie_in.rsunph[j-1])/(mie_in.rsunph[j]-mie_in.rsunph[j-1]);
  120. nr = mie_in.nrsunph[j-1] + nr*(mie_in.nrsunph[j] - mie_in.nrsunph[j-1]);
  121. break;
  122. }
  123. }
  124. }
  125. /* The Mie's calculations have to be called several times (min=2, max=10 for
  126. each type of particle): at wavelengths bounding the range of the selected
  127. wavelengths,and at 0.550 microns to normalized the extinction coefficient
  128. (if it's not in the selected range of wavelengths). */
  129. double xndpr2 = nr * dr * M_PI * (r * r);
  130. /* relatif number of particle for each type of particle (has to be equal to 1) */
  131. np[i]+= nr * dr;
  132. for(int j = 0; j < 10; j++)
  133. {
  134. if( (xndpr2*mie_in.cij[i]) < (1e-8 / sqrt(sixs_disc.wldis[j])) ) break;
  135. double alpha = 2. * M_PI * r / sixs_disc.wldis[j];
  136. double Qext, Qsca;
  137. double p11[83];
  138. exscphase(alpha, mie_in.rn[j][i], mie_in.ri[j][i], Qext, Qsca, p11);
  139. ext[j][i] += xndpr2 * Qext;
  140. sca[j][i] += xndpr2 * Qsca;
  141. /* phase function for each type of particle */
  142. for(int k = 0; k < 83; k++) p1[j][i][k] += p11[k]*xndpr2;
  143. }
  144. r += dr;
  145. dr = r * rmul;
  146. } while (r < mie_in.rmax);
  147. }
  148. /* NOW WE MIXTE THE DIFFERENT TYPES OF PARTICLE
  149. computation of the scattering and extinction coefficients. We first start
  150. at 0.550 micron (the extinction coefficient is normalized at 0.550 micron) */
  151. int j;
  152. for(j = 0; j < 10; j++)
  153. for(int i = 0; i < mie_in.icp; i++)
  154. {
  155. ext[j][i] /= np[i] * 1000;
  156. sca[j][i] /= np[i] * 1000;
  157. ex[0][j] += (float)(mie_in.cij[i] * ext[j][i]);
  158. sc[0][j] += (float)(mie_in.cij[i] * sca[j][i]);
  159. }
  160. /* computation of the phase function and the asymetry coefficient
  161. of the mixture of particles */
  162. for(j = 0; j < 10; j++)
  163. {
  164. double asy_n = 0;
  165. double asy_d = 0;
  166. for(int k = 0; k < 83; k++)
  167. {
  168. sixs_aerbas.usr_ph[j][k] = 0;
  169. for(int i = 0; i < mie_in.icp; i++)
  170. sixs_aerbas.usr_ph[j][k] += (float)(mie_in.cij[i] * p1[j][i][k] / np[i] / 1000);
  171. sixs_aerbas.usr_ph[j][k] += (float)sc[0][j];
  172. asy_n += sixs_sos.cgaus[k] * sixs_aerbas.usr_ph[j][k] * sixs_sos.pdgs[k] / 10.;
  173. asy_d += sixs_aerbas.usr_ph[j][k] * sixs_sos.pdgs[k] / 10.;
  174. }
  175. asy[0][j] = (float)(asy_n / asy_d);
  176. }
  177. sixs_aerbas.ph = &sixs_aerbas.usr_ph;
  178. }
  179. /***************************************************************************
  180. Using the Mie's theory, this subroutine compute the scattering and
  181. extinction efficiency factors (usually written Qsca and Qext) and it also
  182. compute the scattering intensity efficiency
  183. ***************************************************************************/
  184. void AerosolModel::exscphase(const double X, const double nr,
  185. const double ni, double& Qext,
  186. double& Qsca, double (&p11)[83])
  187. {
  188. double Ren=nr/(nr*nr+ni*ni);
  189. double Imn=ni/(nr*nr+ni*ni);
  190. /* ---Identification of the greater order of computation (=mu)
  191. as defined by F.J. Corbato, J. Assoc. Computing Machinery, 1959,
  192. 6, 366-375 */
  193. int N=int(0.5*(-1+sqrt(1+4*X*X)))+1;
  194. if (N == 1) N = 2;
  195. int mu2 = 1000000;
  196. double Up = 2 * X / (2 * N + 1);
  197. int mu1 = int(N + 30. * (0.1 + 0.35 * Up * (2. - Up * Up) / 2 / (1 - Up)));
  198. int Np = int(X - 0.5 * sqrt(30. * 0.35 * X));
  199. if(Np > N)
  200. {
  201. Up = 2 * X / (2 * Np + 1);
  202. mu2 = int(Np + 30. * (0.1 + 0.35 * Up * (2 - Up * Up)/ 2 / (1 - Up)));
  203. }
  204. int mu = (mu1 < mu2) ? mu1 : mu2; /* min(mu1, mu2) */
  205. /* --- Identification of the transition line. Below this line the Bessel
  206. function j behaves as oscillating functions. Above the behavior
  207. becomes monotonic. We start at a order greater than this transition
  208. line (order max=mu) because a downward recursion is called for. */
  209. double Rn[10001], xj[10001];
  210. int k = mu + 1;
  211. Rn[mu] = 0;
  212. int mub;
  213. while(true)
  214. {
  215. k--;
  216. xj[k] = 0;
  217. Rn[k-1] = X / (2 * k + 1 - X * Rn[k]);
  218. if ( k == 2)
  219. {
  220. xj[mu + 1] = 0;
  221. xj[mu] = 1;
  222. mub = mu;
  223. break;
  224. }
  225. if(Rn[k-1] > 1)
  226. {
  227. xj[k] = Rn[k-1];
  228. xj[k-1] = 1;
  229. mub = k - 1;
  230. break;
  231. }
  232. }
  233. for(k = mub; k >= 1; k--) xj[k-1] = (2 * k + 1) * xj[k] / X - xj[k+1];
  234. double coxj = xj[0] - X * xj[1] * cos(X) + X * xj[0] * sin(X);
  235. /* --- Computation Dn(alpha) and Dn(alpha*m) (cf MIE's theory)
  236. downward recursion - real and imaginary parts */
  237. double RDnY[10001];
  238. double IDnY[10001];
  239. double RDnX[10001];
  240. RDnY[mu] = 0;
  241. IDnY[mu] = 0;
  242. RDnX[mu] = 0;
  243. for(k = mu; k >= 1; k--)
  244. {
  245. RDnX[k-1] = k / X - 1 / (RDnX[k] + k / X);
  246. double XnumRDnY = RDnY[k] + Ren * k / X;
  247. double XnumIDnY = IDnY[k] + Imn * k / X;
  248. double XdenDnY = XnumRDnY * XnumRDnY + XnumIDnY * XnumIDnY;
  249. RDnY[k-1] = k * Ren / X - XnumRDnY / XdenDnY;
  250. IDnY[k-1] = k * Imn / X + XnumIDnY / XdenDnY;
  251. }
  252. /* --- Initialization of the upward recursions
  253. macro to help keep indexing correct, can't be to safe */
  254. #define INDEX(X) ((X)+1)
  255. double xy[10002];
  256. xy[INDEX(-1)] = sin(X) / X;
  257. xy[INDEX(0)] = -cos(X) / X;
  258. double RGnX[10001];
  259. double IGnX[10001];
  260. RGnX[0] = 0;
  261. IGnX[0] = -1;
  262. Qsca = 0;
  263. Qext = 0;
  264. double RAn[10001];
  265. double IAn[10001];
  266. double RBn[10001];
  267. double IBn[10001];
  268. for(k = 1; k <= mu; k++)
  269. {
  270. if (k <= mub) xj[k] /= coxj;
  271. else xj[k] = Rn[k-1] * xj[k-1];
  272. /* --- Computation of bessel's function y(alpha) */
  273. xy[INDEX(k)] = (2 * k - 1) * xy[INDEX(k-1)] / X - xy[INDEX(k-2)];
  274. double xJonH = xj[k] / ( xj[k] * xj[k] + xy[INDEX(k)] * xy[INDEX(k)] );
  275. /* --- Computation of Gn(alpha), Real and Imaginary part */
  276. double XdenGNX = (RGnX[k-1] - k/X)*(RGnX[k-1] - k/X) + IGnX[k-1] * IGnX[k-1];
  277. RGnX[k] = (k / X - RGnX[k-1])/XdenGNX - k / X;
  278. IGnX[k] = IGnX[k-1] / XdenGNX;
  279. /* --- Computation of An(alpha) and Bn(alpha), Real and Imaginary part */
  280. double Xnum1An = RDnY[k] - nr * RDnX[k];
  281. double Xnum2An = IDnY[k] + ni * RDnX[k];
  282. double Xden1An = RDnY[k] - nr * RGnX[k] - ni * IGnX[k];
  283. double Xden2An = IDnY[k] + ni * RGnX[k] - nr * IGnX[k];
  284. double XdenAn = Xden1An * Xden1An + Xden2An * Xden2An;
  285. double RAnb = (Xnum1An * Xden1An + Xnum2An * Xden2An) / XdenAn;
  286. double IAnb = (-Xnum1An * Xden2An + Xnum2An * Xden1An) / XdenAn;
  287. RAn[k] = xJonH * (xj[k] * RAnb - xy[INDEX(k)] * IAnb);
  288. IAn[k] = xJonH * (xy[INDEX(k)] * RAnb + xj[k] * IAnb);
  289. double Xnum1Bn = nr * RDnY[k] + ni * IDnY[k] - RDnX[k];
  290. double Xnum2Bn = nr * IDnY[k] - ni * RDnY[k];
  291. double Xden1Bn = nr * RDnY[k] + ni * IDnY[k] - RGnX[k];
  292. double Xden2Bn = nr * IDnY[k] - ni * RDnY[k] - IGnX[k];
  293. double XdenBn = Xden1Bn * Xden1Bn + Xden2Bn * Xden2Bn;
  294. double RBnb = (Xnum1Bn * Xden1Bn + Xnum2Bn * Xden2Bn) / XdenBn;
  295. double IBnb = (-Xnum1Bn * Xden2Bn + Xnum2Bn * Xden1Bn) / XdenBn;
  296. RBn[k] = xJonH * (xj[k] * RBnb - xy[INDEX(k)] * IBnb);
  297. IBn[k] = xJonH * (xy[INDEX(k)] * RBnb + xj[k] * IBnb);
  298. /* ---Criterion on the recursion formulas as defined by D. Deirmendjian
  299. et al., J. Opt. Soc. Am., 1961, 51, 6, 620-633 */
  300. double temp = RAn[k] * RAn[k] + IAn[k] * IAn[k] + RBn[k] * RBn[k] + IBn[k] * IBn[k];
  301. if((temp/k) < 1e-14)
  302. {
  303. mu = k;
  304. break;
  305. }
  306. /* --- Computation of the scattering and extinction efficiency factor */
  307. double xpond = 2 / X / X * (2 * k + 1);
  308. Qsca = Qsca + xpond * temp;
  309. Qext = Qext + xpond * (RAn[k] + RBn[k]);
  310. }
  311. /* --- Computation of the amplitude functions S1 and S2 (cf MIE's theory)
  312. defined by PIn, TAUn, An and Bn with PIn and TAUn related to the
  313. Legendre polynomials. */
  314. for(int j = 0; j < 83; j++)
  315. {
  316. double RS1 = 0;
  317. double RS2 = 0;
  318. double IS1 = 0;
  319. double IS2 = 0;
  320. double PIn[10001];
  321. double TAUn[10001];
  322. PIn[0] = 0;
  323. PIn[1] = 0;
  324. TAUn[1] = sixs_sos.cgaus[j];
  325. for(int k = 1; k <= mu; k++)
  326. {
  327. double co_n = (2 * k + 1) / k / (k + 1);
  328. RS1 += co_n * (RAn[k] * PIn[k] + RBn[k] * TAUn[k]);
  329. RS2 += co_n * (RAn[k] * TAUn[k] + RBn[k] * PIn[k]);
  330. IS1 += co_n * (IAn[k] * PIn[k] + IBn[k] * TAUn[k]);
  331. IS2 += co_n * (IAn[k] * TAUn[k] + IBn[k] * PIn[k]);
  332. PIn[k+1] = ((2 * k + 1) * sixs_sos.cgaus[j] * PIn[k] - (k + 1) * PIn[k-1])/k;
  333. TAUn[k+1] = (k + 1) * sixs_sos.cgaus[j] * PIn[k + 1] - (k + 2) * PIn[k];
  334. }
  335. /* --- Computation of the scattering intensity efficiency */
  336. p11[j] = 2 * (RS1 *RS1 + IS1 * IS1 + RS2 * RS2 + IS2 * IS2)/X/X;
  337. }
  338. }
  339. /* load parameters from .mie file */
  340. void AerosolModel::load()
  341. {
  342. int i;
  343. ifstream in(filename.c_str());
  344. cin.ignore(numeric_limits<int>::max(),'\n'); /* ignore this line */
  345. in.ignore(8);
  346. for(i = 0; i < 10; i++)
  347. {
  348. in.ignore(3);
  349. in >> sixs_aer.ext[i];
  350. in.ignore(6);
  351. in >> sca[i];
  352. in.ignore(6);
  353. in >> sixs_aer.ome[i];
  354. in.ignore(6);
  355. in >> sixs_aer.gasym[i];
  356. in.ignore(3);
  357. cin.ignore(numeric_limits<int>::max(),'\n'); /* ignore the rest */
  358. }
  359. /* ignore 3 lines */
  360. cin.ignore(numeric_limits<int>::max(),'\n'); /* ignore this line */
  361. cin.ignore(numeric_limits<int>::max(),'\n'); /* ignore this line */
  362. cin.ignore(numeric_limits<int>::max(),'\n'); /* ignore this line */
  363. for(i = 0; i < 83; i++)
  364. {
  365. in.ignore(8);
  366. for(int j = 0; j < 10; j++)
  367. {
  368. in.ignore(1);
  369. in >> sixs_sos.phasel[j][i];
  370. }
  371. cin.ignore(numeric_limits<int>::max(),'\n'); /* ignore the rest */
  372. }
  373. }
  374. /* do we wish to save this? */
  375. void AerosolModel::save()
  376. {
  377. ofstream out(filename.c_str());
  378. /* output header */
  379. out << " Wlgth Nor_Ext_Co Nor_Sca_Co Sg_Sca_Alb Asymm_Para Extinct_Co Scatter_Co" << endl;
  380. int i;
  381. for(i = 0; i < 10; i++)
  382. {
  383. out << setprecision(4); /* set the required precision */
  384. out << " " << setw(10) << sixs_disc.wldis[0]
  385. << " " << setw(10) << sixs_aer.ext[i]
  386. << " " << setw(10) << sca[i]
  387. << " " << setw(10) << sixs_aer.ome[i]
  388. << " " << setw(10) << sixs_aer.gasym[i]
  389. << " " << setw(10) << sixs_aer.ext[i]/nis
  390. << " " << setw(10) << sca[i]/nis << endl;
  391. }
  392. out << endl << endl << setw(20) << " " << " Phase Function " << endl;
  393. out << " TETA ";
  394. for(i = 0; i < 10; i++) out << " " << setw(10) << sixs_disc.wldis[i] << " ";
  395. out << endl;
  396. for(i = 0; i < 83; i++)
  397. {
  398. out << setprecision(2);
  399. out << " " << setw(8) << (180.*acos(sixs_sos.cgaus[i])/M_PI);
  400. out << setprecision(4);
  401. out.setf(ios::scientific, ios::floatfield);
  402. for(int j = 0; j < 10; j++) out << " " << setw(14) << sixs_sos.phasel[j][i];
  403. out.setf(ios::fixed, ios::floatfield);
  404. out << endl;
  405. }
  406. }
  407. /*
  408. To compute the optical scattering parameters (extinction and scattering
  409. coefficients, single scattering albedo, phase function, assymetry factor) at the ten discrete
  410. wavelengths for the selected model (or created model) from:
  411. (1) the characteristics of the basic components of the International Radiation Commission.
  412. (1983).
  413. dust-like component (D.L., SUBROUTINE DUST)
  414. oceanic component (O.C., SUBROUTINE OCEA)
  415. water-soluble component (W.S., SUBROUTINE WATE)
  416. soot component (S.O., SUBROUTINE SOOT)
  417. (2) pre-computed caracteristics,
  418. now available are the desertic aerosol model corresponding to background conditions, as
  419. described in Shettle(1984), a stratospheric aerosol model as measured Mona Loa (Hawaii)
  420. during El Chichon eruption and as described by King et al. (1984), and a biomass burning
  421. aerosol model as deduced from measurements taken by sunphotometers in Amazonia.
  422. (SUBROUTINES BDM, STM and BBM)
  423. (3) computed using the MIE theory with inputs (size distribution, refractive indexes...) given
  424. by the user (see SUBROUTINES MIE and EXSCPHASE).
  425. These models don't correspond to a mixture of the four basic components.
  426. */
  427. void AerosolModel::aeroso(const float xmud)
  428. {
  429. /* sra basic components for aerosol model, extinction coefficients are */
  430. /* in km-1. */
  431. /* dust-like = 1 */
  432. /* water-soluble = 2 */
  433. /* oceanique = 3 */
  434. /* soot = 4 */
  435. static const double vi[4] = { 113.983516, 1.13983516e-4, 5.1444150196, 5.977353425e-5 };
  436. static const double ni[4] = { 54.734, 1868550., 276.05, 1805820. };
  437. /* i: 1=dust-like 2=water-soluble 3=oceanic 4=soot */
  438. static const float s_ex[4][10] =
  439. {
  440. {0.1796674e-01,0.1815135e-01,0.1820247e-01,0.1827016e-01,0.1842182e-01,
  441. 0.1853081e-01,0.1881427e-01,0.1974608e-01,0.1910712e-01,0.1876025e-01},
  442. {0.7653460e-06,0.6158538e-06,0.5793444e-06,0.5351736e-06,0.4480091e-06,
  443. 0.3971033e-06,0.2900993e-06,0.1161433e-06,0.3975192e-07,0.1338443e-07},
  444. {0.3499458e-02,0.3574996e-02,0.3596592e-02,0.3622467e-02,0.3676341e-02,
  445. 0.3708866e-02,0.3770822e-02,0.3692255e-02,0.3267943e-02,0.2801670e-02},
  446. {0.8609083e-06,0.6590103e-06,0.6145787e-06,0.5537643e-06,0.4503008e-06,
  447. 0.3966041e-06,0.2965532e-06,0.1493927e-06,0.1017134e-06,0.6065031e-07}
  448. };
  449. static const float s_sc[4][10] =
  450. {
  451. {0.1126647e-01,0.1168918e-01,0.1180978e-01,0.1196792e-01,0.1232056e-01,
  452. 0.1256952e-01,0.1319347e-01,0.1520712e-01,0.1531952e-01,0.1546761e-01},
  453. {0.7377123e-06,0.5939413e-06,0.5587120e-06,0.5125148e-06,0.4289210e-06,
  454. 0.3772760e-06,0.2648252e-06,0.9331806e-07,0.3345499e-07,0.1201109e-07},
  455. {0.3499455e-02,0.3574993e-02,0.3596591e-02,0.3622465e-02,0.3676338e-02,
  456. 0.3708858e-02,0.3770696e-02,0.3677038e-02,0.3233194e-02,0.2728013e-02},
  457. {0.2299196e-06,0.1519321e-06,0.1350890e-06,0.1155423e-06,0.8200095e-07,
  458. 0.6469735e-07,0.3610638e-07,0.6227224e-08,0.1779378e-08,0.3050002e-09}
  459. };
  460. static const float ex2[10] =
  461. {
  462. 43.83631f, 42.12415f, 41.57425f, 40.85399f, 39.1404f,
  463. 37.89763f, 34.67506f, 24.59f, 17.96726f, 10.57569f
  464. };
  465. static const float sc2[10] =
  466. {
  467. 40.28625f, 39.04473f, 38.6147f, 38.03645f, 36.61054f,
  468. 35.54456f, 32.69951f, 23.41019f, 17.15375f,10.09731f
  469. };
  470. static const float ex3[10] =
  471. {
  472. 95397.86f, 75303.6f, 70210.64f, 64218.28f, 52430.56f,
  473. 45577.68f, 31937.77f, 9637.68f, 3610.691f, 810.5614f
  474. };
  475. static const float sc3[10] =
  476. {
  477. 92977.9f, 73397.17f, 68425.49f, 62571.8f, 51049.87f,
  478. 44348.77f, 31006.21f, 9202.678f, 3344.476f, 664.1915f
  479. };
  480. static const float ex4[10] =
  481. {
  482. 54273040.f, 61981440.f, 63024320.f, 63489470.f, 61467600.f,
  483. 58179720.f, 46689090.f, 15190620.f, 5133055.f, 899859.4f
  484. };
  485. static const float sc4[10] =
  486. {
  487. 54273040.f, 61981440.f, 63024320.f, 63489470.f, 61467600.f,
  488. 58179720.f, 46689090.f, 15190620.f, 5133055.f, 899859.4f
  489. };
  490. static const float s_asy[4][10] =
  491. {
  492. {0.896,0.885,0.880,0.877,0.867,0.860,0.845,0.836,0.905,0.871},
  493. {0.642,0.633,0.631,0.628,0.621,0.616,0.610,0.572,0.562,0.495},
  494. {0.795,0.790,0.788,0.781,0.783,0.782,0.778,0.783,0.797,0.750},
  495. {0.397,0.359,0.348,0.337,0.311,0.294,0.253,0.154,0.103,0.055}
  496. };
  497. static const float asy2[10] = { .718f, .712f, .71f, .708f, .704f, .702f, .696f, .68f, .668f, .649f };
  498. static const float asy3[10] = { .704f, .69f, .686f, .68f, .667f, .659f, .637f, .541f, .437f, .241f };
  499. static const float asy4[10] = { .705f, .744f, .751f, .757f, .762f, .759f, .737f, .586f, .372f, .139f };
  500. /* local */
  501. double coef;
  502. float sigm;
  503. double sumni;
  504. double dd[4][10];
  505. double pha[5][10][83];
  506. float ex[4][10];
  507. float sc[4][10];
  508. float asy[4][10];
  509. int i; /* crappy VS6 */
  510. /* initialize ex, sc & asy */
  511. for(i = 0; i < 4; i++)
  512. {
  513. int j;
  514. for(j = 0; j < 10; j++) ex[i][j] = s_ex[i][j];
  515. for(j = 0; j < 10; j++) sc[i][j] = s_sc[i][j];
  516. for(j = 0; j < 10; j++) asy[i][j] = s_asy[i][j];
  517. }
  518. /* optical properties of aerosol model computed from sra basic comp */
  519. for (i = 0; i < 10; ++i)
  520. {
  521. if(i == 4 && iaer == 0) sixs_aer.ext[i] = 1.f;
  522. else sixs_aer.ext[i] = 0.f;
  523. sca[i] = 0.f;
  524. sixs_aer.ome[i] = 0.f;
  525. sixs_aer.gasym[i] = 0.f;
  526. sixs_aer.phase[i] = 0.f;
  527. for (int k = 1; k <= 83; ++k) sixs_sos.phasel[i][k] = 0.f;
  528. }
  529. /* return if iear = 0 */
  530. if(iaer == 0) return;
  531. /* look for an interval in cgaus */
  532. long int j1 = -1;
  533. for (i = 0; i < 82; ++i)
  534. if (xmud >= sixs_sos.cgaus[i] && xmud < sixs_sos.cgaus[i+1]) { j1 = i; break; }
  535. if(j1 == -1) return; /* unable to find interval */
  536. coef = -(xmud - sixs_sos.cgaus[j1]) / (sixs_sos.cgaus[j1+1] - sixs_sos.cgaus[j1]);
  537. switch(iaer)
  538. {
  539. case 12: /* read from file */
  540. {
  541. load();
  542. for(i = 0; i < 10; i++)
  543. sixs_aer.phase[i] = (float)(sixs_sos.phasel[i][j1] +
  544. coef*(sixs_sos.phasel[i][j1]-sixs_sos.phasel[i][j1+1]));
  545. return;
  546. }
  547. case 5:
  548. {
  549. for(i = 0; i < 10; i++)
  550. {
  551. asy[0][i] = asy2[i];
  552. ex[0][i] = ex2[i];
  553. sc[0][i] = sc2[i];
  554. }
  555. break;
  556. }
  557. case 6:
  558. {
  559. for(i = 0; i < 10; i++)
  560. {
  561. asy[0][i] = asy3[i];
  562. ex[0][i] = ex3[i];
  563. sc[0][i] = sc3[i];
  564. }
  565. break;
  566. }
  567. case 7:
  568. {
  569. for(i = 0; i < 10; i++)
  570. {
  571. asy[0][i] = asy4[i];
  572. ex[0][i] = ex4[i];
  573. sc[0][i] = sc4[i];
  574. }
  575. break;
  576. }
  577. default:;
  578. }
  579. if(iaer >= 5 && iaer <= 11)
  580. {
  581. /* calling a special aerosol model */
  582. switch(iaer)
  583. {
  584. /* (background desert model...) */
  585. case 5: bdm(); break;
  586. /* (biomass burning model...) */
  587. case 6: bbm(); break;
  588. /* (stratospherique aerosol model...) */
  589. case 7: stm(); break;
  590. /* (user defined model from size distribution) */
  591. case 8:
  592. case 9:
  593. case 10:
  594. case 11: mie (ex, sc, asy); break;
  595. }
  596. for (int i = 0; i < 10; i++)
  597. {
  598. dd[0][i] = (*sixs_aerbas.ph)[i][j1] + coef * ((*sixs_aerbas.ph)[i][j1] - (*sixs_aerbas.ph)[i][j1+1]);
  599. for(int k = 0; k < 83; k++) pha[0][i][k] = (*sixs_aerbas.ph)[i][k];
  600. }
  601. mie_in.icp = 1;
  602. mie_in.cij[0] = 1.f;
  603. /* for normalization of the extinction coefficient */
  604. nis = 1. / ex[0][3];
  605. }
  606. else {
  607. /* calling each sra components */
  608. mie_in.icp = 4;
  609. /* -dust */
  610. dust();
  611. for(i = 0; i < 10; i++)
  612. {
  613. dd[0][i] = (*sixs_aerbas.ph)[i][j1] + coef * ((*sixs_aerbas.ph)[i][j1] - (*sixs_aerbas.ph)[i][j1+1]);
  614. for(int k = 0; k < 83; k++) pha[0][i][k] = ((*sixs_aerbas.ph))[i][k];
  615. }
  616. /* -water soluble */
  617. wate();
  618. for(i = 0; i < 10; i++)
  619. {
  620. dd[1][i] = (*sixs_aerbas.ph)[i][j1]+coef*((*sixs_aerbas.ph)[i][j1]-(*sixs_aerbas.ph)[i][j1+1]);
  621. for(int k = 0; k < 83; k++) pha[1][i][k] = (*sixs_aerbas.ph)[i][k];
  622. }
  623. /* -oceanic type */
  624. ocea();
  625. for(i = 0; i < 10; i++)
  626. {
  627. dd[2][i] = (*sixs_aerbas.ph)[i][j1]+coef*((*sixs_aerbas.ph)[i][j1]-(*sixs_aerbas.ph)[i][j1+1]);
  628. for(int k = 0; k < 83; k++) pha[2][i][k] = (*sixs_aerbas.ph)[i][k];
  629. }
  630. /* -soot */
  631. soot();
  632. for(i = 0; i < 10; i++)
  633. {
  634. dd[3][i] = (*sixs_aerbas.ph)[i][j1]+coef*((*sixs_aerbas.ph)[i][j1]-(*sixs_aerbas.ph)[i][j1+1]);
  635. for(int k = 0; k < 83; k++) pha[3][i][k] = (*sixs_aerbas.ph)[i][k];
  636. }
  637. /* summ of the c/vi calculation */
  638. sumni = 0.f;
  639. sigm = 0.f;
  640. for(i = 0; i < 4; i++) sigm+=(float)(c[i]/vi[i]);
  641. /* cij coefficients calculation */
  642. for(i = 0; i < 4; i++) {
  643. mie_in.cij[i] = (float)(c[i]/vi[i]/sigm);
  644. sumni += mie_in.cij[i]/ni[i];
  645. }
  646. nis = 1. / sumni;
  647. }
  648. /* mixing parameters calculation */
  649. for(i = 0; i < 10; i++)
  650. {
  651. for(int j = 0; j < mie_in.icp; j++)
  652. {
  653. sixs_aer.ext[i] += (float)(ex[j][i] * mie_in.cij[j]);
  654. sca[i] += (float)(sc[j][i] * mie_in.cij[j]);
  655. sixs_aer.gasym[i] += (float)(sc[j][i] * mie_in.cij[j] * asy[j][i]);
  656. sixs_aer.phase[i] += (float)(sc[j][i] * mie_in.cij[j] * dd[j][i]);
  657. for(int k = 0; k < 83; k++)
  658. sixs_sos.phasel[i][k] += (float)(sc[j][i] * mie_in.cij[j] * pha[j][i][k]);
  659. }
  660. sixs_aer.ome[i] = sca[i]/sixs_aer.ext[i];
  661. sixs_aer.gasym[i] /= sca[i];
  662. sixs_aer.phase[i] /= sca[i];
  663. for(int k = 0; k < 83; k++) sixs_sos.phasel[i][k] /= sca[i];
  664. sixs_aer.ext[i] *= (float)nis;
  665. sca[i] *= (float)nis;
  666. }
  667. if (filename.size() != 0 && iaer >= 8 && iaer <= 11) save();
  668. }
  669. void AerosolModel::parse(const float xmud)
  670. {
  671. cin >> iaer;
  672. cin.ignore(numeric_limits<int>::max(),'\n');
  673. /* initialize vars; */
  674. mie_in.rmin = 0.f;
  675. mie_in.rmax = 0.f;
  676. mie_in.icp = 1;
  677. int i;
  678. for(i = 0; i < 4; i++)
  679. {
  680. mie_in.cij[i] = 0.f;
  681. mie_in.x1[i] = 0.f;
  682. mie_in.x2[i] = 0.f;
  683. mie_in.x3[i] = 0.f;
  684. for(int j = 0; j < 10; j++)
  685. {
  686. mie_in.rn[j][i] = 0.f;
  687. mie_in.ri[j][i] = 0.f;
  688. }
  689. }
  690. for(i = 0; i < 50; i++)
  691. {
  692. mie_in.rsunph[i] = 0.f;
  693. mie_in.nrsunph[i] = 0.f;
  694. }
  695. mie_in.cij[0] = 1.00f;
  696. switch (iaer)
  697. {
  698. case 0:
  699. case 5:
  700. case 6:
  701. case 7: break; /* do nothing */
  702. case 1:
  703. {
  704. c[0]=0.70f;
  705. c[1]=0.29f;
  706. c[2]=0.00f;
  707. c[3]=0.01f;
  708. break;
  709. }
  710. case 2:
  711. {
  712. c[0]=0.00f;
  713. c[1]=0.05f;
  714. c[2]=0.95f;
  715. c[3]=0.00f;
  716. break;
  717. }
  718. case 3:
  719. {
  720. c[0]=0.17f;
  721. c[1]=0.61f;
  722. c[2]=0.00f;
  723. c[3]=0.22f;
  724. break;
  725. }
  726. case 4:
  727. {
  728. for(int i = 0; i < 4; i++) cin >> c[i];
  729. cin.ignore(numeric_limits<int>::max(),'\n');
  730. break;
  731. }
  732. case 8:
  733. {
  734. cin >> mie_in.rmin;
  735. cin >> mie_in.rmax;
  736. cin >> mie_in.icp;
  737. cin.ignore(numeric_limits<int>::max(),'\n');
  738. if(mie_in.icp >= 4) {
  739. G_fatal_error(_("mie_in.icp: %ld > 4, will cause internal buffer overflow"), mie_in.icp);
  740. }
  741. for(int i = 0; i < mie_in.icp; i++)
  742. {
  743. cin >> mie_in.x1[i];
  744. cin >> mie_in.x2[i];
  745. cin >> mie_in.cij[i];
  746. cin.ignore(numeric_limits<int>::max(),'\n');
  747. int j;
  748. for(j = 0; j < 10; j++) cin >> mie_in.rn[j][i];
  749. cin.ignore(numeric_limits<int>::max(),'\n');
  750. for(j = 0; j < 10; j++) cin >> mie_in.ri[j][i];
  751. cin.ignore(numeric_limits<int>::max(),'\n');
  752. }
  753. break;
  754. }
  755. case 9:
  756. {
  757. cin >> mie_in.rmin;
  758. cin >> mie_in.rmax;
  759. cin.ignore(numeric_limits<int>::max(),'\n');
  760. cin >> mie_in.x1[0];
  761. cin >> mie_in.x2[0];
  762. cin >> mie_in.x3[0];
  763. cin.ignore(numeric_limits<int>::max(),'\n');
  764. int j;
  765. for(j = 0; j < 10; j++) cin >> mie_in.rn[j][0];
  766. cin.ignore(numeric_limits<int>::max(),'\n');
  767. for(j = 0; j < 10; j++) cin >> mie_in.ri[j][0];
  768. cin.ignore(numeric_limits<int>::max(),'\n');
  769. break;
  770. }
  771. case 10:
  772. {
  773. cin >> mie_in.rmin;
  774. cin >> mie_in.rmax;
  775. cin.ignore(numeric_limits<int>::max(),'\n');
  776. cin >> mie_in.x1[0];
  777. cin.ignore(numeric_limits<int>::max(),'\n');
  778. int j;
  779. for(j = 0; j < 10; j++) cin >> mie_in.rn[j][0];
  780. cin.ignore(numeric_limits<int>::max(),'\n');
  781. for(j = 0; j < 10; j++) cin >> mie_in.ri[j][0];
  782. cin.ignore(numeric_limits<int>::max(),'\n');
  783. break;
  784. }
  785. case 11:
  786. {
  787. cin >> mie_in.irsunph;
  788. cin.ignore(numeric_limits<int>::max(),'\n');
  789. if(mie_in.irsunph >= 50) {
  790. G_fatal_error(_("mie_in.irsunph: %ld > 50, will cause internal buffer overflow"), mie_in.irsunph);
  791. }
  792. int i;
  793. for(i = 0; i < mie_in.irsunph; i++)
  794. {
  795. cin >> mie_in.rsunph[i];
  796. cin >> mie_in.nrsunph[i];
  797. cin.ignore(numeric_limits<int>::max(),'\n');
  798. double sq = mie_in.rsunph[i]*mie_in.rsunph[i];
  799. const double ln10 = 2.3025850929940456840179914546844;
  800. mie_in.nrsunph[i] = (float)(mie_in.nrsunph[i]/(sq*sq)/ln10);
  801. }
  802. mie_in.rmin=mie_in.rsunph[0];
  803. mie_in.rmax=mie_in.rsunph[mie_in.irsunph-1]+1e-07f;
  804. for(i = 0; i < 10; i++) cin >> mie_in.rn[i][0];
  805. cin.ignore(numeric_limits<int>::max(),'\n');
  806. for(i = 0; i < 10; i++) cin >> mie_in.ri[i][0];
  807. cin.ignore(numeric_limits<int>::max(),'\n');
  808. break;
  809. }
  810. case 12:
  811. { /* read file name */
  812. getline(cin,filename);
  813. filename = filename.substr(0, filename.find(" "));
  814. break;
  815. }
  816. default: G_warning(_("Unknown aerosol model!"));
  817. }
  818. if(iaer >= 8 && iaer <= 11)
  819. {
  820. cin >> iaerp;
  821. if( iaerp == 1 ) /* read file name */
  822. {
  823. getline(cin,filename);
  824. filename = filename.substr(0, filename.find(" "));
  825. filename += ".mie";
  826. }
  827. }
  828. aeroso(xmud);
  829. }
  830. /* format 132 */
  831. void AerosolModel::print132(string s)
  832. {
  833. Output::Begin();
  834. Output::Repeat(15, ' ');
  835. Output::Print(s);
  836. Output::Print(" aerosols model");
  837. Output::End();
  838. }
  839. /* --- aerosols model ---- */
  840. void AerosolModel::print()
  841. {
  842. /* --- aerosols model (type) ---- */
  843. Output::Begin();
  844. Output::Repeat(10, ' ');
  845. Output::Print(" aerosols type identity :");
  846. Output::End();
  847. if(iaer == 4 || (iaer >= 8 && iaer != 11))
  848. {
  849. Output::Begin();
  850. Output::Repeat(15, ' ');
  851. Output::Print(" user defined aerosols model ");
  852. Output::End();
  853. }
  854. switch(iaer)
  855. {
  856. case 0:
  857. {
  858. Output::Begin();
  859. Output::Repeat(15, ' ');
  860. Output::Print(" no aerosols computed ");
  861. Output::End();
  862. break;
  863. }
  864. case 1: print132(" Continental"); break;
  865. case 2: print132(" Maritime"); break;
  866. case 3: print132(" Urban"); break;
  867. case 4:
  868. {
  869. static const string desc[4] = {
  870. string(" % of dust-like"),
  871. string(" % of water-soluble"),
  872. string(" % of oceanic"),
  873. string(" % of soot")
  874. };
  875. for(int i = 0; i < 4; i++)
  876. {
  877. Output::Begin();
  878. Output::Repeat(26, ' ');
  879. ostringstream s;
  880. s.setf(ios::fixed, ios::floatfield);
  881. s << setprecision(3);
  882. s << c[i] << desc[i] << ends;
  883. Output::Print(s.str());
  884. Output::End();
  885. }
  886. break;
  887. }
  888. case 5: print132(" Desertic"); break;
  889. case 6: print132(" Smoke"); break;
  890. case 7: print132(" Stratospheric"); break;
  891. case 8:
  892. {
  893. Output::Begin();
  894. Output::Repeat(15, ' ');
  895. ostringstream s;
  896. s << "using " << mie_in.icp << " Log-normal size-distribution(s)" << ends;
  897. Output::Print(s.str());
  898. Output::End();
  899. Output::Begin();
  900. Output::Repeat(15, ' ');
  901. Output::Print("Mean radius Stand. Dev. Percent. dencity");
  902. Output::End();
  903. for(int i = 0; i < mie_in.icp; i++)
  904. {
  905. Output::Begin();
  906. Output::Position(41);
  907. ostringstream s1;
  908. s1.setf(ios::fixed, ios::floatfield);
  909. s1 << setprecision(4);
  910. s1 << setw(10) << mie_in.x1[i] << ends;
  911. Output::Print(s1.str());
  912. Output::Position(55);
  913. ostringstream s2;
  914. s2.setf(ios::fixed, ios::floatfield);
  915. s2 << setprecision(3);
  916. s2 << setw(8) << mie_in.x2[i] << ends;
  917. Output::Print(s2.str());
  918. Output::Position(69);
  919. ostringstream s3;
  920. s3.setf(ios::fixed, ios::floatfield);
  921. s3 << setprecision(3);
  922. s3 << setw(11) << mie_in.cij[i] << ends;
  923. Output::Print(s3.str());
  924. Output::End();
  925. }
  926. break;
  927. }
  928. case 9:
  929. {
  930. Output::Begin();
  931. Output::Repeat(15, ' ');
  932. Output::Print("using a Modified Gamma size-distribution");
  933. Output::End();
  934. Output::Begin();
  935. Output::Repeat(19, ' ');
  936. Output::Print("Alpha b Gamma");
  937. Output::End();
  938. Output::Begin();
  939. Output::Position(20);
  940. ostringstream s1;
  941. s1.setf(ios::fixed, ios::floatfield);
  942. s1 << setprecision(3);
  943. s1 << setw(9) << mie_in.x1[0] << ends;
  944. Output::Print(s1.str());
  945. Output::Position(31);
  946. ostringstream s2;
  947. s2.setf(ios::fixed, ios::floatfield);
  948. s2 << setprecision(3);
  949. s2 << setw(9) << mie_in.x2[0] << ends;
  950. Output::Print(s2.str());
  951. Output::Position(47);
  952. ostringstream s3;
  953. s3.setf(ios::fixed, ios::floatfield);
  954. s3 << setprecision(3);
  955. s3 << setw(9) << mie_in.x3[0] << ends;
  956. Output::Print(s3.str());
  957. Output::End();
  958. break;
  959. }
  960. case 10:
  961. {
  962. Output::Begin();
  963. Output::Repeat(15, ' ');
  964. Output::Print("using a Power law size-distribution with alpha=");
  965. ostringstream s;
  966. s.setf(ios::fixed, ios::floatfield);
  967. s << setprecision(1);
  968. s << setw(4) << mie_in.x1[0] << ends;
  969. Output::Print(s.str());
  970. Output::End();
  971. break;
  972. }
  973. case 11: print132(" Sun Photometer"); break;
  974. case 12:
  975. {
  976. Output::Begin();
  977. Output::Repeat(15, ' ');
  978. Output::Print("using data from the file:");
  979. Output::End();
  980. Output::Begin();
  981. Output::Position(25);
  982. Output::Print(filename);
  983. Output::End();
  984. }
  985. }
  986. if(iaer > 7 && iaerp == 1)
  987. {
  988. Output::Begin();
  989. Output::Repeat(15, ' ');
  990. Output::Print(" results saved into the file:");
  991. Output::End();
  992. Output::Begin();
  993. Output::Position(25);
  994. Output::Print(filename);
  995. Output::End();
  996. }
  997. }
  998. AerosolModel AerosolModel::Parse(const float xmud)
  999. {
  1000. AerosolModel aero;
  1001. aero.parse(xmud);
  1002. return aero;
  1003. }