USGS

Isis 3.0 Object Programmers' Reference

Home

Anisotropic2.cpp

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 }