|
Isis 3.0 Object Programmers' Reference |
Home |
00001 #include <cmath> 00002 #include "Anisotropic2.h" 00003 #include "AtmosModel.h" 00004 #include "Constants.h" 00005 #include "Pvl.h" 00006 #include "PvlGroup.h" 00007 #include "iException.h" 00008 #include "iString.h" 00009 00010 using std::min; 00011 using std::max; 00012 00013 namespace Isis { 00014 Anisotropic2::Anisotropic2 (Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl,pmodel) { 00015 00016 // Set default value 00017 SetAtmosHnorm(0.003); 00018 00019 // Get value from user 00020 PvlGroup &algorithm = pvl.FindObject("AtmosphericModel").FindGroup("Algorithm",Pvl::Traverse); 00021 if (algorithm.HasKeyword("Hnorm")) { 00022 SetAtmosHnorm(algorithm["Hnorm"]); 00023 } 00024 } 00025 00036 void Anisotropic2::SetAtmosHnorm (const double hnorm) { 00037 if (hnorm < 0.0) { 00038 std::string msg = "Invalid value of Atmospheric hnorm [" + iString(hnorm) + "]"; 00039 throw iException::Message(iException::User,msg,_FILEINFO_); 00040 } 00041 00042 p_atmosHnorm = hnorm; 00043 } 00044 00068 void Anisotropic2::AtmosModelAlgorithm (double phase, double incidence, double emission) 00069 { 00070 double xx; 00071 double munot,mu; 00072 double emunot,emu; 00073 double munotp,mup; 00074 double gmunot,gmu; 00075 double hpsq1; 00076 double f1munot,f2munot,f3munot; 00077 double f1mmunot,f2mmunot,f3mmunot; 00078 double maxval; 00079 double f1mu,f2mu,f3mu; 00080 double f1mmu,f2mmu,f3mmu; 00081 double sum; 00082 double prod; 00083 double cosazss; 00084 double xystuff; 00085 double xmunot_0,ymunot_0; 00086 double xmu_0,ymu_0; 00087 double cxx,cyy; 00088 double xmunot_1,ymunot_1; 00089 double xmu_1,ymu_1; 00090 00091 if (p_atmosBha == 0.0) { 00092 p_atmosBha = 1.0e-6; 00093 } 00094 00095 if (p_atmosTau == 0.0) { 00096 p_pstd = 0.0; 00097 p_trans = 1.0; 00098 p_trans0 = 1.0; 00099 p_sbar = 0.0; 00100 return; 00101 } 00102 00103 if (p_atmosWha == 1.0) { 00104 std::string msg = "Anisotropic conservative case not implemented yet"; 00105 throw iException::Message(iException::User,msg,_FILEINFO_); 00106 } 00107 00108 if (TauOrWhaChanged()) { 00109 // preparation includes exponential integrals e sub 2 through 5 00110 p_wha2 = 0.5 * p_atmosWha; 00111 p_wham = 1.0 - p_atmosWha; 00112 p_e1 = AtmosModel::En(1,p_atmosTau); 00113 p_e1_2 = AtmosModel::En(1,2.0*p_atmosTau); 00114 p_e2 = AtmosModel::En(2,p_atmosTau); 00115 p_e3 = AtmosModel::En(3,p_atmosTau); 00116 p_e4 = AtmosModel::En(4,p_atmosTau); 00117 p_e5 = AtmosModel::En(5,p_atmosTau); 00118 00119 // chandra's gmn functions require fm and fn at mu=-1 00120 xx = -p_atmosTau; 00121 if (xx < -69.0) { 00122 p_em = 0.0; 00123 } 00124 else if (xx > 69.0) { 00125 p_em = 1.0e30; 00126 } 00127 else { 00128 p_em = exp(xx); 00129 } 00130 00131 p_f1m = log(2.0) - p_em * p_e1 + p_e1_2; 00132 p_f2m = -1.0 * (p_f1m + p_em * p_e2 - 1.0); 00133 p_f3m = -1.0 * (p_f2m + p_em * p_e3 - 0.5); 00134 p_f4m = -1.0 * (p_f3m + p_em * p_e4 - (1.0/3.0)); 00135 p_g12 = (p_atmosTau * p_e1 * p_e2 + p_f1m + p_f2m) * 0.5; 00136 p_g13 = (p_atmosTau * p_e1 * p_e3 + p_f1m + p_f3m) * (1.0/3.0); 00137 p_g14 = (p_atmosTau * p_e1 * p_e4 + p_f1m + p_f4m) * 0.25; 00138 p_g32 = (p_atmosTau * p_e3 * p_e2 + p_f3m + p_f2m) * 0.25; 00139 p_g33 = (p_atmosTau * p_e3 * p_e3 + p_f3m + p_f3m) * 0.2; 00140 p_g34 = (p_atmosTau * p_e3 * p_e4 + p_f3m * p_f4m) * (1.0/6.0); 00141 00142 // chandra's g'mn functions require g'11 and f at mu=+1 00143 xx = p_atmosTau; 00144 if (xx < -69.0) { 00145 p_e = 0.0; 00146 } 00147 else if (xx > 69.0) { 00148 p_e = 1.0e30; 00149 } 00150 else { 00151 p_e = exp(xx); 00152 } 00153 00154 p_f1 = Eulgam() + log(p_atmosTau) + p_e * p_e1; 00155 p_f2 = p_f1 + p_e * p_e2 - 1.0; 00156 p_f3 = p_f2 + p_e * p_e3 - 0.5; 00157 p_f4 = p_f3 + p_e * p_e4 - (1.0/3.0); 00158 p_g11p = AtmosModel::G11Prime(p_atmosTau); 00159 p_g12p = (p_atmosTau * (p_e1 - p_g11p) + p_em * (p_f1 + p_f2)) * 0.25; 00160 p_g13p = (p_atmosTau * (0.5 * p_e1 - p_g12p) + p_em * (p_f1 + p_f3)) * 0.2; 00161 p_g14p = (p_atmosTau * ((1.0/3.0) * p_e1 - p_g13p) + p_em * (p_f1 + p_f4)) * (1.0/6.0); 00162 p_g32p = (p_atmosTau * (p_e1 - p_g13p) + p_em * (p_f3 + p_f2)) * (1.0/6.0); 00163 p_g33p = (p_atmosTau * (0.5 * p_e1 - p_g32p) + p_em * (p_f3 + p_f3)) * 0.142857; 00164 p_g34p = (p_atmosTau * ((1.0/3.0) * p_e1 - p_g33p) + p_em * (p_f3 + p_f4)) * 0.125; 00165 00166 // first, get the required quantities for the axisymmetric m=0 part 00167 // zeroth moments of (uncorrected) x and y times characteristic fn 00168 p_x0_0 = p_wha2 * (1.0 + (1.0/3.0) * p_atmosBha * p_wham + p_wha2 * (p_g12 + p_atmosBha * 00169 p_wham * (p_g14 + p_g32) + pow(p_atmosBha, 2.0) * pow(p_wham,2.0) * p_g34)); 00170 p_y0_0 = p_wha2 * (p_e2 + p_atmosBha * p_wham * p_e4 + p_wha2 * (p_g12p 00171 + p_atmosBha * p_wham * (p_g14p + p_g32p) + 00172 pow(p_atmosBha, 2.0) * pow(p_wham,2.0) * p_g34p)); 00173 00174 // higher-order correction term for x and y 00175 p_delta_0 = (1.0 - (p_x0_0 + p_y0_0) - (1.0 - p_atmosWha * (1.0 + (1.0/3.0) * p_atmosBha * 00176 p_wham)) / (1.0 - (p_x0_0 - p_y0_0))) / (p_atmosWha * (0.5 - p_e3 + p_atmosBha * p_wham * (0.25 - p_e5))); 00177 00178 // moments of (corrected) x and y 00179 p_alpha0_0 = 1.0 + p_wha2 * (p_g12 + p_atmosBha * p_wham * p_g32) + p_delta_0 * (0.5 - p_e3); 00180 p_alpha1_0 = 0.5 + p_wha2 * (p_g13 + p_atmosBha * p_wham * p_g33) + p_delta_0 * ((1.0/3.0) - p_e4); 00181 p_beta0_0 = p_e2 + p_wha2 * (p_g12p + p_atmosBha * p_wham * p_g32p) + p_delta_0 * (0.5 - p_e3); 00182 p_beta1_0 = p_e3 + p_wha2 * (p_g13p + p_atmosBha * p_wham * p_g33p) + p_delta_0 * ((1.0/3.0) - p_e4); 00183 00184 // gamma will be a weighted sum of m=0 x and y functions 00185 // but unlike before, call the weights q1 and p1, and we also 00186 // need additional weights q0 and p0 00187 p_fac = 2.0 - p_atmosWha * p_alpha0_0; 00188 p_den = pow(p_fac,2.0) - pow((p_atmosWha*p_beta0_0),2.0); 00189 p_q0 = p_atmosBha * p_atmosWha * p_wham * (p_fac * p_alpha1_0 - p_atmosWha * p_beta0_0 * p_beta1_0) / p_den; 00190 p_p0 = p_atmosBha * p_atmosWha * p_wham * (-p_fac * p_beta1_0 - p_atmosWha * p_beta0_0 * p_alpha1_0) / p_den; 00191 p_q02p02 = p_q0 * p_q0 - p_p0 * p_p0; 00192 p_q1 = (2.0 * p_wham * p_fac) / p_den; 00193 p_p1 = (2.0 * p_wham * p_atmosWha * p_beta0_0) / p_den; 00194 p_q12p12 = p_q1 * p_q1 - p_p1 * p_p1; 00195 00196 // sbar is total diffuse illumination and comes from moments 00197 p_sbar = 1.0 - 2.0 * (p_q1 * p_alpha1_0 + p_p1 * p_beta1_0); 00198 00199 // we're not done yet! still have to calculate the m=1 portion 00200 // zeroth moments of (uncorrected) x and y times characteristic fn 00201 p_x0_1 = 0.5 * p_wha2 * p_atmosBha * (1.0 - (1.0/3.0) + 0.5 * p_wha2 * p_atmosBha * 00202 (p_g12 - (p_g14 + p_g32) + p_g34)); 00203 p_y0_1 = 0.5 * p_wha2 * p_atmosBha * (p_e2 - p_e4 + 0.5 * p_wha2 * p_atmosBha * 00204 (p_g12p - (p_g14p + p_g32p) + p_g34p)); 00205 00206 // higher-order correction term for x and y 00207 p_delta_1 = (1.0 - (p_x0_1 + p_y0_1) - (1.0 - (1.0/3.0) * p_atmosWha * p_atmosBha) / 00208 (1.0 - (p_x0_1 - p_y0_1))) / (p_wha2 * p_atmosBha * 00209 ((0.5 - 0.25) - (p_e3 - p_e5))); 00210 00211 // moments of (corrected) x and y are not needed for m=1, so we're done 00212 SetOldTau(p_atmosTau); 00213 SetOldWha(p_atmosWha); 00214 } 00215 00216 // correct the path lengths for planetary curvature 00217 hpsq1 = pow((1.0+p_atmosHnorm),2.0) - 1.0; 00218 00219 if (incidence == 90.0) { 00220 munot = 0.0; 00221 } 00222 else { 00223 munot = cos((PI/180.0)*incidence); 00224 } 00225 00226 maxval = max(1.0e-30,hpsq1+munot*munot); 00227 munotp = p_atmosHnorm / (sqrt(maxval) - munot); 00228 munotp = max(munotp,p_atmosTau/69.0); 00229 00230 if (emission == 90.0) { 00231 mu = 0.0; 00232 } 00233 else { 00234 mu = cos((PI/180.0)*emission); 00235 } 00236 00237 maxval = max(1.0e-30,hpsq1+mu*mu); 00238 mup = p_atmosHnorm / (sqrt(maxval) - mu); 00239 mup = max(mup,p_atmosTau/69.0); 00240 00241 // build the x and y functions of mu0 and mu 00242 maxval = max(1.0e-30,munotp); 00243 xx = -p_atmosTau / maxval; 00244 if (xx < -69.0) { 00245 emunot = 0.0; 00246 } 00247 else if (xx > 69.0) { 00248 emunot = 1.0e30; 00249 } 00250 else { 00251 emunot = exp(-p_atmosTau/munotp); 00252 } 00253 00254 maxval = max(1.0e-30,mup); 00255 xx = -p_atmosTau / maxval; 00256 if (xx < -69.0) { 00257 emu = 0.0; 00258 } 00259 else if (xx > 69.0) { 00260 emu = 1.0e30; 00261 } 00262 else { 00263 emu = exp(-p_atmosTau/mup); 00264 } 00265 00266 // in the second approximation the x and y include the f1, f3 functions 00267 xx = munotp; 00268 if (fabs(xx-1.0) < 1.0e-10) { 00269 f1munot = p_f1; 00270 f1mmunot = xx * (log(1.0+1.0/xx) - p_e1 * emunot + 00271 AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); 00272 } 00273 else if (xx > 0.0) { 00274 f1munot = xx * (log(xx/(1.0-xx)) + p_e1 / emunot + 00275 AtmosModel::Ei(p_atmosTau*(1.0/xx-1.0))); 00276 f1mmunot = xx * (log(1.0+1.0/xx) - p_e1 * emunot + 00277 AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); 00278 } 00279 else { 00280 std::string msg = "Negative length of planetary curvature encountered"; 00281 throw iException::Message(iException::Math,msg,_FILEINFO_); 00282 } 00283 00284 f2munot = munotp * (f1munot + p_e2 / emunot - 1); 00285 f2mmunot = -munotp * (f1mmunot + p_e2 * emunot - 1); 00286 f3munot = munotp * (f2munot + p_e3 / emunot - 0.5); 00287 f3mmunot = -munotp * (f2mmunot + p_e3 * emunot - 0.5); 00288 xx = mup; 00289 00290 if (fabs(xx-1.0) < 1.0e-10) { 00291 f1mu = p_f1; 00292 f1mmu = xx * (log(1.0+1.0/xx) - p_e1 * emu + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); 00293 } 00294 else if (xx > 0.0) { 00295 f1mu = xx * (log(xx/(1.0-xx)) + p_e1 / emu + AtmosModel::Ei(p_atmosTau*(1.0/xx-1.0))); 00296 f1mmu = xx * (log(1.0+1.0/xx) - p_e1 * emu + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); 00297 } 00298 else { 00299 std::string msg = "Negative length of planetary curvature encountered"; 00300 throw iException::Message(iException::Math,msg,_FILEINFO_); 00301 } 00302 00303 f2mu = mup * (f1mu + p_e2 / emu - 1); 00304 f2mmu = -mup * (f1mmu + p_e2 * emu - 1); 00305 f3mu = mup * (f2mu + p_e3 / emu - 0.5); 00306 f3mmu = -mup * (f2mmu + p_e3 * emu - 0.5); 00307 00308 // first for m=0 00309 xmunot_0 = 1.0 + p_wha2 * (f1mmunot + p_atmosBha * p_wham * f3mmunot) + p_delta_0 * munotp * (1.0 - emunot); 00310 ymunot_0 = emunot * (1.0 + p_wha2 * (f1munot + p_atmosBha * p_wham * f3munot)) + 00311 p_delta_0 * munotp * (1.0 - emunot); 00312 xmu_0 = 1.0 + p_wha2 * (f1mmu + p_atmosBha * p_wham * f3mmu) + p_delta_0 * mup * (1.0 - emu); 00313 ymu_0 = emu * (1.0 + p_wha2 * (f1mu + p_atmosBha * p_wham * f3mu)) + p_delta_0 * mup * (1.0 - emu); 00314 00315 // then for m=1 00316 xmunot_1 = 1.0 + 0.5 * p_wha2 * p_atmosBha * (f1mmunot - f3mmunot) + p_delta_1 * munotp * (1.0 - emunot); 00317 ymunot_1 = emunot * (1.0 + 0.5 * p_wha2 * p_atmosBha * 00318 (f1munot - f3munot)) + p_delta_1 * munotp * (1.0 - emunot); 00319 xmu_1 = 1.0 + 0.5 * p_wha2 * p_atmosBha * (f1mmu - f3mmu) + p_delta_1 * mup * (1.0 - emu); 00320 ymu_1 = emu * (1.0 + 0.5 * p_wha2 * p_atmosBha * (f1mu - f3mu)) + p_delta_1 * mup * (1.0 - emu); 00321 00322 // gamma1 functions come from x and y with m=0 00323 gmunot = p_p1 * xmunot_0 + p_q1 * ymunot_0; 00324 gmu = p_p1 * xmu_0 + p_q1 * ymu_0; 00325 00326 // purely atmos term uses x and y of both orders and is complex 00327 sum = munot + mu; 00328 prod = munot * mu; 00329 cxx = 1.0 - p_q0 * sum + (p_q02p02 - p_atmosBha * p_q12p12) * prod; 00330 cyy = 1.0 + p_q0 * sum + (p_q02p02 - p_atmosBha * p_q12p12) * prod; 00331 00332 if (phase == 90.0) { 00333 cosazss = 0.0 - munot * mu; 00334 } 00335 else { 00336 cosazss = cos((PI/180.0)*phase) - munot * mu; 00337 } 00338 00339 xystuff = cxx * xmunot_0 * xmu_0 - cyy * ymunot_0 * 00340 ymu_0 - p_p0 * sum * (xmu_0 * ymunot_0 + ymu_0 * xmunot_0) + cosazss * p_atmosBha * (xmu_1 * 00341 xmunot_1 - ymu_1 * ymunot_1); 00342 p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * xystuff; 00343 00344 // xmitted surface term uses gammas from m=0 00345 p_trans = gmunot * gmu; 00346 00347 // finally, never-scattered term is given by pure attenuation 00348 p_trans0 = emunot * emu; 00349 } 00350 } 00351 00352 extern "C" Isis::AtmosModel *Anisotropic2Plugin (Isis::Pvl &pvl, 00353 Isis::PhotoModel &pmodel) { 00354 00355 return new Isis::Anisotropic2(pvl,pmodel); 00356 }