Altitude.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. #include "common.h"
  2. #include "Altitude.h"
  3. #include "AtmosModel.h"
  4. #include "AerosolConcentration.h"
  5. /* Update the atmospheric profile (P(z),T(z),H2O(z),O3(z)) in case the target
  6. is not at sea level.
  7. Given the altitude of the target in kilometers as input, we transform the
  8. original atmospheric profile (Pressure, Temperature, Water Vapor, Ozone)
  9. so that first level of the new profile is the one at the target altitude.
  10. We also compute the new integrated content in water vapor and ozone, that
  11. are used as outputs or in computations when the user chooses to enter a
  12. specific amount of Ozone and Water Vapor.
  13. */
  14. void Altitude::pressure(AtmosModel& atms, float& uw, float& uo3)
  15. {
  16. /* log linear interpolation */
  17. if(xps >= 100) xps = 99.99f;
  18. int i;
  19. for(i = 0; atms.z[i] <= xps; i++);
  20. int isup = i;
  21. int iinf = i - 1;
  22. float xa = (float)((atms.z[isup] - atms.z[iinf]) / log(atms.p[isup] / atms.p[iinf]));
  23. float xb = (float)(atms.z[isup] - xa * log(atms.p[isup]));
  24. float ps = (float)exp((xps - xb) / xa);
  25. /* interpolating temperature wator vapor and ozone profile versus altitude */
  26. float xalt = xps;
  27. float xtemp = (atms.t[isup] - atms.t[iinf]) / (atms.z[isup] - atms.z[iinf]);
  28. xtemp = xtemp * (xalt - atms.z[iinf]) + atms.t[iinf];
  29. float xwo = (atms.wo[isup] - atms.wo[iinf]) / (atms.z[isup] - atms.z[iinf]);
  30. xwo = xwo * (xalt - atms.z[iinf]) + atms.wo[iinf];
  31. float xwh = (atms.wh[isup] - atms.wh[iinf]) / (atms.z[isup] - atms.z[iinf]);
  32. xwh = xwh * (xalt - atms.z[iinf]) + atms.wh[iinf];
  33. /* updating atmospheric profile
  34. 1rst level: target , complete to 34
  35. with interpolated layers */
  36. atms.z[0] = xalt;
  37. atms.p[0] = ps;
  38. atms.t[0] = xtemp;
  39. atms.wh[0] = xwh;
  40. atms.wo[0] = xwo;
  41. for (i = 1; i < 33 - iinf; ++i)
  42. {
  43. atms.z[i] = atms.z[i + iinf];
  44. atms.p[i] = atms.p[i + iinf];
  45. atms.t[i] = atms.t[i + iinf];
  46. atms.wh[i] = atms.wh[i + iinf];
  47. atms.wo[i] = atms.wo[i + iinf];
  48. }
  49. int l = 33 - iinf - 1;
  50. for (i = l; i < 34; ++i)
  51. {
  52. atms.z[i] = (atms.z[33] - atms.z[l]) * (i - l) / (33 - l) + atms.z[l];
  53. atms.p[i] = (atms.p[33] - atms.p[l]) * (i - l) / (33 - l) + atms.p[l];
  54. atms.t[i] = (atms.t[33] - atms.t[l]) * (i - l) / (33 - l) + atms.t[l];
  55. atms.wh[i] = (atms.wh[33] - atms.wh[l]) * (i - l) / (33 - l) + atms.wh[l];
  56. atms.wo[i] = (atms.wo[33] - atms.wo[l]) * (i - l) / (33 - l) + atms.wo[l];
  57. }
  58. /* compute modified h2o and o3 integrated content */
  59. uw = 0;
  60. uo3 = 0;
  61. const float g = 98.1f;
  62. const float air = 0.028964f/0.0224f;
  63. const float ro3 = 0.048f/0.0224f;
  64. float rmwh[34];
  65. float rmo3[34];
  66. int k;
  67. for (k = 0; k < 33; ++k)
  68. {
  69. float roair = air * 273.16f * atms.p[k] / (atms.t[k] * 1013.25f);
  70. rmwh[k] = atms.wh[k] / (roair * 1e3f);
  71. rmo3[k] = atms.wo[k] / (roair * 1e3f);
  72. }
  73. for (k = 1; k < 33; ++k)
  74. {
  75. float ds = (atms.p[k - 1] - atms.p[k]) / atms.p[0];
  76. uw += (rmwh[k] + rmwh[k - 1]) * ds / 2.f;
  77. uo3 += (rmo3[k] + rmo3[k - 1]) * ds / 2.f;
  78. }
  79. uw = uw * atms.p[0] * 100.f / g;
  80. uo3 = uo3 * atms.p[0] * 100.f / g;
  81. uo3 = uo3 * 1e3f / ro3;
  82. }
  83. /*
  84. Function: Update the atmospheric profile (P(z),T(z),H2O(z),O3(z)) in case the observer is on
  85. board an aircraft.
  86. Description: Given the altitude or pressure at aircraft level as input, the first task is to
  87. compute the altitude (in case the pressure has been entered) or the pressure (in case the altitude has
  88. been entered) at plane level. Then, a new atmospheric profile is created (Pp,Tp,H2Op,O3p) for which
  89. the last level is located at the plane altitude. This profile is used in the gaseous absorption
  90. computation (ABSTRA.f) for the path from target to sensor (upward transmission). The ozone and
  91. water vapor integrated content of the "plane" atmospheric profile are also an output of this
  92. subroutine. The last output is the proportion of molecules below plane level which is useful in
  93. scattering computations (OS.f,ISO.f).
  94. */
  95. void Altitude::presplane(AtmosModel& atms)
  96. {
  97. /* log linear interpolation */
  98. xpp += atms.z[0];
  99. if(xpp >= 100) xpp = 1000;
  100. int i;
  101. for(i = 0; atms.z[i] <= xpp; i++);
  102. int isup = i;
  103. int iinf = i-1;
  104. float xa = (float)((atms.z[isup] - atms.z[iinf]) / log(atms.p[isup] / atms.p[iinf]));
  105. float xb = (float)(atms.z[isup] - xa * log(atms.p[isup]));
  106. float ps = (float)(exp((xpp - xb) / xa));
  107. /* interpolating temperature wator vapor and ozone profile versus altitud */
  108. float xalt = xpp;
  109. float xtemp = (atms.t[isup] - atms.t[iinf])/ (atms.z[isup] - atms.z[iinf]);
  110. xtemp = xtemp * (xalt - atms.z[iinf]) + atms.t[iinf];
  111. float xwo = (atms.wo[isup] - atms.wo[iinf]) / (atms.z[isup] - atms.z[iinf]);
  112. xwo = xwo * (xalt - atms.z[iinf]) + atms.wo[iinf];
  113. float xwh = (atms.wh[isup] - atms.wh[iinf]) / (atms.z[isup] - atms.z[iinf]);
  114. xwh = xwh * (xalt - atms.z[iinf]) + atms.wh[iinf];
  115. /* updating atmospheric profile
  116. last level: plane , complete to 34
  117. with interpolated layers */
  118. for(i = 0; i <= iinf; i++)
  119. {
  120. plane_sim.zpl[i] = atms.z[i];
  121. plane_sim.ppl[i] = atms.p[i];
  122. plane_sim.tpl[i] = atms.t[i];
  123. plane_sim.whpl[i] = atms.wh[i];
  124. plane_sim.wopl[i] = atms.wo[i];
  125. }
  126. for(i = iinf+1; i < 34; i++)
  127. {
  128. plane_sim.zpl[i] = xalt;
  129. plane_sim.ppl[i] = ps;
  130. plane_sim.tpl[i] = xtemp;
  131. plane_sim.whpl[i] = xwh;
  132. plane_sim.wopl[i] = xwo;
  133. }
  134. /* compute modified h2o and o3 integrated content
  135. compute conversion factor for rayleigh optical thickness computation
  136. ftray=rp/rt */
  137. atms.uw = 0;
  138. atms.uo3 = 0;
  139. const float g = 98.1f;
  140. const float air = 0.028964f/0.0224f;
  141. const float ro3 = 0.048f/0.0224f;
  142. float rt = 0;
  143. float rp = 0;
  144. float rmo3[34];
  145. float rmwh[34];
  146. int k;
  147. for(k = 0; k < 33; k++)
  148. {
  149. float roair = (float)(air * 273.16 * plane_sim.ppl[k] / (1013.25 * plane_sim.tpl[k]));
  150. rmwh[k] = atms.wh[k] / (roair * 1000);
  151. rmo3[k] = atms.wo[k] / (roair * 1000);
  152. rt += (atms.p[k+1] / atms.t[k+1] + atms.p[k] / atms.p[k]) * (atms.z[k+1] - atms.z[k]);
  153. rp += (plane_sim.ppl[k+1] / plane_sim.tpl[k+1] + plane_sim.ppl[k] / plane_sim.tpl[k])
  154. * (plane_sim.zpl[k+1] - plane_sim.zpl[k]);
  155. }
  156. ftray = rp / rt;
  157. for(k = 1; k < 33; k++)
  158. {
  159. float ds = (plane_sim.ppl[k-1] - plane_sim.ppl[k]) / plane_sim.ppl[0];
  160. atms.uw += (rmwh[k] + rmwh[k-1])*ds/2;
  161. atms.uo3+= (rmo3[k] + rmo3[k-1])*ds/2;
  162. }
  163. atms.uw *= plane_sim.ppl[0] * 100 / g;
  164. atms.uo3*= plane_sim.ppl[0] * 100 / g;
  165. atms.uo3*= 1000 / ro3;
  166. }
  167. void Altitude::init(AtmosModel &atms, const AerosolConcentration &aerocon)
  168. {
  169. xps = original_xps;
  170. xpp = original_xpp;
  171. float uwus;
  172. float uo3us;
  173. if(xps <= 0)
  174. {
  175. xps = 0;
  176. uwus = 1.424f;
  177. uo3us = 0.344f;
  178. }
  179. else if(atms.idatm != 8) pressure(atms, atms.uw, atms.uo3);
  180. else pressure(atms, uwus, uo3us);
  181. if(xpp <= 0)
  182. {
  183. /* ground measurement option */
  184. palt = 0;
  185. pps = atms.p[0];
  186. idatmp = 0;
  187. original_taer55p = taer55p = 0;
  188. puw = 0;
  189. }
  190. else if(xpp >= 100)
  191. {
  192. /* satellite case of equivalent */
  193. palt = 1000;
  194. pps = 0;
  195. original_taer55p = taer55p = aerocon.taer55;
  196. puw = 0;
  197. ftray = 1;
  198. idatmp = 4;
  199. }
  200. else
  201. {
  202. /* "real" plane case */
  203. cin >> original_puw;
  204. cin >> original_puo3;
  205. cin.ignore(numeric_limits < int >::max(), '\n'); /* ignore comments */
  206. puw = original_puw;
  207. puo3 = original_puo3;
  208. if ( puw < 0 )
  209. {
  210. presplane(atms);
  211. idatmp = 2;
  212. if (atms.idatm == 8)
  213. {
  214. puwus = puw;
  215. puo3us = puo3;
  216. puw *= atms.uw / uwus;
  217. puo3 *= atms.uo3 / uo3us;
  218. idatmp = 8;
  219. }
  220. }
  221. else
  222. {
  223. presplane(atms);
  224. idatmp = 8;
  225. }
  226. palt = plane_sim.zpl[33] - atms.z[0];
  227. pps = plane_sim.ppl[33];
  228. cin >> original_taer55p;
  229. taer55p = original_taer55p;
  230. if ((taer55p > 0) || ((aerocon.taer55 - taer55p) < 1e-03))
  231. {
  232. /* a scale heigh of 2km is assumed in case no value is given for taer55p */
  233. taer55p = (float)(aerocon.taer55 * (1 - exp(-palt / 2)));
  234. }
  235. else
  236. {
  237. /* compute effective scale heigh */
  238. double sham = exp(-palt / 4);
  239. double sha = 1 - (taer55p / aerocon.taer55);
  240. if( sha >= sham) taer55p = (float)(aerocon.taer55 * (1 - exp(-palt / 4)));
  241. else {
  242. sha = -palt/log(sha);
  243. taer55p = (float)(aerocon.taer55 * (1 - exp(-palt/sha)));
  244. }
  245. }
  246. }
  247. }
  248. void Altitude::update_hv(AtmosModel & atms, const AerosolConcentration & aerocon)
  249. {
  250. xps = original_xps;
  251. xpp = original_xpp;
  252. float uwus;
  253. float uo3us;
  254. if (xps <= 0) {
  255. xps = 0;
  256. uwus = 1.424f;
  257. uo3us = 0.344f;
  258. }
  259. else if (atms.idatm != 8)
  260. pressure(atms, atms.uw, atms.uo3);
  261. else
  262. pressure(atms, uwus, uo3us);
  263. if (xpp <= 0) {
  264. /* ground measurement option */
  265. palt = 0;
  266. pps = atms.p[0];
  267. idatmp = 0;
  268. taer55p = 0;
  269. puw = 0;
  270. }
  271. else if (xpp >= 100) {
  272. /* satellite case of equivalent */
  273. palt = 1000;
  274. pps = 0;
  275. taer55p = aerocon.taer55;
  276. puw = 0;
  277. ftray = 1;
  278. idatmp = 4;
  279. }
  280. else {
  281. /* "real" plane case */
  282. puw = original_puw;
  283. puo3 = original_puo3;
  284. if (puw < 0) {
  285. presplane(atms);
  286. idatmp = 2;
  287. if (atms.idatm == 8) {
  288. puwus = puw;
  289. puo3us = puo3;
  290. puw *= atms.uw / uwus;
  291. puo3 *= atms.uo3 / uo3us;
  292. idatmp = 8;
  293. }
  294. }
  295. else {
  296. presplane(atms);
  297. idatmp = 8;
  298. }
  299. palt = plane_sim.zpl[33] - atms.z[0];
  300. pps = plane_sim.ppl[33];
  301. taer55p = original_taer55p;
  302. if ((taer55p > 0) || ((aerocon.taer55 - taer55p) < 1e-03)) {
  303. /* a scale heigh of 2km is assumed in case no value is given for taer55p */
  304. taer55p = (float)(aerocon.taer55 * (1 - exp(-palt / 2)));
  305. }
  306. else {
  307. /* compute effective scale heigh */
  308. double sham = exp(-palt / 4);
  309. double sha = 1 - (taer55p / aerocon.taer55);
  310. if (sha >= sham)
  311. taer55p = (float)(aerocon.taer55 * (1 - exp(-palt / 4)));
  312. else {
  313. sha = -palt / log(sha);
  314. taer55p = (float)(aerocon.taer55 * (1 - exp(-palt / sha)));
  315. }
  316. }
  317. }
  318. }
  319. void Altitude::parse()
  320. {
  321. cin >> original_xps;
  322. cin.ignore(numeric_limits<int>::max(),'\n'); /* ignore comments */
  323. original_xps = -original_xps;
  324. cin >> original_xpp;
  325. cin.ignore(numeric_limits<int>::max(),'\n'); /* ignore comments */
  326. original_xpp = -original_xpp;
  327. }
  328. /* --- plane simulation output if selected ---- */
  329. void Altitude::print()
  330. {
  331. if(palt < 1000)
  332. {
  333. Output::Ln();
  334. Output::WriteLn(22," plane simulation description ");
  335. Output::WriteLn(22," ---------------------------- ");
  336. ostringstream s1;
  337. s1.setf(ios::fixed, ios::floatfield);
  338. s1.precision(2);
  339. s1 << " plane pressure [mb] " << setw(9) << pps << ends;
  340. Output::WriteLn(10,s1.str());
  341. ostringstream s2;
  342. s2.setf(ios::fixed, ios::floatfield);
  343. s2.precision(3);
  344. s2 << " plane altitude absolute [km] " << setw(9) << plane_sim.zpl[33] << ends;
  345. Output::WriteLn(10,s2.str());
  346. Output::WriteLn(15," atmosphere under plane description: ");
  347. ostringstream s3;
  348. s3.setf(ios::fixed, ios::floatfield);
  349. s3.precision(3);
  350. s3 << " ozone content " << setw(9) << puo3 << ends;
  351. Output::WriteLn(15,s3.str());
  352. ostringstream s4;
  353. s4.setf(ios::fixed, ios::floatfield);
  354. s4.precision(3);
  355. s4 << " h2o content " << setw(9) << puw << ends;
  356. Output::WriteLn(15,s4.str());
  357. ostringstream s5;
  358. s5.setf(ios::fixed, ios::floatfield);
  359. s5.precision(3);
  360. s5 << "aerosol opt. thick. 550nm " << setw(9) << taer55p << ends;
  361. Output::WriteLn(15,s5.str());
  362. }
  363. }
  364. Altitude Altitude::Parse()
  365. {
  366. Altitude alt;
  367. alt.parse();
  368. return alt;
  369. }