USGS

Isis 3.0 Object Programmers' Reference

Home

NumericalAtmosApprox.cpp

Go to the documentation of this file.
00001 
00023 #include <cmath>
00024 #include "AtmosModel.h"
00025 #include "NumericalAtmosApprox.h"
00026 #include "NumericalApproximation.h"
00027 #include "iException.h"
00028 #include "iString.h"
00029 
00030 using namespace std;
00031 namespace Isis {
00068   double NumericalAtmosApprox::RombergsMethod (AtmosModel *am, IntegFunc sub, double a, double b) throw (iException &){
00069     // This method was derived from an algorithm in the text 
00070     // Numerical Recipes in C: The Art of Scientific Computing
00071     // Section 4.3 by Flannery, Press, Teukolsky, and Vetterling
00072     int maxits = 20;       // maximium number of iterations allowed to converge
00073     double dss = 0;        // error estimate for 
00074     double h[maxits+1];    // relative stepsizes for trap
00075     double trap[maxits+1]; // successive trapeziodal approximations
00076     double epsilon;        // desired fractional accuracy
00077     double epsilon2;       // desired fractional accuracy
00078     double ss;             // result
00079 
00080     epsilon = 1.0e-4;
00081     epsilon2 = 1.0e-6;
00082 
00083     h[0] = 1.0;
00084     try{
00085       NumericalApproximation interp(NumericalApproximation::PolynomialNeville);
00086       for (int i=0; i<maxits; i++) { 
00087         // i will determine number of trapezoidal partitions of area  
00088         // under curve for "integration" using refined trapezoidal rule
00089         trap[i] = RefineExtendedTrap(am,sub,a,b,trap[i],i+1); // validates data here
00090         if (i >= 4) {
00091           interp.AddData(5, &h[i-4], &trap[i-4]);
00092           ss = interp.Evaluate(0.0,NumericalApproximation::Extrapolate);
00093           dss = interp.PolynomialNevilleErrorEstimate()[0];
00094           interp.Reset();
00095           // we work only until our necessary accuracy is achieved
00096           if (fabs(dss) <= epsilon*fabs(ss)) return ss;
00097           if (fabs(dss) <= epsilon2) return ss;
00098         }
00099         trap[i+1] = trap[i];
00100         h[i+1] = 0.25 * h[i];
00101         // This is a key step:  the factor is 0.25d0 even though    
00102         // the stepsize is decreased by 0.5d0.  This makes the      
00103         // extraplolation a polynomial in h-squared as allowed      
00104         // by the equation from Numerical Recipes 4.2.1 pg.132, 
00105         // not just a polynomial in h.
00106       }
00107     }
00108     catch (iException e){ // catch error from RefineExtendedTrap, Constructor, Evaluate, PolynomialNevilleErrorEstimate
00109       throw e.Message(e.Type(),
00110                       "NumericalAtmosApprox::RombergsMethod() - Caught the following error: ",
00111                       _FILEINFO_);
00112     }
00113     throw iException::Message(iException::Programmer, 
00114                               "NumericalAtmosApprox::RombergsMethod() - Failed to converge in " 
00115                               + iString(maxits) + " iterations.", 
00116                               _FILEINFO_);
00117   }
00118 
00151   double NumericalAtmosApprox::RefineExtendedTrap(AtmosModel *am, IntegFunc sub, double a, double b, double s, unsigned int n) throw (iException &){
00152     // This method was derived from an algorithm in the text 
00153     // Numerical Recipes in C: The Art of Scientific Computing
00154     // Section 4.2 by Flannery, Press, Teukolsky, and Vetterling
00155     try{
00156       if (n == 1) {
00157         double begin;
00158         double end;
00159         if (sub == InnerFunction) {
00160           begin = InrFunc2Bint(am,a);
00161           end = InrFunc2Bint(am,b);
00162         }
00163         else {
00164           begin = OutrFunc2Bint(am,a);
00165           end = OutrFunc2Bint(am,b);
00166         }
00167         return (0.5 * (b - a) * (begin + end));
00168       }
00169       else {
00170         int it;
00171         double delta,tnm,x,sum;
00172         it = (int)(pow(2.0,(double)(n-2)));
00173         tnm = it;
00174         delta = (b - a) / tnm; // spacing of the points to be added
00175         x = a + 0.5 * delta;
00176         sum = 0.0;
00177         for (int i=0; i<it; i++) {
00178           if (sub == InnerFunction) {
00179             sum = sum + InrFunc2Bint(am,x);
00180           }
00181           else {
00182             sum = sum + OutrFunc2Bint(am,x);
00183           }
00184           x = x + delta;
00185         }
00186         return (0.5 * (s + (b - a) * sum / tnm));// replace s with refined value
00187       }
00188     }
00189     catch (iException e){ // catch exception from Evaluate()
00190       throw e.Message(e.Type(),
00191                       "NumericalAtmosApprox::RefineExtendedTrap() - Caught the following error: ",
00192                       _FILEINFO_);
00193     }
00194   }
00195 
00215   double NumericalAtmosApprox::OutrFunc2Bint(AtmosModel *am, double phi) {
00216     double result;
00217     NumericalAtmosApprox::IntegFunc sub;
00218     sub = NumericalAtmosApprox::InnerFunction;
00219 
00220     am->p_atmosPhi = phi;
00221     am->p_atmosCosphi = cos((PI/180.0)*phi);
00222 
00223     NumericalAtmosApprox qromb;
00224     try{
00225       result = qromb.RombergsMethod(am,sub,1.0e-6,1.0);
00226       return result;
00227     }
00228     catch (iException e){ // catch exception from RombergsMethod()
00229       throw e.Message(e.Type(),
00230                       "NumericalAtmosApprox::OutrFunc2Bint() - Caught the following error: ",
00231                       _FILEINFO_);
00232     }
00233   }
00234 
00263   double NumericalAtmosApprox::InrFunc2Bint(AtmosModel *am, double mu) {
00264     double ema;    //pass in mu, get emission angle
00265     double sine;   //sin(ema)
00266     double alpha; 
00267     double phase;  //angle between sun and camera
00268     double result;
00269     double phasefn;//Henyey-Greenstein phase fn
00270     double xx;     //temp var to calculate emunot, emu
00271     double emunot; //exp(-tau/munot)
00272     double emu;    //exp(-tau/mu)
00273     double tfac;   //factor that occurs in the integrals for transmission
00274 
00275     //  calculate the phase angle
00276     //  also calculate any of the other redundant parameters
00277     ema = acos(mu) * (180.0/PI);
00278     sine = sin(ema*(PI/180.0));
00279     if ((am->p_atmosAtmSwitch == 0) || (am->p_atmosAtmSwitch == 2)) { // Reflection phase <= 90
00280       alpha = am->p_atmosSini * sine * am->p_atmosCosphi +
00281           am->p_atmosMunot * mu;
00282     }
00283     else { // Transmission phase <= 90
00284       alpha = am->p_atmosSini * sine * am->p_atmosCosphi -
00285           am->p_atmosMunot * mu;
00286     }
00287     phase = acos(alpha) * (180.0/PI);
00288     //  now evaluate the integrand; all needed parameters
00289     //  have been hidden separately and passed to it in COMMON.
00290     if (am->p_atmosAtmSwitch == 0) {
00291       // integrand for hemispheric albedo
00292       result = mu * am->p_atmosPM->CalcSurfAlbedo(phase,am->p_atmosInc,ema);
00293     }
00294     else {
00295       phasefn = (1.0 - am->AtmosHga() * am->AtmosHga()) /pow((1.0+2.0*am->AtmosHga()*alpha+am->AtmosHga()*am->AtmosHga()),1.5);
00296       xx = -am->AtmosTau() / max(am->p_atmosMunot,1.0e-30);
00297       if (xx < -69.0) {
00298         emunot = 0.0;
00299       }
00300       else if (xx > 69.0) {
00301         emunot = 1.0e30;
00302       }
00303       else {
00304         emunot = exp(xx);
00305       }
00306       xx = -am->AtmosTau() / max(mu,1.0e-30);
00307 
00308       if (xx < -69.0) {
00309         emu = 0.0;
00310       }
00311       else if (xx > 69.0) {
00312         emu = 1.0e30;
00313       }
00314       else {
00315         emu = exp(xx);
00316       }
00317       if (mu == am->p_atmosMunot) {
00318         tfac = am->AtmosTau() * emunot / (am->p_atmosMunot * am->p_atmosMunot);
00319       }
00320       else {
00321         tfac = (emunot - emu) / (am->p_atmosMunot - mu);
00322       }
00323       if (am->p_atmosAtmSwitch == 1) {
00324         result = mu * (phasefn - 1.0) * tfac;
00325       }
00326       else if (am->p_atmosAtmSwitch == 2) {
00327         result = am->p_atmosMunot * mu * (phasefn - 1.0) * (1.0 - emunot * emu) / (am->p_atmosMunot + mu);
00328       }
00329       else if (am->p_atmosAtmSwitch == 3) {
00330         result = -sine * am->p_atmosCosphi * (phasefn - 1.0) * tfac;
00331       }
00332       else {
00333         string msg = "NumericalAtmosApprox::InrFunc2Bint() - Invalid value of atmospheric ";
00334         msg += "switch used as argument to this function";
00335         throw iException::Message(iException::Programmer,msg,_FILEINFO_);
00336       }
00337     }
00338     return result;
00339   }
00340 }//end NumericalAtmosApprox.cpp