USGS

Isis 3.0 Object Programmers' Reference

Home

Anisotropic1.cpp

00001 #include <cmath>
00002 #include "Anisotropic1.h"
00003 #include "AtmosModel.h"
00004 #include "iException.h"
00005 #include "iString.h"
00006 
00007 using std::max;
00008 
00009 namespace Isis {
00010   Anisotropic1::Anisotropic1 (Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl,pmodel) {
00011 
00012     // Set default values
00013     p_atmosAlpha0_0 = 0.0;
00014     p_atmosAlpha1_0 = 0.0;
00015     p_atmosBeta0_0 = 0.0;
00016     p_atmosBeta1_0 = 0.0;
00017     p_atmosDelta_0 = 0.0;
00018     p_atmosDelta_1 = 0.0;
00019     p_atmosDen = 0.0;
00020     p_atmosE2 = 0.0;
00021     p_atmosE3 = 0.0;
00022     p_atmosE4 = 0.0;
00023     p_atmosE5 = 0.0;
00024     p_atmosFac = 0.0;
00025     p_atmosHnorm = 0.003;
00026     p_atmosP0 = 0.0;
00027     p_atmosP1 = 0.0;
00028     p_atmosQ0 = 0.0;
00029     p_atmosQ02p02 = 0.0;
00030     p_atmosQ1 = 0.0;
00031     p_atmosQ12p12 = 0.0;
00032     p_atmosWha2 = 0.0;
00033     p_atmosWham = 0.0;
00034     p_atmosX0_0 = 0.0;
00035     p_atmosX0_1 = 0.0;
00036     p_atmosY0_0 = 0.0;
00037     p_atmosY0_1 = 0.0;
00038 
00039   }
00040 
00051   void Anisotropic1::SetAtmosHnorm (const double hnorm) {
00052     if (hnorm < 0.0) {
00053       std::string msg = "Invalid value of Atmospheric hnorm [" +
00054                         iString(hnorm) + "]";
00055       throw iException::Message(iException::User,msg,_FILEINFO_);
00056     }
00057 
00058     p_atmosHnorm = hnorm;
00059   }
00060 
00082   void Anisotropic1::AtmosModelAlgorithm (double phase, double incidence, double emission)
00083   {
00084     double hpsq1;
00085     double munot,munotp;
00086     double maxval;
00087     double mu,mup;
00088     double xx;
00089     double emunot,emu;
00090     double gmunot,gmu;
00091     double sum,prod;
00092     double cosazss;
00093     double xmunot_0,ymunot_0;
00094     double xmu_0,ymu_0;
00095     double xmunot_1,ymunot_1;
00096     double xmu_1,ymu_1;
00097     double cxx,cyy;
00098     double xystuff;
00099 
00100     if (p_atmosBha == 0.0) {
00101       p_atmosBha = 1.0e-6;
00102     }
00103 
00104     if (p_atmosTau == 0.0) {
00105       p_pstd = 0.0;
00106       p_trans = 1.0;
00107       p_trans0 = 1.0;
00108       p_sbar = 0.0;
00109       return;
00110     }
00111 
00112     if (p_atmosWha == 1.0) {
00113       std::string msg = "Anisotropic conservative case not implemented yet";
00114       throw iException::Message(iException::User,msg,_FILEINFO_);
00115     }
00116 
00117     if (TauOrWhaChanged()) {
00118       // preparation includes exponential integrals e sub 2 through 5
00119       p_atmosWha2 = 0.5 * p_atmosWha;
00120       p_atmosWham = 1.0 - p_atmosWha;
00121       p_atmosE2 = AtmosModel::En(2,p_atmosTau);
00122       p_atmosE3 = AtmosModel::En(3,p_atmosTau);
00123       p_atmosE4 = AtmosModel::En(4,p_atmosTau);
00124       p_atmosE5 = AtmosModel::En(5,p_atmosTau);
00125       // first, get the required quantities for the axisymmetric m=0 part
00126       // zeroth moments of (uncorrected) x and y times characteristic fn
00127       p_atmosX0_0 = p_atmosWha2 * (1.0 + (1.0/3.0) * p_atmosBha * 
00128                                    p_atmosWham);
00129       p_atmosY0_0 = p_atmosWha2 * (p_atmosE2 + p_atmosBha * p_atmosWham * 
00130                                    p_atmosE4);
00131       // higher-order correction term for x and y
00132       p_atmosDelta_0 = (1.0 - (p_atmosX0_0 + p_atmosY0_0) - (1.0 - p_atmosWha *
00133                        (1.0 + (1.0/3.0) * p_atmosBha * p_atmosWham)) / (1.0 - 
00134                        (p_atmosX0_0 - p_atmosY0_0))) / (p_atmosWha * (0.5 - p_atmosE3 + 
00135                        p_atmosBha * p_atmosWham * (0.25 - p_atmosE5)));
00136 
00137       // moments of (corrected) x and y
00138       p_atmosAlpha0_0 = 1.0 + p_atmosDelta_0 * (0.5 - p_atmosE3);
00139       p_atmosAlpha1_0 = 0.5 + p_atmosDelta_0 * ((1.0/3.0) - p_atmosE4);
00140       p_atmosBeta0_0 = p_atmosE2 + p_atmosDelta_0 * (0.5 - p_atmosE3);
00141       p_atmosBeta1_0 = p_atmosE3 + p_atmosDelta_0 * ((1.0/3.0) - p_atmosE4);
00142       // gamma will be a weighted sum of m=0 x and y functions
00143       // but unlike before, call the weights q1 and p1, and we also
00144       // need additional weights q0 and p0
00145       p_atmosFac = 2.0 - p_atmosWha * p_atmosAlpha0_0;
00146       p_atmosDen = pow(p_atmosFac,2.0) - pow(p_atmosWha*p_atmosBeta0_0,2.0);
00147       p_atmosQ0 = p_atmosBha * p_atmosWha * p_atmosWham * (p_atmosFac * 
00148                                p_atmosAlpha1_0 - p_atmosWha * p_atmosBeta0_0 * p_atmosBeta1_0) / 
00149                                p_atmosDen;
00150       p_atmosP0 = p_atmosBha * p_atmosWha * p_atmosWham * (-p_atmosFac * 
00151                                p_atmosBeta1_0 - p_atmosWha * p_atmosBeta0_0 * p_atmosAlpha1_0) / 
00152                                p_atmosDen;
00153       p_atmosQ02p02 = p_atmosQ0 * p_atmosQ0 - p_atmosP0 * p_atmosP0;
00154       p_atmosQ1 = (2.0 * p_atmosWham * p_atmosFac) / p_atmosDen;
00155       p_atmosP1 = (2.0 * p_atmosWham * p_atmosWha * p_atmosBeta0_0) / 
00156                          p_atmosDen;
00157       p_atmosQ12p12 = p_atmosQ1 * p_atmosQ1 - p_atmosP1 * p_atmosP1;
00158       // sbar is total diffuse illumination and comes from moments
00159       p_sbar = 1.0 - 2.0 * (p_atmosQ1 * p_atmosAlpha1_0 + p_atmosP1 * 
00160                             p_atmosBeta1_0);
00161       // we're not done yet!  still have to calculate the m=1 portion
00162       // zeroth moments of (uncorrected) x and y times characteristic fn
00163       p_atmosX0_1 = 0.5 * p_atmosWha2 * p_atmosBha * (1.0 - (1.0/3.0));
00164       p_atmosY0_1 = 0.5 * p_atmosWha2 * p_atmosBha * (p_atmosE2 - p_atmosE4);
00165       // higher-order correction term for x and y
00166       p_atmosDelta_1 = (1.0 - (p_atmosX0_1 + p_atmosY0_1) - (1.0 - 
00167                               (1.0/3.0) * p_atmosWha * p_atmosBha) / (1.0 - (p_atmosX0_1 - 
00168                               p_atmosY0_1))) / (p_atmosWha2 * p_atmosBha * ((0.5 - 0.25) - 
00169                               (p_atmosE3 - p_atmosE5)));
00170       // moments of (corrected) x and y are not needed for m=1, so we're done
00171       SetOldTau(p_atmosTau);
00172       SetOldWha(p_atmosWha);
00173     }
00174 
00175     // correct the path lengths for planetary curvature
00176     hpsq1 = pow((1.0+p_atmosHnorm),2.0) - 1.0;
00177 
00178     if (incidence == 90.0) {
00179       munot = 0.0;
00180     }
00181     else {
00182       munot = cos((PI/180.0)*incidence);
00183     }
00184 
00185     maxval = max(1.0e-30,hpsq1+munot*munot);
00186     munotp = p_atmosHnorm / (sqrt(maxval) - munot);
00187     munotp = max(munotp,p_atmosTau/69.0);
00188     if (emission == 90.0) {
00189       mu = 0.0;
00190     }
00191     else {
00192       mu = cos((PI/180.0)*emission);
00193     }
00194 
00195     maxval = max(1.0e-30,hpsq1+mu*mu);
00196     mup = p_atmosHnorm / (sqrt(maxval) - mu);
00197     mup = max(mup,p_atmosTau/69.0);
00198     // build the x and y functions of mu0 and mu
00199     maxval = max(1.0e-30,munotp);
00200     xx = -p_atmosTau / maxval;
00201 
00202     if (xx < -69.0) {
00203       emunot = 0.0;
00204     }
00205     else if (xx > 69.0) {
00206       emunot = 1.0e30;
00207     }
00208     else {
00209       emunot = exp(-p_atmosTau/munotp);
00210     }
00211 
00212     maxval = max(1.0e-30,mup);
00213     xx = -p_atmosTau / maxval;
00214 
00215     if (xx < -69.0) {
00216       emu = 0.0;
00217     }
00218     else if (xx > 69.0) {
00219       emu = 1.0e30;
00220     }
00221     else {
00222       emu = exp(-p_atmosTau/mup);
00223     }
00224 
00225     // first for m=0
00226     xmunot_0 = 1.0 + p_atmosDelta_0 * munotp * (1.0 - emunot);
00227     ymunot_0 = emunot + p_atmosDelta_0 * munotp * (1.0 - emunot);
00228     xmu_0 = 1.0 + p_atmosDelta_0 * mup * (1.0 - emu);
00229     ymu_0 = emu + p_atmosDelta_0 * mup * (1.0 - emu);
00230 
00231     // then for m=1
00232     xmunot_1 = 1.0 + p_atmosDelta_1 * munotp * (1.0 - emunot);
00233     ymunot_1 = emunot + p_atmosDelta_1 * munotp * (1.0 - emunot);
00234     xmu_1 = 1.0 + p_atmosDelta_1 * mup * (1.0 - emu);
00235     ymu_1 = emu + p_atmosDelta_1 * mup * (1.0 - emu);
00236 
00237     // gamma1 functions come from x and y with m=0
00238     gmunot = p_atmosP1 * xmunot_0 + p_atmosQ1 * ymunot_0;
00239     gmu = p_atmosP1 * xmu_0 + p_atmosQ1 * ymu_0;
00240 
00241     // purely atmos term uses x and y of both orders and is complex
00242     sum = munot + mu;
00243     prod = munot * mu;
00244     cxx = 1.0 - p_atmosQ0 * sum + (p_atmosQ02p02 - p_atmosBha * 
00245                                    p_atmosQ12p12) * prod;
00246     cyy = 1.0 + p_atmosQ0 * sum + (p_atmosQ02p02 - p_atmosBha * 
00247                                    p_atmosQ12p12) * prod;
00248 
00249     if (phase == 90.0) {
00250       cosazss = 0.0 - munot * mu;
00251     }
00252     else {
00253       cosazss = cos((PI/180.0)*phase) - munot * mu;
00254     }
00255 
00256     xystuff = cxx * xmunot_0 * xmu_0 - cyy * ymunot_0 *
00257               ymu_0 - p_atmosP0 * sum * (xmu_0 * ymunot_0 + ymu_0 *
00258               xmunot_0) + cosazss * p_atmosBha * (xmu_1 * 
00259               xmunot_1 - ymu_1 * ymunot_1);
00260     p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * xystuff;
00261 
00262     // xmitted surface term uses gammas from m=0
00263     p_trans = gmunot * gmu;
00264 
00265     // finally, never-scattered term is given by pure attenuation
00266     p_trans0 = emunot * emu;
00267   }
00268 }
00269 
00270 extern "C" Isis::AtmosModel *Anisotropic1Plugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) {
00271   return new Isis::Anisotropic1(pvl,pmodel);
00272 }